Home | History | Annotate | Download | only in tests
      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/tests/test_utils.h"
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #if defined(_MSC_VER)
     11 #include <windows.h>
     12 #else
     13 #include <unistd.h>
     14 #endif
     15 
     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"
     23 
     24 namespace {
     25 
     26 bool IsBigEndian() {
     27   union {
     28     uint32_t integer32;
     29     uint8_t integer8[4];
     30   } data = { 0x01020304 };
     31 
     32   return data.integer8[0] == 1;
     33 }
     34 
     35 }  // namespace
     36 
     37 const int kActionTimeoutMs = 10000;
     38 
     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;
     45 }
     46 
     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: ") +
     51       error_as_string;
     52   return result;
     53 }
     54 
     55 void PlatformSleep(int duration_ms) {
     56 #if defined(_MSC_VER)
     57   ::Sleep(duration_ms);
     58 #else
     59   usleep(duration_ms * 1000);
     60 #endif
     61 }
     62 
     63 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port) {
     64   if (!host || !port)
     65     return false;
     66 
     67   const PPB_Testing_Private* testing = GetTestingInterface();
     68   if (!testing)
     69     return false;
     70 
     71   PP_URLComponents_Dev components;
     72   pp::Var pp_url(pp::PASS_REF,
     73                  testing->GetDocumentURL(instance, &components));
     74   if (!pp_url.is_string())
     75     return false;
     76   std::string url = pp_url.AsString();
     77 
     78   if (components.host.len < 0)
     79     return false;
     80   host->assign(url.substr(components.host.begin, components.host.len));
     81 
     82   if (components.port.len <= 0)
     83     return false;
     84 
     85   int i = atoi(url.substr(components.port.begin, components.port.len).c_str());
     86   if (i < 0 || i > 65535)
     87     return false;
     88   *port = static_cast<uint16_t>(i);
     89 
     90   return true;
     91 }
     92 
     93 uint16_t ConvertFromNetEndian16(uint16_t x) {
     94   if (IsBigEndian())
     95     return x;
     96   else
     97     return (x << 8) | (x >> 8);
     98 }
     99 
    100 uint16_t ConvertToNetEndian16(uint16_t x) {
    101   if (IsBigEndian())
    102     return x;
    103   else
    104     return (x << 8) | (x >> 8);
    105 }
    106 
    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) {
    110     return false;
    111   }
    112 
    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)) {
    117       return false;
    118     }
    119 
    120     return ipv4_addr1.port == ipv4_addr2.port &&
    121            !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
    122   } else {
    123     PP_NetAddress_IPv6 ipv6_addr1, ipv6_addr2;
    124     if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
    125         !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
    126       return false;
    127     }
    128 
    129     return ipv6_addr1.port == ipv6_addr2.port &&
    130            !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
    131   }
    132 }
    133 
    134 bool ResolveHost(PP_Instance instance,
    135                  const std::string& host,
    136                  uint16_t port,
    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 };
    143 
    144   TestCompletionCallback callback(instance);
    145   callback.WaitForResult(
    146       host_resolver.Resolve(host, port, hint, callback.GetCallback()));
    147 
    148   PP_NetAddress_Private addr_private;
    149   if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
    150       !host_resolver.GetNetAddress(0, &addr_private)) {
    151     return false;
    152   }
    153 
    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))) {
    161         return false;
    162       }
    163       *addr = pp::NetAddress(instance_handle, ipv4_addr);
    164       return true;
    165     }
    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))) {
    172         return false;
    173       }
    174       *addr = pp::NetAddress(instance_handle, ipv6_addr);
    175       return true;
    176     }
    177     default: {
    178       return false;
    179     }
    180   }
    181 }
    182 
    183 bool ReplacePort(PP_Instance instance,
    184                  const pp::NetAddress& input_addr,
    185                  uint16_t port,
    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))
    191         return false;
    192       ipv4_addr.port = ConvertToNetEndian16(port);
    193       *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv4_addr);
    194       return true;
    195     }
    196     case PP_NETADDRESS_FAMILY_IPV6: {
    197       PP_NetAddress_IPv6 ipv6_addr;
    198       if (!input_addr.DescribeAsIPv6Address(&ipv6_addr))
    199         return false;
    200       ipv6_addr.port = ConvertToNetEndian16(port);
    201       *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv6_addr);
    202       return true;
    203     }
    204     default: {
    205       return false;
    206     }
    207   }
    208 }
    209 
    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))
    215         return 0;
    216       return ConvertFromNetEndian16(ipv4_addr.port);
    217     }
    218     case PP_NETADDRESS_FAMILY_IPV6: {
    219       PP_NetAddress_IPv6 ipv6_addr;
    220       if (!addr.DescribeAsIPv6Address(&ipv6_addr))
    221         return 0;
    222       return ConvertFromNetEndian16(ipv6_addr.port);
    223     }
    224     default: {
    225       return 0;
    226     }
    227   }
    228 }
    229 
    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_);
    235   if (signalled_)
    236     return;
    237   waiting_ = true;
    238   while (!signalled_)
    239     GetTestingInterface()->RunMessageLoop(instance_);
    240   waiting_ = false;
    241 }
    242 
    243 void NestedEvent::Signal() {
    244   if (pp::Module::Get()->core()->IsMainThread())
    245     SignalOnMainThread();
    246   else
    247     PostSignal(0);
    248 }
    249 
    250 void NestedEvent::PostSignal(int32_t wait_ms) {
    251   pp::Module::Get()->core()->CallOnMainThread(
    252       wait_ms,
    253       pp::CompletionCallback(&SignalThunk, this),
    254       0);
    255 }
    256 
    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_);
    261   signalled_ = false;
    262 }
    263 
    264 void NestedEvent::SignalOnMainThread() {
    265   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
    266   signalled_ = true;
    267   if (waiting_)
    268     GetTestingInterface()->QuitMessageLoop(instance_);
    269 }
    270 
    271 void NestedEvent::SignalThunk(void* event, int32_t /* result */) {
    272   static_cast<NestedEvent*>(event)->SignalOnMainThread();
    273 }
    274 
    275 TestCompletionCallback::TestCompletionCallback(PP_Instance instance)
    276     : wait_for_result_called_(false),
    277       have_result_(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),
    283       instance_(instance),
    284       delegate_(NULL) {
    285 }
    286 
    287 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
    288                                                bool force_async)
    289     : wait_for_result_called_(false),
    290       have_result_(false),
    291       result_(PP_OK_COMPLETIONPENDING),
    292       callback_type_(force_async ? PP_REQUIRED : PP_OPTIONAL),
    293       post_quit_task_(false),
    294       instance_(instance),
    295       delegate_(NULL) {
    296 }
    297 
    298 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
    299                                                CallbackType callback_type)
    300     : wait_for_result_called_(false),
    301       have_result_(false),
    302       result_(PP_OK_COMPLETIONPENDING),
    303       callback_type_(callback_type),
    304       post_quit_task_(false),
    305       instance_(instance),
    306       delegate_(NULL) {
    307 }
    308 
    309 void TestCompletionCallback::WaitForResult(int32_t result) {
    310   PP_DCHECK(!wait_for_result_called_);
    311   wait_for_result_called_ = true;
    312   errors_.clear();
    313   if (result == PP_OK_COMPLETIONPENDING) {
    314     if (!have_result_) {
    315       post_quit_task_ = true;
    316       RunMessageLoop();
    317     }
    318     if (callback_type_ == PP_BLOCKING) {
    319       errors_.assign(
    320           ReportError("TestCompletionCallback: Call did not run synchronously "
    321                       "when passed a blocking completion callback!",
    322                       result_));
    323       return;
    324     }
    325   } else {
    326     result_ = result;
    327     have_result_ = true;
    328     if (callback_type_ == PP_REQUIRED) {
    329       errors_.assign(
    330           ReportError("TestCompletionCallback: Call ran synchronously when "
    331                       "passed a required completion callback!",
    332                       result_));
    333       return;
    334     }
    335   }
    336   PP_DCHECK(have_result_ == true);
    337 }
    338 
    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) {
    344       errors_.assign(
    345           ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
    346                       "PP_OK. Ran asynchronously.",
    347                       final_result));
    348       return;
    349     }
    350   } else if (result < PP_OK) {
    351     errors_.assign(
    352         ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
    353                     "non-error response. Ran synchronously.",
    354                     result));
    355     return;
    356   }
    357 }
    358 
    359 pp::CompletionCallback TestCompletionCallback::GetCallback() {
    360   Reset();
    361   int32_t flags = 0;
    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),
    369                                 flags);
    370 }
    371 
    372 void TestCompletionCallback::Reset() {
    373   wait_for_result_called_ = false;
    374   result_ = PP_OK_COMPLETIONPENDING;
    375   have_result_ = false;
    376   post_quit_task_ = false;
    377   delegate_ = NULL;
    378   errors_.clear();
    379 }
    380 
    381 // static
    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();
    395   }
    396   if (callback->target_loop_ != pp::MessageLoop::GetCurrent()) {
    397     // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
    398     // still be equal.
    399     callback->errors_.assign(
    400         ReportError("TestCompletionCallback: Callback ran on the wrong message "
    401                     "loop!",
    402                     result));
    403   }
    404 }
    405 
    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_);
    412   else
    413     loop.Run();
    414 }
    415 
    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_);
    422   } else {
    423     const bool should_quit = false;
    424     loop.PostQuit(should_quit);
    425   }
    426 }
    427