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_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;
     44 }
     45 
     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: ") +
     50       error_as_string;
     51   return result;
     52 }
     53 
     54 void PlatformSleep(int duration_ms) {
     55 #if defined(_MSC_VER)
     56   ::Sleep(duration_ms);
     57 #else
     58   usleep(duration_ms * 1000);
     59 #endif
     60 }
     61 
     62 bool GetLocalHostPort(PP_Instance instance, std::string* host, uint16_t* port) {
     63   if (!host || !port)
     64     return false;
     65 
     66   const PPB_Testing_Dev* testing = GetTestingInterface();
     67   if (!testing)
     68     return false;
     69 
     70   PP_URLComponents_Dev components;
     71   pp::Var pp_url(pp::PASS_REF,
     72                  testing->GetDocumentURL(instance, &components));
     73   if (!pp_url.is_string())
     74     return false;
     75   std::string url = pp_url.AsString();
     76 
     77   if (components.host.len < 0)
     78     return false;
     79   host->assign(url.substr(components.host.begin, components.host.len));
     80 
     81   if (components.port.len <= 0)
     82     return false;
     83 
     84   int i = atoi(url.substr(components.port.begin, components.port.len).c_str());
     85   if (i < 0 || i > 65535)
     86     return false;
     87   *port = static_cast<uint16_t>(i);
     88 
     89   return true;
     90 }
     91 
     92 uint16_t ConvertFromNetEndian16(uint16_t x) {
     93   if (IsBigEndian())
     94     return x;
     95   else
     96     return (x << 8) | (x >> 8);
     97 }
     98 
     99 uint16_t ConvertToNetEndian16(uint16_t x) {
    100   if (IsBigEndian())
    101     return x;
    102   else
    103     return (x << 8) | (x >> 8);
    104 }
    105 
    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) {
    109     return false;
    110   }
    111 
    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)) {
    116       return false;
    117     }
    118 
    119     return ipv4_addr1.port == ipv4_addr2.port &&
    120            !memcmp(ipv4_addr1.addr, ipv4_addr2.addr, sizeof(ipv4_addr1.addr));
    121   } else {
    122     PP_NetAddress_IPv6 ipv6_addr1, ipv6_addr2;
    123     if (!addr1.DescribeAsIPv6Address(&ipv6_addr1) ||
    124         !addr2.DescribeAsIPv6Address(&ipv6_addr2)) {
    125       return false;
    126     }
    127 
    128     return ipv6_addr1.port == ipv6_addr2.port &&
    129            !memcmp(ipv6_addr1.addr, ipv6_addr2.addr, sizeof(ipv6_addr1.addr));
    130   }
    131 }
    132 
    133 bool ResolveHost(PP_Instance instance,
    134                  const std::string& host,
    135                  uint16_t port,
    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 };
    142 
    143   TestCompletionCallback callback(instance);
    144   callback.WaitForResult(
    145       host_resolver.Resolve(host, port, hint, callback.GetCallback()));
    146 
    147   PP_NetAddress_Private addr_private;
    148   if (callback.result() != PP_OK || host_resolver.GetSize() == 0 ||
    149       !host_resolver.GetNetAddress(0, &addr_private)) {
    150     return false;
    151   }
    152 
    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))) {
    160         return false;
    161       }
    162       *addr = pp::NetAddress(instance_handle, ipv4_addr);
    163       return true;
    164     }
    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))) {
    171         return false;
    172       }
    173       *addr = pp::NetAddress(instance_handle, ipv6_addr);
    174       return true;
    175     }
    176     default: {
    177       return false;
    178     }
    179   }
    180 }
    181 
    182 void NestedEvent::Wait() {
    183   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
    184   // Don't allow nesting more than once; it doesn't work with the code as-is,
    185   // and probably is a bad idea most of the time anyway.
    186   PP_DCHECK(!waiting_);
    187   if (signalled_)
    188     return;
    189   waiting_ = true;
    190   while (!signalled_)
    191     GetTestingInterface()->RunMessageLoop(instance_);
    192   waiting_ = false;
    193 }
    194 
    195 void NestedEvent::Signal() {
    196   if (pp::Module::Get()->core()->IsMainThread())
    197     SignalOnMainThread();
    198   else
    199     PostSignal(0);
    200 }
    201 
    202 void NestedEvent::PostSignal(int32_t wait_ms) {
    203   pp::Module::Get()->core()->CallOnMainThread(
    204       wait_ms,
    205       pp::CompletionCallback(&SignalThunk, this),
    206       0);
    207 }
    208 
    209 void NestedEvent::Reset() {
    210   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
    211   // It doesn't make sense to reset when we're still waiting.
    212   PP_DCHECK(!waiting_);
    213   signalled_ = false;
    214 }
    215 
    216 void NestedEvent::SignalOnMainThread() {
    217   PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
    218   signalled_ = true;
    219   if (waiting_)
    220     GetTestingInterface()->QuitMessageLoop(instance_);
    221 }
    222 
    223 void NestedEvent::SignalThunk(void* event, int32_t /* result */) {
    224   static_cast<NestedEvent*>(event)->SignalOnMainThread();
    225 }
    226 
    227 TestCompletionCallback::TestCompletionCallback(PP_Instance instance)
    228     : wait_for_result_called_(false),
    229       have_result_(false),
    230       result_(PP_OK_COMPLETIONPENDING),
    231       // TODO(dmichael): The default should probably be PP_REQUIRED, but this is
    232       //                 what the tests currently expect.
    233       callback_type_(PP_OPTIONAL),
    234       post_quit_task_(false),
    235       instance_(instance),
    236       delegate_(NULL) {
    237 }
    238 
    239 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
    240                                                bool force_async)
    241     : wait_for_result_called_(false),
    242       have_result_(false),
    243       result_(PP_OK_COMPLETIONPENDING),
    244       callback_type_(force_async ? PP_REQUIRED : PP_OPTIONAL),
    245       post_quit_task_(false),
    246       instance_(instance),
    247       delegate_(NULL) {
    248 }
    249 
    250 TestCompletionCallback::TestCompletionCallback(PP_Instance instance,
    251                                                CallbackType callback_type)
    252     : wait_for_result_called_(false),
    253       have_result_(false),
    254       result_(PP_OK_COMPLETIONPENDING),
    255       callback_type_(callback_type),
    256       post_quit_task_(false),
    257       instance_(instance),
    258       delegate_(NULL) {
    259 }
    260 
    261 void TestCompletionCallback::WaitForResult(int32_t result) {
    262   PP_DCHECK(!wait_for_result_called_);
    263   wait_for_result_called_ = true;
    264   errors_.clear();
    265   if (result == PP_OK_COMPLETIONPENDING) {
    266     if (!have_result_) {
    267       post_quit_task_ = true;
    268       RunMessageLoop();
    269     }
    270     if (callback_type_ == PP_BLOCKING) {
    271       errors_.assign(
    272           ReportError("TestCompletionCallback: Call did not run synchronously "
    273                       "when passed a blocking completion callback!",
    274                       result_));
    275       return;
    276     }
    277   } else {
    278     result_ = result;
    279     have_result_ = true;
    280     if (callback_type_ == PP_REQUIRED) {
    281       errors_.assign(
    282           ReportError("TestCompletionCallback: Call ran synchronously when "
    283                       "passed a required completion callback!",
    284                       result_));
    285       return;
    286     }
    287   }
    288   PP_DCHECK(have_result_ == true);
    289 }
    290 
    291 void TestCompletionCallback::WaitForAbortResult(int32_t result) {
    292   WaitForResult(result);
    293   int32_t final_result = result_;
    294   if (result == PP_OK_COMPLETIONPENDING) {
    295     if (final_result != PP_ERROR_ABORTED) {
    296       errors_.assign(
    297           ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
    298                       "PP_OK. Ran asynchronously.",
    299                       final_result));
    300       return;
    301     }
    302   } else if (result < PP_OK) {
    303     errors_.assign(
    304         ReportError("TestCompletionCallback: Expected PP_ERROR_ABORTED or "
    305                     "non-error response. Ran synchronously.",
    306                     result));
    307     return;
    308   }
    309 }
    310 
    311 pp::CompletionCallback TestCompletionCallback::GetCallback() {
    312   Reset();
    313   int32_t flags = 0;
    314   if (callback_type_ == PP_BLOCKING)
    315     return pp::CompletionCallback();
    316   else if (callback_type_ == PP_OPTIONAL)
    317     flags = PP_COMPLETIONCALLBACK_FLAG_OPTIONAL;
    318   target_loop_ = pp::MessageLoop::GetCurrent();
    319   return pp::CompletionCallback(&TestCompletionCallback::Handler,
    320                                 const_cast<TestCompletionCallback*>(this),
    321                                 flags);
    322 }
    323 
    324 void TestCompletionCallback::Reset() {
    325   wait_for_result_called_ = false;
    326   result_ = PP_OK_COMPLETIONPENDING;
    327   have_result_ = false;
    328   post_quit_task_ = false;
    329   delegate_ = NULL;
    330   errors_.clear();
    331 }
    332 
    333 // static
    334 void TestCompletionCallback::Handler(void* user_data, int32_t result) {
    335   TestCompletionCallback* callback =
    336       static_cast<TestCompletionCallback*>(user_data);
    337   // If this check fails, it means that the callback was invoked twice or that
    338   // the PPAPI call completed synchronously, but also ran the callback.
    339   PP_DCHECK(!callback->have_result_);
    340   callback->result_ = result;
    341   callback->have_result_ = true;
    342   if (callback->delegate_)
    343     callback->delegate_->OnCallback(user_data, result);
    344   if (callback->post_quit_task_) {
    345     callback->post_quit_task_ = false;
    346     callback->QuitMessageLoop();
    347   }
    348   if (callback->target_loop_ != pp::MessageLoop::GetCurrent()) {
    349     // Note, in-process, loop_ and GetCurrent() will both be NULL, so should
    350     // still be equal.
    351     callback->errors_.assign(
    352         ReportError("TestCompletionCallback: Callback ran on the wrong message "
    353                     "loop!",
    354                     result));
    355   }
    356 }
    357 
    358 void TestCompletionCallback::RunMessageLoop() {
    359   pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
    360   // If we don't have a message loop, we're probably running in process, where
    361   // PPB_MessageLoop is not supported. Just use the Testing message loop.
    362   if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread())
    363     GetTestingInterface()->RunMessageLoop(instance_);
    364   else
    365     loop.Run();
    366 }
    367 
    368 void TestCompletionCallback::QuitMessageLoop() {
    369   pp::MessageLoop loop(pp::MessageLoop::GetCurrent());
    370   // If we don't have a message loop, we're probably running in process, where
    371   // PPB_MessageLoop is not supported. Just use the Testing message loop.
    372   if (loop.is_null() || loop == pp::MessageLoop::GetForMainThread()) {
    373     GetTestingInterface()->QuitMessageLoop(instance_);
    374   } else {
    375     const bool should_quit = false;
    376     loop.PostQuit(should_quit);
    377   }
    378 }
    379