@@ -258,7 +258,7 @@ TEST(WriteConnectionResumed, FlushNonEmpty) {
258258 EXPECT_THAT (write.get (), StatusIs (StatusCode::kOk ));
259259}
260260
261- TEST (WriteConnectionResumed, ResumeUsesGenerationFromFirstResponse ) {
261+ TEST (WriteConnectionResumed, ResumeUsesWriteObjectSpecFromInitialRequest ) {
262262 AsyncSequencer<bool > sequencer;
263263 auto mock = std::make_unique<MockAsyncWriterConnection>();
264264 auto initial_request = google::storage::v2::BidiWriteObjectRequest{};
@@ -316,6 +316,72 @@ TEST(WriteConnectionResumed, ResumeUsesGenerationFromFirstResponse) {
316316 // factory.
317317 EXPECT_THAT (write.get (), StatusIs (StatusCode::kAborted ));
318318
319+ EXPECT_FALSE (captured_request.has_write_object_spec ());
320+ EXPECT_TRUE (captured_request.has_append_object_spec ());
321+ EXPECT_EQ (captured_request.append_object_spec ().generation (), 12345 );
322+ EXPECT_EQ (captured_request.append_object_spec ().object (), " test-object" );
323+ EXPECT_EQ (captured_request.append_object_spec ().bucket (),
324+ " projects/_/buckets/test-bucket" );
325+ }
326+
327+ TEST (WriteConnectionResumed, ResumeUsesAppendObjectSpecFromInitialRequest) {
328+ AsyncSequencer<bool > sequencer;
329+ auto mock = std::make_unique<MockAsyncWriterConnection>();
330+ auto initial_request = google::storage::v2::BidiWriteObjectRequest{};
331+ initial_request.mutable_append_object_spec ()->set_bucket (
332+ " projects/_/buckets/test-bucket" );
333+ initial_request.mutable_append_object_spec ()->set_object (" test-object" );
334+
335+ google::storage::v2::BidiWriteObjectResponse first_response;
336+ first_response.mutable_resource ()->set_generation (12345 );
337+
338+ EXPECT_CALL (*mock, PersistedState)
339+ .WillRepeatedly (Return (MakePersistedState (0 )));
340+
341+ // Expect Flush to be called because flush_ is true by default.
342+ // Make it fail to trigger Resume().
343+ EXPECT_CALL (*mock, Flush (_)).WillOnce ([&](auto ) {
344+ return sequencer.PushBack (" Flush" ).then ([](auto f) {
345+ if (f.get ()) return google::cloud::Status{}; // Should not be true
346+ return TransientError ();
347+ });
348+ });
349+
350+ MockFactory mock_factory;
351+ google::storage::v2::BidiWriteObjectRequest captured_request;
352+ EXPECT_CALL (mock_factory, Call (_))
353+ .WillOnce ([&](google::storage::v2::BidiWriteObjectRequest request) {
354+ captured_request = std::move (request);
355+ return sequencer.PushBack (" Factory" ).then ([](auto ) {
356+ return StatusOr<WriteObject::WriteResult>(
357+ internal::AbortedError (" stop test" , GCP_ERROR_INFO ()));
358+ });
359+ });
360+
361+ auto connection = MakeWriterConnectionResumed (
362+ mock_factory.AsStdFunction (), std::move (mock), initial_request, nullptr ,
363+ first_response, Options{});
364+
365+ // This will call FlushStep -> mock->Flush()
366+ auto write = connection->Write (TestPayload (1 ));
367+ ASSERT_FALSE (write.is_ready ());
368+
369+ // Trigger the Flush error in the mock
370+ auto next = sequencer.PopFrontWithName ();
371+ EXPECT_EQ (next.second , " Flush" );
372+ next.first .set_value (false ); // This makes the lambda return TransientError
373+
374+ // The error in OnFlush triggers Resume(), which calls the mock_factory.
375+ // Allow the factory callback to proceed.
376+ next = sequencer.PopFrontWithName ();
377+ EXPECT_EQ (next.second , " Factory" );
378+ next.first .set_value (true );
379+
380+ // The write future should now be ready, containing the error from the
381+ // factory.
382+ EXPECT_THAT (write.get (), StatusIs (StatusCode::kAborted ));
383+
384+ EXPECT_FALSE (captured_request.has_write_object_spec ());
319385 EXPECT_TRUE (captured_request.has_append_object_spec ());
320386 EXPECT_EQ (captured_request.append_object_spec ().generation (), 12345 );
321387 EXPECT_EQ (captured_request.append_object_spec ().object (), " test-object" );
0 commit comments