1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <string>
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/plugin_proxy_delegate.h"
#include "ppapi/proxy/plugin_resource_tracker.h"
#include "ppapi/proxy/plugin_var_tracker.h"
#include "ppapi/proxy/resource_message_test_sink.h"
#include "ppapi/shared_impl/test_globals.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class MessageLoopProxy;
class RunLoop;
}
namespace ppapi {
namespace proxy {
class MessageLoopResource;
// Base class for plugin and host test harnesses. Tests will not use this
// directly. Instead, use the PluginProxyTest, HostProxyTest, or TwoWayTest.
class ProxyTestHarnessBase {
public:
enum GlobalsConfiguration {
PER_THREAD_GLOBALS,
SINGLETON_GLOBALS
};
ProxyTestHarnessBase();
virtual ~ProxyTestHarnessBase();
PP_Module pp_module() const { return pp_module_; }
PP_Instance pp_instance() const { return pp_instance_; }
ResourceMessageTestSink& sink() { return sink_; }
virtual PpapiGlobals* GetGlobals() = 0;
// Returns either the plugin or host dispatcher, depending on the test.
virtual Dispatcher* GetDispatcher() = 0;
// Set up the harness using an IPC::TestSink to capture messages.
virtual void SetUpHarness() = 0;
// Set up the harness using a real IPC channel.
virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
base::MessageLoopProxy* ipc_message_loop,
base::WaitableEvent* shutdown_event,
bool is_client) = 0;
virtual void TearDownHarness() = 0;
// Implementation of GetInterface for the dispatcher. This will
// return NULL for all interfaces unless one is registered by calling
// RegisterTestInterface();
const void* GetInterface(const char* name);
// Allows the test to specify an interface implementation for a given
// interface name. This will be returned when any of the proxy logic
// requests a local interface.
void RegisterTestInterface(const char* name, const void* test_interface);
// Sends a "supports interface" message to the current dispatcher and returns
// true if it's supported. This is just for the convenience of tests.
bool SupportsInterface(const char* name);
private:
// Destination for IPC messages sent by the test.
ResourceMessageTestSink sink_;
// The module and instance ID associated with the plugin dispatcher.
PP_Module pp_module_;
PP_Instance pp_instance_;
// Stores the data for GetInterface/RegisterTestInterface.
std::map<std::string, const void*> registered_interfaces_;
};
// Test harness for the plugin side of the proxy.
class PluginProxyTestHarness : public ProxyTestHarnessBase {
public:
explicit PluginProxyTestHarness(GlobalsConfiguration globals_config);
virtual ~PluginProxyTestHarness();
PluginDispatcher* plugin_dispatcher() { return plugin_dispatcher_.get(); }
PluginResourceTracker& resource_tracker() {
return *plugin_globals_->plugin_resource_tracker();
}
PluginVarTracker& var_tracker() {
return *plugin_globals_->plugin_var_tracker();
}
// ProxyTestHarnessBase implementation.
virtual PpapiGlobals* GetGlobals();
virtual Dispatcher* GetDispatcher();
virtual void SetUpHarness();
virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
base::MessageLoopProxy* ipc_message_loop,
base::WaitableEvent* shutdown_event,
bool is_client);
virtual void TearDownHarness();
class PluginDelegateMock : public PluginDispatcher::PluginDelegate,
public PluginProxyDelegate {
public:
PluginDelegateMock() : ipc_message_loop_(NULL), shutdown_event_() {}
virtual ~PluginDelegateMock() {}
void Init(base::MessageLoopProxy* ipc_message_loop,
base::WaitableEvent* shutdown_event) {
ipc_message_loop_ = ipc_message_loop;
shutdown_event_ = shutdown_event;
}
void set_browser_sender(IPC::Sender* browser_sender) {
browser_sender_ = browser_sender;
}
// ProxyChannel::Delegate implementation.
virtual base::MessageLoopProxy* GetIPCMessageLoop() OVERRIDE;
virtual base::WaitableEvent* GetShutdownEvent() OVERRIDE;
virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
base::PlatformFile handle,
base::ProcessId remote_pid,
bool should_close_source) OVERRIDE;
// PluginDispatcher::PluginDelegate implementation.
virtual std::set<PP_Instance>* GetGloballySeenInstanceIDSet() OVERRIDE;
virtual uint32 Register(PluginDispatcher* plugin_dispatcher) OVERRIDE;
virtual void Unregister(uint32 plugin_dispatcher_id) OVERRIDE;
// PluginProxyDelegate implementation.
virtual IPC::Sender* GetBrowserSender() OVERRIDE;
virtual std::string GetUILanguage() OVERRIDE;
virtual void PreCacheFont(const void* logfontw) OVERRIDE;
virtual void SetActiveURL(const std::string& url) OVERRIDE;
private:
base::MessageLoopProxy* ipc_message_loop_; // Weak
base::WaitableEvent* shutdown_event_; // Weak
std::set<PP_Instance> instance_id_set_;
IPC::Sender* browser_sender_;
DISALLOW_COPY_AND_ASSIGN(PluginDelegateMock);
};
private:
void CreatePluginGlobals();
GlobalsConfiguration globals_config_;
scoped_ptr<PluginGlobals> plugin_globals_;
scoped_ptr<PluginDispatcher> plugin_dispatcher_;
PluginDelegateMock plugin_delegate_mock_;
};
class PluginProxyTest : public PluginProxyTestHarness, public testing::Test {
public:
PluginProxyTest();
virtual ~PluginProxyTest();
// testing::Test implementation.
virtual void SetUp();
virtual void TearDown();
private:
MessageLoop message_loop_;
};
// This class provides support for multi-thread testing. A secondary thread is
// created with a Pepper message loop.
// Subclasses need to implement the two SetUpTestOn*Thread() methods to do the
// actual testing work; and call both PostQuitFor*Thread() when testing is
// done.
class PluginProxyMultiThreadTest
: public PluginProxyTest,
public base::DelegateSimpleThread::Delegate {
public:
PluginProxyMultiThreadTest();
virtual ~PluginProxyMultiThreadTest();
// Called before the secondary thread is started, but after all the member
// variables, including |secondary_thread_| and
// |secondary_thread_message_loop_|, are initialized.
virtual void SetUpTestOnMainThread() = 0;
virtual void SetUpTestOnSecondaryThread() = 0;
// TEST_F() should call this method.
void RunTest();
enum ThreadType {
MAIN_THREAD,
SECONDARY_THREAD
};
void CheckOnThread(ThreadType thread_type);
// These can be called on any thread.
void PostQuitForMainThread();
void PostQuitForSecondaryThread();
protected:
scoped_refptr<MessageLoopResource> secondary_thread_message_loop_;
scoped_refptr<base::MessageLoopProxy> main_thread_message_loop_proxy_;
private:
// base::DelegateSimpleThread::Delegate implementation.
virtual void Run() OVERRIDE;
void QuitNestedLoop();
static void InternalSetUpTestOnSecondaryThread(void* user_data,
int32_t result);
scoped_ptr<base::DelegateSimpleThread> secondary_thread_;
scoped_ptr<base::RunLoop> nested_main_thread_message_loop_;
};
class HostProxyTestHarness : public ProxyTestHarnessBase {
public:
explicit HostProxyTestHarness(GlobalsConfiguration globals_config);
virtual ~HostProxyTestHarness();
HostDispatcher* host_dispatcher() { return host_dispatcher_.get(); }
ResourceTracker& resource_tracker() {
return *host_globals_->GetResourceTracker();
}
VarTracker& var_tracker() {
return *host_globals_->GetVarTracker();
}
// ProxyTestBase implementation.
virtual PpapiGlobals* GetGlobals();
virtual Dispatcher* GetDispatcher();
virtual void SetUpHarness();
virtual void SetUpHarnessWithChannel(const IPC::ChannelHandle& channel_handle,
base::MessageLoopProxy* ipc_message_loop,
base::WaitableEvent* shutdown_event,
bool is_client);
virtual void TearDownHarness();
class DelegateMock : public ProxyChannel::Delegate {
public:
DelegateMock() : ipc_message_loop_(NULL), shutdown_event_(NULL) {
}
virtual ~DelegateMock() {}
void Init(base::MessageLoopProxy* ipc_message_loop,
base::WaitableEvent* shutdown_event) {
ipc_message_loop_ = ipc_message_loop;
shutdown_event_ = shutdown_event;
}
// ProxyChannel::Delegate implementation.
virtual base::MessageLoopProxy* GetIPCMessageLoop();
virtual base::WaitableEvent* GetShutdownEvent();
virtual IPC::PlatformFileForTransit ShareHandleWithRemote(
base::PlatformFile handle,
base::ProcessId remote_pid,
bool should_close_source) OVERRIDE;
private:
base::MessageLoopProxy* ipc_message_loop_; // Weak
base::WaitableEvent* shutdown_event_; // Weak
DISALLOW_COPY_AND_ASSIGN(DelegateMock);
};
private:
class MockSyncMessageStatusReceiver;
void CreateHostGlobals();
GlobalsConfiguration globals_config_;
scoped_ptr<ppapi::TestGlobals> host_globals_;
scoped_ptr<HostDispatcher> host_dispatcher_;
DelegateMock delegate_mock_;
scoped_ptr<MockSyncMessageStatusReceiver> status_receiver_;
};
class HostProxyTest : public HostProxyTestHarness, public testing::Test {
public:
HostProxyTest();
virtual ~HostProxyTest();
// testing::Test implementation.
virtual void SetUp();
virtual void TearDown();
private:
MessageLoop message_loop_;
};
// Use this base class to test both sides of a proxy.
class TwoWayTest : public testing::Test {
public:
enum TwoWayTestMode {
TEST_PPP_INTERFACE,
TEST_PPB_INTERFACE
};
TwoWayTest(TwoWayTestMode test_mode);
virtual ~TwoWayTest();
HostProxyTestHarness& host() { return host_; }
PluginProxyTestHarness& plugin() { return plugin_; }
PP_Module pp_module() const { return host_.pp_module(); }
PP_Instance pp_instance() const { return host_.pp_instance(); }
TwoWayTestMode test_mode() { return test_mode_; }
// testing::Test implementation.
virtual void SetUp();
virtual void TearDown();
protected:
// Post a task to the thread where the remote harness lives. This
// is typically used to test the state of the var tracker on the plugin
// thread. This runs the task synchronously for convenience.
void PostTaskOnRemoteHarness(const base::Closure& task);
private:
TwoWayTestMode test_mode_;
HostProxyTestHarness host_;
PluginProxyTestHarness plugin_;
// In order to use sync IPC, we need to have an IO thread.
base::Thread io_thread_;
// The plugin side of the proxy runs on its own thread.
base::Thread plugin_thread_;
// The message loop for the main (host) thread.
MessageLoop message_loop_;
// Aliases for the host and plugin harnesses; if we're testing a PPP
// interface, remote_harness will point to plugin_, and local_harness
// will point to host_. This makes it convenient when we're starting and
// stopping the harnesses.
ProxyTestHarnessBase* remote_harness_;
ProxyTestHarnessBase* local_harness_;
base::WaitableEvent channel_created_;
base::WaitableEvent shutdown_event_;
};
// Used during Gtests when you have a PP_Var that you want to EXPECT is equal
// to a certain constant string value:
//
// EXPECT_VAR_IS_STRING("foo", my_var);
#define EXPECT_VAR_IS_STRING(str, var) { \
StringVar* sv = StringVar::FromPPVar(var); \
EXPECT_TRUE(sv); \
if (sv) \
EXPECT_EQ(str, sv->value()); \
}
} // namespace proxy
} // namespace ppapi
|