Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: content/child/web_data_producer_handle_impl_unittest.cc

Issue 850043008: [DO NOT REVIEW][DO NOT COMMIT] Implement WebDataProducerHandleImpl. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/child/web_data_producer_handle_impl.cc ('k') | content/content_child.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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_producer_handle_impl.h"
6
7 #include <algorithm>
8 #include <deque>
9 #include <string>
10 #include <vector>
11 #include "base/bind.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/threading/thread.h"
17 #include "mojo/public/cpp/system/data_pipe.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace content {
21
22 namespace {
23
24 using blink::WebDataProducerHandle;
25
26 class WriteDataOperationBase {
27 public:
28 virtual ~WriteDataOperationBase() {}
29 virtual void WriteMore() = 0;
30
31 static const WebDataProducerHandle::Flags kNone =
32 WebDataProducerHandle::FlagNone;
33 static const WebDataProducerHandle::Result kOk = WebDataProducerHandle::Ok;
34 // static const WebDataProducerHandle::Result kAlreadyClosed =
35 // WebDataProducerHandle::AlreadyClosed;
36 static const WebDataProducerHandle::Result kShouldWait =
37 WebDataProducerHandle::ShouldWait;
38 };
39
40 class ClientImpl final : public WebDataProducerHandle::Client {
41 public:
42 explicit ClientImpl(WriteDataOperationBase* operation)
43 : operation_(operation) {}
44
45 void didGetWritable() override {
46 base::MessageLoop::current()->PostTask(
47 FROM_HERE,
48 base::Bind(&WriteDataOperationBase::WriteMore,
49 base::Unretained(operation_)));
50 }
51
52 private:
53 WriteDataOperationBase* operation_;
54 };
55
56 class WriteDataOperation : public WriteDataOperationBase {
57 public:
58 typedef WebDataProducerHandle::Result Result;
59 WriteDataOperation(mojo::ScopedDataPipeProducerHandle handle,
60 const std::deque<char>& input)
61 : handle_(new WebDataProducerHandleImpl(handle.Pass())),
62 input_(input) {}
63
64 Result final_result() const { return final_result_; }
65
66 void WriteMore() override { WriteData(); }
67
68 void WriteData() {
69 if (!client_) {
70 client_.reset(new ClientImpl(this));
71 handle_->registerClient(client_.get());
72 }
73
74 Result rv = kOk;
75
76 while (!input_.empty()) {
77 const size_t size = std::min(static_cast<size_t>(16), input_.size());
78 std::vector<char> buffer;
79 size_t written_size = 0;
80 buffer.insert(buffer.end(), input_.begin(), input_.begin() + size);
81 rv = handle_->write(&buffer[0], size, kNone, &written_size);
82 if (rv != kOk)
83 break;
84 input_.erase(input_.begin(), input_.begin() + written_size);
85 }
86
87 if (rv == kShouldWait) {
88 // Wait a while...
89 return;
90 }
91
92 final_result_ = rv;
93
94 // The operation is done.
95 handle_ = nullptr;
96 }
97
98 private:
99 scoped_ptr<WebDataProducerHandle> handle_;
100 scoped_ptr<WebDataProducerHandle::Client> client_;
101 std::deque<char> input_;
102 Result final_result_;
103 };
104
105 class TwoPhaseWriteDataOperation : public WriteDataOperationBase {
106 public:
107 typedef WebDataProducerHandle::Result Result;
108 TwoPhaseWriteDataOperation(mojo::ScopedDataPipeProducerHandle handle,
109 const std::deque<char>& input)
110 : handle_(new WebDataProducerHandleImpl(handle.Pass())),
111 input_(input) {}
112
113 Result final_result() const { return final_result_; }
114
115 void WriteMore() override {
116 WriteData();
117 }
118
119 void WriteData() {
120 if (!client_) {
121 client_.reset(new ClientImpl(this));
122 handle_->registerClient(client_.get());
123 }
124
125 Result rv = kOk;
126 while (!input_.empty()) {
127 void* buffer = nullptr;
128 size_t size;
129 rv = handle_->beginWrite(&buffer, kNone, &size);
130 if (rv != kOk)
131 break;
132 // In order to verify endWrite, we write at most one byte for each time.
133 size_t written_size = std::max(static_cast<size_t>(1), size);
134 std::copy(input_.begin(),
135 input_.begin() + written_size,
136 static_cast<char*>(buffer));
137 rv = handle_->endWrite(written_size);
138 if (rv != kOk)
139 break;
140 input_.erase(input_.begin(), input_.begin() + written_size);
141 }
142
143 if (rv == kShouldWait) {
144 // Wait a while...
145 return;
146 }
147
148 final_result_ = rv;
149
150 // The operation is done.
151 handle_ = nullptr;
152 }
153
154 private:
155 scoped_ptr<WebDataProducerHandle> handle_;
156 scoped_ptr<WebDataProducerHandle::Client> client_;
157 std::deque<char> input_;
158 Result final_result_;
159 };
160
161 class WebDataProducerHandleImplTest : public ::testing::Test {
162 public:
163 typedef WebDataProducerHandle::Result Result;
164
165 void SetUp() override {
166 MojoCreateDataPipeOptions options;
167 options.struct_size = sizeof(MojoCreateDataPipeOptions);
168 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
169 options.element_num_bytes = 1;
170 options.capacity_num_bytes = 4;
171
172 MojoResult result = mojo::CreateDataPipe(&options, &producer_, &consumer_);
173 ASSERT_EQ(MOJO_RESULT_OK, result);
174 }
175
176 // This function can be blocked if the associated consumer doesn't consume
177 // the data.
178 std::string ProduceData(size_t total_size) {
179 int index = 0;
180 std::string expected;
181 for (size_t i = 0; i < total_size; ++i) {
182 expected += static_cast<char>(index + 'a');
183 index = (37 * index + 11) % 26;
184 }
185 return expected;
186 }
187
188 std::string Read() {
189 std::string result;
190 const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
191 MojoResult rv;
192 while (true) {
193 char buffer[16];
194 uint32_t size = sizeof(buffer);
195 rv = mojo::ReadDataRaw(consumer_.get(), buffer, &size, kNone);
196 if (rv == MOJO_RESULT_OK) {
197 result.insert(result.end(), buffer, buffer + size);
198 } else if (rv == MOJO_RESULT_FAILED_PRECONDITION) {
199 break;
200 } else if (rv != MOJO_RESULT_SHOULD_WAIT) {
201 // Something is wrong.
202 EXPECT_TRUE(false) << "mojo::ReadDataRaw returns an invalid value.";
203 return "error on reading";
204 }
205 }
206 return result;
207 }
208
209 mojo::ScopedDataPipeProducerHandle producer_;
210 mojo::ScopedDataPipeConsumerHandle consumer_;
211 };
212
213 TEST_F(WebDataProducerHandleImplTest, WriteData) {
214 std::string expected = ProduceData(24 * 1024);
215 std::deque<char> input(expected.begin(), expected.end());
216
217 auto operation =
218 make_scoped_ptr(new WriteDataOperation(producer_.Pass(), input));
219
220 base::Thread t("DataProducerHandle test thread");
221 ASSERT_TRUE(t.Start());
222
223 t.message_loop()->PostTask(
224 FROM_HERE,
225 base::Bind(&WriteDataOperation::WriteData,
226 base::Unretained(operation.get())));
227
228 std::string actual = Read();
229 t.Stop();
230
231 EXPECT_EQ(WebDataProducerHandle::Ok, operation->final_result());
232 EXPECT_EQ(expected, actual);
233 }
234
235 TEST_F(WebDataProducerHandleImplTest, TwoPhaseWriteData) {
236 std::string expected = ProduceData(24 * 1024);
237 std::deque<char> input(expected.begin(), expected.end());
238
239 auto operation =
240 make_scoped_ptr(new TwoPhaseWriteDataOperation(producer_.Pass(), input));
241
242 base::Thread t("DataProducerHandle test thread");
243 ASSERT_TRUE(t.Start());
244
245 t.message_loop()->PostTask(
246 FROM_HERE,
247 base::Bind(&TwoPhaseWriteDataOperation::WriteData,
248 base::Unretained(operation.get())));
249
250 std::string actual = Read();
251
252 t.Stop();
253
254 EXPECT_EQ(WebDataProducerHandle::Ok, operation->final_result());
255 EXPECT_EQ(expected, actual);
256 }
257
258 TEST_F(WebDataProducerHandleImplTest, WriteToClosedPipe) {
259 auto handle =
260 make_scoped_ptr(new WebDataProducerHandleImpl(producer_.Pass()));
261 const auto kNone = WebDataProducerHandleImpl::FlagNone;
262 const auto kAlreadyClosed = WebDataProducerHandleImpl::AlreadyClosed;
263
264 size_t written_size = 0;
265 void* buffer = nullptr;
266 size_t available = 0;
267
268 consumer_.reset();
269
270 EXPECT_EQ(kAlreadyClosed, handle->write(nullptr, 0, kNone, &written_size));
271 EXPECT_EQ(kAlreadyClosed, handle->beginWrite(&buffer, kNone, &available));
272 }
273
274 } // namespace
275
276 } // namespace content
OLDNEW
« no previous file with comments | « content/child/web_data_producer_handle_impl.cc ('k') | content/content_child.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698