• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SetOnCall(bool * called)28 void SetOnCall(bool* called) {
29   *called = true;
30 }
31 
32 }  // namespace
33 
TEST(PortReservationTest,Normal)34 TEST(PortReservationTest, Normal) {
35   bool called = false;
36   {
37     PortReservation r(base::Bind(&SetOnCall, &called), 100);
38   }
39   ASSERT_TRUE(called);
40 }
41 
TEST(PortReservationTest,Leak)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 
TEST(PortReservationTest,MultipleLeaks)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 
RunServerOnThread(const std::string & path,const std::string & response,base::WaitableEvent * listen_event,std::string * request)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 
GenerateRandomPath()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:
PortServerTest()119   PortServerTest() : thread_("server") {
120     EXPECT_TRUE(thread_.Start());
121   }
122 
RunServer(const std::string & path,const std::string & response,std::string * request)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 
TEST_F(PortServerTest,Reserve)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 
TEST_F(PortServerTest,ReserveResetReserve)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 
TEST_F(PortServerTest,ReserveReserve)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 
TEST(PortManagerTest,ReservePort)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 
TEST(PortManagerTest,ReservePortFromPool)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