@@ -364,6 +364,7 @@ async def test_close(mock_write_object_stream, mock_client):
364364 writer = AsyncAppendableObjectWriter (mock_client , BUCKET , OBJECT )
365365 writer ._is_stream_open = True
366366 writer .offset = 1024
367+ writer .persisted_size = 1024
367368 mock_stream = mock_write_object_stream .return_value
368369 mock_stream .send = mock .AsyncMock ()
369370 mock_stream .recv = mock .AsyncMock (
@@ -435,16 +436,20 @@ async def test_finalize(mock_write_object_stream, mock_client):
435436 mock_stream .recv = mock .AsyncMock (
436437 return_value = _storage_v2 .BidiWriteObjectResponse (resource = mock_resource )
437438 )
439+ mock_stream .close = mock .AsyncMock ()
438440
439441 gcs_object = await writer .finalize ()
440442
441443 mock_stream .send .assert_awaited_once_with (
442444 _storage_v2 .BidiWriteObjectRequest (finish_write = True )
443445 )
444446 mock_stream .recv .assert_awaited_once ()
447+ mock_stream .close .assert_awaited_once ()
445448 assert writer .object_resource == mock_resource
446449 assert writer .persisted_size == 123
447450 assert gcs_object == mock_resource
451+ assert writer ._is_stream_open is False
452+ assert writer .offset is None
448453
449454
450455@pytest .mark .asyncio
@@ -501,30 +506,39 @@ async def test_append_sends_data_in_chunks(mock_write_object_stream, mock_client
501506 writer .persisted_size = 100
502507 mock_stream = mock_write_object_stream .return_value
503508 mock_stream .send = mock .AsyncMock ()
504- writer .simple_flush = mock .AsyncMock ()
505509
506510 data = b"a" * (_MAX_CHUNK_SIZE_BYTES + 1 )
511+ mock_stream .recv = mock .AsyncMock (
512+ return_value = _storage_v2 .BidiWriteObjectResponse (
513+ persisted_size = 100 + len (data )
514+ )
515+ )
516+
507517 await writer .append (data )
508518
509519 assert mock_stream .send .await_count == 2
510- first_call = mock_stream .send .await_args_list [0 ]
511- second_call = mock_stream .send .await_args_list [1 ]
520+ first_request = mock_stream .send .await_args_list [ 0 ]. args [0 ]
521+ second_request = mock_stream .send .await_args_list [1 ]. args [ 0 ]
512522
513523 # First chunk
514- assert first_call [ 0 ][ 0 ] .write_offset == 100
515- assert len (first_call [ 0 ][ 0 ] .checksummed_data .content ) == _MAX_CHUNK_SIZE_BYTES
516- assert first_call [ 0 ][ 0 ] .checksummed_data .crc32c == int .from_bytes (
524+ assert first_request .write_offset == 100
525+ assert len (first_request .checksummed_data .content ) == _MAX_CHUNK_SIZE_BYTES
526+ assert first_request .checksummed_data .crc32c == int .from_bytes (
517527 Checksum (data [:_MAX_CHUNK_SIZE_BYTES ]).digest (), byteorder = "big"
518528 )
519- # Second chunk
520- assert second_call [0 ][0 ].write_offset == 100 + _MAX_CHUNK_SIZE_BYTES
521- assert len (second_call [0 ][0 ].checksummed_data .content ) == 1
522- assert second_call [0 ][0 ].checksummed_data .crc32c == int .from_bytes (
529+ assert not first_request .flush
530+ assert not first_request .state_lookup
531+
532+ # Second chunk (last chunk)
533+ assert second_request .write_offset == 100 + _MAX_CHUNK_SIZE_BYTES
534+ assert len (second_request .checksummed_data .content ) == 1
535+ assert second_request .checksummed_data .crc32c == int .from_bytes (
523536 Checksum (data [_MAX_CHUNK_SIZE_BYTES :]).digest (), byteorder = "big"
524537 )
538+ assert second_request .flush
539+ assert second_request .state_lookup
525540
526541 assert writer .offset == 100 + len (data )
527- writer .simple_flush .assert_not_awaited ()
528542
529543
530544@pytest .mark .asyncio
@@ -541,12 +555,25 @@ async def test_append_flushes_when_buffer_is_full(
541555 writer .persisted_size = 0
542556 mock_stream = mock_write_object_stream .return_value
543557 mock_stream .send = mock .AsyncMock ()
544- writer . simple_flush = mock .AsyncMock ()
558+ mock_stream . recv = mock .AsyncMock ()
545559
546560 data = b"a" * _DEFAULT_FLUSH_INTERVAL_BYTES
547561 await writer .append (data )
548562
549- writer .simple_flush .assert_awaited_once ()
563+ num_chunks = _DEFAULT_FLUSH_INTERVAL_BYTES // _MAX_CHUNK_SIZE_BYTES
564+ assert mock_stream .send .await_count == num_chunks
565+
566+ # All but the last request should not have flush or state_lookup set.
567+ for i in range (num_chunks - 1 ):
568+ request = mock_stream .send .await_args_list [i ].args [0 ]
569+ assert not request .flush
570+ assert not request .state_lookup
571+
572+ # The last request should have flush and state_lookup set.
573+ last_request = mock_stream .send .await_args_list [- 1 ].args [0 ]
574+ assert last_request .flush
575+ assert last_request .state_lookup
576+ assert writer .bytes_appended_since_last_flush == 0
550577
551578
552579@pytest .mark .asyncio
@@ -561,12 +588,18 @@ async def test_append_handles_large_data(mock_write_object_stream, mock_client):
561588 writer .persisted_size = 0
562589 mock_stream = mock_write_object_stream .return_value
563590 mock_stream .send = mock .AsyncMock ()
564- writer . simple_flush = mock .AsyncMock ()
591+ mock_stream . recv = mock .AsyncMock ()
565592
566593 data = b"a" * (_DEFAULT_FLUSH_INTERVAL_BYTES * 2 + 1 )
567594 await writer .append (data )
568595
569- assert writer .simple_flush .await_count == 2
596+ flushed_requests = [
597+ call .args [0 ] for call in mock_stream .send .await_args_list if call .args [0 ].flush
598+ ]
599+ assert len (flushed_requests ) == 3
600+
601+ last_request = mock_stream .send .await_args_list [- 1 ].args [0 ]
602+ assert last_request .state_lookup
570603
571604
572605@pytest .mark .asyncio
@@ -584,17 +617,35 @@ async def test_append_data_two_times(mock_write_object_stream, mock_client):
584617 writer .persisted_size = 0
585618 mock_stream = mock_write_object_stream .return_value
586619 mock_stream .send = mock .AsyncMock ()
587- writer .simple_flush = mock .AsyncMock ()
588620
589621 data1 = b"a" * (_MAX_CHUNK_SIZE_BYTES + 10 )
622+ mock_stream .recv = mock .AsyncMock (
623+ return_value = _storage_v2 .BidiWriteObjectResponse (
624+ persisted_size = len (data1 )
625+ )
626+ )
590627 await writer .append (data1 )
591628
629+ assert mock_stream .send .await_count == 2
630+ last_request_data1 = mock_stream .send .await_args_list [- 1 ].args [0 ]
631+ assert last_request_data1 .flush
632+ assert last_request_data1 .state_lookup
633+
592634 data2 = b"b" * (_MAX_CHUNK_SIZE_BYTES + 20 )
635+ mock_stream .recv = mock .AsyncMock (
636+ return_value = _storage_v2 .BidiWriteObjectResponse (
637+ persisted_size = len (data2 ) + len (data1 )
638+ )
639+ )
593640 await writer .append (data2 )
594641
642+ assert mock_stream .send .await_count == 4
643+ last_request_data2 = mock_stream .send .await_args_list [- 1 ].args [0 ]
644+ assert last_request_data2 .flush
645+ assert last_request_data2 .state_lookup
646+
595647 total_data_length = len (data1 ) + len (data2 )
596648 assert writer .offset == total_data_length
597- assert writer .simple_flush .await_count == 0
598649
599650
600651@pytest .mark .asyncio
0 commit comments