| Index: ppapi/host/resource_message_filter_unittest.cc
|
| diff --git a/ppapi/host/resource_message_filter_unittest.cc b/ppapi/host/resource_message_filter_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..647d2aee68e026a622dd3f8beb3e9b5f3e05ce1d
|
| --- /dev/null
|
| +++ b/ppapi/host/resource_message_filter_unittest.cc
|
| @@ -0,0 +1,202 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/message_loop.h"
|
| +#include "base/message_loop_proxy.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/thread.h"
|
| +#include "ipc/ipc_message.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/host/host_message_context.h"
|
| +#include "ppapi/host/resource_host.h"
|
| +#include "ppapi/host/resource_message_filter.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace ppapi {
|
| +namespace host {
|
| +
|
| +typedef testing::Test ResourceMessageFilterTest;
|
| +
|
| +namespace {
|
| +
|
| +base::WaitableEvent g_handler_completion(true, false);
|
| +
|
| +enum TestMessageTypes {
|
| + MSG1_TYPE = 1,
|
| + MSG2_TYPE,
|
| + MSG3_TYPE,
|
| + REPLY_MSG1_TYPE,
|
| + REPLY_MSG2_TYPE,
|
| + REPLY_MSG3_TYPE,
|
| +};
|
| +
|
| +// Dummy resource host which simply stores a copy messages it handles.
|
| +// |SendReply| is overridden to store a copy of the outgoing message and the
|
| +// message loop on which it was sent.
|
| +class MyResourceHost : public ResourceHost {
|
| + public:
|
| + // Messages of type |msg_type| will be handled (simply by replying with a
|
| + // message of type |reply_msg_type|).
|
| + MyResourceHost(PpapiHost* host,
|
| + PP_Instance instance,
|
| + PP_Resource resource,
|
| + uint32 msg_type,
|
| + uint32 reply_msg_type)
|
| + : ResourceHost(host, instance, resource),
|
| + msg_type_(msg_type),
|
| + reply_msg_type_(reply_msg_type),
|
| + last_reply_message_loop_(NULL) {
|
| + }
|
| +
|
| + const IPC::Message& last_handled_msg() { return last_handled_msg_; }
|
| + const IPC::Message& last_reply_msg() { return last_reply_msg_; }
|
| + MessageLoop* last_reply_message_loop() {
|
| + return last_reply_message_loop_;
|
| + }
|
| +
|
| + void AddMessageFilter(scoped_refptr<ResourceMessageFilter> filter) {
|
| + AddFilter(filter);
|
| + }
|
| +
|
| + virtual int32_t OnResourceMessageReceived(
|
| + const IPC::Message& msg,
|
| + HostMessageContext* context) OVERRIDE {
|
| + last_handled_msg_ = msg;
|
| + if (msg.type() == msg_type_) {
|
| + context->reply_msg = IPC::Message(0, reply_msg_type_,
|
| + IPC::Message::PRIORITY_NORMAL);
|
| + return PP_OK;
|
| + }
|
| + return PP_ERROR_FAILED;
|
| + }
|
| +
|
| + virtual void SendReply(const ReplyMessageContext& context,
|
| + const IPC::Message& msg) OVERRIDE {
|
| + last_reply_msg_ = msg;
|
| + last_reply_message_loop_ = MessageLoop::current();
|
| + g_handler_completion.Signal();
|
| + }
|
| +
|
| + private:
|
| + uint32 msg_type_;
|
| + uint32 reply_msg_type_;
|
| +
|
| + IPC::Message last_handled_msg_;
|
| + IPC::Message last_reply_msg_;
|
| + MessageLoop* last_reply_message_loop_;
|
| +};
|
| +
|
| +// Dummy message filter which simply stores a copy of messages it handles.
|
| +// The message loop on which the message is handled is also stored for checking
|
| +// later.
|
| +class MyResourceFilter : public ResourceMessageFilter {
|
| + public:
|
| + // Messages of type |msg_type| will be handled (simply by replying with a
|
| + // message of type |reply_msg_type|). |io_thread| is the thread on which
|
| + // replies should be sent. |bg_thread| is the thread on which the message
|
| + // should be handled.
|
| + MyResourceFilter(const base::Thread& io_thread,
|
| + const base::Thread& bg_thread,
|
| + uint32 msg_type,
|
| + uint32 reply_msg_type)
|
| + : ResourceMessageFilter(io_thread.message_loop_proxy()),
|
| + message_loop_proxy_(bg_thread.message_loop_proxy()),
|
| + msg_type_(msg_type),
|
| + reply_msg_type_(reply_msg_type),
|
| + last_message_loop_(NULL) {
|
| + }
|
| +
|
| + const IPC::Message& last_handled_msg() { return last_handled_msg_; }
|
| + MessageLoop* last_message_loop() { return last_message_loop_; }
|
| +
|
| + virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
|
| + const IPC::Message& msg) OVERRIDE {
|
| + if (msg.type() == msg_type_)
|
| + return message_loop_proxy_;
|
| + return NULL;
|
| + }
|
| +
|
| + virtual int32_t OnResourceMessageReceived(
|
| + const IPC::Message& msg,
|
| + HostMessageContext* context) OVERRIDE {
|
| + last_handled_msg_ = msg;
|
| + last_message_loop_ = MessageLoop::current();
|
| + if (msg.type() == msg_type_) {
|
| + context->reply_msg = IPC::Message(0, reply_msg_type_,
|
| + IPC::Message::PRIORITY_NORMAL);
|
| + return PP_OK;
|
| + }
|
| + return PP_ERROR_FAILED;
|
| + }
|
| +
|
| + private:
|
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
|
| + uint32 msg_type_;
|
| + uint32 reply_msg_type_;
|
| +
|
| + IPC::Message last_handled_msg_;
|
| + MessageLoop* last_message_loop_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// Test that messages are filtered correctly and handlers are run on the correct
|
| +// threads.
|
| +TEST_F(ResourceMessageFilterTest, TestHandleMessage) {
|
| + base::Thread io_thread("test_io_thread");
|
| + ASSERT_TRUE(io_thread.Start());
|
| +
|
| + base::Thread bg_thread1("test_background_thread1");
|
| + ASSERT_TRUE(bg_thread1.Start());
|
| + scoped_refptr<MyResourceFilter> filter1 =
|
| + new MyResourceFilter(io_thread, bg_thread1, MSG1_TYPE, REPLY_MSG1_TYPE);
|
| +
|
| + base::Thread bg_thread2("test_background_thread2");
|
| + ASSERT_TRUE(bg_thread2.Start());
|
| + scoped_refptr<MyResourceFilter> filter2 =
|
| + new MyResourceFilter(io_thread, bg_thread2, MSG2_TYPE, REPLY_MSG2_TYPE);
|
| +
|
| + PP_Instance instance = 12345;
|
| + PP_Resource resource = 67890;
|
| + MyResourceHost host(NULL, instance, resource, MSG3_TYPE, REPLY_MSG3_TYPE);
|
| + host.AddMessageFilter(filter1);
|
| + host.AddMessageFilter(filter2);
|
| +
|
| + proxy::ResourceMessageCallParams params(resource, 1);
|
| + params.set_has_callback();
|
| + HostMessageContext context(params);
|
| + IPC::Message message1(0, MSG1_TYPE, IPC::Message::PRIORITY_NORMAL);
|
| + IPC::Message message2(0, MSG2_TYPE, IPC::Message::PRIORITY_NORMAL);
|
| + IPC::Message message3(0, MSG3_TYPE, IPC::Message::PRIORITY_NORMAL);
|
| +
|
| + // Message 1 handled by the first filter.
|
| + host.HandleMessage(message1, &context);
|
| + g_handler_completion.Wait();
|
| + EXPECT_EQ(filter1->last_handled_msg().type(), message1.type());
|
| + EXPECT_EQ(filter1->last_message_loop(), bg_thread1.message_loop());
|
| + EXPECT_EQ(host.last_reply_msg().type(), REPLY_MSG1_TYPE);
|
| + EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
|
| + g_handler_completion.Reset();
|
| +
|
| + // Message 2 handled by the second filter.
|
| + host.HandleMessage(message2, &context);
|
| + g_handler_completion.Wait();
|
| + EXPECT_EQ(filter2->last_handled_msg().type(), message2.type());
|
| + EXPECT_EQ(filter2->last_message_loop(), bg_thread2.message_loop());
|
| + EXPECT_EQ(host.last_reply_msg().type(), REPLY_MSG2_TYPE);
|
| + EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
|
| + g_handler_completion.Reset();
|
| +
|
| + // Message 3 handled by the resource host.
|
| + host.HandleMessage(message3, &context);
|
| + EXPECT_EQ(host.last_handled_msg().type(), message3.type());
|
| + EXPECT_EQ(host.last_reply_msg().type(), REPLY_MSG3_TYPE);
|
| +
|
| + io_thread.Stop();
|
| + bg_thread1.Stop();
|
| + bg_thread2.Stop();
|
| +}
|
| +
|
| +} // namespace proxy
|
| +} // namespace ppapi
|
|
|