- add sources.
[platform/framework/web/crosswalk.git] / src / ppapi / host / resource_message_filter_unittest.cc
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.
4
5 #include "base/message_loop/message_loop.h"
6 #include "base/message_loop/message_loop_proxy.h"
7 #include "base/synchronization/waitable_event.h"
8 #include "base/threading/thread.h"
9 #include "ipc/ipc_message.h"
10 #include "ppapi/c/pp_errors.h"
11 #include "ppapi/host/host_message_context.h"
12 #include "ppapi/host/resource_host.h"
13 #include "ppapi/host/resource_message_filter.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace ppapi {
17 namespace host {
18
19 typedef testing::Test ResourceMessageFilterTest;
20
21 namespace {
22
23 base::WaitableEvent g_handler_completion(true, false);
24
25 enum TestMessageTypes {
26   MSG1_TYPE = 1,
27   MSG2_TYPE,
28   MSG3_TYPE,
29   REPLY_MSG1_TYPE,
30   REPLY_MSG2_TYPE,
31   REPLY_MSG3_TYPE,
32 };
33
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 {
38  public:
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,
42                  PP_Instance instance,
43                  PP_Resource resource,
44                  uint32 msg_type,
45                  uint32 reply_msg_type)
46       : ResourceHost(host, instance, resource),
47         msg_type_(msg_type),
48         reply_msg_type_(reply_msg_type),
49         last_reply_message_loop_(NULL) {
50   }
51
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_;
56   }
57
58   void AddMessageFilter(scoped_refptr<ResourceMessageFilter> filter) {
59     AddFilter(filter);
60   }
61
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);
69       return PP_OK;
70     }
71     return PP_ERROR_FAILED;
72   }
73
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();
79   }
80
81  private:
82   uint32 msg_type_;
83   uint32 reply_msg_type_;
84
85   IPC::Message last_handled_msg_;
86   IPC::Message last_reply_msg_;
87   base::MessageLoop* last_reply_message_loop_;
88 };
89
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
92 // later.
93 class MyResourceFilter : public ResourceMessageFilter {
94  public:
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
98   // should be handled.
99   MyResourceFilter(const base::Thread& io_thread,
100                    const base::Thread& bg_thread,
101                    uint32 msg_type,
102                    uint32 reply_msg_type)
103       : ResourceMessageFilter(io_thread.message_loop_proxy()),
104         message_loop_proxy_(bg_thread.message_loop_proxy()),
105         msg_type_(msg_type),
106         reply_msg_type_(reply_msg_type),
107         last_message_loop_(NULL) {
108   }
109
110   const IPC::Message& last_handled_msg() const { return last_handled_msg_; }
111   base::MessageLoop* last_message_loop() const { return last_message_loop_; }
112
113   virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
114       const IPC::Message& msg) OVERRIDE {
115     if (msg.type() == msg_type_)
116       return message_loop_proxy_;
117     return NULL;
118   }
119
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);
128       return PP_OK;
129     }
130     return PP_ERROR_FAILED;
131   }
132
133  private:
134   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
135   uint32 msg_type_;
136   uint32 reply_msg_type_;
137
138   IPC::Message last_handled_msg_;
139   base::MessageLoop* last_message_loop_;
140 };
141
142 }  // namespace
143
144 // Test that messages are filtered correctly and handlers are run on the correct
145 // threads.
146 TEST_F(ResourceMessageFilterTest, TestHandleMessage) {
147   base::Thread io_thread("test_io_thread");
148   ASSERT_TRUE(io_thread.Start());
149
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);
154
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);
159
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);
165
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);
172
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(), static_cast<uint32>(REPLY_MSG1_TYPE));
179   EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
180   g_handler_completion.Reset();
181
182   // Message 2 handled by the second filter.
183   host.HandleMessage(message2, &context);
184   g_handler_completion.Wait();
185   EXPECT_EQ(filter2->last_handled_msg().type(), message2.type());
186   EXPECT_EQ(filter2->last_message_loop(), bg_thread2.message_loop());
187   EXPECT_EQ(host.last_reply_msg().type(), static_cast<uint32>(REPLY_MSG2_TYPE));
188   EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
189   g_handler_completion.Reset();
190
191   // Message 3 handled by the resource host.
192   host.HandleMessage(message3, &context);
193   EXPECT_EQ(host.last_handled_msg().type(), message3.type());
194   EXPECT_EQ(host.last_reply_msg().type(), static_cast<uint32>(REPLY_MSG3_TYPE));
195
196   io_thread.Stop();
197   bg_thread1.Stop();
198   bg_thread2.Stop();
199 }
200
201 }  // namespace proxy
202 }  // namespace ppapi