Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / ppapi_proxy_test.cc
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 "ppapi/proxy/ppapi_proxy_test.h"
6
7 #include <sstream>
8
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"
21
22 namespace ppapi {
23 namespace proxy {
24
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();
30 };
31
32 PP_Instance GetInstanceForResource(PP_Resource resource) {
33   // If a test relies on this, we need to implement it.
34   NOTREACHED();
35   return 0;
36 }
37
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.
42 }
43
44 void AddRefModule(PP_Module module) {}
45 void ReleaseModule(PP_Module module) {}
46 PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; }
47
48 PPB_Proxy_Private ppb_proxy_private = {
49   &PluginCrashed,
50   &GetInstanceForResource,
51   &SetReserveInstanceIDCallback,
52   &AddRefModule,
53   &ReleaseModule,
54   &IsInModuleDestructor
55 };
56
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_;
66
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;
74   }
75   if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0)
76     return &ppb_proxy_private;
77   return NULL;
78 }
79
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();
88 }
89
90 void TearDownRemoteHarness(ProxyTestHarnessBase* harness,
91                            base::WaitableEvent* harness_torn_down) {
92   harness->TearDownHarness();
93   harness_torn_down->Signal();
94 }
95
96 void RunTaskOnRemoteHarness(const base::Closure& task,
97                             base::WaitableEvent* task_complete) {
98  task.Run();
99  task_complete->Signal();
100 }
101
102 }  // namespace
103
104 // ProxyTestHarnessBase --------------------------------------------------------
105
106 ProxyTestHarnessBase::ProxyTestHarnessBase() : pp_module_(0x98765),
107                                                pp_instance_(0x12345) {
108   get_interface_handlers_.AddObserver(this);
109 }
110
111 ProxyTestHarnessBase::~ProxyTestHarnessBase() {
112   get_interface_handlers_.RemoveObserver(this);
113 }
114
115 const void* ProxyTestHarnessBase::GetInterface(const char* name) {
116   return registered_interfaces_[name];
117 }
118
119 void ProxyTestHarnessBase::RegisterTestInterface(const char* name,
120                                                  const void* test_interface) {
121   registered_interfaces_[name] = test_interface;
122 }
123
124 bool ProxyTestHarnessBase::SupportsInterface(const char* name) {
125   sink().ClearMessages();
126
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);
132
133   const IPC::Message* reply_msg =
134       sink().GetUniqueMessageMatching(IPC_REPLY_ID);
135   EXPECT_TRUE(reply_msg);
136   if (!reply_msg)
137     return false;
138
139   TupleTypes<PpapiMsg_SupportsInterface::ReplyParam>::ValueTuple reply_data;
140   EXPECT_TRUE(PpapiMsg_SupportsInterface::ReadReplyParam(
141       reply_msg, &reply_data));
142
143   sink().ClearMessages();
144   return reply_data.a;
145 }
146
147 // PluginProxyTestHarness ------------------------------------------------------
148
149 PluginProxyTestHarness::PluginProxyTestHarness(
150     GlobalsConfiguration globals_config)
151     : globals_config_(globals_config) {
152 }
153
154 PluginProxyTestHarness::~PluginProxyTestHarness() {
155 }
156
157 PpapiGlobals* PluginProxyTestHarness::GetGlobals() {
158   return plugin_globals_.get();
159 }
160
161 Dispatcher* PluginProxyTestHarness::GetDispatcher() {
162   return plugin_dispatcher_.get();
163 }
164
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;
170
171   resource_tracker().DidCreateInstance(pp_instance());
172
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());
186 }
187
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;
197
198   resource_tracker().DidCreateInstance(pp_instance());
199   plugin_delegate_mock_.Init(ipc_message_loop, shutdown_event);
200
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());
212 }
213
214 void PluginProxyTestHarness::TearDownHarness() {
215   {
216     // Some of the methods called during tear-down check that the lock is held.
217     ProxyAutoLock lock;
218
219     plugin_dispatcher_->DidDestroyInstance(pp_instance());
220     plugin_dispatcher_.reset();
221
222     resource_tracker().DidDeleteInstance(pp_instance());
223   }
224   plugin_globals_.reset();
225 }
226
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();
237   }
238 }
239
240 base::MessageLoopProxy*
241 PluginProxyTestHarness::PluginDelegateMock::GetIPCMessageLoop() {
242   return ipc_message_loop_;
243 }
244
245 base::WaitableEvent*
246 PluginProxyTestHarness::PluginDelegateMock::GetShutdownEvent() {
247   return shutdown_event_;
248 }
249
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);
258 }
259
260 std::set<PP_Instance>*
261 PluginProxyTestHarness::PluginDelegateMock::GetGloballySeenInstanceIDSet() {
262   return &instance_id_set_;
263 }
264
265 uint32 PluginProxyTestHarness::PluginDelegateMock::Register(
266     PluginDispatcher* plugin_dispatcher) {
267   return 0;
268 }
269
270 void PluginProxyTestHarness::PluginDelegateMock::Unregister(
271     uint32 plugin_dispatcher_id) {
272 }
273
274 IPC::Sender* PluginProxyTestHarness::PluginDelegateMock::GetBrowserSender() {
275   return browser_sender_;
276 }
277
278 std::string PluginProxyTestHarness::PluginDelegateMock::GetUILanguage() {
279   return std::string("en-US");
280 }
281
282 void PluginProxyTestHarness::PluginDelegateMock::PreCacheFont(
283     const void* logfontw) {
284 }
285
286 void PluginProxyTestHarness::PluginDelegateMock::SetActiveURL(
287     const std::string& url) {
288 }
289
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;
296 }
297
298 // PluginProxyTest -------------------------------------------------------------
299
300 PluginProxyTest::PluginProxyTest() : PluginProxyTestHarness(SINGLETON_GLOBALS) {
301 }
302
303 PluginProxyTest::~PluginProxyTest() {
304 }
305
306 void PluginProxyTest::SetUp() {
307   SetUpHarness();
308 }
309
310 void PluginProxyTest::TearDown() {
311   TearDownHarness();
312 }
313
314 // PluginProxyMultiThreadTest --------------------------------------------------
315
316 PluginProxyMultiThreadTest::PluginProxyMultiThreadTest() {
317 }
318
319 PluginProxyMultiThreadTest::~PluginProxyMultiThreadTest() {
320 }
321
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());
328
329   secondary_thread_.reset(new base::DelegateSimpleThread(
330       this, "PluginProxyMultiThreadTest"));
331
332   {
333     ProxyAutoLock auto_lock;
334
335     // MessageLoopResource assumes that the proxy lock has been acquired.
336     secondary_thread_message_loop_ = new MessageLoopResource(pp_instance());
337
338     ASSERT_EQ(PP_OK,
339         secondary_thread_message_loop_->PostWork(
340             PP_MakeCompletionCallback(
341                 &PluginProxyMultiThreadTest::InternalSetUpTestOnSecondaryThread,
342                 this),
343             0));
344   }
345
346   SetUpTestOnMainThread();
347
348   secondary_thread_->Start();
349   nested_main_thread_message_loop_->Run();
350   secondary_thread_->Join();
351
352   {
353     ProxyAutoLock auto_lock;
354
355     // The destruction requires a valid PpapiGlobals instance, so we should
356     // explicitly release it.
357     secondary_thread_message_loop_ = NULL;
358   }
359
360   secondary_thread_.reset(NULL);
361   nested_main_thread_message_loop_.reset(NULL);
362   main_thread_message_loop_proxy_ = NULL;
363 }
364
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());
372   }
373 }
374
375 void PluginProxyMultiThreadTest::PostQuitForMainThread() {
376   main_thread_message_loop_proxy_->PostTask(
377       FROM_HERE,
378       base::Bind(&PluginProxyMultiThreadTest::QuitNestedLoop,
379                  base::Unretained(this)));
380 }
381
382 void PluginProxyMultiThreadTest::PostQuitForSecondaryThread() {
383   ProxyAutoLock auto_lock;
384   secondary_thread_message_loop_->PostQuit(PP_TRUE);
385 }
386
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();
392 }
393
394 void PluginProxyMultiThreadTest::QuitNestedLoop() {
395   nested_main_thread_message_loop_->Quit();
396 }
397
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();
407 }
408
409 // HostProxyTestHarness --------------------------------------------------------
410
411 HostProxyTestHarness::HostProxyTestHarness(GlobalsConfiguration globals_config)
412     : globals_config_(globals_config) {
413 }
414
415 HostProxyTestHarness::~HostProxyTestHarness() {
416 }
417
418 PpapiGlobals* HostProxyTestHarness::GetGlobals() {
419   return host_globals_.get();
420 }
421
422 Dispatcher* HostProxyTestHarness::GetDispatcher() {
423   return host_dispatcher_.get();
424 }
425
426 void HostProxyTestHarness::SetUpHarness() {
427   // These must be first since the dispatcher set-up uses them.
428   CreateHostGlobals();
429
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());
436 }
437
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();
445
446   delegate_mock_.Init(ipc_message_loop, shutdown_event);
447
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());
457 }
458
459 void HostProxyTestHarness::TearDownHarness() {
460   HostDispatcher::RemoveForInstance(pp_instance());
461   host_dispatcher_.reset();
462   host_globals_.reset();
463 }
464
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());
474   }
475 }
476
477 base::MessageLoopProxy*
478 HostProxyTestHarness::DelegateMock::GetIPCMessageLoop() {
479   return ipc_message_loop_;
480 }
481
482 base::WaitableEvent* HostProxyTestHarness::DelegateMock::GetShutdownEvent() {
483   return shutdown_event_;
484 }
485
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);
494 }
495
496
497 // HostProxyTest ---------------------------------------------------------------
498
499 HostProxyTest::HostProxyTest() : HostProxyTestHarness(SINGLETON_GLOBALS) {
500 }
501
502 HostProxyTest::~HostProxyTest() {
503 }
504
505 void HostProxyTest::SetUp() {
506   SetUpHarness();
507 }
508
509 void HostProxyTest::TearDown() {
510   TearDownHarness();
511 }
512
513 // TwoWayTest ---------------------------------------------------------------
514
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_;
531   }
532 }
533
534 TwoWayTest::~TwoWayTest() {
535   shutdown_event_.Signal();
536 }
537
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();
543
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
563 }
564
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();
573
574   local_harness_->TearDownHarness();
575
576   io_thread_.Stop();
577 }
578
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();
586 }
587
588
589 }  // namespace proxy
590 }  // namespace ppapi