1 // Copyright 2017 The Chromium 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 <algorithm>
6 #include <list>
7 #include <memory>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/macros.h"
13 #include "base/run_loop.h"
14 #include "base/strings/string_piece.h"
15 #include "base/test/scoped_task_environment.h"
16 #include "mojo/public/cpp/system/data_pipe.h"
17 #include "mojo/public/cpp/system/simple_watcher.h"
18 #include "mojo/public/cpp/system/string_data_pipe_producer.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 namespace mojo {
22 namespace {
23
24 // Test helper. Reads a consumer handle, accumulating data into a string. Reads
25 // until encountering an error (e.g. peer closure), at which point it invokes an
26 // async callback.
27 class DataPipeReader {
28 public:
DataPipeReader(ScopedDataPipeConsumerHandle consumer_handle,base::OnceClosure on_read_done)29 explicit DataPipeReader(ScopedDataPipeConsumerHandle consumer_handle,
30 base::OnceClosure on_read_done)
31 : consumer_handle_(std::move(consumer_handle)),
32 on_read_done_(std::move(on_read_done)),
33 watcher_(FROM_HERE,
34 SimpleWatcher::ArmingPolicy::AUTOMATIC,
35 base::SequencedTaskRunnerHandle::Get()) {
36 watcher_.Watch(
37 consumer_handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
38 MOJO_WATCH_CONDITION_SATISFIED,
39 base::Bind(&DataPipeReader::OnDataAvailable, base::Unretained(this)));
40 }
41 ~DataPipeReader() = default;
42
data() const43 const std::string& data() const { return data_; }
44
45 private:
OnDataAvailable(MojoResult result,const HandleSignalsState & state)46 void OnDataAvailable(MojoResult result, const HandleSignalsState& state) {
47 if (result == MOJO_RESULT_OK) {
48 uint32_t size = 64;
49 std::vector<char> buffer(size, 0);
50 MojoResult read_result;
51 do {
52 read_result = consumer_handle_->ReadData(buffer.data(), &size,
53 MOJO_READ_DATA_FLAG_NONE);
54 if (read_result == MOJO_RESULT_OK) {
55 std::copy(buffer.begin(), buffer.begin() + size,
56 std::back_inserter(data_));
57 }
58 } while (read_result == MOJO_RESULT_OK);
59
60 if (read_result == MOJO_RESULT_SHOULD_WAIT)
61 return;
62 }
63
64 if (result != MOJO_RESULT_CANCELLED)
65 watcher_.Cancel();
66
67 std::move(on_read_done_).Run();
68 }
69
70 ScopedDataPipeConsumerHandle consumer_handle_;
71 base::OnceClosure on_read_done_;
72 SimpleWatcher watcher_;
73 std::string data_;
74
75 DISALLOW_COPY_AND_ASSIGN(DataPipeReader);
76 };
77
78 class StringDataPipeProducerTest : public testing::Test {
79 public:
80 StringDataPipeProducerTest() = default;
81 ~StringDataPipeProducerTest() override = default;
82
83 protected:
WriteStringThenCloseProducer(std::unique_ptr<StringDataPipeProducer> producer,const base::StringPiece & str,StringDataPipeProducer::AsyncWritingMode mode)84 static void WriteStringThenCloseProducer(
85 std::unique_ptr<StringDataPipeProducer> producer,
86 const base::StringPiece& str,
87 StringDataPipeProducer::AsyncWritingMode mode) {
88 StringDataPipeProducer* raw_producer = producer.get();
89 raw_producer->Write(
90 str, mode,
91 base::BindOnce([](std::unique_ptr<StringDataPipeProducer> producer,
92 MojoResult result) {},
93 std::move(producer)));
94 }
95
WriteStringsThenCloseProducer(std::unique_ptr<StringDataPipeProducer> producer,std::list<base::StringPiece> strings,StringDataPipeProducer::AsyncWritingMode mode)96 static void WriteStringsThenCloseProducer(
97 std::unique_ptr<StringDataPipeProducer> producer,
98 std::list<base::StringPiece> strings,
99 StringDataPipeProducer::AsyncWritingMode mode) {
100 StringDataPipeProducer* raw_producer = producer.get();
101 base::StringPiece str = strings.front();
102 strings.pop_front();
103 raw_producer->Write(str, mode,
104 base::BindOnce(
105 [](std::unique_ptr<StringDataPipeProducer> producer,
106 std::list<base::StringPiece> strings,
107 StringDataPipeProducer::AsyncWritingMode mode,
108 MojoResult result) {
109 if (!strings.empty())
110 WriteStringsThenCloseProducer(
111 std::move(producer), std::move(strings),
112 mode);
113 },
114 std::move(producer), std::move(strings), mode));
115 }
116
117 private:
118 base::test::ScopedTaskEnvironment task_environment_;
119
120 DISALLOW_COPY_AND_ASSIGN(StringDataPipeProducerTest);
121 };
122
TEST_F(StringDataPipeProducerTest,EqualCapacity)123 TEST_F(StringDataPipeProducerTest, EqualCapacity) {
124 const std::string kTestString = "Hello, world!";
125
126 base::RunLoop loop;
127 mojo::DataPipe pipe(static_cast<uint32_t>(kTestString.size()));
128 DataPipeReader reader(std::move(pipe.consumer_handle), loop.QuitClosure());
129 WriteStringThenCloseProducer(
130 std::make_unique<StringDataPipeProducer>(std::move(pipe.producer_handle)),
131 kTestString,
132 StringDataPipeProducer::AsyncWritingMode::
133 STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
134 loop.Run();
135
136 EXPECT_EQ(kTestString, reader.data());
137 }
138
TEST_F(StringDataPipeProducerTest,UnderCapacity)139 TEST_F(StringDataPipeProducerTest, UnderCapacity) {
140 const std::string kTestString = "Hello, world!";
141
142 base::RunLoop loop;
143 mojo::DataPipe pipe(static_cast<uint32_t>(kTestString.size() * 2));
144 DataPipeReader reader(std::move(pipe.consumer_handle), loop.QuitClosure());
145 WriteStringThenCloseProducer(
146 std::make_unique<StringDataPipeProducer>(std::move(pipe.producer_handle)),
147 kTestString,
148 StringDataPipeProducer::AsyncWritingMode::
149 STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
150 loop.Run();
151
152 EXPECT_EQ(kTestString, reader.data());
153 }
154
TEST_F(StringDataPipeProducerTest,OverCapacity)155 TEST_F(StringDataPipeProducerTest, OverCapacity) {
156 const std::string kTestString = "Hello, world!";
157
158 base::RunLoop loop;
159 mojo::DataPipe pipe(static_cast<uint32_t>(kTestString.size() / 2));
160 DataPipeReader reader(std::move(pipe.consumer_handle), loop.QuitClosure());
161 WriteStringThenCloseProducer(
162 std::make_unique<StringDataPipeProducer>(std::move(pipe.producer_handle)),
163 kTestString,
164 StringDataPipeProducer::AsyncWritingMode::
165 STRING_STAYS_VALID_UNTIL_COMPLETION);
166 loop.Run();
167
168 EXPECT_EQ(kTestString, reader.data());
169 }
170
TEST_F(StringDataPipeProducerTest,TinyPipe)171 TEST_F(StringDataPipeProducerTest, TinyPipe) {
172 const std::string kTestString = "Hello, world!";
173
174 base::RunLoop loop;
175 mojo::DataPipe pipe(1);
176 DataPipeReader reader(std::move(pipe.consumer_handle), loop.QuitClosure());
177 WriteStringThenCloseProducer(
178 std::make_unique<StringDataPipeProducer>(std::move(pipe.producer_handle)),
179 kTestString,
180 StringDataPipeProducer::AsyncWritingMode::
181 STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
182 loop.Run();
183
184 EXPECT_EQ(kTestString, reader.data());
185 }
186
TEST_F(StringDataPipeProducerTest,MultipleWrites)187 TEST_F(StringDataPipeProducerTest, MultipleWrites) {
188 const std::string kTestString1 = "Hello, world!";
189 const std::string kTestString2 = "There is a lot of data coming your way!";
190 const std::string kTestString3 = "So many strings!";
191 const std::string kTestString4 = "Your cup runneth over!";
192
193 base::RunLoop loop;
194 mojo::DataPipe pipe(4);
195 DataPipeReader reader(std::move(pipe.consumer_handle), loop.QuitClosure());
196 WriteStringsThenCloseProducer(
197 std::make_unique<StringDataPipeProducer>(std::move(pipe.producer_handle)),
198 {kTestString1, kTestString2, kTestString3, kTestString4},
199 StringDataPipeProducer::AsyncWritingMode::
200 STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION);
201 loop.Run();
202
203 EXPECT_EQ(kTestString1 + kTestString2 + kTestString3 + kTestString4,
204 reader.data());
205 }
206
207 } // namespace
208 } // namespace mojo
209