Make o.o.p. proxy handle PPP_Instance versions 0.4 and 0.5.

Move & tweak PPP_Instance_Combined to ppapi_shared so the proxy can use it.  Use versioned PPP_Instance types only.

BUG=82606
TEST=run tests o.o.p.

Review URL: http://codereview.chromium.org/7189045

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90984 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc
index 1782302..733f04c 100644
--- a/ppapi/proxy/ppapi_proxy_test.cc
+++ b/ppapi/proxy/ppapi_proxy_test.cc
@@ -4,48 +4,113 @@
 
 #include "ppapi/proxy/ppapi_proxy_test.h"
 
+#include "base/message_loop_proxy.h"
+#include "base/observer_list.h"
+#include "ipc/ipc_sync_channel.h"
 #include "ppapi/c/pp_errors.h"
+#include "ppapi/c/private/ppb_proxy_private.h"
 #include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppapi_preferences.cc"
 
 namespace pp {
 namespace proxy {
 
 namespace {
+// HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback
+// do-nothing implementation.
+void PluginCrashed(PP_Module module) {
+  NOTREACHED();
+};
 
-ProxyTestBase* current_test = NULL;
+PP_Instance GetInstanceForResource(PP_Resource resource) {
+  // If a test relies on this, we need to implement it.
+  NOTREACHED();
+  return 0;
+}
+
+void SetReserveInstanceIDCallback(PP_Module module,
+                                  PP_Bool (*is_seen)(PP_Module, PP_Instance)) {
+  // This function gets called in HostDispatcher's constructor.  We simply don't
+  // worry about Instance uniqueness in tests, so we can ignore the call.
+}
+
+int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) {
+  NOTREACHED();
+  return 0;
+}
+
+void AddRefModule(PP_Module module) {}
+void ReleaseModule(PP_Module module) {}
+
+PPB_Proxy_Private ppb_proxy_private = { PluginCrashed,
+                                        GetInstanceForResource,
+                                        SetReserveInstanceIDCallback,
+                                        GetURLLoaderBufferedBytes,
+                                        AddRefModule,
+                                        ReleaseModule };
+
+// We allow multiple harnesses at a time to respond to 'GetInterface' calls.
+// We assume that only 1 harness's GetInterface function will ever support a
+// given interface name. In practice, there will either be only 1 GetInterface
+// handler (for PluginProxyTest or HostProxyTest), or there will be only 2
+// GetInterface handlers (for TwoWayTest).  In the latter case, one handler is
+// for the PluginProxyTestHarness and should only respond for PPP interfaces,
+// and the other handler is for the HostProxyTestHarness which should only
+// ever respond for PPB interfaces.
+ObserverList<ProxyTestHarnessBase> get_interface_handlers_;
 
 const void* MockGetInterface(const char* name) {
-  if (!current_test) {
-    NOTREACHED();
-    return NULL;
+  ObserverList<ProxyTestHarnessBase>::Iterator it =
+      get_interface_handlers_;
+  while (ProxyTestHarnessBase* observer = it.GetNext()) {
+    const void* interface = observer->GetInterface(name);
+    if (interface)
+      return interface;
   }
-  return current_test->GetInterface(name);
+  if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
+    return &ppb_proxy_private;
+  return NULL;
+}
+
+void SetUpRemoteHarness(ProxyTestHarnessBase* harness,
+                        const IPC::ChannelHandle& handle,
+                        base::MessageLoopProxy* ipc_message_loop_proxy,
+                        base::WaitableEvent* shutdown_event,
+                        base::WaitableEvent* harness_set_up) {
+  harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy,
+                                   shutdown_event, false);
+  harness_set_up->Signal();
+}
+
+void TearDownRemoteHarness(ProxyTestHarnessBase* harness,
+                           base::WaitableEvent* harness_torn_down) {
+  harness->TearDownHarness();
+  harness_torn_down->Signal();
 }
 
 }  // namespace
 
-// ProxyTestBase ---------------------------------------------------------------
+// ProxyTestHarnessBase --------------------------------------------------------
 
-ProxyTestBase::ProxyTestBase() : pp_module_(0x98765), pp_instance_(0x12345) {
-  DCHECK(!current_test);
-  current_test = this;
+ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
+                                               pp_instance_(0x12345) {
+  get_interface_handlers_.AddObserver(this);
 }
 
-ProxyTestBase::~ProxyTestBase() {
-  DCHECK(current_test == this);
-  current_test = NULL;
+ProxyTestHarnessBase::~ProxyTestHarnessBase() {
+  get_interface_handlers_.RemoveObserver(this);
 }
 
-const void* ProxyTestBase::GetInterface(const char* name) {
+const void* ProxyTestHarnessBase::GetInterface(const char* name) {
   return registered_interfaces_[name];
 }
 
-void ProxyTestBase::RegisterTestInterface(const char* name,
-                                          const void* interface) {
+void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
+                                                 const void* interface) {
   registered_interfaces_[name] = interface;
 }
 
-bool ProxyTestBase::SupportsInterface(const char* name) {
+bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
   sink().ClearMessages();
 
   // IPC doesn't actually write to this when we send a message manually
@@ -68,19 +133,19 @@
   return reply_data.a;
 }
 
-// PluginProxyTest -------------------------------------------------------------
+// PluginProxyTestHarness ------------------------------------------------------
 
-PluginProxyTest::PluginProxyTest() {
+PluginProxyTestHarness::PluginProxyTestHarness() {
 }
 
-PluginProxyTest::~PluginProxyTest() {
+PluginProxyTestHarness::~PluginProxyTestHarness() {
 }
 
-Dispatcher* PluginProxyTest::GetDispatcher() {
+Dispatcher* PluginProxyTestHarness::GetDispatcher() {
   return plugin_dispatcher_.get();
 }
 
-void PluginProxyTest::SetUp() {
+void PluginProxyTestHarness::SetUpHarness() {
   // These must be first since the dispatcher set-up uses them.
   PluginResourceTracker::SetInstanceForTest(&resource_tracker_);
   PluginVarTracker::SetInstanceForTest(&var_tracker_);
@@ -92,7 +157,26 @@
   plugin_dispatcher_->DidCreateInstance(pp_instance());
 }
 
-void PluginProxyTest::TearDown() {
+void PluginProxyTestHarness::SetUpHarnessWithChannel(
+    const IPC::ChannelHandle& channel_handle,
+    base::MessageLoopProxy* ipc_message_loop,
+    base::WaitableEvent* shutdown_event,
+    bool is_client) {
+  // These must be first since the dispatcher set-up uses them.
+  PluginResourceTracker::SetInstanceForTest(&resource_tracker_);
+  PluginVarTracker::SetInstanceForTest(&var_tracker_);
+  plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
+
+  plugin_dispatcher_.reset(new PluginDispatcher(
+      base::Process::Current().handle(),
+      &MockGetInterface));
+  plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_,
+                                            channel_handle,
+                                            is_client);
+  plugin_dispatcher_->DidCreateInstance(pp_instance());
+}
+
+void PluginProxyTestHarness::TearDownHarness() {
   plugin_dispatcher_->DidDestroyInstance(pp_instance());
   plugin_dispatcher_.reset();
 
@@ -100,6 +184,107 @@
   PluginResourceTracker::SetInstanceForTest(NULL);
 }
 
+base::MessageLoopProxy*
+PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
+  return ipc_message_loop_;
+}
+
+base::WaitableEvent*
+PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
+  return shutdown_event_;
+}
+
+std::set<PP_Instance>*
+PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
+  return &instance_id_set_;
+}
+
+ppapi::WebKitForwarding*
+PluginProxyTestHarness::PluginDelegateMock::GetWebKitForwarding() {
+  NOTREACHED();
+  return NULL;
+}
+
+void PluginProxyTestHarness::PluginDelegateMock::PostToWebKitThread(
+    const tracked_objects::Location& from_here, const base::Closure& task) {
+  NOTREACHED();
+}
+
+bool PluginProxyTestHarness::PluginDelegateMock::SendToBrowser(
+    IPC::Message* msg) {
+  NOTREACHED();
+  return false;
+}
+
+
+// PluginProxyTest -------------------------------------------------------------
+
+PluginProxyTest::PluginProxyTest() {
+}
+
+PluginProxyTest::~PluginProxyTest() {
+}
+
+void PluginProxyTest::SetUp() {
+  SetUpHarness();
+}
+
+void PluginProxyTest::TearDown() {
+  TearDownHarness();
+}
+
+// HostProxyTestHarness --------------------------------------------------------
+
+HostProxyTestHarness::HostProxyTestHarness() {
+}
+
+HostProxyTestHarness::~HostProxyTestHarness() {
+}
+
+Dispatcher* HostProxyTestHarness::GetDispatcher() {
+  return host_dispatcher_.get();
+}
+
+void HostProxyTestHarness::SetUpHarness() {
+  host_dispatcher_.reset(new HostDispatcher(
+      base::Process::Current().handle(),
+      pp_module(),
+      &MockGetInterface));
+  host_dispatcher_->InitWithTestSink(&sink());
+  HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
+}
+
+void HostProxyTestHarness::SetUpHarnessWithChannel(
+    const IPC::ChannelHandle& channel_handle,
+    base::MessageLoopProxy* ipc_message_loop,
+    base::WaitableEvent* shutdown_event,
+    bool is_client) {
+  delegate_mock_.Init(ipc_message_loop, shutdown_event);
+  host_dispatcher_.reset(new HostDispatcher(
+      base::Process::Current().handle(),
+      pp_module(),
+      &MockGetInterface));
+  ppapi::Preferences preferences;
+  host_dispatcher_->InitHostWithChannel(&delegate_mock_, channel_handle,
+                                        is_client, preferences);
+  HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
+}
+
+void HostProxyTestHarness::TearDownHarness() {
+  HostDispatcher::RemoveForInstance(pp_instance());
+  host_dispatcher_.reset();
+}
+
+base::MessageLoopProxy*
+HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
+  return ipc_message_loop_;
+}
+
+base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
+  return shutdown_event_;
+}
+
+
 // HostProxyTest ---------------------------------------------------------------
 
 HostProxyTest::HostProxyTest() {
@@ -108,23 +293,76 @@
 HostProxyTest::~HostProxyTest() {
 }
 
-Dispatcher* HostProxyTest::GetDispatcher() {
-  return host_dispatcher_.get();
-}
-
 void HostProxyTest::SetUp() {
-  host_dispatcher_.reset(new HostDispatcher(
-      base::Process::Current().handle(),
-      pp_module(),
-      &MockGetInterface));
-  host_dispatcher_->InitWithTestSink(&sink());
-  HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
+  SetUpHarness();
 }
 
 void HostProxyTest::TearDown() {
-  HostDispatcher::RemoveForInstance(pp_instance());
-  host_dispatcher_.reset();
+  TearDownHarness();
 }
 
+// TwoWayTest ---------------------------------------------------------------
+
+TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)
+    : test_mode_(test_mode),
+      io_thread_("TwoWayTest_IOThread"),
+      plugin_thread_("TwoWayTest_PluginThread"),
+      remote_harness_(NULL),
+      local_harness_(NULL),
+      channel_created_(true, false),
+      shutdown_event_(true, false) {
+  if (test_mode == TEST_PPP_INTERFACE) {
+    remote_harness_ = &plugin_;
+    local_harness_ = &host_;
+  } else {
+    remote_harness_ = &host_;
+    local_harness_ = &plugin_;
+  }
+}
+
+TwoWayTest::~TwoWayTest() {
+  shutdown_event_.Signal();
+}
+
+void TwoWayTest::SetUp() {
+  base::Thread::Options options;
+  options.message_loop_type = MessageLoop::TYPE_IO;
+  io_thread_.StartWithOptions(options);
+  plugin_thread_.Start();
+
+  IPC::ChannelHandle handle;
+  handle.name = "TwoWayTestChannel";
+
+  base::WaitableEvent remote_harness_set_up(true, false);
+  plugin_thread_.message_loop_proxy()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(&SetUpRemoteHarness,
+                          remote_harness_,
+                          handle,
+                          io_thread_.message_loop_proxy(),
+                          &shutdown_event_,
+                          &remote_harness_set_up));
+  remote_harness_set_up.Wait();
+  local_harness_->SetUpHarnessWithChannel(handle,
+                                          io_thread_.message_loop_proxy(),
+                                          &shutdown_event_,
+                                          true);  // is_client
+}
+
+void TwoWayTest::TearDown() {
+  base::WaitableEvent remote_harness_torn_down(true, false);
+  plugin_thread_.message_loop_proxy()->PostTask(
+      FROM_HERE,
+      NewRunnableFunction(&TearDownRemoteHarness,
+                          remote_harness_,
+                          &remote_harness_torn_down));
+  remote_harness_torn_down.Wait();
+
+  local_harness_->TearDownHarness();
+
+  io_thread_.Stop();
+}
+
+
 }  // namespace proxy
 }  // namespace pp