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