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