OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/public/test/test_launcher.h" | 5 #include "content/public/test/test_launcher.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "base/containers/hash_tables.h" | 11 #include "base/containers/hash_tables.h" |
12 #include "base/environment.h" | 12 #include "base/environment.h" |
13 #include "base/file_util.h" | 13 #include "base/file_util.h" |
14 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
15 #include "base/logging.h" | 15 #include "base/logging.h" |
16 #include "base/memory/linked_ptr.h" | 16 #include "base/memory/linked_ptr.h" |
17 #include "base/memory/scoped_ptr.h" | 17 #include "base/memory/scoped_ptr.h" |
18 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
19 #include "base/stl_util.h" | |
19 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
20 #include "base/strings/string_util.h" | 21 #include "base/strings/string_util.h" |
21 #include "base/strings/utf_string_conversions.h" | 22 #include "base/strings/utf_string_conversions.h" |
23 #include "base/test/parallel_test_launcher.h" | |
22 #include "base/test/test_launcher.h" | 24 #include "base/test/test_launcher.h" |
23 #include "base/test/test_suite.h" | 25 #include "base/test/test_suite.h" |
26 #include "base/test/test_switches.h" | |
24 #include "base/test/test_timeouts.h" | 27 #include "base/test/test_timeouts.h" |
25 #include "base/time/time.h" | 28 #include "base/time/time.h" |
26 #include "content/public/app/content_main.h" | 29 #include "content/public/app/content_main.h" |
27 #include "content/public/app/content_main_delegate.h" | 30 #include "content/public/app/content_main_delegate.h" |
28 #include "content/public/app/startup_helper_win.h" | 31 #include "content/public/app/startup_helper_win.h" |
29 #include "content/public/common/content_switches.h" | 32 #include "content/public/common/content_switches.h" |
30 #include "content/public/common/sandbox_init.h" | 33 #include "content/public/common/sandbox_init.h" |
31 #include "content/public/test/browser_test.h" | 34 #include "content/public/test/browser_test.h" |
32 #include "net/base/escape.h" | 35 #include "net/base/escape.h" |
33 #include "testing/gtest/include/gtest/gtest.h" | 36 #include "testing/gtest/include/gtest/gtest.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
50 // that span browser restarts. | 53 // that span browser restarts. |
51 const char kPreTestPrefix[] = "PRE_"; | 54 const char kPreTestPrefix[] = "PRE_"; |
52 | 55 |
53 // Manual tests only run when --run-manual is specified. This allows writing | 56 // Manual tests only run when --run-manual is specified. This allows writing |
54 // tests that don't run automatically but are still in the same test binary. | 57 // tests that don't run automatically but are still in the same test binary. |
55 // This is useful so that a team that wants to run a few tests doesn't have to | 58 // This is useful so that a team that wants to run a few tests doesn't have to |
56 // add a new binary that must be compiled on all builds. | 59 // add a new binary that must be compiled on all builds. |
57 const char kManualTestPrefix[] = "MANUAL_"; | 60 const char kManualTestPrefix[] = "MANUAL_"; |
58 | 61 |
59 TestLauncherDelegate* g_launcher_delegate; | 62 TestLauncherDelegate* g_launcher_delegate; |
60 } | |
61 | 63 |
62 namespace { | 64 std::string RemoveAnyPrePrefixes(const std::string& test_name) { |
63 | 65 std::string result(test_name); |
64 int DoRunTestInternal(const testing::TestCase* test_case, | 66 ReplaceSubstringsAfterOffset(&result, 0, kPreTestPrefix, std::string()); |
65 const std::string& test_name, | 67 return result; |
66 const CommandLine& command_line, | |
67 base::TimeDelta default_timeout, | |
68 bool* was_timeout) { | |
69 if (test_case) { | |
70 std::string pre_test_name = test_name; | |
71 std::string replace_string = std::string(".") + kPreTestPrefix; | |
72 ReplaceFirstSubstringAfterOffset(&pre_test_name, 0, ".", replace_string); | |
73 for (int i = 0; i < test_case->total_test_count(); ++i) { | |
74 const testing::TestInfo* test_info = test_case->GetTestInfo(i); | |
75 std::string cur_test_name = test_info->test_case_name(); | |
76 cur_test_name.append("."); | |
77 cur_test_name.append(test_info->name()); | |
78 if (cur_test_name == pre_test_name) { | |
79 int exit_code = DoRunTestInternal(test_case, | |
80 pre_test_name, | |
81 command_line, | |
82 default_timeout, | |
83 was_timeout); | |
84 if (exit_code != 0) | |
85 return exit_code; | |
86 } | |
87 } | |
88 } | |
89 | |
90 CommandLine new_cmd_line(command_line.GetProgram()); | |
91 CommandLine::SwitchMap switches = command_line.GetSwitches(); | |
92 | |
93 // Strip out gtest_output flag because otherwise we would overwrite results | |
94 // of the other tests. | |
95 switches.erase(base::kGTestOutputFlag); | |
96 | |
97 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | |
98 iter != switches.end(); ++iter) { | |
99 new_cmd_line.AppendSwitchNative(iter->first, iter->second); | |
100 } | |
101 | |
102 // Always enable disabled tests. This method is not called with disabled | |
103 // tests unless this flag was specified to the browser test executable. | |
104 new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests"); | |
105 new_cmd_line.AppendSwitchASCII("gtest_filter", test_name); | |
106 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag); | |
107 | |
108 char* browser_wrapper = getenv("BROWSER_WRAPPER"); | |
109 int exit_code = base::LaunchChildGTestProcess( | |
110 new_cmd_line, | |
111 browser_wrapper ? browser_wrapper : std::string(), | |
112 default_timeout, | |
113 was_timeout); | |
114 if (*was_timeout) { | |
115 LOG(ERROR) << "Test timeout (" << default_timeout.InMilliseconds() | |
116 << " ms) exceeded for " << test_name; | |
117 } | |
118 | |
119 return exit_code; | |
120 } | |
121 | |
122 // Runs test specified by |test_name| in a child process, | |
123 // and returns the exit code. | |
124 int DoRunTest(TestLauncherDelegate* launcher_delegate, | |
125 const testing::TestCase* test_case, | |
126 const std::string& test_name, | |
127 base::TimeDelta default_timeout, | |
128 bool* was_timeout) { | |
129 if (was_timeout) | |
130 *was_timeout = false; | |
131 | |
132 #if defined(OS_MACOSX) | |
133 // Some of the below method calls will leak objects if there is no | |
134 // autorelease pool in place. | |
135 base::mac::ScopedNSAutoreleasePool pool; | |
136 #endif | |
137 | |
138 base::ScopedTempDir temp_dir; | |
139 // Create a new data dir and pass it to the child. | |
140 if (!temp_dir.CreateUniqueTempDir() || !temp_dir.IsValid()) { | |
141 LOG(ERROR) << "Error creating temp data directory"; | |
142 return -1; | |
143 } | |
144 | |
145 CommandLine new_cmd_line(*CommandLine::ForCurrentProcess()); | |
146 if (!launcher_delegate->AdjustChildProcessCommandLine(&new_cmd_line, | |
147 temp_dir.path())) { | |
148 return -1; | |
149 } | |
150 | |
151 return DoRunTestInternal( | |
152 test_case, test_name, new_cmd_line, default_timeout, was_timeout); | |
153 } | 68 } |
154 | 69 |
155 void PrintUsage() { | 70 void PrintUsage() { |
156 fprintf(stdout, | 71 fprintf(stdout, |
157 "Runs tests using the gtest framework, each test being run in its own\n" | 72 "Runs tests using the gtest framework, each test being run in its own\n" |
158 "process. Any gtest flags can be specified.\n" | 73 "process. Any gtest flags can be specified.\n" |
159 " --single_process\n" | 74 " --single_process\n" |
160 " Runs the tests and the launcher in the same process. Useful for \n" | 75 " Runs the tests and the launcher in the same process. Useful for \n" |
161 " debugging a specific test in a debugger.\n" | 76 " debugging a specific test in a debugger.\n" |
162 " --single-process\n" | 77 " --single-process\n" |
163 " Same as above, and also runs Chrome in single-process mode.\n" | 78 " Same as above, and also runs Chrome in single-process mode.\n" |
164 " --help\n" | 79 " --help\n" |
165 " Shows this message.\n" | 80 " Shows this message.\n" |
166 " --gtest_help\n" | 81 " --gtest_help\n" |
167 " Shows the gtest help message.\n"); | 82 " Shows the gtest help message.\n"); |
168 } | 83 } |
169 | 84 |
170 // Implementation of base::TestLauncherDelegate. This is also a test launcher, | 85 // Implementation of base::TestLauncherDelegate. This is also a test launcher, |
171 // wrapping a lower-level test launcher with content-specific code. | 86 // wrapping a lower-level test launcher with content-specific code. |
172 class WrapperTestLauncherDelegate : public base::TestLauncherDelegate { | 87 class WrapperTestLauncherDelegate : public base::TestLauncherDelegate { |
173 public: | 88 public: |
174 explicit WrapperTestLauncherDelegate( | 89 WrapperTestLauncherDelegate(content::TestLauncherDelegate* launcher_delegate, |
175 content::TestLauncherDelegate* launcher_delegate) | 90 size_t jobs) |
176 : launcher_delegate_(launcher_delegate), | 91 : launcher_delegate_(launcher_delegate), |
177 timeout_count_(0), | 92 timeout_count_(0), |
178 printed_timeout_message_(false) { | 93 printed_timeout_message_(false), |
94 parallel_launcher_(jobs) { | |
95 CHECK(temp_dir_.CreateUniqueTempDir()); | |
179 } | 96 } |
180 | 97 |
181 // base::TestLauncherDelegate: | 98 // base::TestLauncherDelegate: |
99 virtual std::string GetTestNameForFiltering( | |
100 const testing::TestCase* test_case, | |
101 const testing::TestInfo* test_info) OVERRIDE; | |
182 virtual bool ShouldRunTest(const testing::TestCase* test_case, | 102 virtual bool ShouldRunTest(const testing::TestCase* test_case, |
183 const testing::TestInfo* test_info) OVERRIDE; | 103 const testing::TestInfo* test_info) OVERRIDE; |
184 virtual void RunTest( | 104 virtual void RunTest( |
185 const testing::TestCase* test_case, | 105 const testing::TestCase* test_case, |
186 const testing::TestInfo* test_info, | 106 const testing::TestInfo* test_info, |
187 const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE; | 107 const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE; |
188 virtual void RunRemainingTests() OVERRIDE; | 108 virtual void RunRemainingTests() OVERRIDE; |
189 | 109 |
190 private: | 110 private: |
111 struct TestInfo { | |
112 std::string test_case_name; | |
113 std::string test_name; | |
114 base::TestLauncherDelegate::TestResultCallback callback; | |
115 }; | |
116 | |
117 friend bool CompareTestInfo(const TestInfo& a, const TestInfo& b); | |
118 | |
119 // Launches test from |test_info| using |command_line| and parallel launcher. | |
120 void DoRunTest(const TestInfo& test_info, const CommandLine& command_line); | |
121 | |
122 // Callback to receive result of a test. | |
123 void GTestCallback( | |
124 const TestInfo& test_info, | |
125 int exit_code, | |
126 const base::TimeDelta& elapsed_time, | |
127 bool was_timeout, | |
128 const std::string& output); | |
129 | |
191 content::TestLauncherDelegate* launcher_delegate_; | 130 content::TestLauncherDelegate* launcher_delegate_; |
192 | 131 |
193 // Number of times a test timeout occurred. | 132 // Number of times a test timeout occurred. |
194 size_t timeout_count_; | 133 size_t timeout_count_; |
195 | 134 |
196 // True after a message about too many timeouts has been printed, | 135 // True after a message about too many timeouts has been printed, |
197 // to avoid doing it more than once. | 136 // to avoid doing it more than once. |
198 bool printed_timeout_message_; | 137 bool printed_timeout_message_; |
199 | 138 |
139 base::ParallelTestLauncher parallel_launcher_; | |
140 | |
141 // Store all tests to run before running any of them to properly | |
142 // handle PRE_ tests. | |
143 std::vector<TestInfo> tests_to_run_; | |
144 | |
145 // Temporary directory for user data directories. | |
146 base::ScopedTempDir temp_dir_; | |
147 | |
200 DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate); | 148 DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate); |
201 }; | 149 }; |
202 | 150 |
151 std::string WrapperTestLauncherDelegate::GetTestNameForFiltering( | |
152 const testing::TestCase* test_case, | |
153 const testing::TestInfo* test_info) { | |
154 return RemoveAnyPrePrefixes( | |
155 std::string(test_case->name()) + "." + test_info->name()); | |
156 } | |
157 | |
203 bool WrapperTestLauncherDelegate::ShouldRunTest( | 158 bool WrapperTestLauncherDelegate::ShouldRunTest( |
204 const testing::TestCase* test_case, | 159 const testing::TestCase* test_case, |
205 const testing::TestInfo* test_info) { | 160 const testing::TestInfo* test_info) { |
206 std::string test_name = | |
207 std::string(test_case->name()) + "." + test_info->name(); | |
208 | |
209 if (StartsWithASCII(test_info->name(), kPreTestPrefix, true)) | |
210 return false; | |
211 | |
212 if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) && | 161 if (StartsWithASCII(test_info->name(), kManualTestPrefix, true) && |
213 !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) { | 162 !CommandLine::ForCurrentProcess()->HasSwitch(kRunManualTestsFlag)) { |
214 return false; | 163 return false; |
215 } | 164 } |
216 | 165 |
217 // Stop test execution after too many timeouts. | 166 // Stop test execution after too many timeouts. |
218 if (timeout_count_ > 5) { | 167 if (timeout_count_ > 5) { |
219 if (!printed_timeout_message_) { | 168 if (!printed_timeout_message_) { |
220 printed_timeout_message_ = true; | 169 printed_timeout_message_ = true; |
221 printf("Too many timeouts, aborting test\n"); | 170 printf("Too many timeouts, aborting test\n"); |
222 } | 171 } |
223 return false; | 172 return false; |
224 } | 173 } |
225 | 174 |
226 return true; | 175 return true; |
227 } | 176 } |
228 | 177 |
229 void WrapperTestLauncherDelegate::RunTest( | 178 void WrapperTestLauncherDelegate::RunTest( |
230 const testing::TestCase* test_case, | 179 const testing::TestCase* test_case, |
231 const testing::TestInfo* test_info, | 180 const testing::TestInfo* test_info, |
232 const base::TestLauncherDelegate::TestResultCallback& callback) { | 181 const base::TestLauncherDelegate::TestResultCallback& callback) { |
233 base::TimeTicks start_time = base::TimeTicks::Now(); | 182 TestInfo run_test_info; |
234 bool was_timeout = false; | 183 run_test_info.test_case_name = test_case->name(); |
235 std::string test_name = | 184 run_test_info.test_name = test_info->name(); |
236 std::string(test_case->name()) + "." + test_info->name(); | 185 run_test_info.callback = callback; |
237 int exit_code = DoRunTest(launcher_delegate_, | 186 tests_to_run_.push_back(run_test_info); |
238 test_case, | 187 } |
239 test_name, | |
240 TestTimeouts::action_max_timeout(), | |
241 &was_timeout); | |
242 if (was_timeout) | |
243 timeout_count_++; | |
244 | 188 |
189 bool CompareTestInfo(const WrapperTestLauncherDelegate::TestInfo& a, | |
190 const WrapperTestLauncherDelegate::TestInfo& b) { | |
191 if (a.test_case_name == b.test_case_name) { | |
192 // Put PRE_ tests before tests that depend on them (e.g. PRE_Foo before Foo, | |
193 // and PRE_PRE_Foo before PRE_Foo). | |
194 if (std::string(kPreTestPrefix) + a.test_name == b.test_name) | |
loislo
2013/09/26 05:47:33
This comparer doesn't work properly. It doesn't Tr
jam
2013/09/26 21:36:03
Pawel: ping
can this cause PRE tests to run in the
Paweł Hajdan Jr.
2013/09/26 23:32:28
Given this comparator is not StrictWeakOrdering, a
| |
195 return false; | |
196 if (a.test_name == std::string(kPreTestPrefix) + b.test_name) | |
197 return true; | |
198 } | |
199 | |
200 // Otherwise sort by full names, disregarding PRE_ completely so that | |
201 // this can still be Strict Weak Ordering. | |
202 std::string a_full( | |
203 RemoveAnyPrePrefixes(a.test_case_name + "." + a.test_name)); | |
204 std::string b_full( | |
205 RemoveAnyPrePrefixes(b.test_case_name + "." + b.test_name)); | |
206 | |
207 return a_full < b_full; | |
208 } | |
209 | |
210 void WrapperTestLauncherDelegate::RunRemainingTests() { | |
211 std::sort(tests_to_run_.begin(), tests_to_run_.end(), CompareTestInfo); | |
212 | |
213 // PRE_ tests and tests that depend on them must share the same | |
214 // data directory. Using test name as directory name leads to too long | |
215 // names (exceeding UNIX_PATH_MAX, which creates a problem with | |
216 // process_singleton_linux). Create a randomly-named temporary directory | |
217 // and keep track of the names so that PRE_ tests can still re-use them. | |
218 std::map<std::string, base::FilePath> temp_directories; | |
219 | |
220 for (size_t i = 0; i < tests_to_run_.size(); i++) { | |
221 TestInfo test_info(tests_to_run_[i]); | |
222 | |
223 // Make sure PRE_ tests and tests that depend on them share the same | |
224 // data directory - based it on the test name without prefixes. | |
225 std::string test_name_no_pre = RemoveAnyPrePrefixes( | |
226 test_info.test_case_name + "." + test_info.test_name); | |
227 if (!ContainsKey(temp_directories, test_name_no_pre)) { | |
228 base::FilePath temp_dir; | |
229 CHECK(file_util::CreateTemporaryDirInDir( | |
230 temp_dir_.path(), FILE_PATH_LITERAL("d"), &temp_dir)); | |
231 temp_directories[test_name_no_pre] = temp_dir; | |
232 } | |
233 | |
234 CommandLine new_cmd_line(*CommandLine::ForCurrentProcess()); | |
235 CHECK(launcher_delegate_->AdjustChildProcessCommandLine( | |
236 &new_cmd_line, temp_directories[test_name_no_pre])); | |
237 | |
238 DoRunTest(test_info, new_cmd_line); | |
239 } | |
240 } | |
241 | |
242 void WrapperTestLauncherDelegate::DoRunTest(const TestInfo& test_info, | |
243 const CommandLine& command_line) { | |
244 CommandLine new_cmd_line(command_line.GetProgram()); | |
245 CommandLine::SwitchMap switches = command_line.GetSwitches(); | |
246 | |
247 // Strip out gtest_output flag because otherwise we would overwrite results | |
248 // of the other tests. | |
249 switches.erase(base::kGTestOutputFlag); | |
250 | |
251 for (CommandLine::SwitchMap::const_iterator iter = switches.begin(); | |
252 iter != switches.end(); ++iter) { | |
253 new_cmd_line.AppendSwitchNative(iter->first, iter->second); | |
254 } | |
255 | |
256 // Always enable disabled tests. This method is not called with disabled | |
257 // tests unless this flag was specified to the browser test executable. | |
258 new_cmd_line.AppendSwitch("gtest_also_run_disabled_tests"); | |
259 new_cmd_line.AppendSwitchASCII( | |
260 "gtest_filter", | |
261 test_info.test_case_name + "." + test_info.test_name); | |
262 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag); | |
263 | |
264 char* browser_wrapper = getenv("BROWSER_WRAPPER"); | |
265 | |
266 // PRE_ tests and tests that depend on them should share the sequence token | |
267 // name, so that they are run serially. | |
268 std::string test_name_no_pre = RemoveAnyPrePrefixes( | |
269 test_info.test_case_name + "." + test_info.test_name); | |
270 | |
271 parallel_launcher_.LaunchNamedSequencedChildGTestProcess( | |
272 test_name_no_pre, | |
273 new_cmd_line, | |
274 browser_wrapper ? browser_wrapper : std::string(), | |
275 TestTimeouts::action_max_timeout(), | |
276 base::Bind(&WrapperTestLauncherDelegate::GTestCallback, | |
277 base::Unretained(this), | |
278 test_info)); | |
279 } | |
280 | |
281 void WrapperTestLauncherDelegate::GTestCallback( | |
282 const TestInfo& test_info, | |
283 int exit_code, | |
284 const base::TimeDelta& elapsed_time, | |
285 bool was_timeout, | |
286 const std::string& output) { | |
245 base::TestResult result; | 287 base::TestResult result; |
246 result.test_case_name = test_case->name(); | 288 result.test_case_name = test_info.test_case_name; |
247 result.test_name = test_info->name(); | 289 result.test_name = test_info.test_name; |
248 | 290 |
249 // TODO(phajdan.jr): Recognize crashes. | 291 // TODO(phajdan.jr): Recognize crashes. |
250 if (exit_code == 0) | 292 if (exit_code == 0) |
251 result.status = base::TestResult::TEST_SUCCESS; | 293 result.status = base::TestResult::TEST_SUCCESS; |
252 else if (was_timeout) | 294 else if (was_timeout) |
253 result.status = base::TestResult::TEST_TIMEOUT; | 295 result.status = base::TestResult::TEST_TIMEOUT; |
254 else | 296 else |
255 result.status = base::TestResult::TEST_FAILURE; | 297 result.status = base::TestResult::TEST_FAILURE; |
256 | 298 |
257 result.elapsed_time = (base::TimeTicks::Now() - start_time); | 299 result.elapsed_time = elapsed_time; |
258 | 300 |
259 callback.Run(result); | 301 // TODO(phajdan.jr): Use base::PrintTestOutputSnippetOnFailure after migrating |
302 // away from run_test_cases.py (http://crbug.com/236893). | |
303 fprintf(stdout, "%s", output.c_str()); | |
304 fflush(stdout); | |
305 | |
306 test_info.callback.Run(result); | |
307 parallel_launcher_.ResetOutputWatchdog(); | |
260 } | 308 } |
261 | 309 |
262 void WrapperTestLauncherDelegate::RunRemainingTests() { | 310 bool GetSwitchValueAsInt(const std::string& switch_name, int* result) { |
263 // No need to do anything else here, we launch tests synchronously. | 311 if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) |
312 return true; | |
313 | |
314 std::string switch_value = | |
315 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name); | |
316 if (!base::StringToInt(switch_value, result) || *result < 1) { | |
317 LOG(ERROR) << "Invalid value for " << switch_name << ": " << switch_value; | |
318 return false; | |
319 } | |
320 | |
321 return true; | |
264 } | 322 } |
265 | 323 |
266 } // namespace | 324 } // namespace |
267 | 325 |
268 // The following is kept for historical reasons (so people that are used to | 326 // The following is kept for historical reasons (so people that are used to |
269 // using it don't get surprised). | 327 // using it don't get surprised). |
270 const char kChildProcessFlag[] = "child"; | 328 const char kChildProcessFlag[] = "child"; |
271 | 329 |
272 const char kHelpFlag[] = "help"; | 330 const char kHelpFlag[] = "help"; |
273 | 331 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
350 "For debugging a test inside a debugger, use the\n" | 408 "For debugging a test inside a debugger, use the\n" |
351 "--gtest_filter=<your_test_name> flag along with either\n" | 409 "--gtest_filter=<your_test_name> flag along with either\n" |
352 "--single_process (to run the test in one launcher/browser process) or\n" | 410 "--single_process (to run the test in one launcher/browser process) or\n" |
353 "--single-process (to do the above, and also run Chrome in single-" | 411 "--single-process (to do the above, and also run Chrome in single-" |
354 "process mode).\n"); | 412 "process mode).\n"); |
355 | 413 |
356 base::AtExitManager at_exit; | 414 base::AtExitManager at_exit; |
357 testing::InitGoogleTest(&argc, argv); | 415 testing::InitGoogleTest(&argc, argv); |
358 TestTimeouts::Initialize(); | 416 TestTimeouts::Initialize(); |
359 | 417 |
418 int jobs = 1; // TODO(phajdan.jr): Default to half the number of CPU cores. | |
419 if (!GetSwitchValueAsInt(switches::kTestLauncherJobs, &jobs)) | |
420 return 1; | |
421 | |
360 base::MessageLoopForIO message_loop; | 422 base::MessageLoopForIO message_loop; |
361 | 423 |
362 WrapperTestLauncherDelegate delegate(launcher_delegate); | 424 WrapperTestLauncherDelegate delegate(launcher_delegate, jobs); |
363 return base::LaunchTests(&delegate, argc, argv); | 425 return base::LaunchTests(&delegate, argc, argv); |
364 } | 426 } |
365 | 427 |
366 TestLauncherDelegate* GetCurrentTestLauncherDelegate() { | 428 TestLauncherDelegate* GetCurrentTestLauncherDelegate() { |
367 return g_launcher_delegate; | 429 return g_launcher_delegate; |
368 } | 430 } |
369 | 431 |
370 } // namespace content | 432 } // namespace content |
OLD | NEW |