port_server_unittest.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// found in the LICENSE file.
468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <string>
668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/bind.h"
868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/guid.h"
968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/location.h"
1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/message_loop/message_loop.h"
1168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/sync_socket.h"
1268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/synchronization/waitable_event.h"
1368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/threading/thread.h"
1468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "base/time/time.h"
1568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
1668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "chrome/test/chromedriver/net/port_server.h"
1768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "net/base/sys_addrinfo.h"
1868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
1968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(OS_LINUX)
2168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <fcntl.h>
2268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <sys/socket.h>
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include <sys/un.h>
2468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
2768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void SetOnCall(bool* called) {
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  *called = true;
3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
3368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST(PortReservationTest, Normal) {
3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool called = false;
3668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  {
3768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    PortReservation r(base::Bind(&SetOnCall, &called), 100);
3868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
3968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_TRUE(called);
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
4168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
4268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST(PortReservationTest, Leak) {
4368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool called = false;
4468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  {
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    PortReservation r(base::Bind(&SetOnCall, &called), 100);
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    r.Leak();
4768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
4868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_FALSE(called);
4968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
5168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST(PortReservationTest, MultipleLeaks) {
5268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  bool called = false;
5368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  {
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    PortReservation r(base::Bind(&SetOnCall, &called), 100);
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    r.Leak();
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    r.Leak();
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
5868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_FALSE(called);
5968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
6068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#if defined(OS_LINUX)
6268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)namespace {
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
6468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void RunServerOnThread(const std::string& path,
6568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                       const std::string& response,
6668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                       base::WaitableEvent* listen_event,
6768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                       std::string* request) {
6868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int server_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
6968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_GE(server_sock_fd, 0);
7068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_GE(fcntl(server_sock_fd, F_SETFL, O_NONBLOCK), 0);
7168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::SyncSocket server_sock(server_sock_fd);
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
7368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct sockaddr_un addr;
7468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  memset(&addr, 0, sizeof(addr));
7568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  addr.sun_family = AF_UNIX;
7668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  memcpy(addr.sun_path, &path[0], path.length());
7768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(0,
7868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            bind(server_sock_fd,
7968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 reinterpret_cast<struct sockaddr*>(&addr),
8068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 sizeof(sa_family_t) + path.length()));
8168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(0, listen(server_sock_fd, 1));
8268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  listen_event->Signal();
8368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
8468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  struct sockaddr_un  cli_addr;
8568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  socklen_t clilen = sizeof(cli_addr);
8668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::TimeTicks deadline =
8768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      base::TimeTicks::Now() + base::TimeDelta::FromSeconds(2);
8868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int client_sock_fd = -1;
8968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  while (base::TimeTicks::Now() < deadline && client_sock_fd < 0) {
9068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    client_sock_fd = accept(
9168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        server_sock_fd, reinterpret_cast<struct sockaddr*>(&cli_addr), &clilen);
9268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
9368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_GE(client_sock_fd, 0);
9468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::SyncSocket sock(client_sock_fd);
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  do {
9668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    char c = 0;
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    size_t rv = sock.Receive(&c, 1);
9868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if (!rv)
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      break;
10068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    request->push_back(c);
10168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } while (sock.Peek());
10268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  sock.Send(response.c_str(), response.length());
10368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
10468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
10568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string GenerateRandomPath() {
10668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string path = base::GenerateGUID();
10768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!path.empty()) {
10868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    std::string pre_path;
10968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    pre_path.push_back(0);  // Linux abstract namespace.
11068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    path = pre_path + path;
11168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
11268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return path;
11368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
11468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
11568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}  // namespace
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
11768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)class PortServerTest : public testing::Test {
11868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) public:
11968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  PortServerTest() : thread_("server") {
12068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    EXPECT_TRUE(thread_.Start());
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
12268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  void RunServer(const std::string& path,
12468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 const std::string& response,
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                 std::string* request) {
12668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    base::WaitableEvent listen_event(false, false);
12768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    thread_.message_loop()->PostTask(
12868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        FROM_HERE,
12968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        base::Bind(
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            &RunServerOnThread, path, response, &listen_event, request));
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    ASSERT_TRUE(listen_event.TimedWait(base::TimeDelta::FromSeconds(5)));
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) private:
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  base::Thread thread_;
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(PortServerTest, Reserve) {
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string path = GenerateRandomPath();
14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  PortServer server(path);
14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string request;
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RunServer(path, "12345\n", &request);
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int port = 0;
14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<PortReservation> reservation;
14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Status status = server.ReservePort(&port, &reservation);
14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(kOk, status.code()) << status.message();
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(port, 12345);
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(PortServerTest, ReserveResetReserve) {
15368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string path = GenerateRandomPath();
15468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  PortServer server(path);
15568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string request;
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RunServer(path, "12345\n", &request);
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int port = 0;
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<PortReservation> reservation;
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Status status = server.ReservePort(&port, &reservation);
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(kOk, status.code()) << status.message();
16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(port, 12345);
16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  reservation.reset();
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  status = server.ReservePort(&port, &reservation);
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(kOk, status.code()) << status.message();
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(port, 12345);
16968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
17068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
17168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)TEST_F(PortServerTest, ReserveReserve) {
17268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string path = GenerateRandomPath();
17368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  PortServer server(path);
17468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
17568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string request;
17668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RunServer(path, "12345\n", &request);
17768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
17868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  int port = 0;
17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  scoped_ptr<PortReservation> reservation;
18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  Status status = server.ReservePort(&port, &reservation);
18168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(kOk, status.code()) << status.message();
18268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(port, 12345);
18368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
18468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  RunServer(path, "12346\n", &request);
18568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  status = server.ReservePort(&port, &reservation);
18668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(kOk, status.code()) << status.message();
18768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(port, 12346);
18868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#endif
190