Add py_trace_event to DEPS.
[chromium-blink-merge.git] / ppapi / proxy / ppapi_proxy_test.cc
bloba23362615329491b148a645cb287efc7c390562c
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/run_loop.h"
14 #include "ipc/ipc_sync_channel.h"
15 #include "ipc/message_filter.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/c/private/ppb_proxy_private.h"
18 #include "ppapi/proxy/ppapi_messages.h"
19 #include "ppapi/proxy/ppb_message_loop_proxy.h"
20 #include "ppapi/shared_impl/proxy_lock.h"
22 namespace ppapi {
23 namespace proxy {
25 namespace {
26 // HostDispatcher requires a PPB_Proxy_Private, so we always provide a fallback
27 // do-nothing implementation.
28 void PluginCrashed(PP_Module module) {
29 NOTREACHED();
32 PP_Instance GetInstanceForResource(PP_Resource resource) {
33 // If a test relies on this, we need to implement it.
34 NOTREACHED();
35 return 0;
38 void SetReserveInstanceIDCallback(PP_Module module,
39 PP_Bool (*is_seen)(PP_Module, PP_Instance)) {
40 // This function gets called in HostDispatcher's constructor. We simply don't
41 // worry about Instance uniqueness in tests, so we can ignore the call.
44 void AddRefModule(PP_Module module) {}
45 void ReleaseModule(PP_Module module) {}
46 PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; }
48 PPB_Proxy_Private ppb_proxy_private = {
49 &PluginCrashed,
50 &GetInstanceForResource,
51 &SetReserveInstanceIDCallback,
52 &AddRefModule,
53 &ReleaseModule,
54 &IsInModuleDestructor
57 // We allow multiple harnesses at a time to respond to 'GetInterface' calls.
58 // We assume that only 1 harness's GetInterface function will ever support a
59 // given interface name. In practice, there will either be only 1 GetInterface
60 // handler (for PluginProxyTest or HostProxyTest), or there will be only 2
61 // GetInterface handlers (for TwoWayTest). In the latter case, one handler is
62 // for the PluginProxyTestHarness and should only respond for PPP interfaces,
63 // and the other handler is for the HostProxyTestHarness which should only
64 // ever respond for PPB interfaces.
65 ObserverList<ProxyTestHarnessBase> get_interface_handlers_;
67 const void* MockGetInterface(const char* name) {
68 ObserverList<ProxyTestHarnessBase>::Iterator it =
69 get_interface_handlers_;
70 while (ProxyTestHarnessBase* observer = it.GetNext()) {
71 const void* interface = observer->GetInterface(name);
72 if (interface)
73 return interface;
75 if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
76 return &ppb_proxy_private;
77 return NULL;
80 void SetUpRemoteHarness(ProxyTestHarnessBase* harness,
81 const IPC::ChannelHandle& handle,
82 base::MessageLoopProxy* ipc_message_loop_proxy,
83 base::WaitableEvent* shutdown_event,
84 base::WaitableEvent* harness_set_up) {
85 harness->SetUpHarnessWithChannel(handle, ipc_message_loop_proxy,
86 shutdown_event, false);
87 harness_set_up->Signal();
90 void TearDownRemoteHarness(ProxyTestHarnessBase* harness,
91 base::WaitableEvent* harness_torn_down) {
92 harness->TearDownHarness();
93 harness_torn_down->Signal();
96 void RunTaskOnRemoteHarness(const base::Closure& task,
97 base::WaitableEvent* task_complete) {
98 task.Run();
99 task_complete->Signal();
102 } // namespace
104 // ProxyTestHarnessBase --------------------------------------------------------
106 ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
107 pp_instance_(0x12345) {
108 get_interface_handlers_.AddObserver(this);
111 ProxyTestHarnessBase::~ProxyTestHarnessBase() {
112 get_interface_handlers_.RemoveObserver(this);
115 const void* ProxyTestHarnessBase::GetInterface(const char* name) {
116 return registered_interfaces_[name];
119 void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
120 const void* test_interface) {
121 registered_interfaces_[name] = test_interface;
124 bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
125 sink().ClearMessages();
127 // IPC doesn't actually write to this when we send a message manually
128 // not actually using IPC.
129 bool unused_result = false;
130 PpapiMsg_SupportsInterface msg(name, &unused_result);
131 GetDispatcher()->OnMessageReceived(msg);
133 const IPC::Message* reply_msg =
134 sink().GetUniqueMessageMatching(IPC_REPLY_ID);
135 EXPECT_TRUE(reply_msg);
136 if (!reply_msg)
137 return false;
139 TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data;
140 EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam(
141 reply_msg, &reply_data));
143 sink().ClearMessages();
144 return reply_data.a;
147 // PluginProxyTestHarness ------------------------------------------------------
149 PluginProxyTestHarness::PluginProxyTestHarness(
150 GlobalsConfiguration globals_config)
151 : globals_config_(globals_config) {
154 PluginProxyTestHarness::~PluginProxyTestHarness() {
157 PpapiGlobals* PluginProxyTestHarness::GetGlobals() {
158 return plugin_globals_.get();
161 Dispatcher* PluginProxyTestHarness::GetDispatcher() {
162 return plugin_dispatcher_.get();
165 void PluginProxyTestHarness::SetUpHarness() {
166 // These must be first since the dispatcher set-up uses them.
167 CreatePluginGlobals();
168 // Some of the methods called during set-up check that the lock is held.
169 ProxyAutoLock lock;
171 resource_tracker().DidCreateInstance(pp_instance());
173 plugin_dispatcher_.reset(new PluginDispatcher(
174 &MockGetInterface,
175 PpapiPermissions(),
176 false));
177 plugin_dispatcher_->InitWithTestSink(&sink());
178 // The plugin proxy delegate is needed for
179 // |PluginProxyDelegate::GetBrowserSender| which is used
180 // in |ResourceCreationProxy::GetConnection| to get the channel to the
181 // browser. In this case we just use the |plugin_dispatcher_| as the channel
182 // for test purposes.
183 plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
184 PluginGlobals::Get()->SetPluginProxyDelegate(&plugin_delegate_mock_);
185 plugin_dispatcher_->DidCreateInstance(pp_instance());
188 void PluginProxyTestHarness::SetUpHarnessWithChannel(
189 const IPC::ChannelHandle& channel_handle,
190 base::MessageLoopProxy* ipc_message_loop,
191 base::WaitableEvent* shutdown_event,
192 bool is_client) {
193 // These must be first since the dispatcher set-up uses them.
194 CreatePluginGlobals();
195 // Some of the methods called during set-up check that the lock is held.
196 ProxyAutoLock lock;
198 resource_tracker().DidCreateInstance(pp_instance());
199 plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
201 plugin_dispatcher_.reset(new PluginDispatcher(
202 &MockGetInterface,
203 PpapiPermissions(),
204 false));
205 plugin_dispatcher_->InitPluginWithChannel(&plugin_delegate_mock_,
206 base::kNullProcessId,
207 channel_handle,
208 is_client);
209 plugin_delegate_mock_.set_browser_sender(plugin_dispatcher_.get());
210 PluginGlobals::Get()->SetPluginProxyDelegate(&plugin_delegate_mock_);
211 plugin_dispatcher_->DidCreateInstance(pp_instance());
214 void PluginProxyTestHarness::TearDownHarness() {
216 // Some of the methods called during tear-down check that the lock is held.
217 ProxyAutoLock lock;
219 plugin_dispatcher_->DidDestroyInstance(pp_instance());
220 plugin_dispatcher_.reset();
222 resource_tracker().DidDeleteInstance(pp_instance());
224 plugin_globals_.reset();
227 void PluginProxyTestHarness::CreatePluginGlobals() {
228 if (globals_config_ == PER_THREAD_GLOBALS) {
229 plugin_globals_.reset(new PluginGlobals(PpapiGlobals::PerThreadForTest()));
230 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
231 // Enable locking in case some other unit test ran before us and disabled
232 // locking.
233 ProxyLock::EnableLockingOnThreadForTest();
234 } else {
235 plugin_globals_.reset(new PluginGlobals());
236 ProxyLock::EnableLockingOnThreadForTest();
240 base::MessageLoopProxy*
241 PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
242 return ipc_message_loop_;
245 base::WaitableEvent*
246 PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
247 return shutdown_event_;
250 IPC::PlatformFileForTransit
251 PluginProxyTestHarness::PluginDelegateMock::ShareHandleWithRemote(
252 base::PlatformFile handle,
253 base::ProcessId /* remote_pid */,
254 bool should_close_source) {
255 return IPC::GetFileHandleForProcess(handle,
256 base::Process::Current().handle(),
257 should_close_source);
260 std::set<PP_Instance>*
261 PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
262 return &instance_id_set_;
265 uint32 PluginProxyTestHarness::PluginDelegateMock::Register(
266 PluginDispatcher* plugin_dispatcher) {
267 return 0;
270 void PluginProxyTestHarness::PluginDelegateMock::Unregister(
271 uint32 plugin_dispatcher_id) {
274 IPC::Sender* PluginProxyTestHarness::PluginDelegateMock::GetBrowserSender() {
275 return browser_sender_;
278 std::string PluginProxyTestHarness::PluginDelegateMock::GetUILanguage() {
279 return std::string("en-US");
282 void PluginProxyTestHarness::PluginDelegateMock::PreCacheFont(
283 const void* logfontw) {
286 void PluginProxyTestHarness::PluginDelegateMock::SetActiveURL(
287 const std::string& url) {
290 PP_Resource PluginProxyTestHarness::PluginDelegateMock::CreateBrowserFont(
291 Connection connection,
292 PP_Instance instance,
293 const PP_BrowserFont_Trusted_Description& desc,
294 const Preferences& prefs) {
295 return 0;
298 // PluginProxyTest -------------------------------------------------------------
300 PluginProxyTest::PluginProxyTest() : PluginProxyTestHarness(SINGLETON_GLOBALS) {
303 PluginProxyTest::~PluginProxyTest() {
306 void PluginProxyTest::SetUp() {
307 SetUpHarness();
310 void PluginProxyTest::TearDown() {
311 TearDownHarness();
314 // PluginProxyMultiThreadTest --------------------------------------------------
316 PluginProxyMultiThreadTest::PluginProxyMultiThreadTest() {
319 PluginProxyMultiThreadTest::~PluginProxyMultiThreadTest() {
322 void PluginProxyMultiThreadTest::RunTest() {
323 main_thread_message_loop_proxy_ =
324 PpapiGlobals::Get()->GetMainThreadMessageLoop();
325 ASSERT_EQ(main_thread_message_loop_proxy_.get(),
326 base::MessageLoopProxy::current().get());
327 nested_main_thread_message_loop_.reset(new base::RunLoop());
329 secondary_thread_.reset(new base::DelegateSimpleThread(
330 this, "PluginProxyMultiThreadTest"));
333 ProxyAutoLock auto_lock;
335 // MessageLoopResource assumes that the proxy lock has been acquired.
336 secondary_thread_message_loop_ = new MessageLoopResource(pp_instance());
338 ASSERT_EQ(PP_OK,
339 secondary_thread_message_loop_->PostWork(
340 PP_MakeCompletionCallback(
341 &PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread,
342 this),
343 0));
346 SetUpTestOnMainThread();
348 secondary_thread_->Start();
349 nested_main_thread_message_loop_->Run();
350 secondary_thread_->Join();
353 ProxyAutoLock auto_lock;
355 // The destruction requires a valid PpapiGlobals instance, so we should
356 // explicitly release it.
357 secondary_thread_message_loop_ = NULL;
360 secondary_thread_.reset(NULL);
361 nested_main_thread_message_loop_.reset(NULL);
362 main_thread_message_loop_proxy_ = NULL;
365 void PluginProxyMultiThreadTest::CheckOnThread(ThreadType thread_type) {
366 ProxyAutoLock auto_lock;
367 if (thread_type == MAIN_THREAD) {
368 ASSERT_TRUE(MessageLoopResource::GetCurrent()->is_main_thread_loop());
369 } else {
370 ASSERT_EQ(secondary_thread_message_loop_.get(),
371 MessageLoopResource::GetCurrent());
375 void PluginProxyMultiThreadTest::PostQuitForMainThread() {
376 main_thread_message_loop_proxy_->PostTask(
377 FROM_HERE,
378 base::Bind(&PluginProxyMultiThreadTest::QuitNestedLoop,
379 base::Unretained(this)));
382 void PluginProxyMultiThreadTest::PostQuitForSecondaryThread() {
383 ProxyAutoLock auto_lock;
384 secondary_thread_message_loop_->PostQuit(PP_TRUE);
387 void PluginProxyMultiThreadTest::Run() {
388 ProxyAutoLock auto_lock;
389 ASSERT_EQ(PP_OK, secondary_thread_message_loop_->AttachToCurrentThread());
390 ASSERT_EQ(PP_OK, secondary_thread_message_loop_->Run());
391 secondary_thread_message_loop_->DetachFromThread();
394 void PluginProxyMultiThreadTest::QuitNestedLoop() {
395 nested_main_thread_message_loop_->Quit();
398 // static
399 void PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread(
400 void* user_data,
401 int32_t result) {
402 EXPECT_EQ(PP_OK, result);
403 PluginProxyMultiThreadTest* thiz =
404 static_cast<PluginProxyMultiThreadTest*>(user_data);
405 thiz->CheckOnThread(SECONDARY_THREAD);
406 thiz->SetUpTestOnSecondaryThread();
409 // HostProxyTestHarness --------------------------------------------------------
411 HostProxyTestHarness::HostProxyTestHarness(GlobalsConfiguration globals_config)
412 : globals_config_(globals_config) {
415 HostProxyTestHarness::~HostProxyTestHarness() {
418 PpapiGlobals* HostProxyTestHarness::GetGlobals() {
419 return host_globals_.get();
422 Dispatcher* HostProxyTestHarness::GetDispatcher() {
423 return host_dispatcher_.get();
426 void HostProxyTestHarness::SetUpHarness() {
427 // These must be first since the dispatcher set-up uses them.
428 CreateHostGlobals();
430 host_dispatcher_.reset(new HostDispatcher(
431 pp_module(),
432 &MockGetInterface,
433 PpapiPermissions::AllPermissions()));
434 host_dispatcher_->InitWithTestSink(&sink());
435 HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
438 void HostProxyTestHarness::SetUpHarnessWithChannel(
439 const IPC::ChannelHandle& channel_handle,
440 base::MessageLoopProxy* ipc_message_loop,
441 base::WaitableEvent* shutdown_event,
442 bool is_client) {
443 // These must be first since the dispatcher set-up uses them.
444 CreateHostGlobals();
446 delegate_mock_.Init(ipc_message_loop, shutdown_event);
448 host_dispatcher_.reset(new HostDispatcher(
449 pp_module(),
450 &MockGetInterface,
451 PpapiPermissions::AllPermissions()));
452 ppapi::Preferences preferences;
453 host_dispatcher_->InitHostWithChannel(&delegate_mock_,
454 base::kNullProcessId, channel_handle,
455 is_client, preferences);
456 HostDispatcher::SetForInstance(pp_instance(), host_dispatcher_.get());
459 void HostProxyTestHarness::TearDownHarness() {
460 HostDispatcher::RemoveForInstance(pp_instance());
461 host_dispatcher_.reset();
462 host_globals_.reset();
465 void HostProxyTestHarness::CreateHostGlobals() {
466 if (globals_config_ == PER_THREAD_GLOBALS) {
467 host_globals_.reset(new TestGlobals(PpapiGlobals::PerThreadForTest()));
468 PpapiGlobals::SetPpapiGlobalsOnThreadForTest(GetGlobals());
469 // The host side of the proxy does not lock.
470 ProxyLock::DisableLockingOnThreadForTest();
471 } else {
472 ProxyLock::DisableLockingOnThreadForTest();
473 host_globals_.reset(new TestGlobals());
477 base::MessageLoopProxy*
478 HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
479 return ipc_message_loop_;
482 base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
483 return shutdown_event_;
486 IPC::PlatformFileForTransit
487 HostProxyTestHarness::DelegateMock::ShareHandleWithRemote(
488 base::PlatformFile handle,
489 base::ProcessId /* remote_pid */,
490 bool should_close_source) {
491 return IPC::GetFileHandleForProcess(handle,
492 base::Process::Current().handle(),
493 should_close_source);
497 // HostProxyTest ---------------------------------------------------------------
499 HostProxyTest::HostProxyTest() : HostProxyTestHarness(SINGLETON_GLOBALS) {
502 HostProxyTest::~HostProxyTest() {
505 void HostProxyTest::SetUp() {
506 SetUpHarness();
509 void HostProxyTest::TearDown() {
510 TearDownHarness();
513 // TwoWayTest ---------------------------------------------------------------
515 TwoWayTest::TwoWayTest(TwoWayTest::TwoWayTestMode test_mode)
516 : test_mode_(test_mode),
517 host_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
518 plugin_(ProxyTestHarnessBase::PER_THREAD_GLOBALS),
519 io_thread_("TwoWayTest_IOThread"),
520 plugin_thread_("TwoWayTest_PluginThread"),
521 remote_harness_(NULL),
522 local_harness_(NULL),
523 channel_created_(true, false),
524 shutdown_event_(true, false) {
525 if (test_mode == TEST_PPP_INTERFACE) {
526 remote_harness_ = &plugin_;
527 local_harness_ = &host_;
528 } else {
529 remote_harness_ = &host_;
530 local_harness_ = &plugin_;
534 TwoWayTest::~TwoWayTest() {
535 shutdown_event_.Signal();
538 void TwoWayTest::SetUp() {
539 base::Thread::Options options;
540 options.message_loop_type = base::MessageLoop::TYPE_IO;
541 io_thread_.StartWithOptions(options);
542 plugin_thread_.Start();
544 // Construct the IPC handle name using the process ID so we can safely run
545 // multiple |TwoWayTest|s concurrently.
546 std::ostringstream handle_name;
547 handle_name << "TwoWayTestChannel" << base::GetCurrentProcId();
548 IPC::ChannelHandle handle(handle_name.str());
549 base::WaitableEvent remote_harness_set_up(true, false);
550 plugin_thread_.message_loop_proxy()->PostTask(
551 FROM_HERE,
552 base::Bind(&SetUpRemoteHarness,
553 remote_harness_,
554 handle,
555 io_thread_.message_loop_proxy(),
556 &shutdown_event_,
557 &remote_harness_set_up));
558 remote_harness_set_up.Wait();
559 local_harness_->SetUpHarnessWithChannel(handle,
560 io_thread_.message_loop_proxy().get(),
561 &shutdown_event_,
562 true); // is_client
565 void TwoWayTest::TearDown() {
566 base::WaitableEvent remote_harness_torn_down(true, false);
567 plugin_thread_.message_loop_proxy()->PostTask(
568 FROM_HERE,
569 base::Bind(&TearDownRemoteHarness,
570 remote_harness_,
571 &remote_harness_torn_down));
572 remote_harness_torn_down.Wait();
574 local_harness_->TearDownHarness();
576 io_thread_.Stop();
579 void TwoWayTest::PostTaskOnRemoteHarness(const base::Closure& task) {
580 base::WaitableEvent task_complete(true, false);
581 plugin_thread_.message_loop_proxy()->PostTask(FROM_HERE,
582 base::Bind(&RunTaskOnRemoteHarness,
583 task,
584 &task_complete));
585 task_complete.Wait();
589 } // namespace proxy
590 } // namespace ppapi