summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/ppapi_proxy_test.h
blob: 775b75c03a2125f5973f92d7fa1257f96ca435ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
// Copyright (c) 2011 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 <map>
#include <string>

#include "base/message_loop.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "ipc/ipc_test_sink.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/plugin_var_tracker.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace pp {
namespace proxy {

// Base class for plugin and host test harnesses. Tests will not use this
// directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest.
class ProxyTestHarnessBase {
 public:
  ProxyTestHarnessBase();
  virtual ~ProxyTestHarnessBase();

  PP_Module pp_module() const { return pp_module_; }
  PP_Instance pp_instance() const { return pp_instance_; }
  IPC::TestSink& sink() { return sink_; }

  // Returns either the plugin or host dispatcher, depending on the test.
  virtual Dispatcher* GetDispatcher() = 0;

  // Set up the harness using an IPC::TestSink to capture messages.
  virtual void SetUpHarness() = 0;

  // Set up the harness using a real IPC channel.
  virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
                                       base::MessageLoopProxy* ipc_message_loop,
                                       base::WaitableEvent* shutdown_event,
                                       bool is_client) = 0;

  virtual void TearDownHarness() = 0;

  // Implementation of GetInterface for the dispatcher. This will
  // return NULL for all interfaces unless one is registered by calling
  // RegisterTestInterface();
  const void* GetInterface(const char* name);

  // Allows the test to specify an interface implementation for a given
  // interface name. This will be returned when any of the proxy logic
  // requests a local interface.
  void RegisterTestInterface(const char* name, const void* interface);

  // Sends a "supports interface" message to the current dispatcher and returns
  // true if it's supported. This is just for the convenience of tests.
  bool SupportsInterface(const char* name);

 private:
  // Destination for IPC messages sent by the test.
  IPC::TestSink sink_;

  // The module and instance ID associated with the plugin dispatcher.
  PP_Module pp_module_;
  PP_Instance pp_instance_;

  // Stores the data for GetInterface/RegisterTestInterface.
  std::map<std::string, const void*> registered_interfaces_;
};

// Test harness for the plugin side of the proxy.
class PluginProxyTestHarness : public ProxyTestHarnessBase {
 public:
  PluginProxyTestHarness();
  virtual ~PluginProxyTestHarness();

  PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); }
  PluginResourceTracker& resource_tracker() { return resource_tracker_; }
  PluginVarTracker& var_tracker() { return var_tracker_; }

  // ProxyTestHarnessBase implementation.
  virtual Dispatcher* GetDispatcher();
  virtual void SetUpHarness();
  virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
                                       base::MessageLoopProxy* ipc_message_loop,
                                       base::WaitableEvent* shutdown_event,
                                       bool is_client);
  virtual void TearDownHarness();

  class PluginDelegateMock : public PluginDispatcher::PluginDelegate {
   public:
    PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {}
    virtual ~PluginDelegateMock() {}

    void Init(base::MessageLoopProxy* ipc_message_loop,
              base::WaitableEvent* shutdown_event) {
      ipc_message_loop_ = ipc_message_loop;
      shutdown_event_ = shutdown_event;
    }

    // ProxyChannel::Delegate implementation.
    virtual base::MessageLoopProxy* GetIPCMessageLoop();
    virtual base::WaitableEvent* GetShutdownEvent();

    // PluginDispatcher::PluginDelegate implementation.
    virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet();
    virtual ppapi::WebKitForwarding* GetWebKitForwarding();
    virtual void PostToWebKitThread(const tracked_objects::Location& from_here,
                                    const base::Closure& task);
    virtual bool SendToBrowser(IPC::Message* msg);
    virtual uint32 Register(PluginDispatcher* plugin_dispatcher);
    virtual void Unregister(uint32 plugin_dispatcher_id);

   private:
    base::MessageLoopProxy* ipc_message_loop_;  // Weak
    base::WaitableEvent* shutdown_event_;  // Weak
    std::set<PP_Instance> instance_id_set_;

    DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock);
  };

 private:
  PluginResourceTracker resource_tracker_;
  PluginVarTracker var_tracker_;
  scoped_ptr<PluginDispatcher> plugin_dispatcher_;
  PluginDelegateMock plugin_delegate_mock_;
};

