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

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

Issue 863253002: Update from https://crrev.com/312600 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 11 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 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 "base/test/launcher/unit_test_launcher.h" 5 #include "base/test/launcher/unit_test_launcher.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 } 237 }
238 238
239 bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) { 239 bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) {
240 DCHECK(thread_checker_.CalledOnValidThread()); 240 DCHECK(thread_checker_.CalledOnValidThread());
241 *output = GetCompiledInTests(); 241 *output = GetCompiledInTests();
242 return true; 242 return true;
243 } 243 }
244 244
245 bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name, 245 bool UnitTestLauncherDelegate::ShouldRunTest(const std::string& test_case_name,
246 const std::string& test_name) { 246 const std::string& test_name) {
247 DCHECK(thread_checker_.CalledOnValidThread()); 247 DCHECK(thread_checker_.CalledOnValidThread());
248 248
249 // There is no additional logic to disable specific tests. 249 // There is no additional logic to disable specific tests.
250 return true; 250 return true;
251 }
252
253 size_t UnitTestLauncherDelegate::RunTests(
254 TestLauncher* test_launcher,
255 const std::vector<std::string>& test_names) {
256 DCHECK(thread_checker_.CalledOnValidThread());
257
258 std::vector<std::string> batch;
259 for (size_t i = 0; i < test_names.size(); i++) {
260 batch.push_back(test_names[i]);
261
262 if (batch.size() >= batch_limit_) {
263 RunBatch(test_launcher, batch);
264 batch.clear();
265 }
251 } 266 }
252 267
253 size_t UnitTestLauncherDelegate::RunTests( 268 RunBatch(test_launcher, batch);
254 TestLauncher* test_launcher, 269
255 const std::vector<std::string>& test_names) { 270 return test_names.size();
256 DCHECK(thread_checker_.CalledOnValidThread()); 271 }
257 272
273 size_t UnitTestLauncherDelegate::RetryTests(
274 TestLauncher* test_launcher,
275 const std::vector<std::string>& test_names) {
276 MessageLoop::current()->PostTask(
277 FROM_HERE, Bind(&UnitTestLauncherDelegate::RunSerially, Unretained(this),
278 test_launcher, test_names));
279 return test_names.size();
280 }
281
282 void UnitTestLauncherDelegate::RunSerially(
283 TestLauncher* test_launcher,
284 const std::vector<std::string>& test_names) {
285 if (test_names.empty())
286 return;
287
288 std::vector<std::string> new_test_names(test_names);
289 std::string test_name(new_test_names.back());
290 new_test_names.pop_back();
291
292 // Create a dedicated temporary directory to store the xml result data
293 // per run to ensure clean state and make it possible to launch multiple
294 // processes in parallel.
295 base::FilePath output_file;
296 CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file));
297 output_file = output_file.AppendASCII("test_results.xml");
298
299 std::vector<std::string> current_test_names;
300 current_test_names.push_back(test_name);
301 CommandLine cmd_line(
302 GetCommandLineForChildGTestProcess(current_test_names, output_file));
303
304 GTestCallbackState callback_state;
305 callback_state.test_launcher = test_launcher;
306 callback_state.test_names = current_test_names;
307 callback_state.output_file = output_file;
308
309 test_launcher->LaunchChildGTestProcess(
310 cmd_line, std::string(), TestTimeouts::test_launcher_timeout(),
311 use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
312 Bind(&UnitTestLauncherDelegate::SerialGTestCallback, Unretained(this),
313 callback_state, new_test_names));
314 }
315
316 void UnitTestLauncherDelegate::RunBatch(
317 TestLauncher* test_launcher,
318 const std::vector<std::string>& test_names) {
319 DCHECK(thread_checker_.CalledOnValidThread());
320
321 if (test_names.empty())
322 return;
323
324 // Create a dedicated temporary directory to store the xml result data
325 // per run to ensure clean state and make it possible to launch multiple
326 // processes in parallel.
327 base::FilePath output_file;
328 CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file));
329 output_file = output_file.AppendASCII("test_results.xml");
330
331 CommandLine cmd_line(
332 GetCommandLineForChildGTestProcess(test_names, output_file));
333
334 // Adjust the timeout depending on how many tests we're running
335 // (note that e.g. the last batch of tests will be smaller).
336 // TODO(phajdan.jr): Consider an adaptive timeout, which can change
337 // depending on how many tests ran and how many remain.
338 // Note: do NOT parse child's stdout to do that, it's known to be
339 // unreliable (e.g. buffering issues can mix up the output).
340 base::TimeDelta timeout =
341 test_names.size() * TestTimeouts::test_launcher_timeout();
342
343 GTestCallbackState callback_state;
344 callback_state.test_launcher = test_launcher;
345 callback_state.test_names = test_names;
346 callback_state.output_file = output_file;
347
348 test_launcher->LaunchChildGTestProcess(
349 cmd_line, std::string(), timeout,
350 use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
351 Bind(&UnitTestLauncherDelegate::GTestCallback, Unretained(this),
352 callback_state));
353 }
354
355 void UnitTestLauncherDelegate::GTestCallback(
356 const GTestCallbackState& callback_state,
357 int exit_code,
358 const TimeDelta& elapsed_time,
359 bool was_timeout,
360 const std::string& output) {
361 DCHECK(thread_checker_.CalledOnValidThread());
362 std::vector<std::string> tests_to_relaunch;
363 ProcessTestResults(callback_state.test_launcher, callback_state.test_names,
364 callback_state.output_file, output, exit_code, was_timeout,
365 &tests_to_relaunch);
366
367 // Relaunch requested tests in parallel, but only use single
368 // test per batch for more precise results (crashes, test passes
369 // but non-zero exit codes etc).
370 for (size_t i = 0; i < tests_to_relaunch.size(); i++) {
258 std::vector<std::string> batch; 371 std::vector<std::string> batch;
372 batch.push_back(tests_to_relaunch[i]);
373 RunBatch(callback_state.test_launcher, batch);
374 }
375
376 // The temporary file's directory is also temporary.
377 DeleteFile(callback_state.output_file.DirName(), true);
378 }
379
380 void UnitTestLauncherDelegate::SerialGTestCallback(
381 const GTestCallbackState& callback_state,
382 const std::vector<std::string>& test_names,
383 int exit_code,
384 const TimeDelta& elapsed_time,
385 bool was_timeout,
386 const std::string& output) {
387 DCHECK(thread_checker_.CalledOnValidThread());
388 std::vector<std::string> tests_to_relaunch;
389 bool called_any_callbacks =
390 ProcessTestResults(callback_state.test_launcher,
391 callback_state.test_names, callback_state.output_file,
392 output, exit_code, was_timeout, &tests_to_relaunch);
393
394 // There is only one test, there cannot be other tests to relaunch
395 // due to a crash.
396 DCHECK(tests_to_relaunch.empty());
397
398 // There is only one test, we should have called back with its result.
399 DCHECK(called_any_callbacks);
400
401 // The temporary file's directory is also temporary.
402 DeleteFile(callback_state.output_file.DirName(), true);
403
404 MessageLoop::current()->PostTask(
405 FROM_HERE, Bind(&UnitTestLauncherDelegate::RunSerially, Unretained(this),
406 callback_state.test_launcher, test_names));
407 }
408
409 // static
410 bool UnitTestLauncherDelegate::ProcessTestResults(
411 TestLauncher* test_launcher,
412 const std::vector<std::string>& test_names,
413 const base::FilePath& output_file,
414 const std::string& output,
415 int exit_code,
416 bool was_timeout,
417 std::vector<std::string>* tests_to_relaunch) {
418 std::vector<TestResult> test_results;
419 bool crashed = false;
420 bool have_test_results =
421 ProcessGTestOutput(output_file, &test_results, &crashed);
422
423 bool called_any_callback = false;
424
425 if (have_test_results) {
426 // TODO(phajdan.jr): Check for duplicates and mismatches between
427 // the results we got from XML file and tests we intended to run.
428 std::map<std::string, TestResult> results_map;
429 for (size_t i = 0; i < test_results.size(); i++)
430 results_map[test_results[i].full_name] = test_results[i];
431
432 bool had_interrupted_test = false;
433
434 // Results to be reported back to the test launcher.
435 std::vector<TestResult> final_results;
436
259 for (size_t i = 0; i < test_names.size(); i++) { 437 for (size_t i = 0; i < test_names.size(); i++) {
260 batch.push_back(test_names[i]); 438 if (ContainsKey(results_map, test_names[i])) {
261 439 TestResult test_result = results_map[test_names[i]];
262 if (batch.size() >= batch_limit_) { 440 if (test_result.status == TestResult::TEST_CRASH) {
263 RunBatch(test_launcher, batch); 441 had_interrupted_test = true;
264 batch.clear(); 442
265 } 443 if (was_timeout) {
266 } 444 // Fix up the test status: we forcibly kill the child process
267 445 // after the timeout, so from XML results it looks just like
268 RunBatch(test_launcher, batch); 446 // a crash.
269 447 test_result.status = TestResult::TEST_TIMEOUT;
270 return test_names.size();
271 }
272
273 size_t UnitTestLauncherDelegate::RetryTests(
274 TestLauncher* test_launcher,
275 const std::vector<std::string>& test_names) {
276 MessageLoop::current()->PostTask(
277 FROM_HERE,
278 Bind(&UnitTestLauncherDelegate::RunSerially,
279 Unretained(this),
280 test_launcher,
281 test_names));
282 return test_names.size();
283 }
284
285 void UnitTestLauncherDelegate::RunSerially(
286 TestLauncher* test_launcher,
287 const std::vector<std::string>& test_names) {
288 if (test_names.empty())
289 return;
290
291 std::vector<std::string> new_test_names(test_names);
292 std::string test_name(new_test_names.back());
293 new_test_names.pop_back();
294
295 // Create a dedicated temporary directory to store the xml result data
296 // per run to ensure clean state and make it possible to launch multiple
297 // processes in parallel.
298 base::FilePath output_file;
299 CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file));
300 output_file = output_file.AppendASCII("test_results.xml");
301
302 std::vector<std::string> current_test_names;
303 current_test_names.push_back(test_name);
304 CommandLine cmd_line(
305 GetCommandLineForChildGTestProcess(current_test_names, output_file));
306
307 GTestCallbackState callback_state;
308 callback_state.test_launcher = test_launcher;
309 callback_state.test_names = current_test_names;
310 callback_state.output_file = output_file;
311
312 test_launcher->LaunchChildGTestProcess(
313 cmd_line,
314 std::string(),
315 TestTimeouts::test_launcher_timeout(),
316 use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
317 Bind(&UnitTestLauncherDelegate::SerialGTestCallback,
318 Unretained(this),
319 callback_state,
320 new_test_names));
321 }
322
323 void UnitTestLauncherDelegate::RunBatch(
324 TestLauncher* test_launcher,
325 const std::vector<std::string>& test_names) {
326 DCHECK(thread_checker_.CalledOnValidThread());
327
328 if (test_names.empty())
329 return;
330
331 // Create a dedicated temporary directory to store the xml result data
332 // per run to ensure clean state and make it possible to launch multiple
333 // processes in parallel.
334 base::FilePath output_file;
335 CHECK(CreateNewTempDirectory(FilePath::StringType(), &output_file));
336 output_file = output_file.AppendASCII("test_results.xml");
337
338 CommandLine cmd_line(
339 GetCommandLineForChildGTestProcess(test_names, output_file));
340
341 // Adjust the timeout depending on how many tests we're running
342 // (note that e.g. the last batch of tests will be smaller).
343 // TODO(phajdan.jr): Consider an adaptive timeout, which can change
344 // depending on how many tests ran and how many remain.
345 // Note: do NOT parse child's stdout to do that, it's known to be
346 // unreliable (e.g. buffering issues can mix up the output).
347 base::TimeDelta timeout =
348 test_names.size() * TestTimeouts::test_launcher_timeout();
349
350 GTestCallbackState callback_state;
351 callback_state.test_launcher = test_launcher;
352 callback_state.test_names = test_names;
353 callback_state.output_file = output_file;
354
355 test_launcher->LaunchChildGTestProcess(
356 cmd_line,
357 std::string(),
358 timeout,
359 use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0,
360 Bind(&UnitTestLauncherDelegate::GTestCallback,
361 Unretained(this),
362 callback_state));
363 }
364
365 void UnitTestLauncherDelegate::GTestCallback(
366 const GTestCallbackState& callback_state,
367 int exit_code,
368 const TimeDelta& elapsed_time,
369 bool was_timeout,
370 const std::string& output) {
371 DCHECK(thread_checker_.CalledOnValidThread());
372 std::vector<std::string> tests_to_relaunch;
373 ProcessTestResults(callback_state.test_launcher,
374 callback_state.test_names,
375 callback_state.output_file,
376 output,
377 exit_code,
378 was_timeout,
379 &tests_to_relaunch);
380
381 // Relaunch requested tests in parallel, but only use single
382 // test per batch for more precise results (crashes, test passes
383 // but non-zero exit codes etc).
384 for (size_t i = 0; i < tests_to_relaunch.size(); i++) {
385 std::vector<std::string> batch;
386 batch.push_back(tests_to_relaunch[i]);
387 RunBatch(callback_state.test_launcher, batch);
388 }
389
390 // The temporary file's directory is also temporary.
391 DeleteFile(callback_state.output_file.DirName(), true);
392 }
393
394 void UnitTestLauncherDelegate::SerialGTestCallback(
395 const GTestCallbackState& callback_state,
396 const std::vector<std::string>& test_names,
397 int exit_code,
398 const TimeDelta& elapsed_time,
399 bool was_timeout,
400 const std::string& output) {
401 DCHECK(thread_checker_.CalledOnValidThread());
402 std::vector<std::string> tests_to_relaunch;
403 bool called_any_callbacks =
404 ProcessTestResults(callback_state.test_launcher,
405 callback_state.test_names,
406 callback_state.output_file,
407 output,
408 exit_code,
409 was_timeout,
410 &tests_to_relaunch);
411
412 // There is only one test, there cannot be other tests to relaunch
413 // due to a crash.
414 DCHECK(tests_to_relaunch.empty());
415
416 // There is only one test, we should have called back with its result.
417 DCHECK(called_any_callbacks);
418
419 // The temporary file's directory is also temporary.
420 DeleteFile(callback_state.output_file.DirName(), true);
421
422 MessageLoop::current()->PostTask(
423 FROM_HERE,
424 Bind(&UnitTestLauncherDelegate::RunSerially,
425 Unretained(this),
426 callback_state.test_launcher,
427 test_names));
428 }
429
430 // static
431 bool UnitTestLauncherDelegate::ProcessTestResults(
432 TestLauncher* test_launcher,
433 const std::vector<std::string>& test_names,
434 const base::FilePath& output_file,
435 const std::string& output,
436 int exit_code,
437 bool was_timeout,
438 std::vector<std::string>* tests_to_relaunch) {
439 std::vector<TestResult> test_results;
440 bool crashed = false;
441 bool have_test_results =
442 ProcessGTestOutput(output_file, &test_results, &crashed);
443
444 bool called_any_callback = false;
445
446 if (have_test_results) {
447 // TODO(phajdan.jr): Check for duplicates and mismatches between
448 // the results we got from XML file and tests we intended to run.
449 std::map<std::string, TestResult> results_map;
450 for (size_t i = 0; i < test_results.size(); i++)
451 results_map[test_results[i].full_name] = test_results[i];
452
453 bool had_interrupted_test = false;
454
455 // Results to be reported back to the test launcher.
456 std::vector<TestResult> final_results;
457
458 for (size_t i = 0; i < test_names.size(); i++) {
459 if (ContainsKey(results_map, test_names[i])) {
460 TestResult test_result = results_map[test_names[i]];
461 if (test_result.status == TestResult::TEST_CRASH) {
462 had_interrupted_test = true;
463
464 if (was_timeout) {
465 // Fix up the test status: we forcibly kill the child process
466 // after the timeout, so from XML results it looks just like
467 // a crash.
468 test_result.status = TestResult::TEST_TIMEOUT;
469 }
470 } else if (test_result.status == TestResult::TEST_SUCCESS ||
471 test_result.status == TestResult::TEST_FAILURE) {
472 // We run multiple tests in a batch with a timeout applied
473 // to the entire batch. It is possible that with other tests
474 // running quickly some tests take longer than the per-test timeout.
475 // For consistent handling of tests independent of order and other
476 // factors, mark them as timing out.
477 if (test_result.elapsed_time >
478 TestTimeouts::test_launcher_timeout()) {
479 test_result.status = TestResult::TEST_TIMEOUT;
480 }
481 } 448 }
482 test_result.output_snippet = 449 } else if (test_result.status == TestResult::TEST_SUCCESS ||
483 GetTestOutputSnippet(test_result, output); 450 test_result.status == TestResult::TEST_FAILURE) {
484 final_results.push_back(test_result); 451 // We run multiple tests in a batch with a timeout applied
485 } else if (had_interrupted_test) { 452 // to the entire batch. It is possible that with other tests
486 tests_to_relaunch->push_back(test_names[i]); 453 // running quickly some tests take longer than the per-test timeout.
487 } else { 454 // For consistent handling of tests independent of order and other
488 // TODO(phajdan.jr): Explicitly pass the info that the test didn't 455 // factors, mark them as timing out.
489 // run for a mysterious reason. 456 if (test_result.elapsed_time >
490 LOG(ERROR) << "no test result for " << test_names[i]; 457 TestTimeouts::test_launcher_timeout()) {
491 TestResult test_result; 458 test_result.status = TestResult::TEST_TIMEOUT;
492 test_result.full_name = test_names[i]; 459 }
493 test_result.status = TestResult::TEST_UNKNOWN;
494 test_result.output_snippet =
495 GetTestOutputSnippet(test_result, output);
496 final_results.push_back(test_result);
497 } 460 }
498 } 461 test_result.output_snippet = GetTestOutputSnippet(test_result, output);
499 462 final_results.push_back(test_result);
500 // TODO(phajdan.jr): Handle the case where processing XML output 463 } else if (had_interrupted_test) {
501 // indicates a crash but none of the test results is marked as crashing. 464 tests_to_relaunch->push_back(test_names[i]);
502 465 } else {
503 if (final_results.empty()) 466 // TODO(phajdan.jr): Explicitly pass the info that the test didn't
504 return false; 467 // run for a mysterious reason.
505 468 LOG(ERROR) << "no test result for " << test_names[i];
506 bool has_non_success_test = false;
507 for (size_t i = 0; i < final_results.size(); i++) {
508 if (final_results[i].status != TestResult::TEST_SUCCESS) {
509 has_non_success_test = true;
510 break;
511 }
512 }
513
514 if (!has_non_success_test && exit_code != 0) {
515 // This is a bit surprising case: all tests are marked as successful,
516 // but the exit code was not zero. This can happen e.g. under memory
517 // tools that report leaks this way.
518
519 if (final_results.size() == 1) {
520 // Easy case. One test only so we know the non-zero exit code
521 // was caused by that one test.
522 final_results[0].status = TestResult::TEST_FAILURE_ON_EXIT;
523 } else {
524 // Harder case. Discard the results and request relaunching all
525 // tests without batching. This will trigger above branch on
526 // relaunch leading to more precise results.
527 LOG(WARNING) << "Not sure which test caused non-zero exit code, "
528 << "relaunching all of them without batching.";
529
530 for (size_t i = 0; i < final_results.size(); i++)
531 tests_to_relaunch->push_back(final_results[i].full_name);
532
533 return false;
534 }
535 }
536
537 for (size_t i = 0; i < final_results.size(); i++) {
538 // Fix the output snippet after possible changes to the test result.
539 final_results[i].output_snippet =
540 GetTestOutputSnippet(final_results[i], output);
541 test_launcher->OnTestFinished(final_results[i]);
542 called_any_callback = true;
543 }
544 } else {
545 fprintf(stdout,
546 "Failed to get out-of-band test success data, "
547 "dumping full stdio below:\n%s\n",
548 output.c_str());
549 fflush(stdout);
550
551 // We do not have reliable details about test results (parsing test
552 // stdout is known to be unreliable), apply the executable exit code
553 // to all tests.
554 // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
555 // individually.
556 for (size_t i = 0; i < test_names.size(); i++) {
557 TestResult test_result; 469 TestResult test_result;
558 test_result.full_name = test_names[i]; 470 test_result.full_name = test_names[i];
559 test_result.status = TestResult::TEST_UNKNOWN; 471 test_result.status = TestResult::TEST_UNKNOWN;
560 test_launcher->OnTestFinished(test_result); 472 test_result.output_snippet = GetTestOutputSnippet(test_result, output);
561 called_any_callback = true; 473 final_results.push_back(test_result);
562 } 474 }
563 } 475 }
564 476
565 return called_any_callback; 477 // TODO(phajdan.jr): Handle the case where processing XML output
478 // indicates a crash but none of the test results is marked as crashing.
479
480 if (final_results.empty())
481 return false;
482
483 bool has_non_success_test = false;
484 for (size_t i = 0; i < final_results.size(); i++) {
485 if (final_results[i].status != TestResult::TEST_SUCCESS) {
486 has_non_success_test = true;
487 break;
488 }
489 }
490
491 if (!has_non_success_test && exit_code != 0) {
492 // This is a bit surprising case: all tests are marked as successful,
493 // but the exit code was not zero. This can happen e.g. under memory
494 // tools that report leaks this way.
495
496 if (final_results.size() == 1) {
497 // Easy case. One test only so we know the non-zero exit code
498 // was caused by that one test.
499 final_results[0].status = TestResult::TEST_FAILURE_ON_EXIT;
500 } else {
501 // Harder case. Discard the results and request relaunching all
502 // tests without batching. This will trigger above branch on
503 // relaunch leading to more precise results.
504 LOG(WARNING) << "Not sure which test caused non-zero exit code, "
505 << "relaunching all of them without batching.";
506
507 for (size_t i = 0; i < final_results.size(); i++)
508 tests_to_relaunch->push_back(final_results[i].full_name);
509
510 return false;
511 }
512 }
513
514 for (size_t i = 0; i < final_results.size(); i++) {
515 // Fix the output snippet after possible changes to the test result.
516 final_results[i].output_snippet =
517 GetTestOutputSnippet(final_results[i], output);
518 test_launcher->OnTestFinished(final_results[i]);
519 called_any_callback = true;
520 }
521 } else {
522 fprintf(stdout,
523 "Failed to get out-of-band test success data, "
524 "dumping full stdio below:\n%s\n",
525 output.c_str());
526 fflush(stdout);
527
528 // We do not have reliable details about test results (parsing test
529 // stdout is known to be unreliable), apply the executable exit code
530 // to all tests.
531 // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
532 // individually.
533 for (size_t i = 0; i < test_names.size(); i++) {
534 TestResult test_result;
535 test_result.full_name = test_names[i];
536 test_result.status = TestResult::TEST_UNKNOWN;
537 test_launcher->OnTestFinished(test_result);
538 called_any_callback = true;
539 }
566 } 540 }
567 541
542 return called_any_callback;
543 }
544
568 } // namespace base 545 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698