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_Dev
* GetTestingInterface() {
40 static const PPB_Testing_Dev
* g_testing_interface
=
41 static_cast<const PPB_Testing_Dev
*>(
42 pp::Module::Get()->GetBrowserInterface(PPB_TESTING_DEV_INTERFACE
));
43 return g_testing_interface
;
46 std::string
ReportError(const char* method
, int32_t error
) {
47 char error_as_string
[12];
48 sprintf(error_as_string
, "%d", static_cast<int>(error
));
49 std::string result
= method
+ std::string(" failed with error: ") +
54 void PlatformSleep(int duration_ms
) {
58 usleep(duration_ms
* 1000);
62 bool GetLocalHostPort(PP_Instance instance
, std::string
* host
, uint16_t* port
) {
66 const PPB_Testing_Dev
* testing
= GetTestingInterface();
70 PP_URLComponents_Dev components
;
71 pp::Var
pp_url(pp::PASS_REF
,
72 testing
->GetDocumentURL(instance
, &components
));
73 if (!pp_url
.is_string())
75 std::string url
= pp_url
.AsString();
77 if (components
.host
.len
< 0)
79 host
->assign(url
.substr(components
.host
.begin
, components
.host
.len
));
81 if (components
.port
.len
<= 0)
84 int i
= atoi(url
.substr(components
.port
.begin
, components
.port
.len
).c_str());
85 if (i
< 0 || i
> 65535)
87 *port
= static_cast<uint16_t>(i
);
92 uint16_t ConvertFromNetEndian16(uint16_t x
) {
96 return (x
<< 8) | (x
>> 8);
99 uint16_t ConvertToNetEndian16(uint16_t x
) {
103 return (x
<< 8) | (x
>> 8);
106 bool EqualNetAddress(const pp::NetAddress
& addr1
, const pp::NetAddress
& addr2
) {
107 if (addr1
.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED
||
108 addr2
.GetFamily() == PP_NETADDRESS_FAMILY_UNSPECIFIED
) {
112 if (addr1
.GetFamily() == PP_NETADDRESS_FAMILY_IPV4
) {
113 PP_NetAddress_IPv4 ipv4_addr1
, ipv4_addr2
;
114 if (!addr1
.DescribeAsIPv4Address(&ipv4_addr1
) ||
115 !addr2
.DescribeAsIPv4Address(&ipv4_addr2
)) {
119 return ipv4_addr1
.port
== ipv4_addr2
.port
&&
120 !memcmp(ipv4_addr1
.addr
, ipv4_addr2
.addr
, sizeof(ipv4_addr1
.addr
));
122 PP_NetAddress_IPv6 ipv6_addr1
, ipv6_addr2
;
123 if (!addr1
.DescribeAsIPv6Address(&ipv6_addr1
) ||
124 !addr2
.DescribeAsIPv6Address(&ipv6_addr2
)) {
128 return ipv6_addr1
.port
== ipv6_addr2
.port
&&
129 !memcmp(ipv6_addr1
.addr
, ipv6_addr2
.addr
, sizeof(ipv6_addr1
.addr
));
133 bool ResolveHost(PP_Instance instance
,
134 const std::string
& host
,
136 pp::NetAddress
* addr
) {
137 // TODO(yzshen): Change to use the public host resolver once it is supported.
138 pp::InstanceHandle
instance_handle(instance
);
139 pp::HostResolverPrivate
host_resolver(instance_handle
);
140 PP_HostResolver_Private_Hint hint
=
141 { PP_NETADDRESSFAMILY_PRIVATE_UNSPECIFIED
, 0 };
143 TestCompletionCallback
callback(instance
);
144 callback
.WaitForResult(
145 host_resolver
.Resolve(host
, port
, hint
, callback
.GetCallback()));
147 PP_NetAddress_Private addr_private
;
148 if (callback
.result() != PP_OK
|| host_resolver
.GetSize() == 0 ||
149 !host_resolver
.GetNetAddress(0, &addr_private
)) {
153 switch (pp::NetAddressPrivate::GetFamily(addr_private
)) {
154 case PP_NETADDRESSFAMILY_PRIVATE_IPV4
: {
155 PP_NetAddress_IPv4 ipv4_addr
;
156 ipv4_addr
.port
= ConvertToNetEndian16(
157 pp::NetAddressPrivate::GetPort(addr_private
));
158 if (!pp::NetAddressPrivate::GetAddress(addr_private
, ipv4_addr
.addr
,
159 sizeof(ipv4_addr
.addr
))) {
162 *addr
= pp::NetAddress(instance_handle
, ipv4_addr
);
165 case PP_NETADDRESSFAMILY_PRIVATE_IPV6
: {
166 PP_NetAddress_IPv6 ipv6_addr
;
167 ipv6_addr
.port
= ConvertToNetEndian16(
168 pp::NetAddressPrivate::GetPort(addr_private
));
169 if (!pp::NetAddressPrivate::GetAddress(addr_private
, ipv6_addr
.addr
,
170 sizeof(ipv6_addr
.addr
))) {
173 *addr
= pp::NetAddress(instance_handle
, ipv6_addr
);
182 bool ReplacePort(PP_Instance instance
,
183 const pp::NetAddress
& input_addr
,
185 pp::NetAddress
* output_addr
) {
186 switch (input_addr
.GetFamily()) {
187 case PP_NETADDRESS_FAMILY_IPV4
: {
188 PP_NetAddress_IPv4 ipv4_addr
;
189 if (!input_addr
.DescribeAsIPv4Address(&ipv4_addr
))
191 ipv4_addr
.port
= ConvertToNetEndian16(port
);
192 *output_addr
= pp::NetAddress(pp::InstanceHandle(instance
), ipv4_addr
);
195 case PP_NETADDRESS_FAMILY_IPV6
: {
196 PP_NetAddress_IPv6 ipv6_addr
;
197 if (!input_addr
.DescribeAsIPv6Address(&ipv6_addr
))
199 ipv6_addr
.port
= ConvertToNetEndian16(port
);
200 *output_addr
= pp::NetAddress(pp::InstanceHandle(instance
), ipv6_addr
);
209 uint16_t GetPort(const pp::NetAddress
& addr
) {
210 switch (addr
.GetFamily()) {
211 case PP_NETADDRESS_FAMILY_IPV4
: {
212 PP_NetAddress_IPv4 ipv4_addr
;
213 if (!addr
.DescribeAsIPv4Address(&ipv4_addr
))
215 return ConvertFromNetEndian16(ipv4_addr
.port
);
217 case PP_NETADDRESS_FAMILY_IPV6
: {
218 PP_NetAddress_IPv6 ipv6_addr
;
219 if (!addr
.DescribeAsIPv6Address(&ipv6_addr
))
221 return ConvertFromNetEndian16(ipv6_addr
.port
);
229 void NestedEvent::Wait() {
230 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
231 // Don't allow nesting more than once; it doesn't work with the code as-is,
232 // and probably is a bad idea most of the time anyway.
233 PP_DCHECK(!waiting_
);
238 GetTestingInterface()->RunMessageLoop(instance_
);
242 void NestedEvent::Signal() {
243 if (pp::Module::Get()->core()->IsMainThread())
244 SignalOnMainThread();
249 void NestedEvent::PostSignal(int32_t wait_ms
) {
250 pp::Module::Get()->core()->CallOnMainThread(
252 pp::CompletionCallback(&SignalThunk
, this),
256 void NestedEvent::Reset() {
257 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
258 // It doesn't make sense to reset when we're still waiting.
259 PP_DCHECK(!waiting_
);
263 void NestedEvent::SignalOnMainThread() {
264 PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
267 GetTestingInterface()->QuitMessageLoop(instance_
);
270 void NestedEvent::SignalThunk(void* event
, int32_t /* result */) {
271 static_cast<NestedEvent
*>(event
)->SignalOnMainThread();
274 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
)
275 : wait_for_result_called_(false),
277 result_(PP_OK_COMPLETIONPENDING
),
278 // TODO(dmichael): The default should probably be PP_REQUIRED, but this is
279 // what the tests currently expect.
280 callback_type_(PP_OPTIONAL
),
281 post_quit_task_(false),
286 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
,
288 : wait_for_result_called_(false),
290 result_(PP_OK_COMPLETIONPENDING
),
291 callback_type_(force_async
? PP_REQUIRED
: PP_OPTIONAL
),
292 post_quit_task_(false),
297 TestCompletionCallback::TestCompletionCallback(PP_Instance instance
,
298 CallbackType callback_type
)
299 : wait_for_result_called_(false),
301 result_(PP_OK_COMPLETIONPENDING
),
302 callback_type_(callback_type
),
303 post_quit_task_(false),
308 void TestCompletionCallback::WaitForResult(int32_t result
) {
309 PP_DCHECK(!wait_for_result_called_
);
310 wait_for_result_called_
= true;
312 if (result
== PP_OK_COMPLETIONPENDING
) {
314 post_quit_task_
= true;
317 if (callback_type_
== PP_BLOCKING
) {
319 ReportError("TestCompletionCallback: Call did not run synchronously "
320 "when passed a blocking completion callback!",
327 if (callback_type_
== PP_REQUIRED
) {
329 ReportError("TestCompletionCallback: Call ran synchronously when "
330 "passed a required completion callback!",
335 PP_DCHECK(have_result_
== true);
338 void TestCompletionCallback::WaitForAbortResult(int32_t result
) {
339 WaitForResult(result
);
340 int32_t final_result
= result_
;
341 if (result
== PP_OK_COMPLETIONPENDING
) {
342 if (final_result
!= PP_ERROR_ABORTED
) {
344 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
345 "PP_OK. Ran asynchronously.",
349 } else if (result
< PP_OK
) {
351 ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
352 "non-error response. Ran synchronously.",
358 pp::CompletionCallback
TestCompletionCallback::GetCallback() {
361 if (callback_type_
== PP_BLOCKING
)
362 return pp::CompletionCallback();
363 else if (callback_type_
== PP_OPTIONAL
)
364 flags
= PP_COMPLETIONCALLBACK_FLAG_OPTIONAL
;
365 target_loop_
= pp::MessageLoop::GetCurrent();
366 return pp::CompletionCallback(&TestCompletionCallback::Handler
,
367 const_cast<TestCompletionCallback
*>(this),
371 void TestCompletionCallback::Reset() {
372 wait_for_result_called_
= false;
373 result_
= PP_OK_COMPLETIONPENDING
;
374 have_result_
= false;
375 post_quit_task_
= false;
381 void TestCompletionCallback::Handler(void* user_data
, int32_t result
) {
382 TestCompletionCallback
* callback
=
383 static_cast<TestCompletionCallback
*>(user_data
);
384 // If this check fails, it means that the callback was invoked twice or that
385 // the PPAPI call completed synchronously, but also ran the callback.
386 PP_DCHECK(!callback
->have_result_
);
387 callback
->result_
= result
;
388 callback
->have_result_
= true;
389 if (callback
->delegate_
)
390 callback
->delegate_
->OnCallback(user_data
, result
);
391 if (callback
->post_quit_task_
) {
392 callback
->post_quit_task_
= false;
393 callback
->QuitMessageLoop();
395 if (callback
->target_loop_
!= pp::MessageLoop::GetCurrent()) {
396 // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
398 callback
->errors_
.assign(
399 ReportError("TestCompletionCallback: Callback ran on the wrong message "
405 void TestCompletionCallback::RunMessageLoop() {
406 pp::MessageLoop
loop(pp::MessageLoop::GetCurrent());
407 // If we don't have a message loop, we're probably running in process, where
408 // PPB_MessageLoop is not supported. Just use the Testing message loop.
409 if (loop
.is_null() || loop
== pp::MessageLoop::GetForMainThread())
410 GetTestingInterface()->RunMessageLoop(instance_
);
415 void TestCompletionCallback::QuitMessageLoop() {
416 pp::MessageLoop
loop(pp::MessageLoop::GetCurrent());
417 // If we don't have a message loop, we're probably running in process, where
418 // PPB_MessageLoop is not supported. Just use the Testing message loop.
419 if (loop
.is_null() || loop
== pp::MessageLoop::GetForMainThread()) {
420 GetTestingInterface()->QuitMessageLoop(instance_
);
422 const bool should_quit
= false;
423 loop
.PostQuit(should_quit
);