@@ -41,8 +41,7 @@ using ::testing::ReturnRef;
4141using ms = std::chrono::milliseconds;
4242
4343/* *
44- * Test the functions in Storage::Client related to writing objects.'Objects:
45- * *'.
44+ * Test the functions in Storage::Client related to writing objects.
4645 */
4746class WriteObjectTest
4847 : public ::google::cloud::storage::testing::ClientUnitTest {};
@@ -118,6 +117,48 @@ TEST_F(WriteObjectTest, WriteObjectPermanentFailure) {
118117 EXPECT_THAT (stream.metadata (), StatusIs (PermanentError ().code ()));
119118}
120119
120+ TEST_F (WriteObjectTest, WriteObjectErrorInChunk) {
121+ auto const session_id = std::string{" test-session-id" };
122+ EXPECT_CALL (*mock_, CreateResumableSession)
123+ .WillOnce ([&](internal::ResumableUploadRequest const & request) {
124+ EXPECT_EQ (" test-bucket-name" , request.bucket_name ());
125+ EXPECT_EQ (" test-object-name" , request.object_name ());
126+
127+ auto mock = absl::make_unique<testing::MockResumableUploadSession>();
128+ using internal::ResumableUploadResponse;
129+ EXPECT_CALL (*mock, done ()).WillRepeatedly (Return (false ));
130+ EXPECT_CALL (*mock, next_expected_byte ()).WillRepeatedly (Return (0 ));
131+ EXPECT_CALL (*mock, UploadChunk)
132+ .WillOnce (Return (Status (StatusCode::kDataLoss , " ooops" )));
133+ EXPECT_CALL (*mock, session_id ()).WillRepeatedly (ReturnRef (session_id));
134+ // The call to Close() below should have no effect and no "final" chunk
135+ // should be uplaoded.
136+ EXPECT_CALL (*mock, UploadFinalChunk).Times (0 );
137+
138+ return make_status_or (
139+ std::unique_ptr<internal::ResumableUploadSession>(std::move (mock)));
140+ });
141+ auto constexpr kQuantum = internal::UploadChunkRequest::kChunkSizeQuantum ;
142+ client_options_.SetUploadBufferSize (kQuantum );
143+ auto client = ClientForMock ();
144+ auto stream = client.WriteObject (" test-bucket-name" , " test-object-name" ,
145+ IfGenerationMatch (0 ));
146+ auto const data = std::string (2 * kQuantum , ' A' );
147+ auto const size = static_cast <std::streamsize>(data.size ());
148+ // The stream is set up to flush for buffers of `data`'s size. This triggers
149+ // the UploadChunk() mock, which returns an error. Because this is a permanent
150+ // error, no further upload attempts are made.
151+ stream.write (data.data (), size);
152+ EXPECT_TRUE (stream.bad ());
153+ EXPECT_THAT (stream.last_status (), StatusIs (StatusCode::kDataLoss ));
154+ stream.write (data.data (), size);
155+ EXPECT_TRUE (stream.bad ());
156+ EXPECT_THAT (stream.last_status (), StatusIs (StatusCode::kDataLoss ));
157+ EXPECT_THAT (stream.metadata (), StatusIs (StatusCode::kUnknown ));
158+ stream.Close ();
159+ EXPECT_THAT (stream.metadata (), StatusIs (StatusCode::kDataLoss ));
160+ }
161+
121162TEST_F (WriteObjectTest, WriteObjectPermanentSessionFailurePropagates) {
122163 auto * mock_session = new testing::MockResumableUploadSession;
123164 auto returner = [mock_session](internal::ResumableUploadRequest const &) {
@@ -154,19 +195,6 @@ class MockFilebuf : public std::filebuf {
154195 }
155196};
156197
157- class MockFilebufStream : public std ::ifstream {
158- public:
159- explicit MockFilebufStream (std::string const & s) {
160- buf_.open (s.c_str (), std::ios_base::in);
161- init (&buf_);
162- clear ();
163- std::cout << " OPEN? " << buf_.is_open () << std::endl;
164- }
165-
166- private:
167- MockFilebuf buf_;
168- };
169-
170198TEST_F (WriteObjectTest, UploadStreamResumable) {
171199 auto const quantum = internal::UploadChunkRequest::kChunkSizeQuantum ;
172200 auto rng = google::cloud::internal::MakeDefaultPRNG ();
0 commit comments