Home | History | Annotate | Download | only in proxy
      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 
     48   PP_Module pp_module() const { return pp_module_; }
     49   PP_Instance pp_instance() const { return pp_instance_; }
     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 
     99   PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); }
    100   PluginResourceTracker& resource_tracker() {
    101     return *plugin_globals_->plugin_resource_tracker();
    102   }
    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:
    120     PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {}
    121     virtual ~PluginDelegateMock() {}
    122 
    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 
    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 
    242   HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); }
    243   ResourceTracker& resource_tracker() {
    244     return *host_globals_->GetResourceTracker();
    245   }
    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:
    262     DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) {
    263     }
    264     virtual ~DelegateMock() {}
    265 
    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   void CreateHostGlobals();
    289 
    290   GlobalsConfiguration globals_config_;
    291   scoped_ptr<ppapi::TestGlobals> host_globals_;
    292   scoped_ptr<HostDispatcher> host_dispatcher_;
    293   DelegateMock delegate_mock_;
    294 };
    295 
    296 class HostProxyTest : public HostProxyTestHarness, public testing::Test {
    297  public:
    298   HostProxyTest();
    299   virtual ~HostProxyTest();
    300 
    301   // testing::Test implementation.
    302   virtual void SetUp();
    303   virtual void TearDown();
    304  private:
    305   base::MessageLoop message_loop_;
    306 };
    307 
    308 // Use this base class to test both sides of a proxy.
    309 class TwoWayTest : public testing::Test {
    310  public:
    311   enum TwoWayTestMode {
    312     TEST_PPP_INTERFACE,
    313     TEST_PPB_INTERFACE
    314   };
    315   TwoWayTest(TwoWayTestMode test_mode);
    316   virtual ~TwoWayTest();
    317 
    318   HostProxyTestHarness& host() { return host_; }
    319   PluginProxyTestHarness& plugin() { return plugin_; }
    320   PP_Module pp_module() const { return host_.pp_module(); }
    321   PP_Instance pp_instance() const { return host_.pp_instance(); }
    322   TwoWayTestMode test_mode() { return test_mode_; }
    323 
    324   // testing::Test implementation.
    325   virtual void SetUp();
    326   virtual void TearDown();
    327 
    328  protected:
    329   // Post a task to the thread where the remote harness lives. This
    330   // is typically used to test the state of the var tracker on the plugin
    331   // thread. This runs the task synchronously for convenience.
    332   void PostTaskOnRemoteHarness(const base::Closure& task);
    333 
    334  private:
    335   TwoWayTestMode test_mode_;
    336   HostProxyTestHarness host_;
    337   PluginProxyTestHarness plugin_;
    338   // In order to use sync IPC, we need to have an IO thread.
    339   base::Thread io_thread_;
    340   // The plugin side of the proxy runs on its own thread.
    341   base::Thread plugin_thread_;
    342   // The message loop for the main (host) thread.
    343   base::MessageLoop message_loop_;
    344 
    345   // Aliases for the host and plugin harnesses; if we're testing a PPP
    346   // interface, remote_harness will point to plugin_, and local_harness
    347   // will point to host_.  This makes it convenient when we're starting and
    348   // stopping the harnesses.
    349   ProxyTestHarnessBase* remote_harness_;
    350   ProxyTestHarnessBase* local_harness_;
    351 
    352   base::WaitableEvent channel_created_;
    353   base::WaitableEvent shutdown_event_;
    354 };
    355 
    356 // Used during Gtests when you have a PP_Var that you want to EXPECT is equal
    357 // to a certain constant string value:
    358 //
    359 //   EXPECT_VAR_IS_STRING("foo", my_var);
    360 #define EXPECT_VAR_IS_STRING(str, var) { \
    361   StringVar* sv = StringVar::FromPPVar(var); \
    362   EXPECT_TRUE(sv); \
    363   if (sv) \
    364     EXPECT_EQ(str, sv->value()); \
    365 }
    366 
    367 }  // namespace proxy
    368 }  // namespace ppapi
    369