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