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_utils.h>
6
7 #include <limits>
8
9 #include <base/bind.h>
10 #include <brillo/message_loops/fake_message_loop.h>
11 #include <brillo/message_loops/message_loop.h>
12 #include <brillo/streams/mock_stream.h>
13 #include <brillo/streams/stream_errors.h>
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16
17 using testing::DoAll;
18 using testing::InSequence;
19 using testing::Return;
20 using testing::StrictMock;
21 using testing::_;
22
ACTION_TEMPLATE(InvokeAsyncCallback,HAS_1_TEMPLATE_PARAMS (int,k),AND_1_VALUE_PARAMS (size))23 ACTION_TEMPLATE(InvokeAsyncCallback,
24 HAS_1_TEMPLATE_PARAMS(int, k),
25 AND_1_VALUE_PARAMS(size)) {
26 brillo::MessageLoop::current()->PostTask(
27 FROM_HERE, base::Bind(std::get<k>(args), size));
28 return true;
29 }
30
ACTION_TEMPLATE(InvokeAsyncCallback,HAS_1_TEMPLATE_PARAMS (int,k),AND_0_VALUE_PARAMS ())31 ACTION_TEMPLATE(InvokeAsyncCallback,
32 HAS_1_TEMPLATE_PARAMS(int, k),
33 AND_0_VALUE_PARAMS()) {
34 brillo::MessageLoop::current()->PostTask(FROM_HERE, std::get<k>(args));
35 return true;
36 }
37
ACTION_TEMPLATE(InvokeAsyncErrorCallback,HAS_1_TEMPLATE_PARAMS (int,k),AND_1_VALUE_PARAMS (code))38 ACTION_TEMPLATE(InvokeAsyncErrorCallback,
39 HAS_1_TEMPLATE_PARAMS(int, k),
40 AND_1_VALUE_PARAMS(code)) {
41 brillo::ErrorPtr error;
42 brillo::Error::AddTo(&error, FROM_HERE, "test", code, "message");
43 brillo::MessageLoop::current()->PostTask(
44 FROM_HERE, base::Bind(std::get<k>(args), base::Owned(error.release())));
45 return true;
46 }
47
48 namespace brillo {
49
TEST(StreamUtils,ErrorStreamClosed)50 TEST(StreamUtils, ErrorStreamClosed) {
51 ErrorPtr error;
52 EXPECT_FALSE(stream_utils::ErrorStreamClosed(FROM_HERE, &error));
53 EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
54 EXPECT_EQ(errors::stream::kStreamClosed, error->GetCode());
55 EXPECT_EQ("Stream is closed", error->GetMessage());
56 }
57
TEST(StreamUtils,ErrorOperationNotSupported)58 TEST(StreamUtils, ErrorOperationNotSupported) {
59 ErrorPtr error;
60 EXPECT_FALSE(stream_utils::ErrorOperationNotSupported(FROM_HERE, &error));
61 EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
62 EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode());
63 EXPECT_EQ("Stream operation not supported", error->GetMessage());
64 }
65
TEST(StreamUtils,ErrorReadPastEndOfStream)66 TEST(StreamUtils, ErrorReadPastEndOfStream) {
67 ErrorPtr error;
68 EXPECT_FALSE(stream_utils::ErrorReadPastEndOfStream(FROM_HERE, &error));
69 EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
70 EXPECT_EQ(errors::stream::kPartialData, error->GetCode());
71 EXPECT_EQ("Reading past the end of stream", error->GetMessage());
72 }
73
TEST(StreamUtils,CheckInt64Overflow)74 TEST(StreamUtils, CheckInt64Overflow) {
75 const int64_t max_int64 = std::numeric_limits<int64_t>::max();
76 const uint64_t max_uint64 = std::numeric_limits<uint64_t>::max();
77 EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 0, 0, nullptr));
78 EXPECT_TRUE(stream_utils::CheckInt64Overflow(
79 FROM_HERE, 0, max_int64, nullptr));
80 EXPECT_TRUE(stream_utils::CheckInt64Overflow(
81 FROM_HERE, max_int64, 0, nullptr));
82 EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -90, nullptr));
83 EXPECT_TRUE(stream_utils::CheckInt64Overflow(
84 FROM_HERE, 1000, -1000, nullptr));
85
86 ErrorPtr error;
87 EXPECT_FALSE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -101, &error));
88 EXPECT_EQ(errors::stream::kDomain, error->GetDomain());
89 EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
90 EXPECT_EQ("The stream offset value is out of range", error->GetMessage());
91
92 EXPECT_FALSE(stream_utils::CheckInt64Overflow(
93 FROM_HERE, max_int64, 1, nullptr));
94 EXPECT_FALSE(stream_utils::CheckInt64Overflow(
95 FROM_HERE, max_uint64, 0, nullptr));
96 EXPECT_FALSE(stream_utils::CheckInt64Overflow(
97 FROM_HERE, max_uint64, max_int64, nullptr));
98 }
99
TEST(StreamUtils,CalculateStreamPosition)100 TEST(StreamUtils, CalculateStreamPosition) {
101 using Whence = Stream::Whence;
102 const uint64_t current_pos = 1234;
103 const uint64_t end_pos = 2000;
104 uint64_t pos = 0;
105
106 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
107 FROM_HERE, 0, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr));
108 EXPECT_EQ(0u, pos);
109
110 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
111 FROM_HERE, 0, Whence::FROM_CURRENT, current_pos, end_pos, &pos, nullptr));
112 EXPECT_EQ(current_pos, pos);
113
114 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
115 FROM_HERE, 0, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
116 EXPECT_EQ(end_pos, pos);
117
118 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
119 FROM_HERE, 10, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr));
120 EXPECT_EQ(10u, pos);
121
122 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
123 FROM_HERE, 10, Whence::FROM_CURRENT, current_pos, end_pos, &pos,
124 nullptr));
125 EXPECT_EQ(current_pos + 10, pos);
126
127 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
128 FROM_HERE, 10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
129 EXPECT_EQ(end_pos + 10, pos);
130
131 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
132 FROM_HERE, -10, Whence::FROM_CURRENT, current_pos, end_pos, &pos,
133 nullptr));
134 EXPECT_EQ(current_pos - 10, pos);
135
136 EXPECT_TRUE(stream_utils::CalculateStreamPosition(
137 FROM_HERE, -10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr));
138 EXPECT_EQ(end_pos - 10, pos);
139
140 ErrorPtr error;
141 EXPECT_FALSE(stream_utils::CalculateStreamPosition(
142 FROM_HERE, -1, Whence::FROM_BEGIN, current_pos, end_pos, &pos, &error));
143 EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode());
144 EXPECT_EQ("The stream offset value is out of range", error->GetMessage());
145
146 EXPECT_FALSE(stream_utils::CalculateStreamPosition(
147 FROM_HERE, -1001, Whence::FROM_CURRENT, 1000, end_pos, &pos, nullptr));
148
149 const uint64_t max_int64 = std::numeric_limits<int64_t>::max();
150 EXPECT_FALSE(stream_utils::CalculateStreamPosition(
151 FROM_HERE, 1, Whence::FROM_CURRENT, max_int64, end_pos, &pos, nullptr));
152 }
153
154 class CopyStreamDataTest : public testing::Test {
155 public:
SetUp()156 void SetUp() override {
157 fake_loop_.SetAsCurrent();
158 in_stream_.reset(new StrictMock<MockStream>{});
159 out_stream_.reset(new StrictMock<MockStream>{});
160 }
161
162 FakeMessageLoop fake_loop_{nullptr};
163 std::unique_ptr<StrictMock<MockStream>> in_stream_;
164 std::unique_ptr<StrictMock<MockStream>> out_stream_;
165 bool succeeded_{false};
166 bool failed_{false};
167
OnSuccess(uint64_t expected,StreamPtr,StreamPtr,uint64_t copied)168 void OnSuccess(uint64_t expected,
169 StreamPtr /* in_stream */,
170 StreamPtr /* out_stream */,
171 uint64_t copied) {
172 EXPECT_EQ(expected, copied);
173 succeeded_ = true;
174 }
175
OnError(const std::string & expected_error,StreamPtr,StreamPtr,const Error * error)176 void OnError(const std::string& expected_error,
177 StreamPtr /* in_stream */,
178 StreamPtr /* out_stream */,
179 const Error* error) {
180 EXPECT_EQ(expected_error, error->GetCode());
181 failed_ = true;
182 }
183
ExpectSuccess()184 void ExpectSuccess() {
185 EXPECT_TRUE(succeeded_);
186 EXPECT_FALSE(failed_);
187 }
188
ExpectFailure()189 void ExpectFailure() {
190 EXPECT_FALSE(succeeded_);
191 EXPECT_TRUE(failed_);
192 }
193 };
194
TEST_F(CopyStreamDataTest,CopyAllAtOnce)195 TEST_F(CopyStreamDataTest, CopyAllAtOnce) {
196 {
197 InSequence seq;
198 EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
199 .WillOnce(InvokeAsyncCallback<2>(100));
200 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 100, _, _, _))
201 .WillOnce(InvokeAsyncCallback<2>());
202 }
203 stream_utils::CopyData(
204 std::move(in_stream_), std::move(out_stream_), 100, 4096,
205 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
206 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
207 fake_loop_.Run();
208 ExpectSuccess();
209 }
210
TEST_F(CopyStreamDataTest,CopyInBlocks)211 TEST_F(CopyStreamDataTest, CopyInBlocks) {
212 {
213 InSequence seq;
214 EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
215 .WillOnce(InvokeAsyncCallback<2>(60));
216 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
217 .WillOnce(InvokeAsyncCallback<2>());
218 EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
219 .WillOnce(InvokeAsyncCallback<2>(40));
220 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _))
221 .WillOnce(InvokeAsyncCallback<2>());
222 }
223 stream_utils::CopyData(
224 std::move(in_stream_), std::move(out_stream_), 100, 4096,
225 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
226 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
227 fake_loop_.Run();
228 ExpectSuccess();
229 }
230
TEST_F(CopyStreamDataTest,CopyTillEndOfStream)231 TEST_F(CopyStreamDataTest, CopyTillEndOfStream) {
232 {
233 InSequence seq;
234 EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _))
235 .WillOnce(InvokeAsyncCallback<2>(60));
236 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
237 .WillOnce(InvokeAsyncCallback<2>());
238 EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
239 .WillOnce(InvokeAsyncCallback<2>(0));
240 }
241 stream_utils::CopyData(
242 std::move(in_stream_), std::move(out_stream_), 100, 4096,
243 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 60),
244 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
245 fake_loop_.Run();
246 ExpectSuccess();
247 }
248
TEST_F(CopyStreamDataTest,CopyInSmallBlocks)249 TEST_F(CopyStreamDataTest, CopyInSmallBlocks) {
250 {
251 InSequence seq;
252 EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
253 .WillOnce(InvokeAsyncCallback<2>(60));
254 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
255 .WillOnce(InvokeAsyncCallback<2>());
256 EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _))
257 .WillOnce(InvokeAsyncCallback<2>(40));
258 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _))
259 .WillOnce(InvokeAsyncCallback<2>());
260 }
261 stream_utils::CopyData(
262 std::move(in_stream_), std::move(out_stream_), 100, 60,
263 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100),
264 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), ""));
265 fake_loop_.Run();
266 ExpectSuccess();
267 }
268
TEST_F(CopyStreamDataTest,ErrorRead)269 TEST_F(CopyStreamDataTest, ErrorRead) {
270 {
271 InSequence seq;
272 EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
273 .WillOnce(InvokeAsyncErrorCallback<3>("read"));
274 }
275 stream_utils::CopyData(
276 std::move(in_stream_), std::move(out_stream_), 100, 60,
277 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0),
278 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "read"));
279 fake_loop_.Run();
280 ExpectFailure();
281 }
282
TEST_F(CopyStreamDataTest,ErrorWrite)283 TEST_F(CopyStreamDataTest, ErrorWrite) {
284 {
285 InSequence seq;
286 EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _))
287 .WillOnce(InvokeAsyncCallback<2>(60));
288 EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _))
289 .WillOnce(InvokeAsyncErrorCallback<3>("write"));
290 }
291 stream_utils::CopyData(
292 std::move(in_stream_), std::move(out_stream_), 100, 60,
293 base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0),
294 base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this),
295 "write"));
296 fake_loop_.Run();
297 ExpectFailure();
298 }
299
300 } // namespace brillo
301