Home | History | Annotate | Download | only in test
      1 // Copyright (c) 2010 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 "net/test/test_server.h"
      6 
      7 #include <poll.h>
      8 
      9 #include <vector>
     10 
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/logging.h"
     14 #include "base/process_util.h"
     15 #include "base/string_number_conversions.h"
     16 #include "base/string_util.h"
     17 #include "base/test/test_timeouts.h"
     18 
     19 namespace {
     20 
     21 // Helper class used to detect and kill orphaned python test server processes.
     22 // Checks if the command line of a process contains |path_string| (the path
     23 // from which the test server was launched) and |port_string| (the port used by
     24 // the test server), and if the parent pid of the process is 1 (indicating that
     25 // it is an orphaned process).
     26 class OrphanedTestServerFilter : public base::ProcessFilter {
     27  public:
     28   OrphanedTestServerFilter(
     29       const std::string& path_string, const std::string& port_string)
     30       : path_string_(path_string),
     31         port_string_(port_string) {}
     32 
     33   virtual bool Includes(const base::ProcessEntry& entry) const {
     34     if (entry.parent_pid() != 1)
     35       return false;
     36     bool found_path_string = false;
     37     bool found_port_string = false;
     38     for (std::vector<std::string>::const_iterator it =
     39          entry.cmd_line_args().begin();
     40          it != entry.cmd_line_args().end();
     41          ++it) {
     42       if (it->find(path_string_) != std::string::npos)
     43         found_path_string = true;
     44       if (it->find(port_string_) != std::string::npos)
     45         found_port_string = true;
     46     }
     47     return found_path_string && found_port_string;
     48   }
     49 
     50  private:
     51   std::string path_string_;
     52   std::string port_string_;
     53   DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
     54 };
     55 
     56 // Given a file descriptor, reads into |buffer| until |bytes_max|
     57 // bytes has been read or an error has been encountered.  Returns true
     58 // if the read was successful.  |remaining_time| is used as a timeout.
     59 bool ReadData(int fd, ssize_t bytes_max, uint8* buffer,
     60               base::TimeDelta* remaining_time) {
     61   ssize_t bytes_read = 0;
     62   base::Time previous_time = base::Time::Now();
     63   while (bytes_read < bytes_max) {
     64     struct pollfd poll_fds[1];
     65 
     66     poll_fds[0].fd = fd;
     67     poll_fds[0].events = POLLIN | POLLPRI;
     68     poll_fds[0].revents = 0;
     69 
     70     int rv = HANDLE_EINTR(poll(poll_fds, 1,
     71                                remaining_time->InMilliseconds()));
     72     if (rv != 1) {
     73       LOG(ERROR) << "Failed to poll for the child file descriptor.";
     74       return false;
     75     }
     76 
     77     base::Time current_time = base::Time::Now();
     78     base::TimeDelta elapsed_time_cycle = current_time - previous_time;
     79     DCHECK(elapsed_time_cycle.InMilliseconds() >= 0);
     80     *remaining_time -= elapsed_time_cycle;
     81     previous_time = current_time;
     82 
     83     ssize_t num_bytes = HANDLE_EINTR(read(fd, buffer + bytes_read,
     84                                           bytes_max - bytes_read));
     85     if (num_bytes <= 0)
     86       return false;
     87     bytes_read += num_bytes;
     88   }
     89   return true;
     90 }
     91 
     92 }  // namespace
     93 
     94 namespace net {
     95 
     96 bool TestServer::LaunchPython(const FilePath& testserver_path) {
     97   CommandLine python_command(FilePath(FILE_PATH_LITERAL("python")));
     98   python_command.AppendArgPath(testserver_path);
     99   if (!AddCommandLineArguments(&python_command))
    100     return false;
    101 
    102   int pipefd[2];
    103   if (pipe(pipefd) != 0) {
    104     PLOG(ERROR) << "Could not create pipe.";
    105     return false;
    106   }
    107 
    108   // Save the read half. The write half is sent to the child.
    109   child_fd_ = pipefd[0];
    110   child_fd_closer_.reset(&child_fd_);
    111   file_util::ScopedFD write_closer(&pipefd[1]);
    112   base::file_handle_mapping_vector map_write_fd;
    113   map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1]));
    114 
    115   python_command.AppendSwitchASCII("startup-pipe",
    116                                    base::IntToString(pipefd[1]));
    117 
    118   // Try to kill any orphaned testserver processes that may be running.
    119   OrphanedTestServerFilter filter(testserver_path.value(),
    120                                   base::IntToString(host_port_pair_.port()));
    121   if (!base::KillProcesses("python", -1, &filter)) {
    122     LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
    123   }
    124 
    125   // Launch a new testserver process.
    126   if (!base::LaunchApp(python_command.argv(), map_write_fd, false,
    127                        &process_handle_)) {
    128     LOG(ERROR) << "Failed to launch " << python_command.command_line_string()
    129                << " ...";
    130     return false;
    131   }
    132 
    133   return true;
    134 }
    135 
    136 bool TestServer::WaitToStart() {
    137   file_util::ScopedFD child_fd_closer(child_fd_closer_.release());
    138 
    139   base::TimeDelta remaining_time = base::TimeDelta::FromMilliseconds(
    140       TestTimeouts::action_max_timeout_ms());
    141 
    142   uint32 server_data_len = 0;
    143   if (!ReadData(child_fd_, sizeof(server_data_len),
    144                 reinterpret_cast<uint8*>(&server_data_len),
    145                 &remaining_time)) {
    146     LOG(ERROR) << "Could not read server_data_len";
    147     return false;
    148   }
    149   std::string server_data(server_data_len, '\0');
    150   if (!ReadData(child_fd_, server_data_len,
    151                 reinterpret_cast<uint8*>(&server_data[0]),
    152                 &remaining_time)) {
    153     LOG(ERROR) << "Could not read server_data (" << server_data_len
    154                << " bytes)";
    155     return false;
    156   }
    157 
    158   if (!ParseServerData(server_data)) {
    159     LOG(ERROR) << "Could not parse server_data: " << server_data;
    160     return false;
    161   }
    162 
    163   return true;
    164 }
    165 
    166 }  // namespace net
    167