Add wfh@ to chrome/browser/resources/plugin_metadata OWNERS.
[chromium-blink-merge.git] / ppapi / proxy / ppapi_proxy_test.cc
blobacd533f1a82e0935916dcd3f4ce16dd11cb71d67
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.
5 #include "ppapi/proxy/ppapi_proxy_test.h"
7 #include <sstream>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/observer_list.h"
13 #include "base/process/process_handle.h"
14 #include "base/run_loop.h"
15 #include "ipc/ipc_sync_channel.h"
16 #include "ipc/message_filter.h"
17 #include "ppapi/c/pp_errors.h"
18 #include "ppapi/c/private/ppb_proxy_private.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/proxy/ppb_message_loop_proxy.h"
21 #include "ppapi/shared_impl/proxy_lock.h"
23 namespace ppapi {
24 namespace proxy {
26 namespace {
27 // HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback
28 // do-nothing implementation.
29 void PluginCrashed(PP_Module module) {
30 NOTREACHED();
33 PP_Instance GetInstanceForResource(PP_Resource resource) {
34 // If a test relies on this, we need to implement it.
35 NOTREACHED();
36 return 0;
39 void SetReserveInstanceIDCallback(PP_Module module,
40 PP_Bool (*is_seen)(PP_Module, PP_Instance)) {
41 // This function gets called in HostDispatcher's constructor. We simply don't
42 // worry about Instance uniqueness in tests, so we can ignore the call.
45 void AddRefModule(PP_Module module) {}
46 void ReleaseModule(PP_Module module) {}
47 PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; }
49 PPB_Proxy_Private ppb_proxy_private = {
50 &PluginCrashed,
51 &GetInstanceForResource,
52 &SetReserveInstanceIDCallback,
53 &AddRefModule,
54 &ReleaseModule,
55 &IsInModuleDestructor
58 // We allow multiple harnesses at a time to respond to 'GetInterface' calls.
59 // We assume that only 1 harness's GetInterface function will ever support a
60 // given interface name. In practice, there will either be only 1 GetInterface
61 // handler (for PluginProxyTest or HostProxyTest), or there will be only 2
62 // GetInterface handlers (for TwoWayTest). In the latter case, one handler is
63 // for the PluginProxyTestHarness and should only respond for PPP interfaces,
64 // and the other handler is for the HostProxyTestHarness which should only
65 // ever respond for PPB interfaces.
66 ObserverList<ProxyTestHarnessBase> get_interface_handlers_;
68 const void* MockGetInterface(const char* name) {
69 ObserverList<ProxyTestHarnessBase>::Iterator it =
70 get_interface_handlers_;
71 while (ProxyTestHarnessBase* observer = it.GetNext()) {
72 const void* interface = observer->GetInterface(name);
73 if (interface)
74 return interface;
76 if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
77 return &ppb_proxy_private;
78 return NULL;
81 void SetUpRemoteHarness(ProxyTestHarnessBase* harness,
82 const IPC::ChannelHandle& handle,
83 base::MessageLoopProxy* ipc_message_loop_proxy,
84 base::WaitableEvent* shutdown_event,
85 base::WaitableEvent* harness_set_up) {
86 harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy,
87 shutdown_event, false);
88 harness_set_up->Signal();
91 void TearDownRemoteHarness(ProxyTestHarnessBase* harness,
92 base::WaitableEvent* harness_torn_down) {
93 harness->TearDownHarness();
94 harness_torn_down->Signal();
97 void RunTaskOnRemoteHarness(const base::Closure& task,
98 base::WaitableEvent* task_complete) {
99 task.Run();
100 task_complete->Signal();
103 } // namespace
105 // ProxyTestHarnessBase --------------------------------------------------------
107 ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
108 pp_instance_(0x12345) {
109 get_interface_handlers_.AddObserver(this);
112 ProxyTestHarnessBase::~ProxyTestHarnessBase() {
113 get_interface_handlers_.RemoveObserver(this);
116 const void* ProxyTestHarnessBase::GetInterface(const char* name) {
117 return registered_interfaces_[name];
120 void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
121 const void* test_interface) {
122 registered_interfaces_[name] = test_interface;
125 bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
126 sink().ClearMessages();
128 // IPC doesn't actually write to this when we send a message manually
129 // not actually using IPC.
130 bool unused_result = false;
131 PpapiMsg_SupportsInterface msg(name, &unused_result);
132 GetDispatcher()->OnMessageReceived(msg);
134 const IPC::Message* reply_msg =
135 sink().GetUniqueMessageMatching(IPC_REPLY_ID);
136 EXPECT_TRUE(reply_msg);
137 if (!reply_msg)
138 return false;
140 TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data;
141 EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam(
142 reply_msg, &reply_data));
144 sink().ClearMessages();
145 return get<0>(reply_data);
148 // PluginProxyTestHarness ------------------------------------------------------
150 PluginProxyTestHarness::PluginProxyTestHarness(
151 GlobalsConfiguration globals_config)
152 : globals_config_(globals_config) {
155 PluginProxyTestHarness::~PluginProxyTestHarness() {
158 PpapiGlobals* PluginProxyTestHarness::GetGlobals() {
159 return plugin_globals_.get();
162 Dispatcher* PluginProxyTestHarness::GetDispatcher() {
163 return plugin_dispatcher_.get();
166 void PluginProxyTestHarness::SetUpHarness() {
167 // These must be first since the dispatcher set-up uses them.
168 CreatePluginGlobals();
169 // Some of the methods called during set-up check that the lock is held.
170 ProxyAutoLock lock;
172 resource_tracker().DidCreateInstance(pp_instance());
174 plugin_dispatcher_.reset(new PluginDispatcher(
175 &MockGetInterface,
176 PpapiPermissions(),
177 false));
178 plugin_dispatcher_->InitWithTestSink(&sink());
179 // The plugin proxy delegate is needed for
180 // |PluginProxyDelegate::GetBrowserSender| which is used
181 // in |ResourceCreationProxy::GetConnection| to get the channel to the
182 // browser. In this case we just use the |plugin_dispatcher_| as the channel
183 // for test purposes.
184 plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
185 PluginGlobals::Get()->SetPluginProxyDelegate(&plugin_delegate_mock_);
186 plugin_dispatcher_->DidCreateInstance(pp_instance());
189 void PluginProxyTestHarness::SetUpHarnessWithChannel(
190 const IPC::ChannelHandle& channel_handle,
191 base::MessageLoopProxy* ipc_message_loop,
192 base::WaitableEvent* shutdown_event,
193 bool is_client) {
194 // These must be first since the dispatcher set-up uses them.
195 CreatePluginGlobals();
196 // Some of the methods called during set-up check that the lock is held.
197 ProxyAutoLock lock;
199 resource_tracker().DidCreateInstance(pp_instance());
200 plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
202 plugin_dispatcher_.reset(new PluginDispatcher(
203 &MockGetInterface,
204 PpapiPermissions(),
205 false));
206 plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_,
207 base::kNullProcessId,
208 channel_handle,
209 is_client);
210 plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
211 PluginGlobals::Get()->SetPluginProxyDelegate(&plugin_delegate_mock_);
212 plugin_dispatcher_->DidCreateInstance(pp_instance());
215 void PluginProxyTestHarness::TearDownHarness() {
217 // Some of the methods called during tear-down check that the lock is held.
218 ProxyAutoLock lock;
220 plugin_dispatcher_->DidDestroyInstance(pp_instance());
221 plugin_dispatcher_.reset();
223 resource_tracker().DidDeleteInstance(pp_instance());
225 plugin_globals_.reset();
228 void PluginProxyTestHarness::CreatePluginGlobals() {
229 if (globals_config_ == PER_THREAD_GLOBALS) {
230 plugin_globals_.reset(new PluginGlobals(PpapiGlobals::PerThreadForTest()));
231 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
232 // Enable locking in case some other unit test ran before us and disabled
233 // locking.
234 ProxyLock::EnableLockingOnThreadForTest();
235 } else {
236 plugin_globals_.reset(new PluginGlobals());
237 ProxyLock::EnableLockingOnThreadForTest();
241 base::MessageLoopProxy*
242 PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
243 return ipc_message_loop_;
246 base::WaitableEvent*
247 PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
248 return shutdown_event_;
251 IPC::PlatformFileForTransit
252 PluginProxyTestHarness::PluginDelegateMock::ShareHandleWithRemote(
253 base::PlatformFile handle,
254 base::ProcessId /* remote_pid */,
255 bool should_close_source) {
256 return IPC::GetFileHandleForProcess(handle,
257 base::GetCurrentProcessHandle(),
258 should_close_source);
261 std::set<PP_Instance>*
262 PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
263 return &instance_id_set_;
266 uint32 PluginProxyTestHarness::PluginDelegateMock::Register(
267 PluginDispatcher* plugin_dispatcher) {
268 return 0;
271 void PluginProxyTestHarness::PluginDelegateMock::Unregister(
272 uint32 plugin_dispatcher_id) {
275 IPC::Sender* PluginProxyTestHarness::PluginDelegateMock::GetBrowserSender() {
276 return browser_sender_;
279 std::string PluginProxyTestHarness::PluginDelegateMock::GetUILanguage() {
280 return std::string("en-US");
283 void PluginProxyTestHarness::PluginDelegateMock::PreCacheFont(
284 const void* logfontw) {
287 void PluginProxyTestHarness::PluginDelegateMock::SetActiveURL(
288 const std::string& url) {
291 PP_Resource PluginProxyTestHarness::PluginDelegateMock::CreateBrowserFont(
292 Connection connection,
293 PP_Instance instance,
294 const PP_BrowserFont_Trusted_Description& desc,
295 const Preferences& prefs) {
296 return 0;
299 // PluginProxyTest -------------------------------------------------------------
301 PluginProxyTest::PluginProxyTest() : PluginProxyTestHarness(SINGLETON_GLOBALS) {
304 PluginProxyTest::~PluginProxyTest() {
307 void PluginProxyTest::SetUp() {
308 SetUpHarness();
311 void PluginProxyTest::TearDown() {
312 TearDownHarness();
315 // PluginProxyMultiThreadTest --------------------------------------------------
317 PluginProxyMultiThreadTest::PluginProxyMultiThreadTest() {
320 PluginProxyMultiThreadTest::~PluginProxyMultiThreadTest() {
323 void PluginProxyMultiThreadTest::RunTest() {
324 main_thread_message_loop_proxy_ =
325 PpapiGlobals::Get()->GetMainThreadMessageLoop();
326 ASSERT_EQ(main_thread_message_loop_proxy_.get(),
327 base::MessageLoopProxy::current().get());
328 nested_main_thread_message_loop_.reset(new base::RunLoop());
330 secondary_thread_.reset(new base::DelegateSimpleThread(
331 this, "PluginProxyMultiThreadTest"));
334 ProxyAutoLock auto_lock;
336 // MessageLoopResource assumes that the proxy lock has been acquired.
337 secondary_thread_message_loop_ = new MessageLoopResource(pp_instance());
339 ASSERT_EQ(PP_OK,
340 secondary_thread_message_loop_->PostWork(
341 PP_MakeCompletionCallback(
342 &PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread,
343 this),
344 0));
347 SetUpTestOnMainThread();
349 secondary_thread_->Start();
350 nested_main_thread_message_loop_->Run();
351 secondary_thread_->Join();
354 ProxyAutoLock auto_lock;
356 // The destruction requires a valid PpapiGlobals instance, so we should
357 // explicitly release it.
358 secondary_thread_message_loop_ = NULL;
361 secondary_thread_.reset(NULL);
362 nested_main_thread_message_loop_.reset(NULL);
363 main_thread_message_loop_proxy_ = NULL;
366 void PluginProxyMultiThreadTest::CheckOnThread(ThreadType thread_type) {
367 ProxyAutoLock auto_lock;
368 if (thread_type == MAIN_THREAD) {
369 ASSERT_TRUE(MessageLoopResource::GetCurrent()->is_main_thread_loop());
370 } else {
371 ASSERT_EQ(secondary_thread_message_loop_.get(),
372 MessageLoopResource::GetCurrent());
376 void PluginProxyMultiThreadTest::PostQuitForMainThread() {
377 main_thread_message_loop_proxy_->PostTask(
378 FROM_HERE,
379 base::Bind(&PluginProxyMultiThreadTest::QuitNestedLoop,
380 base::Unretained(this)));
383 void PluginProxyMultiThreadTest::PostQuitForSecondaryThread() {
384 ProxyAutoLock auto_lock;
385 secondary_thread_message_loop_->PostQuit(PP_TRUE);
388 void PluginProxyMultiThreadTest::Run() {
389 ProxyAutoLock auto_lock;
390 ASSERT_EQ(PP_OK, secondary_thread_message_loop_->AttachToCurrentThread());
391 ASSERT_EQ(PP_OK, secondary_thread_message_loop_->Run());
392 secondary_thread_message_loop_->DetachFromThread();
395 void PluginProxyMultiThreadTest::QuitNestedLoop() {
396 nested_main_thread_message_loop_->Quit();
399 // static
400 void PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread(
401 void* user_data,
402 int32_t result) {
403 EXPECT_EQ(PP_OK, result);
404 PluginProxyMultiThreadTest* thiz =
405 static_cast<PluginProxyMultiThreadTest*>(user_data);
406 thiz->CheckOnThread(SECONDARY_THREAD);
407 thiz->SetUpTestOnSecondaryThread();
410 // HostProxyTestHarness --------------------------------------------------------
412 HostProxyTestHarness::HostProxyTestHarness(GlobalsConfiguration globals_config)
413 : globals_config_(globals_config) {
416 HostProxyTestHarness::~HostProxyTestHarness() {
419 PpapiGlobals* HostProxyTestHarness::GetGlobals() {
420 return host_globals_.get();
423 Dispatcher* HostProxyTestHarness::GetDispatcher() {
424 return host_dispatcher_.get();
427 void HostProxyTestHarness::SetUpHarness() {
428 // These must be first since the dispatcher set-up uses them.
429 CreateHostGlobals();
431 host_dispatcher_.reset(new HostDispatcher(
432 pp_module(),
433 &MockGetInterface,
434 PpapiPermissions::AllPermissions()));
435 host_dispatcher_->InitWithTestSink(&sink());
436 HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
439 void HostProxyTestHarness::SetUpHarnessWithChannel(
440 const IPC::ChannelHandle& channel_handle,
441 base::MessageLoopProxy* ipc_message_loop,
442 base::WaitableEvent* shutdown_event,
443 bool is_client) {
444 // These must be first since the dispatcher set-up uses them.
445 CreateHostGlobals();
447 delegate_mock_.Init(ipc_message_loop, shutdown_event);
449 host_dispatcher_.reset(new HostDispatcher(
450 pp_module(),
451 &MockGetInterface,
452 PpapiPermissions::AllPermissions()));
453 ppapi::Preferences preferences;
454 host_dispatcher_->InitHostWithChannel(&delegate_mock_,
455 base::kNullProcessId, channel_handle,
456 is_client, preferences);
457 HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
460 void HostProxyTestHarness::TearDownHarness() {
461 HostDispatcher::RemoveForInstance(pp_instance());
462 host_dispatcher_.reset();
463 host_globals_.reset();
466 void HostProxyTestHarness::CreateHostGlobals() {
467 if (globals_config_ == PER_THREAD_GLOBALS) {
468 host_globals_.reset(new TestGlobals(PpapiGlobals::PerThreadForTest()));
469 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
470 // The host side of the proxy does not lock.
471 ProxyLock::DisableLockingOnThreadForTest();
472 } else {
473 ProxyLock::DisableLockingOnThreadForTest();
474 host_globals_.reset(new TestGlobals());
478 base::MessageLoopProxy*
479 HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
480 return ipc_message_loop_;
483 base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
484 return shutdown_event_;
487 IPC::PlatformFileForTransit
488 HostProxyTestHarness::DelegateMock::ShareHandleWithRemote(
489 base::PlatformFile handle,
490 base::ProcessId /* remote_pid */,
491 bool should_close_source) {
492 return IPC::GetFileHandleForProcess(handle,
493 base::GetCurrentProcessHandle(),
494 should_close_source);
498 // HostProxyTest ---------------------------------------------------------------
500 HostProxyTest::HostProxyTest() : HostProxyTestHarness(SINGLETON_GLOBALS) {
503 HostProxyTest::~HostProxyTest() {
506 void HostProxyTest::SetUp() {
507 SetUpHarness();
510 void HostProxyTest::TearDown() {
511 TearDownHarness();
514 // TwoWayTest ---------------------------------------------------------------
516 TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)
517 : test_mode_(test_mode),
518 host_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
519 plugin_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
520 io_thread_("TwoWayTest_IOThread"),
521 plugin_thread_("TwoWayTest_PluginThread"),
522 remote_harness_(NULL),
523 local_harness_(NULL),
524 channel_created_(true, false),
525 shutdown_event_(true, false) {
526 if (test_mode == TEST_PPP_INTERFACE) {
527 remote_harness_ = &plugin_;
528 local_harness_ = &host_;
529 } else {
530 remote_harness_ = &host_;
531 local_harness_ = &plugin_;
535 TwoWayTest::~TwoWayTest() {
536 shutdown_event_.Signal();
539 void TwoWayTest::SetUp() {
540 base::Thread::Options options;
541 options.message_loop_type = base::MessageLoop::TYPE_IO;
542 io_thread_.StartWithOptions(options);
543 plugin_thread_.Start();
545 // Construct the IPC handle name using the process ID so we can safely run
546 // multiple |TwoWayTest|s concurrently.
547 std::ostringstream handle_name;
548 handle_name << "TwoWayTestChannel" << base::GetCurrentProcId();
549 IPC::ChannelHandle handle(handle_name.str());
550 base::WaitableEvent remote_harness_set_up(true, false);
551 plugin_thread_.message_loop_proxy()->PostTask(
552 FROM_HERE,
553 base::Bind(&SetUpRemoteHarness,
554 remote_harness_,
555 handle,
556 io_thread_.message_loop_proxy(),
557 &shutdown_event_,
558 &remote_harness_set_up));
559 remote_harness_set_up.Wait();
560 local_harness_->SetUpHarnessWithChannel(handle,
561 io_thread_.message_loop_proxy().get(),
562 &shutdown_event_,
563 true); // is_client
566 void TwoWayTest::TearDown() {
567 base::WaitableEvent remote_harness_torn_down(true, false);
568 plugin_thread_.message_loop_proxy()->PostTask(
569 FROM_HERE,
570 base::Bind(&TearDownRemoteHarness,
571 remote_harness_,
572 &remote_harness_torn_down));
573 remote_harness_torn_down.Wait();
575 local_harness_->TearDownHarness();
577 io_thread_.Stop();
580 void TwoWayTest::PostTaskOnRemoteHarness(const base::Closure& task) {
581 base::WaitableEvent task_complete(true, false);
582 plugin_thread_.message_loop_proxy()->PostTask(FROM_HERE,
583 base::Bind(&RunTaskOnRemoteHarness,
584 task,
585 &task_complete));
586 task_complete.Wait();
590 } // namespace proxy
591 } // namespace ppapi