Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: net/test/local_test_server_posix.cc

Issue 14691006: Move SpawnedTestServer to its own subdirectory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sort gyp Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/test/local_test_server.cc ('k') | net/test/local_test_server_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 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/local_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 #include "net/test/python_utils.h"
19
20 namespace {
21
22 // Helper class used to detect and kill orphaned python test server processes.
23 // Checks if the command line of a process contains |path_string| (the path
24 // from which the test server was launched) and |port_string| (the port used by
25 // the test server), and if the parent pid of the process is 1 (indicating that
26 // it is an orphaned process).
27 class OrphanedTestServerFilter : public base::ProcessFilter {
28 public:
29 OrphanedTestServerFilter(
30 const std::string& path_string, const std::string& port_string)
31 : path_string_(path_string),
32 port_string_(port_string) {}
33
34 virtual bool Includes(const base::ProcessEntry& entry) const OVERRIDE {
35 if (entry.parent_pid() != 1)
36 return false;
37 bool found_path_string = false;
38 bool found_port_string = false;
39 for (std::vector<std::string>::const_iterator it =
40 entry.cmd_line_args().begin();
41 it != entry.cmd_line_args().end();
42 ++it) {
43 if (it->find(path_string_) != std::string::npos)
44 found_path_string = true;
45 if (it->find(port_string_) != std::string::npos)
46 found_port_string = true;
47 }
48 return found_path_string && found_port_string;
49 }
50
51 private:
52 std::string path_string_;
53 std::string port_string_;
54 DISALLOW_COPY_AND_ASSIGN(OrphanedTestServerFilter);
55 };
56
57 // Given a file descriptor, reads into |buffer| until |bytes_max|
58 // bytes has been read or an error has been encountered. Returns true
59 // if the read was successful. |remaining_time| is used as a timeout.
60 bool ReadData(int fd, ssize_t bytes_max, uint8* buffer,
61 base::TimeDelta* remaining_time) {
62 ssize_t bytes_read = 0;
63 base::TimeTicks previous_time = base::TimeTicks::Now();
64 while (bytes_read < bytes_max) {
65 struct pollfd poll_fds[1];
66
67 poll_fds[0].fd = fd;
68 poll_fds[0].events = POLLIN | POLLPRI;
69 poll_fds[0].revents = 0;
70
71 int rv = HANDLE_EINTR(poll(poll_fds, 1,
72 remaining_time->InMilliseconds()));
73 if (rv == 0) {
74 LOG(ERROR) << "poll() timed out; bytes_read=" << bytes_read;
75 return false;
76 } else if (rv < 0) {
77 PLOG(ERROR) << "poll() failed for child file descriptor; bytes_read="
78 << bytes_read;
79 return false;
80 }
81
82 base::TimeTicks current_time = base::TimeTicks::Now();
83 base::TimeDelta elapsed_time_cycle = current_time - previous_time;
84 DCHECK_GE(elapsed_time_cycle.InMilliseconds(), 0);
85 *remaining_time -= elapsed_time_cycle;
86 previous_time = current_time;
87
88 ssize_t num_bytes = HANDLE_EINTR(read(fd, buffer + bytes_read,
89 bytes_max - bytes_read));
90 if (num_bytes <= 0)
91 return false;
92 bytes_read += num_bytes;
93 }
94 return true;
95 }
96
97 } // namespace
98
99 namespace net {
100
101 bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) {
102 // Log is useful in the event you want to run a nearby script (e.g. a test) in
103 // the same environment as the TestServer.
104 VLOG(1) << "LaunchPython called with PYTHONPATH = " << getenv(kPythonPathEnv);
105
106 CommandLine python_command(CommandLine::NO_PROGRAM);
107 if (!GetPythonCommand(&python_command))
108 return false;
109
110 python_command.AppendArgPath(testserver_path);
111 if (!AddCommandLineArguments(&python_command))
112 return false;
113
114 int pipefd[2];
115 if (pipe(pipefd) != 0) {
116 PLOG(ERROR) << "Could not create pipe.";
117 return false;
118 }
119
120 // Save the read half. The write half is sent to the child.
121 child_fd_ = pipefd[0];
122 child_fd_closer_.reset(&child_fd_);
123 file_util::ScopedFD write_closer(&pipefd[1]);
124 base::FileHandleMappingVector map_write_fd;
125 map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1]));
126
127 python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1]));
128
129 // Try to kill any orphaned testserver processes that may be running.
130 OrphanedTestServerFilter filter(testserver_path.value(),
131 base::IntToString(GetPort()));
132 if (!base::KillProcesses("python", -1, &filter)) {
133 LOG(WARNING) << "Failed to clean up older orphaned testserver instances.";
134 }
135
136 // Launch a new testserver process.
137 base::LaunchOptions options;
138
139 // TODO(phajdan.jr): Remove after fixing http://crbug.com/96594 .
140 options.debug = true;
141
142 options.fds_to_remap = &map_write_fd;
143 if (!base::LaunchProcess(python_command, options, &process_handle_)) {
144 LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString();
145 return false;
146 }
147
148 return true;
149 }
150
151 bool LocalTestServer::WaitToStart() {
152 file_util::ScopedFD child_fd_closer(child_fd_closer_.release());
153
154 base::TimeDelta remaining_time = TestTimeouts::action_timeout();
155
156 uint32 server_data_len = 0;
157 if (!ReadData(child_fd_, sizeof(server_data_len),
158 reinterpret_cast<uint8*>(&server_data_len),
159 &remaining_time)) {
160 LOG(ERROR) << "Could not read server_data_len";
161 return false;
162 }
163 std::string server_data(server_data_len, '\0');
164 if (!ReadData(child_fd_, server_data_len,
165 reinterpret_cast<uint8*>(&server_data[0]),
166 &remaining_time)) {
167 LOG(ERROR) << "Could not read server_data (" << server_data_len
168 << " bytes)";
169 return false;
170 }
171
172 if (!ParseServerData(server_data)) {
173 LOG(ERROR) << "Could not parse server_data: " << server_data;
174 return false;
175 }
176
177 return true;
178 }
179
180 } // namespace net
OLDNEW
« no previous file with comments | « net/test/local_test_server.cc ('k') | net/test/local_test_server_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698