@@ -108,6 +108,140 @@ TEST(AsyncWriterTest, FinalizeEmpty) {
108108 EXPECT_STATUS_OK (actual);
109109}
110110
111+ TEST (AsyncWriterTest, Flush) {
112+ auto mock = std::make_unique<MockAsyncWriterConnection>();
113+ ::testing::InSequence sequence;
114+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
115+ return make_ready_future (Status{});
116+ });
117+
118+ AsyncWriter writer (std::move (mock));
119+ auto const actual = writer.Flush ().get ();
120+ EXPECT_STATUS_OK (actual);
121+ }
122+
123+ TEST (AsyncWriterTest, ErrorOnFlush) {
124+ auto mock = std::make_unique<MockAsyncWriterConnection>();
125+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
126+ return make_ready_future (PermanentError ());
127+ });
128+
129+ AsyncWriter writer (std::move (mock));
130+ auto const actual = writer.Flush ().get ();
131+ EXPECT_THAT (actual, StatusIs (PermanentError ().code ()));
132+ }
133+
134+ TEST (AsyncWriterTest, FlushOnDefaultConstructed) {
135+ AsyncWriter writer;
136+ auto const actual = writer.Flush ().get ();
137+ EXPECT_THAT (actual, StatusIs (StatusCode::kCancelled , " closed stream" ));
138+ }
139+
140+ TEST (AsyncWriterTest, FlushThenWrite) {
141+ auto mock = std::make_unique<MockAsyncWriterConnection>();
142+ auto * mock_ptr = mock.get ();
143+ ::testing::InSequence sequence;
144+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
145+ return make_ready_future (Status{});
146+ });
147+ EXPECT_CALL (*mock, Write).WillOnce ([](auto const &) {
148+ return make_ready_future (Status{});
149+ });
150+
151+ AsyncWriter writer (std::move (mock));
152+ ASSERT_STATUS_OK (writer.Flush ().get ());
153+
154+ auto token = storage_internal::MakeAsyncToken (mock_ptr);
155+ auto const actual = writer.Write (std::move (token), {}).get ();
156+ EXPECT_STATUS_OK (actual);
157+ }
158+
159+ TEST (AsyncWriterTest, MultipleFlushesAreQueuedAndSequential) {
160+ auto mock = std::make_unique<MockAsyncWriterConnection>();
161+ ::testing::InSequence sequence;
162+ // Expect three flushes, each with empty payload, and simulate delayed
163+ // completion.
164+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
165+ // Simulate async completion for first flush
166+ return make_ready_future (Status{});
167+ });
168+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
169+ // Simulate async completion for second flush
170+ return make_ready_future (Status{});
171+ });
172+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
173+ // Simulate async completion for third flush
174+ return make_ready_future (Status{});
175+ });
176+
177+ AsyncWriter writer (std::move (mock));
178+ // Issue three flushes in quick succession
179+ auto f1 = writer.Flush ();
180+ auto f2 = writer.Flush ();
181+ auto f3 = writer.Flush ();
182+
183+ // All futures should be satisfied in order
184+ EXPECT_STATUS_OK (f1.get ());
185+ EXPECT_STATUS_OK (f2.get ());
186+ EXPECT_STATUS_OK (f3.get ());
187+ }
188+
189+ TEST (AsyncWriterTest, Close) {
190+ auto mock = std::make_unique<MockAsyncWriterConnection>();
191+ ::testing::InSequence sequence;
192+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
193+ return make_ready_future (Status{});
194+ });
195+
196+ AsyncWriter writer (std::move (mock));
197+ auto const actual = writer.Close ().get ();
198+ EXPECT_STATUS_OK (actual);
199+ }
200+
201+ TEST (AsyncWriterTest, CloseOnDefaultConstructed) {
202+ AsyncWriter writer;
203+ auto const actual = writer.Close ().get ();
204+ EXPECT_THAT (actual, StatusIs (StatusCode::kCancelled , " closed stream" ));
205+ }
206+
207+ TEST (AsyncWriterTest, CloseOnMovedWriter) {
208+ auto mock = std::make_unique<MockAsyncWriterConnection>();
209+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
210+ return make_ready_future (Status{});
211+ });
212+ AsyncWriter writer (std::move (mock));
213+ AsyncWriter moved (std::move (writer));
214+ auto const actual = moved.Close ().get ();
215+ EXPECT_STATUS_OK (actual);
216+ }
217+
218+ TEST (AsyncWriterTest, ErrorOnWriteAfterClose) {
219+ auto mock = std::make_unique<MockAsyncWriterConnection>();
220+ auto * mock_ptr = mock.get ();
221+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
222+ return make_ready_future (Status{});
223+ });
224+
225+ AsyncWriter writer (std::move (mock));
226+ ASSERT_STATUS_OK (writer.Close ().get ());
227+
228+ // Create a token for the (now invalid) writer.
229+ auto token = storage_internal::MakeAsyncToken (mock_ptr);
230+ auto const actual = writer.Write (std::move (token), {}).get ();
231+ EXPECT_THAT (actual, StatusIs (StatusCode::kCancelled ));
232+ }
233+
234+ TEST (AsyncWriterTest, ErrorOnClose) {
235+ auto mock = std::make_unique<MockAsyncWriterConnection>();
236+ EXPECT_CALL (*mock, Flush (WritePayloadContents (IsEmpty ()))).WillOnce ([] {
237+ return make_ready_future (PermanentError ());
238+ });
239+
240+ AsyncWriter writer (std::move (mock));
241+ auto const actual = writer.Close ().get ();
242+ EXPECT_THAT (actual, StatusIs (PermanentError ().code ()));
243+ }
244+
111245TEST (AsyncWriterTest, ErrorDuringWrite) {
112246 auto mock = std::make_unique<MockAsyncWriterConnection>();
113247 EXPECT_CALL (*mock, Write).WillOnce ([] {
0 commit comments