Home | History | Annotate | Download | only in net
      1 // Copyright (c) 2013 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 <string>
      6 
      7 #include "base/bind.h"
      8 #include "base/guid.h"
      9 #include "base/location.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/sync_socket.h"
     12 #include "base/synchronization/waitable_event.h"
     13 #include "base/threading/thread.h"
     14 #include "base/time/time.h"
     15 #include "chrome/test/chromedriver/chrome/status.h"
     16 #include "chrome/test/chromedriver/net/port_server.h"
     17 #include "net/base/sys_addrinfo.h"
     18 #include "testing/gtest/include/gtest/gtest.h"
     19 
     20 #if defined(OS_LINUX)
     21 #include <fcntl.h>
     22 #include <sys/socket.h>
     23 #include <sys/un.h>
     24 #endif
     25 
     26 namespace {
     27 
     28 void SetOnCall(bool* called) {
     29   *called = true;
     30 }
     31 
     32 }  // namespace
     33 
     34 TEST(PortReservationTest, Normal) {
     35   bool called = false;
     36   {
     37     PortReservation r(base::Bind(&SetOnCall, &called), 100);
     38   }
     39   ASSERT_TRUE(called);
     40 }
     41 
     42 TEST(PortReservationTest, Leak) {
     43   bool called = false;
     44   {
     45     PortReservation r(base::Bind(&SetOnCall, &called), 100);
     46     r.Leak();
     47   }
     48   ASSERT_FALSE(called);
     49 }
     50 
     51 TEST(PortReservationTest, MultipleLeaks) {
     52   bool called = false;
     53   {
     54     PortReservation r(base::Bind(&SetOnCall, &called), 100);
     55     r.Leak();
     56     r.Leak();
     57   }
     58   ASSERT_FALSE(called);
     59 }
     60 
     61 #if defined(OS_LINUX)
     62 namespace {
     63 
     64 void RunServerOnThread(const std::string& path,
     65                        const std::string& response,
     66                        base::WaitableEvent* listen_event,
     67                        std::string* request) {
     68   int server_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
     69   ASSERT_GE(server_sock_fd, 0);
     70   ASSERT_GE(fcntl(server_sock_fd, F_SETFL, O_NONBLOCK), 0);
     71   base::SyncSocket server_sock(server_sock_fd);
     72 
     73   struct sockaddr_un addr;
     74   memset(&addr, 0, sizeof(addr));
     75   addr.sun_family = AF_UNIX;
     76   memcpy(addr.sun_path, &path[0], path.length());
     77   ASSERT_EQ(0,
     78             bind(server_sock_fd,
     79                  reinterpret_cast<struct sockaddr*>(&addr),
     80                  sizeof(sa_family_t) + path.length()));
     81   ASSERT_EQ(0, listen(server_sock_fd, 1));
     82   listen_event->Signal();
     83 
     84   struct sockaddr_un  cli_addr;
     85   socklen_t clilen = sizeof(cli_addr);
     86   base::TimeTicks deadline =
     87       base::TimeTicks::Now() + base::TimeDelta::FromSeconds(2);
     88   int client_sock_fd = -1;
     89   while (base::TimeTicks::Now() < deadline && client_sock_fd < 0) {
     90     client_sock_fd = accept(
     91         server_sock_fd, reinterpret_cast<struct sockaddr*>(&cli_addr), &clilen);
     92   }
     93   ASSERT_GE(client_sock_fd, 0);
     94   base::SyncSocket sock(client_sock_fd);
     95   do {
     96     char c = 0;
     97     size_t rv = sock.Receive(&c, 1);
     98     if (!rv)
     99       break;
    100     request->push_back(c);
    101   } while (sock.Peek());
    102   sock.Send(response.c_str(), response.length());
    103 }
    104 
    105 std::string GenerateRandomPath() {
    106   std::string path = base::GenerateGUID();
    107   if (!path.empty()) {
    108     std::string pre_path;
    109     pre_path.push_back(0);  // Linux abstract namespace.
    110     path = pre_path + path;
    111   }
    112   return path;
    113 }
    114 
    115 }  // namespace
    116 
    117 class PortServerTest : public testing::Test {
    118  public:
    119   PortServerTest() : thread_("server") {
    120     EXPECT_TRUE(thread_.Start());
    121   }
    122 
    123   void RunServer(const std::string& path,
    124                  const std::string& response,
    125                  std::string* request) {
    126     base::WaitableEvent listen_event(false, false);
    127     thread_.message_loop()->PostTask(
    128         FROM_HERE,
    129         base::Bind(
    130             &RunServerOnThread, path, response, &listen_event, request));
    131     ASSERT_TRUE(listen_event.TimedWait(base::TimeDelta::FromSeconds(5)));
    132   }
    133 
    134  private:
    135   base::Thread thread_;
    136 };
    137 
    138 TEST_F(PortServerTest, Reserve) {
    139   std::string path = GenerateRandomPath();
    140   PortServer server(path);
    141 
    142   std::string request;
    143   RunServer(path, "12345\n", &request);
    144 
    145   int port = 0;
    146   scoped_ptr<PortReservation> reservation;
    147   Status status = server.ReservePort(&port, &reservation);
    148   ASSERT_EQ(kOk, status.code()) << status.message();
    149   ASSERT_EQ(port, 12345);
    150 }
    151 
    152 TEST_F(PortServerTest, ReserveResetReserve) {
    153   std::string path = GenerateRandomPath();
    154   PortServer server(path);
    155 
    156   std::string request;
    157   RunServer(path, "12345\n", &request);
    158 
    159   int port = 0;
    160   scoped_ptr<PortReservation> reservation;
    161   Status status = server.ReservePort(&port, &reservation);
    162   ASSERT_EQ(kOk, status.code()) << status.message();
    163   ASSERT_EQ(port, 12345);
    164 
    165   reservation.reset();
    166   status = server.ReservePort(&port, &reservation);
    167   ASSERT_EQ(kOk, status.code()) << status.message();
    168   ASSERT_EQ(port, 12345);
    169 }
    170 
    171 TEST_F(PortServerTest, ReserveReserve) {
    172   std::string path = GenerateRandomPath();
    173   PortServer server(path);
    174 
    175   std::string request;
    176   RunServer(path, "12345\n", &request);
    177 
    178   int port = 0;
    179   scoped_ptr<PortReservation> reservation;
    180   Status status = server.ReservePort(&port, &reservation);
    181   ASSERT_EQ(kOk, status.code()) << status.message();
    182   ASSERT_EQ(port, 12345);
    183 
    184   RunServer(path, "12346\n", &request);
    185   status = server.ReservePort(&port, &reservation);
    186   ASSERT_EQ(kOk, status.code()) << status.message();
    187   ASSERT_EQ(port, 12346);
    188 }
    189 #endif
    190 
    191 TEST(PortManagerTest, ReservePort) {
    192   PortManager mgr(15000, 16000);
    193   int port = 0;
    194   scoped_ptr<PortReservation> reservation;
    195   Status status = mgr.ReservePort(&port, &reservation);
    196   ASSERT_EQ(kOk, status.code()) << status.message();
    197 
    198   ASSERT_GE(port, 15000);
    199   ASSERT_LE(port, 16000);
    200   ASSERT_TRUE(reservation);
    201 }
    202 
    203 TEST(PortManagerTest, ReservePortFromPool) {
    204   PortManager mgr(15000, 16000);
    205   int first_port = 0, port = 1;
    206   for (int i = 0; i < 10; i++) {
    207     scoped_ptr<PortReservation> reservation;
    208     Status status = mgr.ReservePortFromPool(&port, &reservation);
    209     ASSERT_EQ(kOk, status.code()) << status.message();
    210     ASSERT_TRUE(reservation);
    211     ASSERT_GE(port, 15000);
    212     ASSERT_LE(port, 16000);
    213     if (i == 0)
    214       first_port = port;
    215     ASSERT_EQ(port, first_port);
    216   }
    217 }
    218