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

Side by Side Diff: base/test/launcher/parallel_test_launcher.cc

Issue 55473002: GTTF: Unify parallel test launching. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: reupload Created 7 years, 1 month 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 | « base/test/launcher/parallel_test_launcher.h ('k') | base/test/launcher/test_launcher.h » ('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 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 "base/test/launcher/parallel_test_launcher.h"
6
7 #if defined(OS_POSIX)
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/types.h>
11 #endif
12
13 #if defined(OS_WIN)
14 #include <windows.h>
15 #endif
16
17 #include "base/bind.h"
18 #include "base/command_line.h"
19 #include "base/file_util.h"
20 #include "base/location.h"
21 #include "base/message_loop/message_loop_proxy.h"
22 #include "base/process/launch.h"
23 #include "base/run_loop.h"
24 #include "base/test/launcher/test_launcher.h"
25 #include "base/test/sequenced_worker_pool_owner.h"
26
27 #if defined(OS_WIN)
28 #include "base/win/scoped_handle.h"
29 #endif
30
31 namespace base {
32
33 namespace {
34
35 // Maximum time of no output after which we print list of processes still
36 // running. This deliberately doesn't use TestTimeouts (which is otherwise
37 // a recommended solution), because they can be increased. This would defeat
38 // the purpose of this timeout, which is 1) to avoid buildbot "no output for
39 // X seconds" timeout killing the process 2) help communicate status of
40 // the test launcher to people looking at the output (no output for a long
41 // time is mysterious and gives no info about what is happening) 3) help
42 // debugging in case the process hangs anyway.
43 const int kOutputTimeoutSeconds = 15;
44
45 void RunCallback(
46 const ParallelTestLauncher::LaunchChildGTestProcessCallback& callback,
47 int exit_code,
48 const TimeDelta& elapsed_time,
49 bool was_timeout,
50 const std::string& output) {
51 callback.Run(exit_code, elapsed_time, was_timeout, output);
52 }
53
54 void DoLaunchChildTestProcess(
55 const CommandLine& command_line,
56 base::TimeDelta timeout,
57 scoped_refptr<MessageLoopProxy> message_loop_proxy,
58 const ParallelTestLauncher::LaunchChildGTestProcessCallback& callback) {
59 TimeTicks start_time = TimeTicks::Now();
60
61 // Redirect child process output to a file.
62 base::FilePath output_file;
63 CHECK(file_util::CreateTemporaryFile(&output_file));
64
65 LaunchOptions options;
66 #if defined(OS_WIN)
67 // Make the file handle inheritable by the child.
68 SECURITY_ATTRIBUTES sa_attr;
69 sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
70 sa_attr.lpSecurityDescriptor = NULL;
71 sa_attr.bInheritHandle = TRUE;
72
73 win::ScopedHandle handle(CreateFile(output_file.value().c_str(),
74 GENERIC_WRITE,
75 FILE_SHARE_READ | FILE_SHARE_DELETE,
76 &sa_attr,
77 OPEN_EXISTING,
78 FILE_ATTRIBUTE_TEMPORARY,
79 NULL));
80 CHECK(handle.IsValid());
81 options.inherit_handles = true;
82 options.stdin_handle = INVALID_HANDLE_VALUE;
83 options.stdout_handle = handle.Get();
84 options.stderr_handle = handle.Get();
85 #elif defined(OS_POSIX)
86 options.new_process_group = true;
87
88 int output_file_fd = open(output_file.value().c_str(), O_RDWR);
89 CHECK_GE(output_file_fd, 0);
90
91 file_util::ScopedFD output_file_fd_closer(&output_file_fd);
92
93 base::FileHandleMappingVector fds_mapping;
94 fds_mapping.push_back(std::make_pair(output_file_fd, STDOUT_FILENO));
95 fds_mapping.push_back(std::make_pair(output_file_fd, STDERR_FILENO));
96 options.fds_to_remap = &fds_mapping;
97 #endif
98
99 bool was_timeout = false;
100 int exit_code = LaunchChildTestProcessWithOptions(
101 command_line, options, timeout, &was_timeout);
102
103 #if defined(OS_WIN)
104 FlushFileBuffers(handle.Get());
105 handle.Close();
106 #elif defined(OS_POSIX)
107 output_file_fd_closer.reset();
108 #endif
109
110 std::string output_file_contents;
111 CHECK(base::ReadFileToString(output_file, &output_file_contents));
112
113 if (!base::DeleteFile(output_file, false)) {
114 // This needs to be non-fatal at least for Windows.
115 LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe();
116 }
117
118 // Run target callback on the thread it was originating from, not on
119 // a worker pool thread.
120 message_loop_proxy->PostTask(
121 FROM_HERE,
122 Bind(&RunCallback,
123 callback,
124 exit_code,
125 TimeTicks::Now() - start_time,
126 was_timeout,
127 output_file_contents));
128 }
129
130 } // namespace
131
132 ParallelTestLauncher::ParallelTestLauncher(size_t jobs)
133 : timer_(FROM_HERE,
134 TimeDelta::FromSeconds(kOutputTimeoutSeconds),
135 this,
136 &ParallelTestLauncher::OnOutputTimeout),
137 launch_sequence_number_(0),
138 worker_pool_owner_(
139 new SequencedWorkerPoolOwner(jobs, "parallel_test_launcher")) {
140 // Start the watchdog timer.
141 timer_.Reset();
142 }
143
144 ParallelTestLauncher::~ParallelTestLauncher() {
145 DCHECK(thread_checker_.CalledOnValidThread());
146
147 worker_pool_owner_->pool()->Shutdown();
148 }
149
150 void ParallelTestLauncher::LaunchChildGTestProcess(
151 const CommandLine& command_line,
152 const std::string& wrapper,
153 base::TimeDelta timeout,
154 const LaunchChildGTestProcessCallback& callback) {
155 DCHECK(thread_checker_.CalledOnValidThread());
156
157 // Record the exact command line used to launch the child.
158 CommandLine new_command_line(
159 PrepareCommandLineForGTest(command_line, wrapper));
160 launch_sequence_number_++;
161 running_processes_map_.insert(
162 std::make_pair(launch_sequence_number_, new_command_line));
163
164 worker_pool_owner_->pool()->PostWorkerTask(
165 FROM_HERE,
166 Bind(&DoLaunchChildTestProcess,
167 new_command_line,
168 timeout,
169 MessageLoopProxy::current(),
170 Bind(&ParallelTestLauncher::OnLaunchTestProcessFinished,
171 Unretained(this),
172 launch_sequence_number_,
173 callback)));
174 }
175
176 void ParallelTestLauncher::ResetOutputWatchdog() {
177 DCHECK(thread_checker_.CalledOnValidThread());
178 timer_.Reset();
179 }
180
181 void ParallelTestLauncher::OnLaunchTestProcessFinished(
182 size_t sequence_number,
183 const LaunchChildGTestProcessCallback& callback,
184 int exit_code,
185 const TimeDelta& elapsed_time,
186 bool was_timeout,
187 const std::string& output) {
188 DCHECK(thread_checker_.CalledOnValidThread());
189 running_processes_map_.erase(sequence_number);
190 callback.Run(exit_code, elapsed_time, was_timeout, output);
191 }
192
193 void ParallelTestLauncher::OnOutputTimeout() {
194 DCHECK(thread_checker_.CalledOnValidThread());
195
196 fprintf(stdout, "Still waiting for the following processes to finish:\n");
197
198 for (RunningProcessesMap::const_iterator i = running_processes_map_.begin();
199 i != running_processes_map_.end();
200 ++i) {
201 #if defined(OS_WIN)
202 fwprintf(stdout, L"\t%s\n", i->second.GetCommandLineString().c_str());
203 #else
204 fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str());
205 #endif
206 }
207
208 fflush(stdout);
209
210 // Arm the timer again - otherwise it would fire only once.
211 timer_.Reset();
212 }
213
214 } // namespace base
OLDNEW
« no previous file with comments | « base/test/launcher/parallel_test_launcher.h ('k') | base/test/launcher/test_launcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698