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/tests/test_utils.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/cpp/instance_handle.h"
18 #include "ppapi/cpp/module.h"
19 #include "ppapi/cpp/net_address.h"
20 #include "ppapi/cpp/private/host_resolver_private.h"
21 #include "ppapi/cpp/private/net_address_private.h"
22 #include "ppapi/cpp/var.h"
30 } data
= { 0x01020304 };
32 return data
.integer8
[0] == 1;
37 const int kActionTimeoutMs
= 10000;
39 const PPB_Testing_Private
* GetTestingInterface() {
40 static const PPB_Testing_Private
* g_testing_interface
=
41 static_cast<const PPB_Testing_Private
*>(
42 pp::Module::Get()->GetBrowserInterface(
43 PPB_TESTING_PRIVATE_INTERFACE
));
44 return g_testing_interface
;
47 std::string
ReportError(const char* method
, int32_t error
) {
48 char error_as_string
[12];
49 sprintf(error_as_string
, "%d", static_cast<int>(error
));
50 std::string result
= method
+ std::string(" failed with error: ") +
55 void PlatformSleep(int duration_ms
) {
59 usleep(duration_ms
* 1000);
63 bool GetLocalHostPort(PP_Instance instance
, std::string
* host
, uint16_t* port
) {
67 const PPB_Testing_Private
* testing
= GetTestingInterface();
71 PP_URLComponents_Dev components
;
72 pp::Var
pp_url(pp::PASS_REF
,
73 testing
->GetDocumentURL(instance
, &components
));
74 if (!pp_url
.is_string())
76 std::string url
= pp_url
.AsString();
78 if (components
.host
.len
< 0)
80 host
->assign(url
.substr(components
.host
.begin
, components
.host
.len
));
82 if (components
.port
.len
<= 0)
85 int i
= atoi(url
.substr(components
.port
.begin
, components
.port
.len
).c_str());
86 if (i
< 0 || i
> 65535)
88 *port
= static_cast<uint16_t>(i
);
93 uint16_t ConvertFromNetEndian16(uint16_t x
) {
97 return (x
<< 8) | (x
>> 8);
100 uint16_t ConvertToNetEndian16(uint16_t x
) {
104 return (x
<< 8) | (x
>> 8);
107 bool EqualNetAddress(const pp::NetAddress
& addr1
, const pp::NetAddress
& addr2
) {
108 if (addr1
.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED
||
109 addr2
.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED
) {
113 if (addr1
.GetFamily() == PP_NETADDRESS_FAMILY_IPV4
) {
114 PP_NetAddress_IPv4 ipv4_addr1
, ipv4_addr2
;
115 if (!addr1
.DescribeAsIPv4Address(&ipv4_addr1
) ||
116 !addr2
.DescribeAsIPv4Address(&ipv4_addr2
)) {
120 return ipv4_addr1
.port
== ipv4_addr2
.port
&&
121 !memcmp(ipv4_addr1
.addr
, ipv4_addr2
.addr
, sizeof(ipv4_addr1
.addr
));
123 PP_NetAddress_IPv6 ipv6_addr1
, ipv6_addr2
;
124 if (!addr1
.DescribeAsIPv6Address(&ipv6_addr1
) ||
125 !addr2
.DescribeAsIPv6Address(&ipv6_addr2
)) {
129 return ipv6_addr1
.port
== ipv6_addr2
.port
&&
130 !memcmp(ipv6_addr1
.addr
, ipv6_addr2
.addr
, sizeof(ipv6_addr1
.addr
));
134 bool ResolveHost(PP_Instance instance
,
135 const std::string
& host
,
137 pp::NetAddress
* addr
) {
138 // TODO(yzshen): Change to use the public host resolver once it is supported.
139 pp::InstanceHandle
instance_handle(instance
);
140 pp::HostResolverPrivate
host_resolver(instance_handle
);
141 PP_HostResolver_Private_Hint hint
=
142 { PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED
, 0 };
144 TestCompletionCallback
callback(instance
);
145 callback
.WaitForResult(
146 host_resolver
.Resolve(host
, port
, hint
, callback
.GetCallback()));
148 PP_NetAddress_Private addr_private
;
149 if (callback
.result() != PP_OK
|| host_resolver
.GetSize() == 0 ||
150 !host_resolver
.GetNetAddress(0, &addr_private
)) {
154 switch (pp::NetAddressPrivate::GetFamily(addr_private
)) {
155 case PP_NETADDRESSFAMILY_PRIVATE_IPV4
: {
156 PP_NetAddress_IPv4 ipv4_addr
;
157 ipv4_addr
.port
= ConvertToNetEndian16(
158 pp::NetAddressPrivate::GetPort(addr_private
));
159 if (!pp::NetAddressPrivate::GetAddress(addr_private
, ipv4_addr
.addr
,
160 sizeof(ipv4_addr
.addr
))) {
163 *addr
= pp::NetAddress(instance_handle
, ipv4_addr
);
166 case PP_NETADDRESSFAMILY_PRIVATE_IPV6
: {
167 PP_NetAddress_IPv6 ipv6_addr
;
168 ipv6_addr
.port
= ConvertToNetEndian16(
169 pp::NetAddressPrivate::GetPort(addr_private
));
170 if (!pp::NetAddressPrivate::GetAddress(addr_private
, ipv6_addr
.addr
,
171 sizeof(ipv6_addr
.addr
))) {
174 *addr
= pp::NetAddress(instance_handle
, ipv6_addr
);
183 bool ReplacePort(PP_Instance instance
,
184 const pp::NetAddress
& input_addr
,
186 pp::NetAddress
* output_addr
) {
187 switch (input_addr
.GetFamily()) {
188 case PP_NETADDRESS_FAMILY_IPV4
: {
189 PP_NetAddress_IPv4 ipv4_addr
;
190 if (!input_addr
.DescribeAsIPv4Address(&ipv4_addr
))
192 ipv4_addr
.port
= ConvertToNetEndian16(port
);
193 *output_addr
= pp::NetAddress(pp::InstanceHandle(instance
), ipv4_addr
);
196 case PP_NETADDRESS_FAMILY_IPV6
: {
197 PP_NetAddress_IPv6 ipv6_addr
;
198 if (!input_addr
.DescribeAsIPv6Address(&ipv6_addr
))
200 ipv6_addr
.port
= ConvertToNetEndian16(port
);
201 *output_addr
= pp::NetAddress(pp::InstanceHandle(instance
), ipv6_addr
);
210 uint16_t GetPort(const pp::NetAddress
& addr
) {
211 switch (addr
.GetFamily()) {
212 case PP_NETADDRESS_FAMILY_IPV4
: {
213 PP_NetAddress_IPv4 ipv4_addr
;
214 if (!addr
.DescribeAsIPv4Address(&ipv4_addr
))
216 return ConvertFromNetEndian16(ipv4_addr
.port
);
218 case PP_NETADDRESS_FAMILY_IPV6
: {
219 PP_NetAddress_IPv6 ipv6_addr
;
220 if (!addr
.DescribeAsIPv6Address(&ipv6_addr
))
222 return ConvertFromNetEndian16(ipv6_addr
.port
);
230 void NestedEvent::Wait() {
231 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
232 // Don't allow nesting more than once; it doesn't work with the code as-is,
233 // and probably is a bad idea most of the time anyway.
234 PP_DCHECK(!waiting_
);
239 GetTestingInterface()->RunMessageLoop(instance_
);
243 void NestedEvent::Signal() {
244 if (pp::Module::Get()->core()->IsMainThread())
245 SignalOnMainThread();
250 void NestedEvent::PostSignal(int32_t wait_ms
) {
251 pp::Module::Get()->core()->CallOnMainThread(
253 pp::CompletionCallback(&SignalThunk
, this),
257 void NestedEvent::Reset() {
258 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
259 // It doesn't make sense to reset when we're still waiting.
260 PP_DCHECK(!waiting_
);
264 void NestedEvent::SignalOnMainThread() {
265 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
268 GetTestingInterface()->QuitMessageLoop(instance_
);
271 void NestedEvent::SignalThunk(void* event
, int32_t /* result */) {
272 static_cast<NestedEvent
*>(event
)->SignalOnMainThread();
275 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
)
276 : wait_for_result_called_(false),
278 result_(PP_OK_COMPLETIONPENDING
),
279 // TODO(dmichael): The default should probably be PP_REQUIRED, but this is
280 // what the tests currently expect.
281 callback_type_(PP_OPTIONAL
),
282 post_quit_task_(false),
287 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
,
289 : wait_for_result_called_(false),
291 result_(PP_OK_COMPLETIONPENDING
),
292 callback_type_(force_async
? PP_REQUIRED
: PP_OPTIONAL
),
293 post_quit_task_(false),
298 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
,
299 CallbackType callback_type
)
300 : wait_for_result_called_(false),
302 result_(PP_OK_COMPLETIONPENDING
),
303 callback_type_(callback_type
),
304 post_quit_task_(false),
309 void TestCompletionCallback::WaitForResult(int32_t result
) {
310 PP_DCHECK(!wait_for_result_called_
);
311 wait_for_result_called_
= true;
313 if (result
== PP_OK_COMPLETIONPENDING
) {
315 post_quit_task_
= true;
318 if (callback_type_
== PP_BLOCKING
) {
320 ReportError("TestCompletionCallback: Call did not run synchronously "
321 "when passed a blocking completion callback!",
328 if (callback_type_
== PP_REQUIRED
) {
330 ReportError("TestCompletionCallback: Call ran synchronously when "
331 "passed a required completion callback!",
336 PP_DCHECK(have_result_
== true);
339 void TestCompletionCallback::WaitForAbortResult(int32_t result
) {
340 WaitForResult(result
);
341 int32_t final_result
= result_
;
342 if (result
== PP_OK_COMPLETIONPENDING
) {
343 if (final_result
!= PP_ERROR_ABORTED
) {
345 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
346 "PP_OK. Ran asynchronously.",
350 } else if (result
< PP_OK
) {
352 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
353 "non-error response. Ran synchronously.",
359 pp::CompletionCallback
TestCompletionCallback::GetCallback() {
362 if (callback_type_
== PP_BLOCKING
)
363 return pp::CompletionCallback();
364 else if (callback_type_
== PP_OPTIONAL
)
365 flags
= PP_COMPLETIONCALLBACK_FLAG_OPTIONAL
;
366 target_loop_
= pp::MessageLoop::GetCurrent();
367 return pp::CompletionCallback(&TestCompletionCallback::Handler
,
368 const_cast<TestCompletionCallback
*>(this),
372 void TestCompletionCallback::Reset() {
373 wait_for_result_called_
= false;
374 result_
= PP_OK_COMPLETIONPENDING
;
375 have_result_
= false;
376 post_quit_task_
= false;
382 void TestCompletionCallback::Handler(void* user_data
, int32_t result
) {
383 TestCompletionCallback
* callback
=
384 static_cast<TestCompletionCallback
*>(user_data
);
385 // If this check fails, it means that the callback was invoked twice or that
386 // the PPAPI call completed synchronously, but also ran the callback.
387 PP_DCHECK(!callback
->have_result_
);
388 callback
->result_
= result
;
389 callback
->have_result_
= true;
390 if (callback
->delegate_
)
391 callback
->delegate_
->OnCallback(user_data
, result
);
392 if (callback
->post_quit_task_
) {
393 callback
->post_quit_task_
= false;
394 callback
->QuitMessageLoop();
396 if (callback
->target_loop_
!= pp::MessageLoop::GetCurrent()) {
397 // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
399 callback
->errors_
.assign(
400 ReportError("TestCompletionCallback: Callback ran on the wrong message "
406 void TestCompletionCallback::RunMessageLoop() {
407 pp::MessageLoop
loop(pp::MessageLoop::GetCurrent());
408 // If we don't have a message loop, we're probably running in process, where
409 // PPB_MessageLoop is not supported. Just use the Testing message loop.
410 if (loop
.is_null() || loop
== pp::MessageLoop::GetForMainThread())
411 GetTestingInterface()->RunMessageLoop(instance_
);
416 void TestCompletionCallback::QuitMessageLoop() {
417 pp::MessageLoop
loop(pp::MessageLoop::GetCurrent());
418 // If we don't have a message loop, we're probably running in process, where
419 // PPB_MessageLoop is not supported. Just use the Testing message loop.
420 if (loop
.is_null() || loop
== pp::MessageLoop::GetForMainThread()) {
421 GetTestingInterface()->QuitMessageLoop(instance_
);
423 const bool should_quit
= false;
424 loop
.PostQuit(should_quit
);