• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <map>
6 #include <string>
7 
8 #include "base/compiler_specific.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/simple_thread.h"
14 #include "base/threading/thread.h"
15 #include "ppapi/c/pp_instance.h"
16 #include "ppapi/proxy/host_dispatcher.h"
17 #include "ppapi/proxy/plugin_dispatcher.h"
18 #include "ppapi/proxy/plugin_globals.h"
19 #include "ppapi/proxy/plugin_proxy_delegate.h"
20 #include "ppapi/proxy/plugin_resource_tracker.h"
21 #include "ppapi/proxy/plugin_var_tracker.h"
22 #include "ppapi/proxy/resource_message_test_sink.h"
23 #include "ppapi/shared_impl/test_globals.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace base {
27 class MessageLoopProxy;
28 class RunLoop;
29 }
30 
31 namespace ppapi {
32 namespace proxy {
33 
34 class MessageLoopResource;
35 
36 // Base class for plugin and host test harnesses. Tests will not use this
37 // directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest.
38 class ProxyTestHarnessBase {
39  public:
40   enum GlobalsConfiguration {
41     PER_THREAD_GLOBALS,
42     SINGLETON_GLOBALS
43   };
44 
45   ProxyTestHarnessBase();
46   virtual ~ProxyTestHarnessBase();
47 
pp_module()48   PP_Module pp_module() const { return pp_module_; }
pp_instance()49   PP_Instance pp_instance() const { return pp_instance_; }
sink()50   ResourceMessageTestSink& sink() { return sink_; }
51 
52   virtual PpapiGlobals* GetGlobals() = 0;
53   // Returns either the plugin or host dispatcher, depending on the test.
54   virtual Dispatcher* GetDispatcher() = 0;
55 
56   // Set up the harness using an IPC::TestSink to capture messages.
57   virtual void SetUpHarness() = 0;
58 
59   // Set up the harness using a real IPC channel.
60   virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
61                                        base::MessageLoopProxy* ipc_message_loop,
62                                        base::WaitableEvent* shutdown_event,
63                                        bool is_client) = 0;
64 
65   virtual void TearDownHarness() = 0;
66 
67   // Implementation of GetInterface for the dispatcher. This will
68   // return NULL for all interfaces unless one is registered by calling
69   // RegisterTestInterface();
70   const void* GetInterface(const char* name);
71 
72   // Allows the test to specify an interface implementation for a given
73   // interface name. This will be returned when any of the proxy logic
74   // requests a local interface.
75   void RegisterTestInterface(const char* name, const void* test_interface);
76 
77   // Sends a "supports interface" message to the current dispatcher and returns
78   // true if it's supported. This is just for the convenience of tests.
79   bool SupportsInterface(const char* name);
80 
81  private:
82   // Destination for IPC messages sent by the test.
83   ResourceMessageTestSink sink_;
84 
85   // The module and instance ID associated with the plugin dispatcher.
86   PP_Module pp_module_;
87   PP_Instance pp_instance_;
88 
89   // Stores the data for GetInterface/RegisterTestInterface.
90   std::map<std::string, const void*> registered_interfaces_;
91 };
92 
93 // Test harness for the plugin side of the proxy.
94 class PluginProxyTestHarness : public ProxyTestHarnessBase {
95  public:
96   explicit PluginProxyTestHarness(GlobalsConfiguration globals_config);
97   virtual ~PluginProxyTestHarness();
98 
plugin_dispatcher()99   PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); }
resource_tracker()100   PluginResourceTracker& resource_tracker() {
101     return *plugin_globals_->plugin_resource_tracker();
102   }
var_tracker()103   PluginVarTracker& var_tracker() {
104     return *plugin_globals_->plugin_var_tracker();
105   }
106 
107   // ProxyTestHarnessBase implementation.
108   virtual PpapiGlobals* GetGlobals();
109   virtual Dispatcher* GetDispatcher();
110   virtual void SetUpHarness();
111   virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
112                                        base::MessageLoopProxy* ipc_message_loop,
113                                        base::WaitableEvent* shutdown_event,
114                                        bool is_client);
115   virtual void TearDownHarness();
116 
117   class PluginDelegateMock : public PluginDispatcher::PluginDelegate,
118                              public PluginProxyDelegate {
119    public:
PluginDelegateMock()120     PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {}
~PluginDelegateMock()121     virtual ~PluginDelegateMock() {}
122 
Init(base::MessageLoopProxy * ipc_message_loop,base::WaitableEvent * shutdown_event)123     void Init(base::MessageLoopProxy* ipc_message_loop,
124               base::WaitableEvent* shutdown_event) {
125       ipc_message_loop_ = ipc_message_loop;
126       shutdown_event_ = shutdown_event;
127     }
128 
set_browser_sender(IPC::Sender * browser_sender)129     void set_browser_sender(IPC::Sender* browser_sender) {
130       browser_sender_ = browser_sender;
131     }
132 
133     // ProxyChannel::Delegate implementation.
134     virtual base::MessageLoopProxy* GetIPCMessageLoop() OVERRIDE;
135     virtual base::WaitableEvent* GetShutdownEvent() OVERRIDE;
136     virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
137         base::PlatformFile handle,
138         base::ProcessId remote_pid,
139         bool should_close_source) OVERRIDE;
140 
141     // PluginDispatcher::PluginDelegate implementation.
142     virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() OVERRIDE;
143     virtual uint32 Register(PluginDispatcher* plugin_dispatcher) OVERRIDE;
144     virtual void Unregister(uint32 plugin_dispatcher_id) OVERRIDE;
145 
146     // PluginProxyDelegate implementation.
147     virtual IPC::Sender* GetBrowserSender() OVERRIDE;
148     virtual std::string GetUILanguage() OVERRIDE;
149     virtual void PreCacheFont(const void* logfontw) OVERRIDE;
150     virtual void SetActiveURL(const std::string& url) OVERRIDE;
151     virtual PP_Resource CreateBrowserFont(
152         Connection connection,
153         PP_Instance instance,
154         const PP_BrowserFont_Trusted_Description& desc,
155         const Preferences& prefs) OVERRIDE;
156 
157    private:
158     base::MessageLoopProxy* ipc_message_loop_;  // Weak
159     base::WaitableEvent* shutdown_event_;  // Weak
160     std::set<PP_Instance> instance_id_set_;
161     IPC::Sender* browser_sender_;
162 
163     DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock);
164   };
165 
166  private:
167   void CreatePluginGlobals();
168 
169   GlobalsConfiguration globals_config_;
170   scoped_ptr<PluginGlobals> plugin_globals_;
171 
172   scoped_ptr<PluginDispatcher> plugin_dispatcher_;
173   PluginDelegateMock plugin_delegate_mock_;
174 };
175 
176 class PluginProxyTest : public PluginProxyTestHarness, public testing::Test {
177  public:
178   PluginProxyTest();
179   virtual ~PluginProxyTest();
180 
181   // testing::Test implementation.
182   virtual void SetUp();
183   virtual void TearDown();
184  private:
185   base::MessageLoop message_loop_;
186 };
187 
188 // This class provides support for multi-thread testing. A secondary thread is
189 // created with a Pepper message loop.
190 // Subclasses need to implement the two SetUpTestOn*Thread() methods to do the
191 // actual testing work; and call both PostQuitFor*Thread() when testing is
192 // done.
193 class PluginProxyMultiThreadTest
194     : public PluginProxyTest,
195       public base::DelegateSimpleThread::Delegate {
196  public:
197   PluginProxyMultiThreadTest();
198   virtual ~PluginProxyMultiThreadTest();
199 
200   // Called before the secondary thread is started, but after all the member
201   // variables, including |secondary_thread_| and
202   // |secondary_thread_message_loop_|, are initialized.
203   virtual void SetUpTestOnMainThread() = 0;
204 
205   virtual void SetUpTestOnSecondaryThread() = 0;
206 
207   // TEST_F() should call this method.
208   void RunTest();
209 
210   enum ThreadType {
211     MAIN_THREAD,
212     SECONDARY_THREAD
213   };
214   void CheckOnThread(ThreadType thread_type);
215 
216   // These can be called on any thread.
217   void PostQuitForMainThread();
218   void PostQuitForSecondaryThread();
219 
220  protected:
221   scoped_refptr<MessageLoopResource> secondary_thread_message_loop_;
222   scoped_refptr<base::MessageLoopProxy> main_thread_message_loop_proxy_;
223 
224  private:
225   // base::DelegateSimpleThread::Delegate implementation.
226   virtual void Run() OVERRIDE;
227 
228   void QuitNestedLoop();
229 
230   static void InternalSetUpTestOnSecondaryThread(void* user_data,
231                                                  int32_t result);
232 
233   scoped_ptr<base::DelegateSimpleThread> secondary_thread_;
234   scoped_ptr<base::RunLoop> nested_main_thread_message_loop_;
235 };
236 
237 class HostProxyTestHarness : public ProxyTestHarnessBase {
238  public:
239   explicit HostProxyTestHarness(GlobalsConfiguration globals_config);
240   virtual ~HostProxyTestHarness();
241 
host_dispatcher()242   HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); }
resource_tracker()243   ResourceTracker& resource_tracker() {
244     return *host_globals_->GetResourceTracker();
245   }
var_tracker()246   VarTracker& var_tracker() {
247     return *host_globals_->GetVarTracker();
248   }
249 
250   // ProxyTestBase implementation.
251   virtual PpapiGlobals* GetGlobals();
252   virtual Dispatcher* GetDispatcher();
253   virtual void SetUpHarness();
254   virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
255                                        base::MessageLoopProxy* ipc_message_loop,
256                                        base::WaitableEvent* shutdown_event,
257                                        bool is_client);
258   virtual void TearDownHarness();
259 
260   class DelegateMock : public ProxyChannel::Delegate {
261    public:
DelegateMock()262     DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) {
263     }
~DelegateMock()264     virtual ~DelegateMock() {}
265 
Init(base::MessageLoopProxy * ipc_message_loop,base::WaitableEvent * shutdown_event)266     void Init(base::MessageLoopProxy* ipc_message_loop,
267               base::WaitableEvent* shutdown_event) {
268       ipc_message_loop_ = ipc_message_loop;
269       shutdown_event_ = shutdown_event;
270     }
271 
272     // ProxyChannel::Delegate implementation.
273     virtual base::MessageLoopProxy* GetIPCMessageLoop();
274     virtual base::WaitableEvent* GetShutdownEvent();
275     virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
276         base::PlatformFile handle,
277         base::ProcessId remote_pid,
278         bool should_close_source) OVERRIDE;
279 
280    private:
281     base::MessageLoopProxy* ipc_message_loop_;  // Weak
282     base::WaitableEvent* shutdown_event_;  // Weak
283 
284     DISALLOW_COPY_AND_ASSIGN(DelegateMock);
285   };
286 
287  private:
288   class MockSyncMessageStatusReceiver;
289 
290   void CreateHostGlobals();
291 
292   GlobalsConfiguration globals_config_;
293   scoped_ptr<ppapi::TestGlobals> host_globals_;
294   scoped_ptr<HostDispatcher> host_dispatcher_;
295   DelegateMock delegate_mock_;
296 
297   scoped_ptr<MockSyncMessageStatusReceiver> status_receiver_;
298 };
299 
300 class HostProxyTest : public HostProxyTestHarness, public testing::Test {
301  public:
302   HostProxyTest();
303   virtual ~HostProxyTest();
304 
305   // testing::Test implementation.
306   virtual void SetUp();
307   virtual void TearDown();
308  private:
309   base::MessageLoop message_loop_;
310 };
311 
312 // Use this base class to test both sides of a proxy.
313 class TwoWayTest : public testing::Test {
314  public:
315   enum TwoWayTestMode {
316     TEST_PPP_INTERFACE,
317     TEST_PPB_INTERFACE
318   };
319   TwoWayTest(TwoWayTestMode test_mode);
320   virtual ~TwoWayTest();
321 
host()322   HostProxyTestHarness& host() { return host_; }
plugin()323   PluginProxyTestHarness& plugin() { return plugin_; }
pp_module()324   PP_Module pp_module() const { return host_.pp_module(); }
pp_instance()325   PP_Instance pp_instance() const { return host_.pp_instance(); }
test_mode()326   TwoWayTestMode test_mode() { return test_mode_; }
327 
328   // testing::Test implementation.
329   virtual void SetUp();
330   virtual void TearDown();
331 
332  protected:
333   // Post a task to the thread where the remote harness lives. This
334   // is typically used to test the state of the var tracker on the plugin
335   // thread. This runs the task synchronously for convenience.
336   void PostTaskOnRemoteHarness(const base::Closure& task);
337 
338  private:
339   TwoWayTestMode test_mode_;
340   HostProxyTestHarness host_;
341   PluginProxyTestHarness plugin_;
342   // In order to use sync IPC, we need to have an IO thread.
343   base::Thread io_thread_;
344   // The plugin side of the proxy runs on its own thread.
345   base::Thread plugin_thread_;
346   // The message loop for the main (host) thread.
347   base::MessageLoop message_loop_;
348 
349   // Aliases for the host and plugin harnesses; if we're testing a PPP
350   // interface, remote_harness will point to plugin_, and local_harness
351   // will point to host_.  This makes it convenient when we're starting and
352   // stopping the harnesses.
353   ProxyTestHarnessBase* remote_harness_;
354   ProxyTestHarnessBase* local_harness_;
355 
356   base::WaitableEvent channel_created_;
357   base::WaitableEvent shutdown_event_;
358 };
359 
360 // Used during Gtests when you have a PP_Var that you want to EXPECT is equal
361 // to a certain constant string value:
362 //
363 //   EXPECT_VAR_IS_STRING("foo", my_var);
364 #define EXPECT_VAR_IS_STRING(str, var) { \
365   StringVar* sv = StringVar::FromPPVar(var); \
366   EXPECT_TRUE(sv); \
367   if (sv) \
368     EXPECT_EQ(str, sv->value()); \
369 }
370 
371 }  // namespace proxy
372 }  // namespace ppapi
373