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 <map> |
7 #include <string> | 8 #include <string> |
8 #include <vector> | 9 #include <vector> |
9 | 10 |
10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
11 #include "base/containers/hash_tables.h" | 12 #include "base/containers/hash_tables.h" |
12 #include "base/environment.h" | 13 #include "base/environment.h" |
13 #include "base/file_util.h" | 14 #include "base/file_util.h" |
14 #include "base/files/scoped_temp_dir.h" | 15 #include "base/files/scoped_temp_dir.h" |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/memory/linked_ptr.h" | 17 #include "base/memory/linked_ptr.h" |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 virtual bool ShouldRunTest(const testing::TestCase* test_case, | 103 virtual bool ShouldRunTest(const testing::TestCase* test_case, |
103 const testing::TestInfo* test_info) OVERRIDE; | 104 const testing::TestInfo* test_info) OVERRIDE; |
104 virtual void RunTest( | 105 virtual void RunTest( |
105 const testing::TestCase* test_case, | 106 const testing::TestCase* test_case, |
106 const testing::TestInfo* test_info, | 107 const testing::TestInfo* test_info, |
107 const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE; | 108 const base::TestLauncherDelegate::TestResultCallback& callback) OVERRIDE; |
108 virtual void RunRemainingTests() OVERRIDE; | 109 virtual void RunRemainingTests() OVERRIDE; |
109 | 110 |
110 private: | 111 private: |
111 struct TestInfo { | 112 struct TestInfo { |
| 113 std::string GetFullName() const { return test_case_name + "." + test_name; } |
| 114 |
112 std::string test_case_name; | 115 std::string test_case_name; |
113 std::string test_name; | 116 std::string test_name; |
114 base::TestLauncherDelegate::TestResultCallback callback; | 117 std::vector<base::TestLauncherDelegate::TestResultCallback> callbacks; |
115 }; | 118 }; |
116 | 119 |
117 friend bool CompareTestInfo(const TestInfo& a, const TestInfo& b); | |
118 | |
119 // Launches test from |test_info| using |command_line| and parallel launcher. | 120 // Launches test from |test_info| using |command_line| and parallel launcher. |
120 void DoRunTest(const TestInfo& test_info, const CommandLine& command_line); | 121 void DoRunTest(const TestInfo& test_info, const CommandLine& command_line); |
121 | 122 |
| 123 // Launches test named |test_name| using |command_line| and parallel launcher, |
| 124 // given result of PRE_ test |pre_test_result|. |
| 125 void RunDependentTest(const std::string test_name, |
| 126 const CommandLine& command_line, |
| 127 const base::TestResult& pre_test_result); |
| 128 |
122 // Callback to receive result of a test. | 129 // Callback to receive result of a test. |
123 void GTestCallback( | 130 void GTestCallback( |
124 const TestInfo& test_info, | 131 const TestInfo& test_info, |
125 int exit_code, | 132 int exit_code, |
126 const base::TimeDelta& elapsed_time, | 133 const base::TimeDelta& elapsed_time, |
127 bool was_timeout, | 134 bool was_timeout, |
128 const std::string& output); | 135 const std::string& output); |
129 | 136 |
130 content::TestLauncherDelegate* launcher_delegate_; | 137 content::TestLauncherDelegate* launcher_delegate_; |
131 | 138 |
132 // Number of times a test timeout occurred. | 139 // Number of times a test timeout occurred. |
133 size_t timeout_count_; | 140 size_t timeout_count_; |
134 | 141 |
135 // True after a message about too many timeouts has been printed, | 142 // True after a message about too many timeouts has been printed, |
136 // to avoid doing it more than once. | 143 // to avoid doing it more than once. |
137 bool printed_timeout_message_; | 144 bool printed_timeout_message_; |
138 | 145 |
139 base::ParallelTestLauncher parallel_launcher_; | 146 base::ParallelTestLauncher parallel_launcher_; |
140 | 147 |
141 // Store all tests to run before running any of them to properly | 148 // Store all tests to run before running any of them to properly |
142 // handle PRE_ tests. | 149 // handle PRE_ tests. The map is indexed by test full name (e.g. "A.B"). |
143 std::vector<TestInfo> tests_to_run_; | 150 typedef std::map<std::string, TestInfo> TestInfoMap; |
| 151 TestInfoMap tests_to_run_; |
144 | 152 |
145 // Temporary directory for user data directories. | 153 // Temporary directory for user data directories. |
146 base::ScopedTempDir temp_dir_; | 154 base::ScopedTempDir temp_dir_; |
147 | 155 |
148 DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate); | 156 DISALLOW_COPY_AND_ASSIGN(WrapperTestLauncherDelegate); |
149 }; | 157 }; |
150 | 158 |
151 std::string WrapperTestLauncherDelegate::GetTestNameForFiltering( | 159 std::string WrapperTestLauncherDelegate::GetTestNameForFiltering( |
152 const testing::TestCase* test_case, | 160 const testing::TestCase* test_case, |
153 const testing::TestInfo* test_info) { | 161 const testing::TestInfo* test_info) { |
(...skipping 21 matching lines...) Expand all Loading... |
175 return true; | 183 return true; |
176 } | 184 } |
177 | 185 |
178 void WrapperTestLauncherDelegate::RunTest( | 186 void WrapperTestLauncherDelegate::RunTest( |
179 const testing::TestCase* test_case, | 187 const testing::TestCase* test_case, |
180 const testing::TestInfo* test_info, | 188 const testing::TestInfo* test_info, |
181 const base::TestLauncherDelegate::TestResultCallback& callback) { | 189 const base::TestLauncherDelegate::TestResultCallback& callback) { |
182 TestInfo run_test_info; | 190 TestInfo run_test_info; |
183 run_test_info.test_case_name = test_case->name(); | 191 run_test_info.test_case_name = test_case->name(); |
184 run_test_info.test_name = test_info->name(); | 192 run_test_info.test_name = test_info->name(); |
185 run_test_info.callback = callback; | 193 run_test_info.callbacks.push_back(callback); |
186 tests_to_run_.push_back(run_test_info); | |
187 } | |
188 | 194 |
189 bool CompareTestInfo(const WrapperTestLauncherDelegate::TestInfo& a, | 195 DCHECK(!ContainsKey(tests_to_run_, run_test_info.GetFullName())); |
190 const WrapperTestLauncherDelegate::TestInfo& b) { | 196 tests_to_run_[run_test_info.GetFullName()] = run_test_info; |
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) | |
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 } | 197 } |
209 | 198 |
210 void WrapperTestLauncherDelegate::RunRemainingTests() { | 199 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 | 200 // 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 | 201 // data directory. Using test name as directory name leads to too long |
215 // names (exceeding UNIX_PATH_MAX, which creates a problem with | 202 // names (exceeding UNIX_PATH_MAX, which creates a problem with |
216 // process_singleton_linux). Create a randomly-named temporary directory | 203 // 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. | 204 // and keep track of the names so that PRE_ tests can still re-use them. |
218 std::map<std::string, base::FilePath> temp_directories; | 205 std::map<std::string, base::FilePath> temp_directories; |
219 | 206 |
220 for (size_t i = 0; i < tests_to_run_.size(); i++) { | 207 // List of tests we can kick off right now, depending on no other tests. |
221 TestInfo test_info(tests_to_run_[i]); | 208 std::vector<std::pair<std::string, CommandLine> > tests_to_run_now; |
| 209 |
| 210 for (TestInfoMap::iterator i = tests_to_run_.begin(); |
| 211 i != tests_to_run_.end(); |
| 212 ++i) { |
| 213 const TestInfo& test_info = i->second; |
222 | 214 |
223 // Make sure PRE_ tests and tests that depend on them share the same | 215 // Make sure PRE_ tests and tests that depend on them share the same |
224 // data directory - based it on the test name without prefixes. | 216 // data directory - based it on the test name without prefixes. |
225 std::string test_name_no_pre = RemoveAnyPrePrefixes( | 217 std::string test_name_no_pre(RemoveAnyPrePrefixes(test_info.GetFullName())); |
226 test_info.test_case_name + "." + test_info.test_name); | |
227 if (!ContainsKey(temp_directories, test_name_no_pre)) { | 218 if (!ContainsKey(temp_directories, test_name_no_pre)) { |
228 base::FilePath temp_dir; | 219 base::FilePath temp_dir; |
229 CHECK(file_util::CreateTemporaryDirInDir( | 220 CHECK(file_util::CreateTemporaryDirInDir( |
230 temp_dir_.path(), FILE_PATH_LITERAL("d"), &temp_dir)); | 221 temp_dir_.path(), FILE_PATH_LITERAL("d"), &temp_dir)); |
231 temp_directories[test_name_no_pre] = temp_dir; | 222 temp_directories[test_name_no_pre] = temp_dir; |
232 } | 223 } |
233 | 224 |
234 CommandLine new_cmd_line(*CommandLine::ForCurrentProcess()); | 225 CommandLine new_cmd_line(*CommandLine::ForCurrentProcess()); |
235 CHECK(launcher_delegate_->AdjustChildProcessCommandLine( | 226 CHECK(launcher_delegate_->AdjustChildProcessCommandLine( |
236 &new_cmd_line, temp_directories[test_name_no_pre])); | 227 &new_cmd_line, temp_directories[test_name_no_pre])); |
237 | 228 |
238 DoRunTest(test_info, new_cmd_line); | 229 std::string pre_test_name( |
| 230 test_info.test_case_name + "." + kPreTestPrefix + test_info.test_name); |
| 231 if (ContainsKey(tests_to_run_, pre_test_name)) { |
| 232 tests_to_run_[pre_test_name].callbacks.push_back( |
| 233 base::Bind(&WrapperTestLauncherDelegate::RunDependentTest, |
| 234 base::Unretained(this), |
| 235 test_info.GetFullName(), |
| 236 new_cmd_line)); |
| 237 } else { |
| 238 tests_to_run_now.push_back( |
| 239 std::make_pair(test_info.GetFullName(), new_cmd_line)); |
| 240 } |
| 241 } |
| 242 |
| 243 for (size_t i = 0; i < tests_to_run_now.size(); i++) { |
| 244 const TestInfo& test_info = tests_to_run_[tests_to_run_now[i].first]; |
| 245 const CommandLine& cmd_line = tests_to_run_now[i].second; |
| 246 DoRunTest(test_info, cmd_line); |
239 } | 247 } |
240 } | 248 } |
241 | 249 |
242 void WrapperTestLauncherDelegate::DoRunTest(const TestInfo& test_info, | 250 void WrapperTestLauncherDelegate::DoRunTest(const TestInfo& test_info, |
243 const CommandLine& command_line) { | 251 const CommandLine& command_line) { |
244 CommandLine new_cmd_line(command_line.GetProgram()); | 252 CommandLine new_cmd_line(command_line.GetProgram()); |
245 CommandLine::SwitchMap switches = command_line.GetSwitches(); | 253 CommandLine::SwitchMap switches = command_line.GetSwitches(); |
246 | 254 |
247 // Strip out gtest_output flag because otherwise we would overwrite results | 255 // Strip out gtest_output flag because otherwise we would overwrite results |
248 // of the other tests. | 256 // of the other tests. |
(...skipping 12 matching lines...) Expand all Loading... |
261 test_info.test_case_name + "." + test_info.test_name); | 269 test_info.test_case_name + "." + test_info.test_name); |
262 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag); | 270 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag); |
263 | 271 |
264 char* browser_wrapper = getenv("BROWSER_WRAPPER"); | 272 char* browser_wrapper = getenv("BROWSER_WRAPPER"); |
265 | 273 |
266 // PRE_ tests and tests that depend on them should share the sequence token | 274 // PRE_ tests and tests that depend on them should share the sequence token |
267 // name, so that they are run serially. | 275 // name, so that they are run serially. |
268 std::string test_name_no_pre = RemoveAnyPrePrefixes( | 276 std::string test_name_no_pre = RemoveAnyPrePrefixes( |
269 test_info.test_case_name + "." + test_info.test_name); | 277 test_info.test_case_name + "." + test_info.test_name); |
270 | 278 |
271 parallel_launcher_.LaunchNamedSequencedChildGTestProcess( | 279 parallel_launcher_.LaunchChildGTestProcess( |
272 test_name_no_pre, | |
273 new_cmd_line, | 280 new_cmd_line, |
274 browser_wrapper ? browser_wrapper : std::string(), | 281 browser_wrapper ? browser_wrapper : std::string(), |
275 TestTimeouts::action_max_timeout(), | 282 TestTimeouts::action_max_timeout(), |
276 base::Bind(&WrapperTestLauncherDelegate::GTestCallback, | 283 base::Bind(&WrapperTestLauncherDelegate::GTestCallback, |
277 base::Unretained(this), | 284 base::Unretained(this), |
278 test_info)); | 285 test_info)); |
279 } | 286 } |
280 | 287 |
| 288 void WrapperTestLauncherDelegate::RunDependentTest( |
| 289 const std::string test_name, |
| 290 const CommandLine& command_line, |
| 291 const base::TestResult& pre_test_result) { |
| 292 const TestInfo& test_info = tests_to_run_[test_name]; |
| 293 if (pre_test_result.status == base::TestResult::TEST_SUCCESS) { |
| 294 // Only run the dependent test if PRE_ test succeeded. |
| 295 DoRunTest(test_info, command_line); |
| 296 } else { |
| 297 // Otherwise skip the test. |
| 298 base::TestResult test_result; |
| 299 test_result.test_case_name = test_info.test_case_name; |
| 300 test_result.test_name = test_info.test_name; |
| 301 test_result.status = base::TestResult::TEST_SKIPPED; |
| 302 for (size_t i = 0; i < test_info.callbacks.size(); i++) |
| 303 test_info.callbacks[i].Run(test_result); |
| 304 } |
| 305 } |
| 306 |
281 void WrapperTestLauncherDelegate::GTestCallback( | 307 void WrapperTestLauncherDelegate::GTestCallback( |
282 const TestInfo& test_info, | 308 const TestInfo& test_info, |
283 int exit_code, | 309 int exit_code, |
284 const base::TimeDelta& elapsed_time, | 310 const base::TimeDelta& elapsed_time, |
285 bool was_timeout, | 311 bool was_timeout, |
286 const std::string& output) { | 312 const std::string& output) { |
287 base::TestResult result; | 313 base::TestResult result; |
288 result.test_case_name = test_info.test_case_name; | 314 result.test_case_name = test_info.test_case_name; |
289 result.test_name = test_info.test_name; | 315 result.test_name = test_info.test_name; |
290 | 316 |
291 // TODO(phajdan.jr): Recognize crashes. | 317 // TODO(phajdan.jr): Recognize crashes. |
292 if (exit_code == 0) | 318 if (exit_code == 0) |
293 result.status = base::TestResult::TEST_SUCCESS; | 319 result.status = base::TestResult::TEST_SUCCESS; |
294 else if (was_timeout) | 320 else if (was_timeout) |
295 result.status = base::TestResult::TEST_TIMEOUT; | 321 result.status = base::TestResult::TEST_TIMEOUT; |
296 else | 322 else |
297 result.status = base::TestResult::TEST_FAILURE; | 323 result.status = base::TestResult::TEST_FAILURE; |
298 | 324 |
299 result.elapsed_time = elapsed_time; | 325 result.elapsed_time = elapsed_time; |
300 | 326 |
301 // TODO(phajdan.jr): Use base::PrintTestOutputSnippetOnFailure after migrating | 327 // TODO(phajdan.jr): Use base::PrintTestOutputSnippetOnFailure after migrating |
302 // away from run_test_cases.py (http://crbug.com/236893). | 328 // away from run_test_cases.py (http://crbug.com/236893). |
303 fprintf(stdout, "%s", output.c_str()); | 329 fprintf(stdout, "%s", output.c_str()); |
304 fflush(stdout); | 330 fflush(stdout); |
305 | 331 |
306 test_info.callback.Run(result); | 332 for (size_t i = 0; i < test_info.callbacks.size(); i++) |
| 333 test_info.callbacks[i].Run(result); |
307 parallel_launcher_.ResetOutputWatchdog(); | 334 parallel_launcher_.ResetOutputWatchdog(); |
308 } | 335 } |
309 | 336 |
310 bool GetSwitchValueAsInt(const std::string& switch_name, int* result) { | 337 bool GetSwitchValueAsInt(const std::string& switch_name, int* result) { |
311 if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) | 338 if (!CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) |
312 return true; | 339 return true; |
313 | 340 |
314 std::string switch_value = | 341 std::string switch_value = |
315 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name); | 342 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switch_name); |
316 if (!base::StringToInt(switch_value, result) || *result < 1) { | 343 if (!base::StringToInt(switch_value, result) || *result < 1) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 | 446 |
420 WrapperTestLauncherDelegate delegate(launcher_delegate, jobs); | 447 WrapperTestLauncherDelegate delegate(launcher_delegate, jobs); |
421 return base::LaunchTests(&delegate, argc, argv); | 448 return base::LaunchTests(&delegate, argc, argv); |
422 } | 449 } |
423 | 450 |
424 TestLauncherDelegate* GetCurrentTestLauncherDelegate() { | 451 TestLauncherDelegate* GetCurrentTestLauncherDelegate() { |
425 return g_launcher_delegate; | 452 return g_launcher_delegate; |
426 } | 453 } |
427 | 454 |
428 } // namespace content | 455 } // namespace content |
OLD | NEW |