Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / child / web_data_consumer_handle_impl_unittest.cc
blob4aaa4dc69c4cd954b8f3daad7b431604c0ed6647
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.
5 #include "content/child/web_data_consumer_handle_impl.h"
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 "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
18 namespace content {
20 namespace {
22 using blink::WebDataConsumerHandle;
24 class ReadDataOperationBase {
25 public:
26 virtual ~ReadDataOperationBase() {}
27 virtual void ReadMore() = 0;
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;
38 class ClientImpl final : public WebDataConsumerHandle::Client {
39 public:
40 explicit ClientImpl(ReadDataOperationBase* operation)
41 : operation_(operation) {}
43 void didGetReadable() override {
44 base::MessageLoop::current()->PostTask(
45 FROM_HERE,
46 base::Bind(&ReadDataOperationBase::ReadMore,
47 base::Unretained(operation_)));
50 private:
51 ReadDataOperationBase* operation_;
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),
62 on_done_(on_done) {}
64 const std::string& result() const { return result_; }
66 void ReadMore() override { ReadData(); }
68 void ReadData() {
69 if (!client_) {
70 client_.reset(new ClientImpl(this));
71 handle_->registerClient(client_.get());
74 Result rv = kOk;
75 size_t readSize = 0;
77 while (true) {
78 char buffer[16];
79 rv = handle_->read(&buffer, sizeof(buffer), kNone, &readSize);
80 if (rv != kOk)
81 break;
82 result_.insert(result_.size(), &buffer[0], readSize);
85 if (rv == kShouldWait) {
86 // Wait a while...
87 return;
90 if (rv != kDone) {
91 // Something is wrong.
92 result_ = "error";
95 // The operation is done.
96 main_message_loop_->PostTask(FROM_HERE, on_done_);
99 private:
100 scoped_ptr<WebDataConsumerHandle> handle_;
101 scoped_ptr<WebDataConsumerHandle::Client> client_;
102 base::MessageLoop* main_message_loop_;
103 base::Closure on_done_;
104 std::string result_;
107 class TwoPhaseReadDataOperation : public ReadDataOperationBase {
108 public:
109 typedef WebDataConsumerHandle::Result Result;
110 TwoPhaseReadDataOperation(mojo::ScopedDataPipeConsumerHandle handle,
111 base::MessageLoop* main_message_loop,
112 const base::Closure& on_done)
113 : handle_(new WebDataConsumerHandleImpl(handle.Pass())),
114 main_message_loop_(main_message_loop), on_done_(on_done) {}
116 const std::string& result() const { return result_; }
118 void ReadMore() override {
119 ReadData();
122 void ReadData() {
123 if (!client_) {
124 client_.reset(new ClientImpl(this));
125 handle_->registerClient(client_.get());
128 Result rv;
129 while (true) {
130 const void* buffer = nullptr;
131 size_t size;
132 rv = handle_->beginRead(&buffer, kNone, &size);
133 if (rv != kOk)
134 break;
135 // In order to verify endRead, we read at most one byte for each time.
136 size_t read_size = std::max(static_cast<size_t>(1), size);
137 result_.insert(result_.size(), static_cast<const char*>(buffer),
138 read_size);
139 rv = handle_->endRead(read_size);
140 if (rv != kOk) {
141 // Something is wrong.
142 result_ = "error";
143 main_message_loop_->PostTask(FROM_HERE, on_done_);
144 return;
148 if (rv == kShouldWait) {
149 // Wait a while...
150 return;
153 if (rv != kDone) {
154 // Something is wrong.
155 result_ = "error";
158 // The operation is done.
159 main_message_loop_->PostTask(FROM_HERE, on_done_);
162 private:
163 scoped_ptr<WebDataConsumerHandle> handle_;
164 scoped_ptr<WebDataConsumerHandle::Client> client_;
165 base::MessageLoop* main_message_loop_;
166 base::Closure on_done_;
167 std::string result_;
170 class WebDataConsumerHandleImplTest : public ::testing::Test {
171 public:
172 typedef WebDataConsumerHandle::Result Result;
174 void SetUp() override {
175 MojoCreateDataPipeOptions options;
176 options.struct_size = sizeof(MojoCreateDataPipeOptions);
177 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
178 options.element_num_bytes = 1;
179 options.capacity_num_bytes = 4;
181 MojoResult result = mojo::CreateDataPipe(&options, &producer_, &consumer_);
182 ASSERT_EQ(MOJO_RESULT_OK, result);
185 // This function can be blocked if the associated consumer doesn't consume
186 // the data.
187 std::string ProduceData(size_t total_size) {
188 int index = 0;
189 std::string expected;
190 for (size_t i = 0; i < total_size; ++i) {
191 expected += static_cast<char>(index + 'a');
192 index = (37 * index + 11) % 26;
195 const char* p = expected.data();
196 size_t remaining = total_size;
197 const MojoWriteDataFlags kNone = MOJO_WRITE_DATA_FLAG_NONE;
198 MojoResult rv;
199 while (remaining > 0) {
200 uint32_t size = remaining;
201 rv = mojo::WriteDataRaw(producer_.get(), p, &size, kNone);
202 if (rv == MOJO_RESULT_OK) {
203 remaining -= size;
204 p += size;
205 } else if (rv != MOJO_RESULT_SHOULD_WAIT) {
206 // Something is wrong.
207 EXPECT_TRUE(false) << "mojo::WriteDataRaw returns an invalid value.";
208 return "error on writing";
211 return expected;
214 base::MessageLoop message_loop_;
216 mojo::ScopedDataPipeProducerHandle producer_;
217 mojo::ScopedDataPipeConsumerHandle consumer_;
220 TEST_F(WebDataConsumerHandleImplTest, ReadData) {
221 base::RunLoop run_loop;
222 auto operation = make_scoped_ptr(new ReadDataOperation(
223 consumer_.Pass(),
224 &message_loop_,
225 run_loop.QuitClosure()));
227 base::Thread t("DataConsumerHandle test thread");
228 ASSERT_TRUE(t.Start());
230 t.message_loop()->PostTask(
231 FROM_HERE,
232 base::Bind(&ReadDataOperation::ReadData,
233 base::Unretained(operation.get())));
235 std::string expected = ProduceData(24 * 1024);
236 producer_.reset();
238 run_loop.Run();
239 t.Stop();
241 EXPECT_EQ(expected, operation->result());
244 TEST_F(WebDataConsumerHandleImplTest, TwoPhaseReadData) {
245 base::RunLoop run_loop;
246 auto operation = make_scoped_ptr(new TwoPhaseReadDataOperation(
247 consumer_.Pass(),
248 &message_loop_,
249 run_loop.QuitClosure()));
251 base::Thread t("DataConsumerHandle test thread");
252 ASSERT_TRUE(t.Start());
254 t.message_loop()->PostTask(
255 FROM_HERE,
256 base::Bind(&TwoPhaseReadDataOperation::ReadData,
257 base::Unretained(operation.get())));
259 std::string expected = ProduceData(24 * 1024);
260 producer_.reset();
262 run_loop.Run();
263 t.Stop();
265 EXPECT_EQ(expected, operation->result());
268 } // namespace
270 } // namespace content