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