• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = [&read_size, &succeeded](size_t size) {
104     read_size = size;
105     succeeded = true;
106   };
107   auto error_callback = [&failed](const Error* /* error */) { failed = true; };
108 
109   MockStreamImpl stream_mock;
110   base::Callback<void(AccessMode)> data_callback;
111   char buf[10];
112 
113   // This sets up an initial non blocking read that would block, so ReadAsync()
114   // should wait for more data.
115   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
116       .WillOnce(
117           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
118   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
119       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
120   EXPECT_TRUE(stream_mock.ReadAsync(buf, sizeof(buf),
121                                     base::Bind(success_callback),
122                                     base::Bind(error_callback), nullptr));
123   EXPECT_EQ(0u, read_size);
124   EXPECT_FALSE(succeeded);
125   EXPECT_FALSE(failed);
126 
127   // Since the previous call is waiting for the data to be available, we can't
128   // schedule another read.
129   ErrorPtr error;
130   EXPECT_FALSE(stream_mock.ReadAsync(buf, sizeof(buf),
131                                      base::Bind(success_callback),
132                                      base::Bind(error_callback), &error));
133   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
134   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
135   EXPECT_EQ("Another asynchronous operation is still pending",
136             error->GetMessage());
137 
138   // Making the data available via data_callback should not schedule the
139   // success callback from the main loop and run it directly instead.
140   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
141       .WillOnce(DoAll(SetArgPointee<2>(7),
142                       SetArgPointee<3>(false),
143                       Return(true)));
144   data_callback.Run(AccessMode::READ);
145   EXPECT_EQ(7u, read_size);
146   EXPECT_FALSE(failed);
147 }
148 
TEST(Stream,ReadAsync_DontWaitForData)149 TEST(Stream, ReadAsync_DontWaitForData) {
150   bool succeeded = false;
151   bool failed = false;
152   auto success_callback = [&succeeded](size_t /* size */) { succeeded = true; };
153   auto error_callback = [&failed](const Error* /* error */) { failed = true; };
154 
155   MockStreamImpl stream_mock;
156   char buf[10];
157   FakeMessageLoop fake_loop_{nullptr};
158   fake_loop_.SetAsCurrent();
159 
160   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
161       .WillOnce(
162           DoAll(SetArgPointee<2>(5), SetArgPointee<3>(false), Return(true)));
163   EXPECT_CALL(stream_mock, WaitForData(_, _, _)).Times(0);
164   EXPECT_TRUE(stream_mock.ReadAsync(buf, sizeof(buf),
165                                     base::Bind(success_callback),
166                                     base::Bind(error_callback), nullptr));
167   // Even if ReadNonBlocking() returned some data without waiting, the
168   // |success_callback| should not run yet.
169   EXPECT_TRUE(fake_loop_.PendingTasks());
170   EXPECT_FALSE(succeeded);
171   EXPECT_FALSE(failed);
172 
173   // Since the previous callback is still waiting in the main loop, we can't
174   // schedule another read yet.
175   ErrorPtr error;
176   EXPECT_FALSE(stream_mock.ReadAsync(buf, sizeof(buf),
177                                      base::Bind(success_callback),
178                                      base::Bind(error_callback), &error));
179   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
180   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
181   EXPECT_EQ("Another asynchronous operation is still pending",
182             error->GetMessage());
183 
184   fake_loop_.Run();
185   EXPECT_TRUE(succeeded);
186   EXPECT_FALSE(failed);
187 }
188 
TEST(Stream,ReadAllAsync)189 TEST(Stream, ReadAllAsync) {
190   bool succeeded = false;
191   bool failed = false;
192   auto success_callback = [&succeeded]() { succeeded = true; };
193   auto error_callback = [&failed](const Error* /* error */) { failed = true; };
194 
195   MockStreamImpl stream_mock;
196   base::Callback<void(AccessMode)> data_callback;
197   char buf[10];
198 
199   // This sets up an initial non blocking read that would block, so
200   // ReadAllAsync() should wait for more data.
201   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
202       .WillOnce(
203           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
204   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
205       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
206   EXPECT_TRUE(stream_mock.ReadAllAsync(buf, sizeof(buf),
207                                        base::Bind(success_callback),
208                                        base::Bind(error_callback),
209                                        nullptr));
210   EXPECT_FALSE(succeeded);
211   EXPECT_FALSE(failed);
212   testing::Mock::VerifyAndClearExpectations(&stream_mock);
213 
214   // ReadAllAsync() will try to read non blocking until the read would block
215   // before it waits for the data to be available again.
216   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
217       .WillOnce(DoAll(SetArgPointee<2>(7),
218                       SetArgPointee<3>(false),
219                       Return(true)));
220   EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
221       .WillOnce(
222           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
223   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
224       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
225   data_callback.Run(AccessMode::READ);
226   EXPECT_FALSE(succeeded);
227   EXPECT_FALSE(failed);
228   testing::Mock::VerifyAndClearExpectations(&stream_mock);
229 
230   EXPECT_CALL(stream_mock, ReadNonBlocking(buf + 7, 3, _, _, _))
231       .WillOnce(DoAll(SetArgPointee<2>(3),
232                       SetArgPointee<3>(true),
233                       Return(true)));
234   data_callback.Run(AccessMode::READ);
235   EXPECT_TRUE(succeeded);
236   EXPECT_FALSE(failed);
237 }
238 
TEST(Stream,ReadAllAsync_EOS)239 TEST(Stream, ReadAllAsync_EOS) {
240   bool succeeded = false;
241   bool failed = false;
242   auto success_callback = [&succeeded]() { succeeded = true; };
243   auto error_callback = [&failed](const Error* error) {
244     ASSERT_EQ(errors::stream::kDomain, error->GetDomain());
245     ASSERT_EQ(errors::stream::kPartialData, error->GetCode());
246     failed = true;
247   };
248 
249   MockStreamImpl stream_mock;
250   base::Callback<void(AccessMode)> data_callback;
251   char buf[10];
252 
253   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
254       .WillOnce(
255           DoAll(SetArgPointee<2>(0), SetArgPointee<3>(false), Return(true)));
256   EXPECT_CALL(stream_mock, WaitForData(AccessMode::READ, _, _))
257       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
258   EXPECT_TRUE(stream_mock.ReadAllAsync(buf, sizeof(buf),
259                                        base::Bind(success_callback),
260                                        base::Bind(error_callback),
261                                        nullptr));
262 
263   // ReadAsyncAll() should finish and fail once ReadNonBlocking() returns an
264   // end-of-stream condition.
265   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 10, _, _, _))
266       .WillOnce(DoAll(SetArgPointee<2>(7),
267                       SetArgPointee<3>(true),
268                       Return(true)));
269   data_callback.Run(AccessMode::READ);
270   EXPECT_FALSE(succeeded);
271   EXPECT_TRUE(failed);
272 }
273 
TEST(Stream,ReadBlocking)274 TEST(Stream, ReadBlocking) {
275   MockStreamImpl stream_mock;
276   char buf[1024];
277   size_t read = 0;
278 
279   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
280       .WillOnce(DoAll(SetArgPointee<2>(24),
281                       SetArgPointee<3>(false),
282                       Return(true)));
283   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
284   EXPECT_EQ(24, read);
285 
286   EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
287       .WillOnce(DoAll(SetArgPointee<2>(0),
288                       SetArgPointee<3>(true),
289                       Return(true)));
290   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
291   EXPECT_EQ(0, read);
292 
293   {
294     InSequence seq;
295     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
296         .WillOnce(DoAll(SetArgPointee<2>(0),
297                         SetArgPointee<3>(false),
298                         Return(true)));
299     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
300         .WillOnce(Return(true));
301     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
302         .WillOnce(DoAll(SetArgPointee<2>(0),
303                         SetArgPointee<3>(false),
304                         Return(true)));
305     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
306         .WillOnce(Return(true));
307     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
308         .WillOnce(DoAll(SetArgPointee<2>(124),
309                         SetArgPointee<3>(false),
310                         Return(true)));
311   }
312   EXPECT_TRUE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
313   EXPECT_EQ(124, read);
314 
315   {
316     InSequence seq;
317     EXPECT_CALL(stream_mock, ReadNonBlocking(buf, 1024, _, _, _))
318         .WillOnce(DoAll(SetArgPointee<2>(0),
319                         SetArgPointee<3>(false),
320                         Return(true)));
321     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::READ, _, _, _))
322         .WillOnce(Return(false));
323   }
324   EXPECT_FALSE(stream_mock.ReadBlocking(buf, sizeof(buf), &read, nullptr));
325 }
326 
TEST(Stream,ReadAllBlocking)327 TEST(Stream, ReadAllBlocking) {
328   class MockReadBlocking : public MockStreamImpl {
329    public:
330     MOCK_METHOD4(ReadBlocking, bool(void*, size_t, size_t*, ErrorPtr*));
331   } stream_mock;
332 
333   char buf[1024];
334 
335   EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
336       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
337   EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
338       .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
339   EXPECT_TRUE(stream_mock.ReadAllBlocking(buf, sizeof(buf), nullptr));
340 
341   ErrorPtr error;
342   EXPECT_CALL(stream_mock, ReadBlocking(buf, 1024, _, _))
343       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
344   EXPECT_CALL(stream_mock, ReadBlocking(buf + 24, 1000, _, _))
345       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
346   EXPECT_FALSE(stream_mock.ReadAllBlocking(buf, sizeof(buf), &error));
347   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
348   EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
349 }
350 
TEST(Stream,WriteAsync)351 TEST(Stream, WriteAsync) {
352   size_t write_size = 0;
353   bool failed = false;
354   auto success_callback = [&write_size](size_t size) { write_size = size; };
355   auto error_callback = [&failed](const Error* /* error */) { failed = true; };
356 
357   MockStreamImpl stream_mock;
358   InSequence s;
359   base::Callback<void(AccessMode)> data_callback;
360   char buf[10] = {};
361 
362   // WriteNonBlocking returns a blocking situation (size_written = 0) so the
363   // WaitForData() is run.
364   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
365       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
366   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
367       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
368   EXPECT_TRUE(stream_mock.WriteAsync(buf, sizeof(buf),
369                                      base::Bind(success_callback),
370                                      base::Bind(error_callback), nullptr));
371   EXPECT_EQ(0u, write_size);
372   EXPECT_FALSE(failed);
373 
374   ErrorPtr error;
375   EXPECT_FALSE(stream_mock.WriteAsync(buf, sizeof(buf),
376                                       base::Bind(success_callback),
377                                       base::Bind(error_callback), &error));
378   EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
379   EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
380   EXPECT_EQ("Another asynchronous operation is still pending",
381             error->GetMessage());
382 
383   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
384       .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
385   data_callback.Run(AccessMode::WRITE);
386   EXPECT_EQ(7u, write_size);
387   EXPECT_FALSE(failed);
388 }
389 
TEST(Stream,WriteAllAsync)390 TEST(Stream, WriteAllAsync) {
391   bool succeeded = false;
392   bool failed = false;
393   auto success_callback = [&succeeded]() { succeeded = true; };
394   auto error_callback = [&failed](const Error* /* error */) { failed = true; };
395 
396   MockStreamImpl stream_mock;
397   base::Callback<void(AccessMode)> data_callback;
398   char buf[10] = {};
399 
400   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
401       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
402   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
403       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
404   EXPECT_TRUE(stream_mock.WriteAllAsync(buf, sizeof(buf),
405                                         base::Bind(success_callback),
406                                         base::Bind(error_callback),
407                                         nullptr));
408   testing::Mock::VerifyAndClearExpectations(&stream_mock);
409   EXPECT_FALSE(succeeded);
410   EXPECT_FALSE(failed);
411 
412   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 10, _, _))
413       .WillOnce(DoAll(SetArgPointee<2>(7), Return(true)));
414   EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
415       .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
416   EXPECT_CALL(stream_mock, WaitForData(AccessMode::WRITE, _, _))
417       .WillOnce(DoAll(SaveArg<1>(&data_callback), Return(true)));
418   data_callback.Run(AccessMode::WRITE);
419   testing::Mock::VerifyAndClearExpectations(&stream_mock);
420   EXPECT_FALSE(succeeded);
421   EXPECT_FALSE(failed);
422 
423   EXPECT_CALL(stream_mock, WriteNonBlocking(buf + 7, 3, _, _))
424       .WillOnce(DoAll(SetArgPointee<2>(3), Return(true)));
425   data_callback.Run(AccessMode::WRITE);
426   EXPECT_TRUE(succeeded);
427   EXPECT_FALSE(failed);
428 }
429 
TEST(Stream,WriteBlocking)430 TEST(Stream, WriteBlocking) {
431   MockStreamImpl stream_mock;
432   char buf[1024];
433   size_t written = 0;
434 
435   EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
436       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
437   EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
438   EXPECT_EQ(24, written);
439 
440   {
441     InSequence seq;
442     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
443           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
444     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
445         .WillOnce(Return(true));
446     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
447           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
448     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
449         .WillOnce(Return(true));
450     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
451           .WillOnce(DoAll(SetArgPointee<2>(124), Return(true)));
452   }
453   EXPECT_TRUE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
454   EXPECT_EQ(124, written);
455 
456   {
457     InSequence seq;
458     EXPECT_CALL(stream_mock, WriteNonBlocking(buf, 1024, _, _))
459           .WillOnce(DoAll(SetArgPointee<2>(0), Return(true)));
460     EXPECT_CALL(stream_mock, WaitForDataBlocking(AccessMode::WRITE, _, _, _))
461         .WillOnce(Return(false));
462   }
463   EXPECT_FALSE(stream_mock.WriteBlocking(buf, sizeof(buf), &written, nullptr));
464 }
465 
TEST(Stream,WriteAllBlocking)466 TEST(Stream, WriteAllBlocking) {
467   class MockWritelocking : public MockStreamImpl {
468    public:
469     MOCK_METHOD4(WriteBlocking, bool(const void*, size_t, size_t*, ErrorPtr*));
470   } stream_mock;
471 
472   char buf[1024];
473 
474   EXPECT_CALL(stream_mock, WriteBlocking(buf, 1024, _, _))
475       .WillOnce(DoAll(SetArgPointee<2>(24), Return(true)));
476   EXPECT_CALL(stream_mock, WriteBlocking(buf + 24, 1000, _, _))
477       .WillOnce(DoAll(SetArgPointee<2>(1000), Return(true)));
478   EXPECT_TRUE(stream_mock.WriteAllBlocking(buf, sizeof(buf), nullptr));
479 }
480 
481 }  // namespace brillo
482