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