1 // Copyright 2015 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <brillo/streams/stream.h>
6 
7 #include <limits>
8 
9 #include <base/callback.h>
10 #include <gmock/gmock.h>
11 #include <gtest/gtest.h>
12 
13 #include <brillo/bind_lambda.h>
14 #include <brillo/message_loops/fake_message_loop.h>
15 #include <brillo/streams/stream_errors.h>
16 
17 using testing::DoAll;
18 using testing::InSequence;
19 using testing::Return;
20 using testing::SaveArg;
21 using testing::SetArgPointee;
22 using testing::_;
23 
24 namespace brillo {
25 
26 using AccessMode = Stream::AccessMode;
27 using Whence = Stream::Whence;
28 
29 // To verify "non-trivial" methods implemented in Stream, mock out the
30 // "trivial" methods to make sure the ones we are interested in testing
31 // actually end up calling the expected methods with right parameters.
32 class MockStreamImpl : public Stream {
33  public:
34   MockStreamImpl() = default;
35 
36   MOCK_CONST_METHOD0(IsOpen, bool());
37   MOCK_CONST_METHOD0(CanRead, bool());
38   MOCK_CONST_METHOD0(CanWrite, bool());
39   MOCK_CONST_METHOD0(CanSeek, bool());
40   MOCK_CONST_METHOD0(CanGetSize, bool());
41 
42   MOCK_CONST_METHOD0(GetSize, uint64_t());
43   MOCK_METHOD2(SetSizeBlocking, bool(uint64_t, ErrorPtr*));
44   MOCK_CONST_METHOD0(GetRemainingSize, uint64_t());
45 
46   MOCK_CONST_METHOD0(GetPosition, uint64_t());
47   MOCK_METHOD4(Seek, bool(int64_t, Whence, uint64_t*, ErrorPtr*));
48 
49   // Omitted: ReadAsync
50   // Omitted: ReadAllAsync
51   MOCK_METHOD5(ReadNonBlocking, bool(void*, size_t, size_t*, bool*, ErrorPtr*));
52   // Omitted: ReadBlocking
53   // Omitted: ReadAllBlocking
54 
55   // Omitted: WriteAsync
56   // Omitted: WriteAllAsync
57   MOCK_METHOD4(WriteNonBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
58   // Omitted: WriteBlocking
59   // Omitted: WriteAllBlocking
60 
61   MOCK_METHOD1(FlushBlocking, bool(ErrorPtr*));
62   MOCK_METHOD1(CloseBlocking, bool(ErrorPtr*));
63 
64   MOCK_METHOD3(WaitForData, bool(AccessMode,
65                                  const base::Callback<void(AccessMode)>&,
66                                  ErrorPtr*));
67   MOCK_METHOD4(WaitForDataBlocking,
68                bool(AccessMode, base::TimeDelta, AccessMode*, ErrorPtr*));
69 
70  private:
71   DISALLOW_COPY_AND_ASSIGN(MockStreamImpl);
72 };
73 
TEST(Stream,TruncateBlocking)74 TEST(Stream, TruncateBlocking) {
75   MockStreamImpl stream_mock;
76   EXPECT_CALL(stream_mock, GetPosition()).WillOnce(Return(123));
77   EXPECT_CALL(stream_mock, SetSizeBlocking(123, _)).WillOnce(Return(true));
78   EXPECT_TRUE(stream_mock.TruncateBlocking(nullptr));
79 }
80 
TEST(Stream,SetPosition)81 TEST(Stream, SetPosition) {
82   MockStreamImpl stream_mock;
83   EXPECT_CALL(stream_mock, Seek(12345, Whence::FROM_BEGIN, _, _))
84       .WillOnce(Return(true));
85   EXPECT_TRUE(stream_mock.SetPosition(12345, nullptr));
86 
87   // Test too large an offset (that doesn't fit in signed 64 bit value).
88   ErrorPtr error;
89   uint64_t max_offset = std::numeric_limits<int64_t>::max();
90   EXPECT_CALL(stream_mock, Seek(max_offset, _, _, _))
91       .WillOnce(Return(true));
92   EXPECT_TRUE(stream_mock.SetPosition(max_offset, nullptr));
93 
94   EXPECT_FALSE(stream_mock.SetPosition(max_offset + 1, &error));
95   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
96   EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
97 }
98 
TEST(Stream,ReadAsync)99 TEST(Stream, ReadAsync) {
100   size_t read_size = 0;
101   bool succeeded = false;
102   bool failed = false;
103   auto success_callback = [](size_t* read_size, bool* succeeded,size_t size) {
104     *read_size = size;
105     *succeeded = true;
106   };
107   auto error_callback = [](bool* failed, const Error* /* error */) {
108     *failed = true;
109   };
110 
111   MockStreamImpl stream_mock;
112   base::Callback<void(AccessMode)> data_callback;
113   char buf[10];
114 
115   // This sets up an initial non blocking read that would block, so ReadAsync()
116   // should wait for more data.
117   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
118       .WillOnce(
119           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
120   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
121       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
122   EXPECT_TRUE(stream_mock.ReadAsync(
123       buf,
124       sizeof(buf),
125       base::Bind(success_callback,
126                  base::Unretained(&read_size),
127                  base::Unretained(&succeeded)),
128       base::Bind(error_callback, base::Unretained(&failed)),
129       nullptr));
130   EXPECT_EQ(0u, read_size);
131   EXPECT_FALSE(succeeded);
132   EXPECT_FALSE(failed);
133 
134   // Since the previous call is waiting for the data to be available, we can't
135   // schedule another read.
136   ErrorPtr error;
137   EXPECT_FALSE(stream_mock.ReadAsync(
138       buf,
139       sizeof(buf),
140       base::Bind(success_callback,
141                  base::Unretained(&read_size),
142                  base::Unretained(&succeeded)),
143       base::Bind(error_callback, base::Unretained(&failed)),
144       &error));
145   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
146   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
147   EXPECT_EQ("Another asynchronous operation is still pending",
148             error->GetMessage());
149 
150   // Making the data available via data_callback should not schedule the
151   // success callback from the main loop and run it directly instead.
152   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
153       .WillOnce(DoAll(SetArgPointee<2>(7),
154                       SetArgPointee<3>(false),
155                       Return(true)));
156   data_callback.Run(AccessMode::READ);
157   EXPECT_EQ(7u, read_size);
158   EXPECT_FALSE(failed);
159 }
160 
TEST(Stream,ReadAsync_DontWaitForData)161 TEST(Stream, ReadAsync_DontWaitForData) {
162   bool succeeded = false;
163   bool failed = false;
164   auto success_callback = [](bool* succeeded, size_t /* size */) {
165     *succeeded = true;
166   };
167   auto error_callback = [](bool* failed, const Error* /* error */) {
168     *failed = true;
169   };
170 
171   MockStreamImpl stream_mock;
172   char buf[10];
173   FakeMessageLoop fake_loop_{nullptr};
174   fake_loop_.SetAsCurrent();
175 
176   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
177       .WillOnce(
178           DoAll(SetArgPointee<2>(5), SetArgPointee<3>(false), Return(true)));
179   EXPECT_CALL(stream_mock, WaitForData(_, _, _)).Times(0);
180   EXPECT_TRUE(stream_mock.ReadAsync(
181       buf,
182       sizeof(buf),
183       base::Bind(success_callback, base::Unretained(&succeeded)),
184       base::Bind(error_callback, base::Unretained(&failed)),
185       nullptr));
186   // Even if ReadNonBlocking() returned some data without waiting, the
187   // |success_callback| should not run yet.
188   EXPECT_TRUE(fake_loop_.PendingTasks());
189   EXPECT_FALSE(succeeded);
190   EXPECT_FALSE(failed);
191 
192   // Since the previous callback is still waiting in the main loop, we can't
193   // schedule another read yet.
194   ErrorPtr error;
195   EXPECT_FALSE(stream_mock.ReadAsync(
196       buf,
197       sizeof(buf),
198       base::Bind(success_callback, base::Unretained(&succeeded)),
199       base::Bind(error_callback, base::Unretained(&failed)),
200       &error));
201   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
202   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
203   EXPECT_EQ("Another asynchronous operation is still pending",
204             error->GetMessage());
205 
206   fake_loop_.Run();
207   EXPECT_TRUE(succeeded);
208   EXPECT_FALSE(failed);
209 }
210 
TEST(Stream,ReadAllAsync)211 TEST(Stream, ReadAllAsync) {
212   bool succeeded = false;
213   bool failed = false;
214   auto success_callback = [](bool* succeeded) { *succeeded = true; };
215   auto error_callback = [](bool* failed, const Error* /* error */) {
216     *failed = true;
217   };
218 
219   MockStreamImpl stream_mock;
220   base::Callback<void(AccessMode)> data_callback;
221   char buf[10];
222 
223   // This sets up an initial non blocking read that would block, so
224   // ReadAllAsync() should wait for more data.
225   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
226       .WillOnce(
227           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
228   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
229       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
230   EXPECT_TRUE(stream_mock.ReadAllAsync(
231       buf,
232       sizeof(buf),
233       base::Bind(success_callback, base::Unretained(&succeeded)),
234       base::Bind(error_callback, base::Unretained(&failed)),
235       nullptr));
236   EXPECT_FALSE(succeeded);
237   EXPECT_FALSE(failed);
238   testing::Mock::VerifyAndClearExpectations(&stream_mock);
239 
240   // ReadAllAsync() will try to read non blocking until the read would block
241   // before it waits for the data to be available again.
242   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
243       .WillOnce(DoAll(SetArgPointee<2>(7),
244                       SetArgPointee<3>(false),
245                       Return(true)));
246   EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
247       .WillOnce(
248           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
249   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
250       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
251   data_callback.Run(AccessMode::READ);
252   EXPECT_FALSE(succeeded);
253   EXPECT_FALSE(failed);
254   testing::Mock::VerifyAndClearExpectations(&stream_mock);
255 
256   EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
257       .WillOnce(DoAll(SetArgPointee<2>(3),
258                       SetArgPointee<3>(true),
259                       Return(true)));
260   data_callback.Run(AccessMode::READ);
261   EXPECT_TRUE(succeeded);
262   EXPECT_FALSE(failed);
263 }
264 
TEST(Stream,ReadAllAsync_EOS)265 TEST(Stream, ReadAllAsync_EOS) {
266   bool succeeded = false;
267   bool failed = false;
268   auto success_callback = [](bool* succeeded) { *succeeded = true; };
269   auto error_callback = [](bool* failed, const Error* error) {
270     ASSERT_EQ(errors::stream::kDomain, error->GetDomain());
271     ASSERT_EQ(errors::stream::kPartialData, error->GetCode());
272     *failed = true;
273   };
274 
275   MockStreamImpl stream_mock;
276   base::Callback<void(AccessMode)> data_callback;
277   char buf[10];
278 
279   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
280       .WillOnce(
281           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
282   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
283       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
284   EXPECT_TRUE(stream_mock.ReadAllAsync(
285       buf,
286       sizeof(buf),
287       base::Bind(success_callback, base::Unretained(&succeeded)),
288       base::Bind(error_callback, base::Unretained(&failed)),
289       nullptr));
290 
291   // ReadAsyncAll() should finish and fail once ReadNonBlocking() returns an
292   // end-of-stream condition.
293   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
294       .WillOnce(DoAll(SetArgPointee<2>(7),
295                       SetArgPointee<3>(true),
296                       Return(true)));
297   data_callback.Run(AccessMode::READ);
298   EXPECT_FALSE(succeeded);
299   EXPECT_TRUE(failed);
300 }
301 
TEST(Stream,ReadBlocking)302 TEST(Stream, ReadBlocking) {
303   MockStreamImpl stream_mock;
304   char buf[1024];
305   size_t read = 0;
306 
307   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
308       .WillOnce(DoAll(SetArgPointee<2>(24),
309                       SetArgPointee<3>(false),
310                       Return(true)));
311   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
312   EXPECT_EQ(24, read);
313 
314   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
315       .WillOnce(DoAll(SetArgPointee<2>(0),
316                       SetArgPointee<3>(true),
317                       Return(true)));
318   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
319   EXPECT_EQ(0, read);
320 
321   {
322     InSequence seq;
323     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
324         .WillOnce(DoAll(SetArgPointee<2>(0),
325                         SetArgPointee<3>(false),
326                         Return(true)));
327     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
328         .WillOnce(Return(true));
329     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
330         .WillOnce(DoAll(SetArgPointee<2>(0),
331                         SetArgPointee<3>(false),
332                         Return(true)));
333     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
334         .WillOnce(Return(true));
335     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
336         .WillOnce(DoAll(SetArgPointee<2>(124),
337                         SetArgPointee<3>(false),
338                         Return(true)));
339   }
340   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
341   EXPECT_EQ(124, read);
342 
343   {
344     InSequence seq;
345     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
346         .WillOnce(DoAll(SetArgPointee<2>(0),
347                         SetArgPointee<3>(false),
348                         Return(true)));
349     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
350         .WillOnce(Return(false));
351   }
352   EXPECT_FALSE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
353 }
354 
TEST(Stream,ReadAllBlocking)355 TEST(Stream, ReadAllBlocking) {
356   class MockReadBlocking : public MockStreamImpl {
357    public:
358     MOCK_METHOD4(ReadBlocking, bool(void*, size_t, size_t*, ErrorPtr*));
359   } stream_mock;
360 
361   char buf[1024];
362 
363   EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
364       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
365   EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
366       .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
367   EXPECT_TRUE(stream_mock.ReadAllBlocking(buf, sizeof(buf), nullptr));
368 
369   ErrorPtr error;
370   EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
371       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
372   EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
373       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
374   EXPECT_FALSE(stream_mock.ReadAllBlocking(buf, sizeof(buf), &error));
375   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
376   EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
377 }
378 
TEST(Stream,WriteAsync)379 TEST(Stream, WriteAsync) {
380   size_t write_size = 0;
381   bool failed = false;
382   auto success_callback = [](size_t* write_size, size_t size) {
383     *write_size = size;
384   };
385   auto error_callback = [](bool* failed, const Error* /* error */) {
386     *failed = true;
387   };
388 
389   MockStreamImpl stream_mock;
390   InSequence s;
391   base::Callback<void(AccessMode)> data_callback;
392   char buf[10] = {};
393 
394   // WriteNonBlocking returns a blocking situation (size_written = 0) so the
395   // WaitForData() is run.
396   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
397       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
398   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
399       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
400   EXPECT_TRUE(stream_mock.WriteAsync(
401       buf,
402       sizeof(buf),
403       base::Bind(success_callback, base::Unretained(&write_size)),
404       base::Bind(error_callback, base::Unretained(&failed)),
405       nullptr));
406   EXPECT_EQ(0u, write_size);
407   EXPECT_FALSE(failed);
408 
409   ErrorPtr error;
410   EXPECT_FALSE(stream_mock.WriteAsync(
411       buf,
412       sizeof(buf),
413       base::Bind(success_callback, base::Unretained(&write_size)),
414       base::Bind(error_callback, base::Unretained(&failed)),
415       &error));
416   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
417   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
418   EXPECT_EQ("Another asynchronous operation is still pending",
419             error->GetMessage());
420 
421   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
422       .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
423   data_callback.Run(AccessMode::WRITE);
424   EXPECT_EQ(7u, write_size);
425   EXPECT_FALSE(failed);
426 }
427 
TEST(Stream,WriteAllAsync)428 TEST(Stream, WriteAllAsync) {
429   bool succeeded = false;
430   bool failed = false;
431   auto success_callback = [](bool* succeeded) { *succeeded = true; };
432   auto error_callback = [](bool* failed, const Error* /* error */) {
433     *failed = true;
434   };
435 
436   MockStreamImpl stream_mock;
437   base::Callback<void(AccessMode)> data_callback;
438   char buf[10] = {};
439 
440   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
441       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
442   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
443       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
444   EXPECT_TRUE(stream_mock.WriteAllAsync(
445       buf,
446       sizeof(buf),
447       base::Bind(success_callback, base::Unretained(&succeeded)),
448       base::Bind(error_callback, base::Unretained(&failed)),
449       nullptr));
450   testing::Mock::VerifyAndClearExpectations(&stream_mock);
451   EXPECT_FALSE(succeeded);
452   EXPECT_FALSE(failed);
453 
454   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
455       .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
456   EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
457       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
458   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
459       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
460   data_callback.Run(AccessMode::WRITE);
461   testing::Mock::VerifyAndClearExpectations(&stream_mock);
462   EXPECT_FALSE(succeeded);
463   EXPECT_FALSE(failed);
464 
465   EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
466       .WillOnce(DoAll(SetArgPointee<2>(3), Return(true)));
467   data_callback.Run(AccessMode::WRITE);
468   EXPECT_TRUE(succeeded);
469   EXPECT_FALSE(failed);
470 }
471 
TEST(Stream,WriteBlocking)472 TEST(Stream, WriteBlocking) {
473   MockStreamImpl stream_mock;
474   char buf[1024];
475   size_t written = 0;
476 
477   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
478       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
479   EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
480   EXPECT_EQ(24, written);
481 
482   {
483     InSequence seq;
484     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
485           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
486     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
487         .WillOnce(Return(true));
488     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
489           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
490     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
491         .WillOnce(Return(true));
492     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
493           .WillOnce(DoAll(SetArgPointee<2>(124), Return(true)));
494   }
495   EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
496   EXPECT_EQ(124, written);
497 
498   {
499     InSequence seq;
500     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
501           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
502     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
503         .WillOnce(Return(false));
504   }
505   EXPECT_FALSE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
506 }
507 
TEST(Stream,WriteAllBlocking)508 TEST(Stream, WriteAllBlocking) {
509   class MockWritelocking : public MockStreamImpl {
510    public:
511     MOCK_METHOD4(WriteBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
512   } stream_mock;
513 
514   char buf[1024];
515 
516   EXPECT_CALL(stream_mock, WriteBlocking(buf, 1024, _, _))
517       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
518   EXPECT_CALL(stream_mock, WriteBlocking(buf + 24, 1000, _, _))
519       .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
520   EXPECT_TRUE(stream_mock.WriteAllBlocking(buf, sizeof(buf), nullptr));
521 }
522 
523 }  // namespace brillo
524