class PluginProxyTest : public PluginProxyTestHarness, public testing::Test {
 public:
  PluginProxyTest();
  virtual ~PluginProxyTest();

  // testing::Test implementation.
  virtual void SetUp();
  virtual void TearDown();
 private:
  MessageLoop message_loop_;
};

class HostProxyTestHarness : public ProxyTestHarnessBase {
 public:
  HostProxyTestHarness();
  virtual ~HostProxyTestHarness();

  HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); }

  // ProxyTestBase implementation.
  virtual Dispatcher* GetDispatcher();
  virtual void SetUpHarness();
  virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
                                       base::MessageLoopProxy* ipc_message_loop,
                                       base::WaitableEvent* shutdown_event,
                                       bool is_client);
  virtual void TearDownHarness();

  class DelegateMock : public ProxyChannel::Delegate {
   public:
    DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) {
    }
    virtual ~DelegateMock() {}

    void Init(base::MessageLoopProxy* ipc_message_loop,
              base::WaitableEvent* shutdown_event) {
      ipc_message_loop_ = ipc_message_loop;
      shutdown_event_ = shutdown_event;
    }

    // ProxyChannel::Delegate implementation.
    virtual base::MessageLoopProxy* GetIPCMessageLoop();
    virtual base::WaitableEvent* GetShutdownEvent();

   private:
    base::MessageLoopProxy* ipc_message_loop_;  // Weak
    base::WaitableEvent* shutdown_event_;  // Weak

    DISALLOW_COPY_AND_ASSIGN(DelegateMock);
  };

 private:
  scoped_ptr<HostDispatcher> host_dispatcher_;
  DelegateMock delegate_mock_;
};

class HostProxyTest : public HostProxyTestHarness, public testing::Test {
 public:
  HostProxyTest();
  virtual ~HostProxyTest();

  // testing::Test implementation.
  virtual void SetUp();
  virtual void TearDown();
 private:
  MessageLoop message_loop_;
};

// Use this base class to test both sides of a proxy.
class TwoWayTest : public testing::Test {
 public:
  enum TwoWayTestMode {
    TEST_PPP_INTERFACE,
    TEST_PPB_INTERFACE
  };
  TwoWayTest(TwoWayTestMode test_mode);
  virtual ~TwoWayTest();

  HostProxyTestHarness& host() { return host_; }
  PluginProxyTestHarness& plugin() { return plugin_; }
  PP_Module pp_module() const { return host_.pp_module(); }
  PP_Instance pp_instance() const { return host_.pp_instance(); }
  TwoWayTestMode test_mode() { return test_mode_; }

  // testing::Test implementation.
  virtual void SetUp();
  virtual void TearDown();

 private:
  TwoWayTestMode test_mode_;
  HostProxyTestHarness host_;
  PluginProxyTestHarness plugin_;
  // In order to use sync IPC, we need to have an IO thread.
  base::Thread io_thread_;
  // The plugin side of the proxy runs on its own thread.
  base::Thread plugin_thread_;
  // The message loop for the main (host) thread.
  MessageLoop message_loop_;

  // Aliases for the host and plugin harnesses; if we're testing a PPP
  // interface, remote_harness will point to plugin_, and local_harness
  // will point to host_.  This makes it convenient when we're starting and
  // stopping the harnesses.
  ProxyTestHarnessBase* remote_harness_;
  ProxyTestHarnessBase* local_harness_;

  base::WaitableEvent channel_created_;
  base::WaitableEvent shutdown_event_;
};

}  // namespace proxy
}  // namespace pp