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