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"
10 #include "base/location.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/run_loop.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/threading/thread.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"
24 using blink::WebDataConsumerHandle
;
26 class ReadDataOperationBase
{
28 virtual ~ReadDataOperationBase() {}
29 virtual void ReadMore() = 0;
31 static const WebDataConsumerHandle::Flags kNone
=
32 WebDataConsumerHandle::FlagNone
;
33 static const WebDataConsumerHandle::Result kOk
= WebDataConsumerHandle::Ok
;
34 static const WebDataConsumerHandle::Result kDone
=
35 WebDataConsumerHandle::Done
;
36 static const WebDataConsumerHandle::Result kShouldWait
=
37 WebDataConsumerHandle::ShouldWait
;
40 class ClientImpl final
: public WebDataConsumerHandle::Client
{
42 explicit ClientImpl(ReadDataOperationBase
* operation
)
43 : operation_(operation
) {}
45 void didGetReadable() override
{
46 base::ThreadTaskRunnerHandle::Get()->PostTask(
47 FROM_HERE
, base::Bind(&ReadDataOperationBase::ReadMore
,
48 base::Unretained(operation_
)));
52 ReadDataOperationBase
* operation_
;
55 class ReadDataOperation
: public ReadDataOperationBase
{
57 typedef WebDataConsumerHandle::Result Result
;
58 ReadDataOperation(mojo::ScopedDataPipeConsumerHandle handle
,
59 base::MessageLoop
* main_message_loop
,
60 const base::Closure
& on_done
)
61 : handle_(new WebDataConsumerHandleImpl(handle
.Pass())),
62 main_message_loop_(main_message_loop
),
65 const std::string
& result() const { return result_
; }
67 void ReadMore() override
{ ReadData(); }
71 client_
.reset(new ClientImpl(this));
72 reader_
= handle_
->ObtainReader(client_
.get());
80 rv
= reader_
->read(&buffer
, sizeof(buffer
), kNone
, &readSize
);
83 result_
.insert(result_
.size(), &buffer
[0], readSize
);
86 if (rv
== kShouldWait
) {
92 // Something is wrong.
96 // The operation is done.
98 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
102 scoped_ptr
<WebDataConsumerHandleImpl
> handle_
;
103 scoped_ptr
<WebDataConsumerHandle::Reader
> reader_
;
104 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
105 base::MessageLoop
* main_message_loop_
;
106 base::Closure on_done_
;
110 class TwoPhaseReadDataOperation
: public ReadDataOperationBase
{
112 typedef WebDataConsumerHandle::Result Result
;
113 TwoPhaseReadDataOperation(mojo::ScopedDataPipeConsumerHandle handle
,
114 base::MessageLoop
* main_message_loop
,
115 const base::Closure
& on_done
)
116 : handle_(new WebDataConsumerHandleImpl(handle
.Pass())),
117 main_message_loop_(main_message_loop
), on_done_(on_done
) {}
119 const std::string
& result() const { return result_
; }
121 void ReadMore() override
{
127 client_
.reset(new ClientImpl(this));
128 reader_
= handle_
->ObtainReader(client_
.get());
133 const void* buffer
= nullptr;
135 rv
= reader_
->beginRead(&buffer
, kNone
, &size
);
138 // In order to verify endRead, we read at most one byte for each time.
139 size_t read_size
= std::max(static_cast<size_t>(1), size
);
140 result_
.insert(result_
.size(), static_cast<const char*>(buffer
),
142 rv
= reader_
->endRead(read_size
);
144 // Something is wrong.
146 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
151 if (rv
== kShouldWait
) {
157 // Something is wrong.
161 // The operation is done.
163 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
167 scoped_ptr
<WebDataConsumerHandleImpl
> handle_
;
168 scoped_ptr
<WebDataConsumerHandle::Reader
> reader_
;
169 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
170 base::MessageLoop
* main_message_loop_
;
171 base::Closure on_done_
;
175 class WebDataConsumerHandleImplTest
: public ::testing::Test
{
177 typedef WebDataConsumerHandle::Result Result
;
179 void SetUp() override
{
180 MojoCreateDataPipeOptions options
;
181 options
.struct_size
= sizeof(MojoCreateDataPipeOptions
);
182 options
.flags
= MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE
;
183 options
.element_num_bytes
= 1;
184 options
.capacity_num_bytes
= 4;
186 MojoResult result
= mojo::CreateDataPipe(&options
, &producer_
, &consumer_
);
187 ASSERT_EQ(MOJO_RESULT_OK
, result
);
190 // This function can be blocked if the associated consumer doesn't consume
192 std::string
ProduceData(size_t total_size
) {
194 std::string expected
;
195 for (size_t i
= 0; i
< total_size
; ++i
) {
196 expected
+= static_cast<char>(index
+ 'a');
197 index
= (37 * index
+ 11) % 26;
200 const char* p
= expected
.data();
201 size_t remaining
= total_size
;
202 const MojoWriteDataFlags kNone
= MOJO_WRITE_DATA_FLAG_NONE
;
204 while (remaining
> 0) {
205 uint32_t size
= remaining
;
206 rv
= mojo::WriteDataRaw(producer_
.get(), p
, &size
, kNone
);
207 if (rv
== MOJO_RESULT_OK
) {
210 } else if (rv
!= MOJO_RESULT_SHOULD_WAIT
) {
211 // Something is wrong.
212 EXPECT_TRUE(false) << "mojo::WriteDataRaw returns an invalid value.";
213 return "error on writing";
219 base::MessageLoop message_loop_
;
221 mojo::ScopedDataPipeProducerHandle producer_
;
222 mojo::ScopedDataPipeConsumerHandle consumer_
;
225 TEST_F(WebDataConsumerHandleImplTest
, ReadData
) {
226 base::RunLoop run_loop
;
227 auto operation
= make_scoped_ptr(new ReadDataOperation(
230 run_loop
.QuitClosure()));
232 base::Thread
t("DataConsumerHandle test thread");
233 ASSERT_TRUE(t
.Start());
235 t
.task_runner()->PostTask(FROM_HERE
,
236 base::Bind(&ReadDataOperation::ReadData
,
237 base::Unretained(operation
.get())));
239 std::string expected
= ProduceData(24 * 1024);
245 EXPECT_EQ(expected
, operation
->result());
248 TEST_F(WebDataConsumerHandleImplTest
, TwoPhaseReadData
) {
249 base::RunLoop run_loop
;
250 auto operation
= make_scoped_ptr(new TwoPhaseReadDataOperation(
253 run_loop
.QuitClosure()));
255 base::Thread
t("DataConsumerHandle test thread");
256 ASSERT_TRUE(t
.Start());
258 t
.task_runner()->PostTask(FROM_HERE
,
259 base::Bind(&TwoPhaseReadDataOperation::ReadData
,
260 base::Unretained(operation
.get())));
262 std::string expected
= ProduceData(24 * 1024);
268 EXPECT_EQ(expected
, operation
->result());
273 } // namespace content