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.
5 #include "ipc/mojo/async_handle_waiter.h"
8 #include "base/location.h"
9 #include "base/run_loop.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/threading/thread.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
19 void ReadOneByteOfX(MojoHandle pipe
) {
22 MojoResult rv
= MojoReadMessage(pipe
, &buffer
, &size
, nullptr, nullptr,
23 MOJO_READ_MESSAGE_FLAG_NONE
);
24 CHECK_EQ(rv
, MOJO_RESULT_OK
);
26 CHECK_EQ(buffer
, 'X');
29 class AsyncHandleWaiterTest
: public testing::Test
{
31 AsyncHandleWaiterTest() : worker_("test_worker") {
32 worker_
.StartWithOptions(
33 base::Thread::Options(base::MessageLoop::TYPE_IO
, 0));
36 void SetUp() override
{
37 message_loop_
.reset(new base::MessageLoopForIO());
38 ResetSignaledStates();
39 mojo::CreateMessagePipe(nullptr, &pipe_to_write_
, &pipe_to_read_
);
40 target_
.reset(new AsyncHandleWaiter(base::Bind(
41 &AsyncHandleWaiterTest::HandleIsReady
, base::Unretained(this))));
46 return target_
->Wait(pipe_to_read_
.get().value(),
47 MOJO_HANDLE_SIGNAL_READABLE
);
50 void ResetSignaledStates() {
51 signaled_result_
= MOJO_RESULT_UNKNOWN
;
52 run_loop_
.reset(new base::RunLoop());
56 MojoResult rv
= MojoWriteMessage(pipe_to_write_
.get().value(), "X", 1,
57 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE
);
58 CHECK_EQ(rv
, MOJO_RESULT_OK
);
61 void WriteToPipeFromWorker() {
62 worker_
.task_runner()->PostTask(
63 FROM_HERE
, base::Bind(&AsyncHandleWaiterTest::WriteToPipe
,
64 base::Unretained(this)));
67 void WaitAndAssertSignaledAndMessageIsArrived() {
69 EXPECT_EQ(MOJO_RESULT_OK
, signaled_result_
);
71 ReadOneByteOfX(pipe_to_read_
.get().value());
74 void WaitAndAssertNotSignaled() {
75 run_loop_
->RunUntilIdle();
76 EXPECT_EQ(MOJO_RESULT_OK
, MojoWait(pipe_to_read_
.get().value(),
77 MOJO_HANDLE_SIGNAL_READABLE
, 0,
79 EXPECT_EQ(MOJO_RESULT_UNKNOWN
, signaled_result_
);
82 void HandleIsReady(MojoResult result
) {
83 CHECK_EQ(base::MessageLoop::current(), message_loop_
.get());
84 CHECK_EQ(signaled_result_
, MOJO_RESULT_UNKNOWN
);
85 signaled_result_
= result
;
90 scoped_ptr
<base::MessageLoop
> message_loop_
;
91 scoped_ptr
<base::RunLoop
> run_loop_
;
92 mojo::ScopedMessagePipeHandle pipe_to_write_
;
93 mojo::ScopedMessagePipeHandle pipe_to_read_
;
95 scoped_ptr
<AsyncHandleWaiter
> target_
;
96 MojoResult signaled_result_
;
99 TEST_F(AsyncHandleWaiterTest
, SignalFromSameThread
) {
100 EXPECT_EQ(MOJO_RESULT_OK
, Start());
102 WaitAndAssertSignaledAndMessageIsArrived();
104 // Ensures that the waiter is reusable.
105 ResetSignaledStates();
107 EXPECT_EQ(MOJO_RESULT_OK
, Start());
109 WaitAndAssertSignaledAndMessageIsArrived();
112 TEST_F(AsyncHandleWaiterTest
, SignalFromDifferentThread
) {
113 EXPECT_EQ(MOJO_RESULT_OK
, Start());
114 WriteToPipeFromWorker();
115 WaitAndAssertSignaledAndMessageIsArrived();
117 // Ensures that the waiter is reusable.
118 ResetSignaledStates();
120 EXPECT_EQ(MOJO_RESULT_OK
, Start());
121 WriteToPipeFromWorker();
122 WaitAndAssertSignaledAndMessageIsArrived();
125 TEST_F(AsyncHandleWaiterTest
, DeleteWaiterBeforeWrite
) {
126 EXPECT_EQ(MOJO_RESULT_OK
, Start());
131 WaitAndAssertNotSignaled();
134 TEST_F(AsyncHandleWaiterTest
, DeleteWaiterBeforeSignal
) {
135 EXPECT_EQ(MOJO_RESULT_OK
, Start());
140 WaitAndAssertNotSignaled();
143 class HandlerThatReenters
{
145 HandlerThatReenters(base::RunLoop
* loop
, MojoHandle handle
)
146 : target_(nullptr), handle_(handle
), loop_(loop
), step_(0) {}
148 void set_target(AsyncHandleWaiter
* target
) { target_
= target
; }
150 void HandleIsReady(MojoResult result
) {
153 RestartAndClose(result
);
156 HandleClosingSignal(result
);
164 void RestartAndClose(MojoResult result
) {
166 CHECK_EQ(result
, MOJO_RESULT_OK
);
169 ReadOneByteOfX(handle_
);
170 target_
->Wait(handle_
, MOJO_HANDLE_SIGNAL_READABLE
);
172 // This signals the |AsyncHandleWaiter|.
173 MojoResult rv
= MojoClose(handle_
);
174 CHECK_EQ(rv
, MOJO_RESULT_OK
);
177 void HandleClosingSignal(MojoResult result
) {
179 CHECK_EQ(result
, MOJO_RESULT_CANCELLED
);
184 bool IsClosingHandled() const { return step_
== 2; }
186 AsyncHandleWaiter
* target_
;
188 base::RunLoop
* loop_
;
192 TEST_F(AsyncHandleWaiterTest
, RestartWaitingWhileSignaled
) {
193 HandlerThatReenters
handler(run_loop_
.get(), pipe_to_read_
.get().value());
194 target_
.reset(new AsyncHandleWaiter(base::Bind(
195 &HandlerThatReenters::HandleIsReady
, base::Unretained(&handler
))));
196 handler
.set_target(target_
.get());
198 EXPECT_EQ(MOJO_RESULT_OK
, Start());
202 EXPECT_TRUE(handler
.IsClosingHandled());
204 // |HandlerThatReenters::RestartAndClose| already closed it.
205 ::ignore_result(pipe_to_read_
.release());
208 class AsyncHandleWaiterIOObserverTest
: public testing::Test
{
210 void SetUp() override
{
211 message_loop_
.reset(new base::MessageLoopForIO());
212 target_
.reset(new AsyncHandleWaiter(
213 base::Bind(&AsyncHandleWaiterIOObserverTest::HandleIsReady
,
214 base::Unretained(this))));
215 invocation_count_
= 0;
218 void HandleIsReady(MojoResult result
) { invocation_count_
++; }
220 scoped_ptr
<base::MessageLoop
> message_loop_
;
221 scoped_ptr
<AsyncHandleWaiter
> target_
;
222 size_t invocation_count_
;
225 TEST_F(AsyncHandleWaiterIOObserverTest
, OutsideIOEvnet
) {
226 target_
->GetWaitCallbackForTest().Run(MOJO_RESULT_OK
);
227 EXPECT_EQ(0U, invocation_count_
);
228 message_loop_
->RunUntilIdle();
229 EXPECT_EQ(1U, invocation_count_
);
232 TEST_F(AsyncHandleWaiterIOObserverTest
, InsideIOEvnet
) {
233 target_
->GetIOObserverForTest()->WillProcessIOEvent();
234 target_
->GetWaitCallbackForTest().Run(MOJO_RESULT_OK
);
235 EXPECT_EQ(0U, invocation_count_
);
236 target_
->GetIOObserverForTest()->DidProcessIOEvent();
237 EXPECT_EQ(1U, invocation_count_
);
240 TEST_F(AsyncHandleWaiterIOObserverTest
, Reenter
) {
241 target_
->GetIOObserverForTest()->WillProcessIOEvent();
242 target_
->GetWaitCallbackForTest().Run(MOJO_RESULT_OK
);
243 EXPECT_EQ(0U, invocation_count_
);
245 // As if some other io handler start nested loop.
246 target_
->GetIOObserverForTest()->WillProcessIOEvent();
247 target_
->GetWaitCallbackForTest().Run(MOJO_RESULT_OK
);
248 target_
->GetIOObserverForTest()->DidProcessIOEvent();
249 EXPECT_EQ(0U, invocation_count_
);
251 target_
->GetIOObserverForTest()->DidProcessIOEvent();
252 EXPECT_EQ(1U, invocation_count_
);
256 } // namespace internal