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 handle_
->registerClient(client_
.get());
80 rv
= handle_
->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.
97 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
101 scoped_ptr
<WebDataConsumerHandle
> handle_
;
102 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
103 base::MessageLoop
* main_message_loop_
;
104 base::Closure on_done_
;
108 class TwoPhaseReadDataOperation
: public ReadDataOperationBase
{
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
) {}
117 const std::string
& result() const { return result_
; }
119 void ReadMore() override
{
125 client_
.reset(new ClientImpl(this));
126 handle_
->registerClient(client_
.get());
131 const void* buffer
= nullptr;
133 rv
= handle_
->beginRead(&buffer
, kNone
, &size
);
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
),
140 rv
= handle_
->endRead(read_size
);
142 // Something is wrong.
144 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
149 if (rv
== kShouldWait
) {
155 // Something is wrong.
159 // The operation is done.
160 main_message_loop_
->task_runner()->PostTask(FROM_HERE
, on_done_
);
164 scoped_ptr
<WebDataConsumerHandle
> handle_
;
165 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
166 base::MessageLoop
* main_message_loop_
;
167 base::Closure on_done_
;
171 class WebDataConsumerHandleImplTest
: public ::testing::Test
{
173 typedef WebDataConsumerHandle::Result Result
;
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;
182 MojoResult result
= mojo::CreateDataPipe(&options
, &producer_
, &consumer_
);
183 ASSERT_EQ(MOJO_RESULT_OK
, result
);
186 // This function can be blocked if the associated consumer doesn't consume
188 std::string
ProduceData(size_t total_size
) {
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;
196 const char* p
= expected
.data();
197 size_t remaining
= total_size
;
198 const MojoWriteDataFlags kNone
= MOJO_WRITE_DATA_FLAG_NONE
;
200 while (remaining
> 0) {
201 uint32_t size
= remaining
;
202 rv
= mojo::WriteDataRaw(producer_
.get(), p
, &size
, kNone
);
203 if (rv
== MOJO_RESULT_OK
) {
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";
215 base::MessageLoop message_loop_
;
217 mojo::ScopedDataPipeProducerHandle producer_
;
218 mojo::ScopedDataPipeConsumerHandle consumer_
;
221 TEST_F(WebDataConsumerHandleImplTest
, ReadData
) {
222 base::RunLoop run_loop
;
223 auto operation
= make_scoped_ptr(new ReadDataOperation(
226 run_loop
.QuitClosure()));
228 base::Thread
t("DataConsumerHandle test thread");
229 ASSERT_TRUE(t
.Start());
231 t
.task_runner()->PostTask(FROM_HERE
,
232 base::Bind(&ReadDataOperation::ReadData
,
233 base::Unretained(operation
.get())));
235 std::string expected
= ProduceData(24 * 1024);
241 EXPECT_EQ(expected
, operation
->result());
244 TEST_F(WebDataConsumerHandleImplTest
, TwoPhaseReadData
) {
245 base::RunLoop run_loop
;
246 auto operation
= make_scoped_ptr(new TwoPhaseReadDataOperation(
249 run_loop
.QuitClosure()));
251 base::Thread
t("DataConsumerHandle test thread");
252 ASSERT_TRUE(t
.Start());
254 t
.task_runner()->PostTask(FROM_HERE
,
255 base::Bind(&TwoPhaseReadDataOperation::ReadData
,
256 base::Unretained(operation
.get())));
258 std::string expected
= ProduceData(24 * 1024);
264 EXPECT_EQ(expected
, operation
->result());
269 } // namespace content