• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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