OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 "content/child/web_data_consumer_handle_impl.h" | |
6 | |
7 #include <algorithm> | |
8 #include <string> | |
9 #include "base/bind.h" | |
10 #include "base/memory/scoped_ptr.h" | |
11 #include "base/message_loop/message_loop.h" | |
12 #include "base/run_loop.h" | |
13 #include "base/synchronization/waitable_event.h" | |
14 #include "base/threading/thread.h" | |
15 #include "mojo/public/cpp/system/data_pipe.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | |
17 | |
18 namespace content { | |
19 | |
20 namespace { | |
21 | |
22 using blink::WebDataConsumerHandle; | |
23 | |
24 class ReadDataOperationBase { | |
25 public: | |
26 virtual ~ReadDataOperationBase() {} | |
27 virtual void ReadMore() = 0; | |
28 | |
29 static const WebDataConsumerHandle::Flags kNone = | |
30 WebDataConsumerHandle::FlagNone; | |
31 static const WebDataConsumerHandle::Result kOk = WebDataConsumerHandle::Ok; | |
32 static const WebDataConsumerHandle::Result kDone = | |
33 WebDataConsumerHandle::Done; | |
34 static const WebDataConsumerHandle::Result kShouldWait = | |
35 WebDataConsumerHandle::ShouldWait; | |
36 }; | |
37 | |
38 class ClientImpl final : public WebDataConsumerHandle::Client { | |
39 public: | |
40 explicit ClientImpl(ReadDataOperationBase* operation) | |
41 : operation_(operation) {} | |
42 | |
43 void didGetReadable() override { | |
44 base::MessageLoop::current()->PostTask( | |
45 FROM_HERE, | |
46 base::Bind(&ReadDataOperationBase::ReadMore, | |
47 base::Unretained(operation_))); | |
48 } | |
49 | |
50 private: | |
51 ReadDataOperationBase* operation_; | |
52 }; | |
53 | |
54 class ReadDataOperation : public ReadDataOperationBase { | |
55 public: | |
56 typedef WebDataConsumerHandle::Result Result; | |
57 ReadDataOperation(mojo::ScopedDataPipeConsumerHandle handle, | |
58 base::MessageLoop* main_message_loop, | |
59 const base::Closure& on_done) | |
60 : handle_(new WebDataConsumerHandleImpl(handle.Pass())), | |
61 main_message_loop_(main_message_loop), on_done_(on_done) {} | |
nasko
2014/10/24 18:13:43
style: each member should be on a separate line
yhirano
2014/10/27 01:11:52
Done.
| |
62 | |
63 const std::string& result() const { return result_; } | |
64 | |
65 void ReadMore() override { | |
nasko
2014/10/24 18:13:43
style: this fits all on one line
yhirano
2014/10/27 01:11:52
Done.
| |
66 ReadData(); | |
67 } | |
68 | |
69 void ReadData() { | |
70 if (!client_) { | |
71 client_.reset(new ClientImpl(this)); | |
72 handle_->registerClient(client_.get()); | |
73 } | |
74 | |
75 Result rv = kOk; | |
76 size_t readSize = 0; | |
77 | |
78 while (true) { | |
79 char buffer[16]; | |
80 rv = handle_->read(&buffer, sizeof(buffer), kNone, &readSize); | |
81 if (rv != kOk) | |
82 break; | |
83 result_.insert(result_.size(), &buffer[0], readSize); | |
84 } | |
85 | |
86 if (rv == kShouldWait) { | |
87 // Wait a while... | |
88 return; | |
89 } | |
90 | |
91 if (rv != kDone) { | |
92 // Something is wrong. | |
93 result_ = "error"; | |
94 } | |
95 | |
96 // The operation is done. | |
97 main_message_loop_->PostTask(FROM_HERE, on_done_); | |
98 } | |
99 | |
100 private: | |
101 scoped_ptr<WebDataConsumerHandle> handle_; | |
102 scoped_ptr<WebDataConsumerHandle::Client> client_; | |
103 base::MessageLoop* main_message_loop_; | |
104 base::Closure on_done_; | |
105 std::string result_; | |
106 }; | |
107 | |
108 class TwoPhaseReadDataOperation : public ReadDataOperationBase { | |
109 public: | |
110 typedef WebDataConsumerHandle::Result Result; | |
111 TwoPhaseReadDataOperation(mojo::ScopedDataPipeConsumerHandle handle, | |
112 base::MessageLoop* main_message_loop, | |
113 const base::Closure& on_done) | |
114 : handle_(new WebDataConsumerHandleImpl(handle.Pass())), | |
115 main_message_loop_(main_message_loop), on_done_(on_done) {} | |
116 | |
117 const std::string& result() const { return result_; } | |
118 | |
119 void ReadMore() override { | |
120 ReadData(); | |
121 } | |
122 | |
123 void ReadData() { | |
124 if (!client_) { | |
125 client_.reset(new ClientImpl(this)); | |
126 handle_->registerClient(client_.get()); | |
127 } | |
128 | |
129 Result rv; | |
130 while (true) { | |
131 const void* buffer = nullptr; | |
132 size_t size; | |
133 rv = handle_->beginRead(&buffer, kNone, &size); | |
134 if (rv != kOk) | |
135 break; | |
136 // In order to verify endRead, we read at most one byte for each time. | |
137 size_t read_size = std::max(static_cast<size_t>(1), size); | |
138 result_.insert(result_.size(), static_cast<const char*>(buffer), | |
139 read_size); | |
140 rv = handle_->endRead(read_size); | |
141 if (rv != kOk) { | |
142 // Something is wrong. | |
143 result_ = "error"; | |
144 main_message_loop_->PostTask(FROM_HERE, on_done_); | |
145 return; | |
146 } | |
147 } | |
148 | |
149 if (rv == kShouldWait) { | |
150 // Wait a while... | |
151 return; | |
152 } | |
153 | |
154 if (rv != kDone) { | |
155 // Something is wrong. | |
156 result_ = "error"; | |
157 } | |
158 | |
159 // The operation is done. | |
160 main_message_loop_->PostTask(FROM_HERE, on_done_); | |
161 } | |
162 | |
163 private: | |
164 scoped_ptr<WebDataConsumerHandle> handle_; | |
165 scoped_ptr<WebDataConsumerHandle::Client> client_; | |
166 base::MessageLoop* main_message_loop_; | |
167 base::Closure on_done_; | |
168 std::string result_; | |
169 }; | |
170 | |
171 class WebDataConsumerHandleImplTest : public ::testing::Test { | |
172 public: | |
173 typedef WebDataConsumerHandle::Result Result; | |
174 | |
175 void SetUp() override { | |
176 MojoCreateDataPipeOptions options; | |
177 options.struct_size = sizeof(MojoCreateDataPipeOptions); | |
178 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; | |
179 options.element_num_bytes = 1; | |
180 options.capacity_num_bytes = 4; | |
181 | |
182 MojoResult result = mojo::CreateDataPipe(&options, &producer_, &consumer_); | |
183 ASSERT_EQ(MOJO_RESULT_OK, result); | |
184 } | |
185 | |
186 // This function can be blocked if the associated consumer doesn't consume | |
187 // the data. | |
188 std::string ProduceData(size_t total_size) { | |
189 int index = 0; | |
190 std::string expected; | |
191 for (size_t i = 0; i < total_size; ++i) { | |
192 expected += static_cast<char>(index + 'a'); | |
193 index = (37 * index + 11) % 26; | |
194 } | |
195 | |
196 const char* p = expected.data(); | |
197 size_t remaining = total_size; | |
198 const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE; | |
199 MojoResult rv; | |
200 while (remaining > 0) { | |
201 uint32_t size = remaining; | |
202 rv = mojo::WriteDataRaw(producer_.get(), p, &size, kNone); | |
203 if (rv == MOJO_RESULT_OK) { | |
204 remaining -= size; | |
205 p += size; | |
206 } else if (rv != MOJO_RESULT_SHOULD_WAIT) { | |
207 // Something is wrong. | |
208 EXPECT_TRUE(false) << "mojo::WriteDataRaw returns an invalid value."; | |
209 return "error on writing"; | |
210 } | |
211 } | |
212 return expected; | |
213 } | |
214 | |
215 base::MessageLoop message_loop_; | |
216 | |
217 mojo::ScopedDataPipeProducerHandle producer_; | |
218 mojo::ScopedDataPipeConsumerHandle consumer_; | |
219 }; | |
220 | |
221 TEST_F(WebDataConsumerHandleImplTest, ReadData) { | |
222 base::RunLoop run_loop; | |
223 auto operation = make_scoped_ptr(new ReadDataOperation( | |
224 consumer_.Pass(), | |
225 &message_loop_, | |
226 run_loop.QuitClosure())); | |
227 | |
228 base::Thread t("DataConsumerHandle test thread"); | |
229 ASSERT_TRUE(t.Start()); | |
230 | |
231 t.message_loop()->PostTask( | |
232 FROM_HERE, | |
233 base::Bind(&ReadDataOperation::ReadData, | |
234 base::Unretained(operation.get()))); | |
235 | |
236 std::string expected = ProduceData(24 * 1024); | |
237 producer_.reset(); | |
238 | |
239 run_loop.Run(); | |
240 t.Stop(); | |
241 | |
242 EXPECT_EQ(expected, operation->result()); | |
243 } | |
244 | |
245 TEST_F(WebDataConsumerHandleImplTest, TwoPhaseReadData) { | |
246 base::RunLoop run_loop; | |
247 auto operation = make_scoped_ptr(new TwoPhaseReadDataOperation( | |
248 consumer_.Pass(), | |
249 &message_loop_, | |
250 run_loop.QuitClosure())); | |
251 | |
252 base::Thread t("DataConsumerHandle test thread"); | |
253 ASSERT_TRUE(t.Start()); | |
254 | |
255 t.message_loop()->PostTask( | |
256 FROM_HERE, | |
257 base::Bind(&TwoPhaseReadDataOperation::ReadData, | |
258 base::Unretained(operation.get()))); | |
259 | |
260 std::string expected = ProduceData(24 * 1024); | |
261 producer_.reset(); | |
262 | |
263 run_loop.Run(); | |
264 t.Stop(); | |
265 | |
266 EXPECT_EQ(expected, operation->result()); | |
267 } | |
268 | |
269 } // namespace | |
270 | |
271 } // namespace content | |
OLD | NEW |