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/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"
22 using blink::WebDataConsumerHandle
;
24 class ReadDataOperationBase
{
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
{
40 explicit ClientImpl(ReadDataOperationBase
* operation
)
41 : operation_(operation
) {}
43 void didGetReadable() override
{
44 base::MessageLoop::current()->PostTask(
46 base::Bind(&ReadDataOperationBase::ReadMore
,
47 base::Unretained(operation_
)));
51 ReadDataOperationBase
* operation_
;
54 class ReadDataOperation
: public ReadDataOperationBase
{
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
),
64 const std::string
& result() const { return result_
; }
66 void ReadMore() override
{ ReadData(); }
70 client_
.reset(new ClientImpl(this));
71 handle_
->registerClient(client_
.get());
79 rv
= handle_
->read(&buffer
, sizeof(buffer
), kNone
, &readSize
);
82 result_
.insert(result_
.size(), &buffer
[0], readSize
);
85 if (rv
== kShouldWait
) {
91 // Something is wrong.
95 // The operation is done.
96 main_message_loop_
->PostTask(FROM_HERE
, on_done_
);
100 scoped_ptr
<WebDataConsumerHandle
> handle_
;
101 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
102 base::MessageLoop
* main_message_loop_
;
103 base::Closure on_done_
;
107 class TwoPhaseReadDataOperation
: public ReadDataOperationBase
{
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
{
124 client_
.reset(new ClientImpl(this));
125 handle_
->registerClient(client_
.get());
130 const void* buffer
= nullptr;
132 rv
= handle_
->beginRead(&buffer
, kNone
, &size
);
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
),
139 rv
= handle_
->endRead(read_size
);
141 // Something is wrong.
143 main_message_loop_
->PostTask(FROM_HERE
, on_done_
);
148 if (rv
== kShouldWait
) {
154 // Something is wrong.
158 // The operation is done.
159 main_message_loop_
->PostTask(FROM_HERE
, on_done_
);
163 scoped_ptr
<WebDataConsumerHandle
> handle_
;
164 scoped_ptr
<WebDataConsumerHandle::Client
> client_
;
165 base::MessageLoop
* main_message_loop_
;
166 base::Closure on_done_
;
170 class WebDataConsumerHandleImplTest
: public ::testing::Test
{
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
187 std::string
ProduceData(size_t total_size
) {
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
;
199 while (remaining
> 0) {
200 uint32_t size
= remaining
;
201 rv
= mojo::WriteDataRaw(producer_
.get(), p
, &size
, kNone
);
202 if (rv
== MOJO_RESULT_OK
) {
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";
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(
225 run_loop
.QuitClosure()));
227 base::Thread
t("DataConsumerHandle test thread");
228 ASSERT_TRUE(t
.Start());
230 t
.message_loop()->PostTask(
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
.message_loop()->PostTask(
256 base::Bind(&TwoPhaseReadDataOperation::ReadData
,
257 base::Unretained(operation
.get())));
259 std::string expected
= ProduceData(24 * 1024);
265 EXPECT_EQ(expected
, operation
->result());
270 } // namespace content