Home | History | Annotate | Download | only in host
      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
    203