1 // Copyright (c) 2012 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.
6 #include "base/bind_helpers.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/message_loop/message_loop_proxy.h"
9 #include "base/run_loop.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread.h"
12 #include "ipc/ipc_message.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/host/host_message_context.h"
15 #include "ppapi/host/resource_host.h"
16 #include "ppapi/host/resource_message_filter.h"
17 #include "testing/gtest/include/gtest/gtest.h"
23 base::WaitableEvent
g_handler_completion(true, false);
25 enum TestMessageTypes
{
34 // Dummy resource host which simply stores a copy of messages it handles.
35 // |SendReply| is overridden to store a copy of the outgoing message and the
36 // message loop on which it was sent.
37 class MyResourceHost
: public ResourceHost
{
39 // Messages of type |msg_type| will be handled (simply by replying with a
40 // message of type |reply_msg_type|).
41 MyResourceHost(PpapiHost
* host
,
45 uint32 reply_msg_type
)
46 : ResourceHost(host
, instance
, resource
),
48 reply_msg_type_(reply_msg_type
),
49 last_reply_message_loop_(NULL
) {
52 const IPC::Message
& last_handled_msg() const { return last_handled_msg_
; }
53 const IPC::Message
& last_reply_msg() const { return last_reply_msg_
; }
54 base::MessageLoop
* last_reply_message_loop() const {
55 return last_reply_message_loop_
;
58 void AddMessageFilter(scoped_refptr
<ResourceMessageFilter
> filter
) {
62 virtual int32_t OnResourceMessageReceived(
63 const IPC::Message
& msg
,
64 HostMessageContext
* context
) OVERRIDE
{
65 last_handled_msg_
= msg
;
66 if (msg
.type() == msg_type_
) {
67 context
->reply_msg
= IPC::Message(0, reply_msg_type_
,
68 IPC::Message::PRIORITY_NORMAL
);
71 return PP_ERROR_FAILED
;
74 virtual void SendReply(const ReplyMessageContext
& context
,
75 const IPC::Message
& msg
) OVERRIDE
{
76 last_reply_msg_
= msg
;
77 last_reply_message_loop_
= base::MessageLoop::current();
78 g_handler_completion
.Signal();
83 uint32 reply_msg_type_
;
85 IPC::Message last_handled_msg_
;
86 IPC::Message last_reply_msg_
;
87 base::MessageLoop
* last_reply_message_loop_
;
90 // Dummy message filter which simply stores a copy of messages it handles.
91 // The message loop on which the message is handled is also stored for checking
93 class MyResourceFilter
: public ResourceMessageFilter
{
95 // Messages of type |msg_type| will be handled (simply by replying with a
96 // message of type |reply_msg_type|). |io_thread| is the thread on which
97 // replies should be sent. |bg_thread| is the thread on which the message
99 MyResourceFilter(const base::Thread
& io_thread
,
100 const base::Thread
& bg_thread
,
102 uint32 reply_msg_type
)
103 : ResourceMessageFilter(io_thread
.message_loop_proxy()),
104 message_loop_proxy_(bg_thread
.message_loop_proxy()),
106 reply_msg_type_(reply_msg_type
),
107 last_message_loop_(NULL
) {
110 const IPC::Message
& last_handled_msg() const { return last_handled_msg_
; }
111 base::MessageLoop
* last_message_loop() const { return last_message_loop_
; }
113 virtual scoped_refptr
<base::TaskRunner
> OverrideTaskRunnerForMessage(
114 const IPC::Message
& msg
) OVERRIDE
{
115 if (msg
.type() == msg_type_
)
116 return message_loop_proxy_
;
120 virtual int32_t OnResourceMessageReceived(
121 const IPC::Message
& msg
,
122 HostMessageContext
* context
) OVERRIDE
{
123 last_handled_msg_
= msg
;
124 last_message_loop_
= base::MessageLoop::current();
125 if (msg
.type() == msg_type_
) {
126 context
->reply_msg
= IPC::Message(0, reply_msg_type_
,
127 IPC::Message::PRIORITY_NORMAL
);
130 return PP_ERROR_FAILED
;
134 scoped_refptr
<base::MessageLoopProxy
> message_loop_proxy_
;
136 uint32 reply_msg_type_
;
138 IPC::Message last_handled_msg_
;
139 base::MessageLoop
* last_message_loop_
;
144 class ResourceMessageFilterTest
: public testing::Test
{
146 void TestHandleMessageImpl() {
147 base::Thread
io_thread("test_io_thread");
148 ASSERT_TRUE(io_thread
.Start());
150 base::Thread
bg_thread1("test_background_thread1");
151 ASSERT_TRUE(bg_thread1
.Start());
152 scoped_refptr
<MyResourceFilter
> filter1
=
153 new MyResourceFilter(io_thread
, bg_thread1
, MSG1_TYPE
, REPLY_MSG1_TYPE
);
155 base::Thread
bg_thread2("test_background_thread2");
156 ASSERT_TRUE(bg_thread2
.Start());
157 scoped_refptr
<MyResourceFilter
> filter2
=
158 new MyResourceFilter(io_thread
, bg_thread2
, MSG2_TYPE
, REPLY_MSG2_TYPE
);
160 PP_Instance instance
= 12345;
161 PP_Resource resource
= 67890;
162 MyResourceHost
host(NULL
, instance
, resource
, MSG3_TYPE
, REPLY_MSG3_TYPE
);
163 host
.AddMessageFilter(filter1
);
164 host
.AddMessageFilter(filter2
);
166 proxy::ResourceMessageCallParams
params(resource
, 1);
167 params
.set_has_callback();
168 HostMessageContext
context(params
);
169 IPC::Message
message1(0, MSG1_TYPE
, IPC::Message::PRIORITY_NORMAL
);
170 IPC::Message
message2(0, MSG2_TYPE
, IPC::Message::PRIORITY_NORMAL
);
171 IPC::Message
message3(0, MSG3_TYPE
, IPC::Message::PRIORITY_NORMAL
);
173 // Message 1 handled by the first filter.
174 host
.HandleMessage(message1
, &context
);
175 g_handler_completion
.Wait();
176 EXPECT_EQ(filter1
->last_handled_msg().type(), message1
.type());
177 EXPECT_EQ(filter1
->last_message_loop(), bg_thread1
.message_loop());
178 EXPECT_EQ(host
.last_reply_msg().type(),
179 static_cast<uint32
>(REPLY_MSG1_TYPE
));
180 EXPECT_EQ(host
.last_reply_message_loop(), io_thread
.message_loop());
181 g_handler_completion
.Reset();
183 // Message 2 handled by the second filter.
184 host
.HandleMessage(message2
, &context
);
185 g_handler_completion
.Wait();
186 EXPECT_EQ(filter2
->last_handled_msg().type(), message2
.type());
187 EXPECT_EQ(filter2
->last_message_loop(), bg_thread2
.message_loop());
188 EXPECT_EQ(host
.last_reply_msg().type(),
189 static_cast<uint32
>(REPLY_MSG2_TYPE
));
190 EXPECT_EQ(host
.last_reply_message_loop(), io_thread
.message_loop());
191 g_handler_completion
.Reset();
193 // Message 3 handled by the resource host.
194 host
.HandleMessage(message3
, &context
);
195 EXPECT_EQ(host
.last_handled_msg().type(), message3
.type());
196 EXPECT_EQ(host
.last_reply_msg().type(),
197 static_cast<uint32
>(REPLY_MSG3_TYPE
));
205 // Test that messages are filtered correctly and handlers are run on the correct
207 TEST_F(ResourceMessageFilterTest
, TestHandleMessage
) {
208 // ResourceMessageFilter instances need to be created on a thread with message
209 // loop. Therefore, we create a message loop and run the testing logic as a
211 base::MessageLoop main_message_loop
;
213 // It should be safe to use base::Unretained() because the object won't be
214 // destroyed before the task is run.
215 main_message_loop
.PostTask(
217 base::Bind(&ResourceMessageFilterTest::TestHandleMessageImpl
,
218 base::Unretained(this)));
220 base::RunLoop().RunUntilIdle();