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

Unified Diff: base/test/unit_test_launcher.cc

Issue 23132002: GTTF: Add a basic new unit test launcher. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed gyp cycle Created 7 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/test/unit_test_launcher.h ('k') | base/test/unit_test_launcher_ios.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/test/unit_test_launcher.cc
diff --git a/base/test/unit_test_launcher.cc b/base/test/unit_test_launcher.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ebf3d40b3cf4d4d39407e2b79086a6d263af620b
--- /dev/null
+++ b/base/test/unit_test_launcher.cc
@@ -0,0 +1,209 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/test_launcher.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// This constant controls how many tests are run in a single batch.
+const size_t kTestBatchLimit = 10;
+
+// Flag to enable the new launcher logic.
+// TODO(phajdan.jr): Remove it, http://crbug.com/236893 .
+const char kBraveNewTestLauncherFlag[] = "brave-new-test-launcher";
+
+// Flag to run all tests in a single process.
+const char kSingleProcessTestsFlag[] = "single-process-tests";
+
+// Returns command line for child GTest process based on the command line
+// of current process. |test_names| is a vector of test full names
+// (e.g. "A.B"), |output_file| is path to the GTest XML output file.
+CommandLine GetCommandLineForChildGTestProcess(
+ const std::vector<std::string>& test_names,
+ const base::FilePath& output_file) {
+ CommandLine new_cmd_line(CommandLine::ForCurrentProcess()->GetProgram());
+ CommandLine::SwitchMap switches =
+ CommandLine::ForCurrentProcess()->GetSwitches();
+
+ switches.erase(kGTestOutputFlag);
+ new_cmd_line.AppendSwitchPath(
+ kGTestOutputFlag,
+ base::FilePath(FILE_PATH_LITERAL("xml:") + output_file.value()));
+
+ for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
+ iter != switches.end(); ++iter) {
+ new_cmd_line.AppendSwitchNative(iter->first, iter->second);
+ }
+
+ new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
+ JoinString(test_names, ":"));
+ new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
+ new_cmd_line.AppendSwitch(kBraveNewTestLauncherFlag);
+
+ return new_cmd_line;
+}
+
+class UnitTestLauncherDelegate : public TestLauncherDelegate {
+ private:
+ struct TestLaunchInfo {
+ std::string GetFullName() const {
+ return test_case_name + "." + test_name;
+ }
+
+ std::string test_case_name;
+ std::string test_name;
+ TestResultCallback callback;
+ };
+
+ virtual bool ShouldRunTest(const testing::TestCase* test_case,
+ const testing::TestInfo* test_info) OVERRIDE {
+ // There is no additional logic to disable specific tests.
+ return true;
+ }
+
+ virtual void RunTest(const testing::TestCase* test_case,
+ const testing::TestInfo* test_info,
+ const TestResultCallback& callback) OVERRIDE {
+ TestLaunchInfo launch_info;
+ launch_info.test_case_name = test_case->name();
+ launch_info.test_name = test_info->name();
+ launch_info.callback = callback;
+ tests_.push_back(launch_info);
+
+ // Run tests in batches no larger than the limit.
+ if (tests_.size() >= kTestBatchLimit)
+ RunRemainingTests();
+ }
+
+ virtual void RunRemainingTests() OVERRIDE {
+ if (tests_.empty())
+ return;
+
+ // Create a dedicated temporary directory to store the xml result data
+ // per run to ensure clean state and make it possible to launch multiple
+ // processes in parallel.
+ base::FilePath output_file;
+ base::ScopedTempDir temp_dir;
+ CHECK(temp_dir.CreateUniqueTempDir());
+ output_file = temp_dir.path().AppendASCII("test_results.xml");
+
+ std::vector<std::string> test_names;
+ for (size_t i = 0; i < tests_.size(); i++)
+ test_names.push_back(tests_[i].GetFullName());
+
+ CommandLine cmd_line(
+ GetCommandLineForChildGTestProcess(test_names, output_file));
+
+ // Adjust the timeout depending on how many tests we're running
+ // (note that e.g. the last batch of tests will be smaller).
+ // TODO(phajdan.jr): Consider an adaptive timeout, which can change
+ // depending on how many tests ran and how many remain.
+ // Note: do NOT parse child's stdout to do that, it's known to be
+ // unreliable (e.g. buffering issues can mix up the output).
+ base::TimeDelta timeout =
+ test_names.size() * TestTimeouts::action_timeout();
+
+ // TODO(phajdan.jr): Distinguish between test failures and crashes.
+ bool was_timeout = false;
+ int exit_code = LaunchChildGTestProcess(cmd_line,
+ std::string(),
+ timeout,
+ &was_timeout);
+
+ ProcessTestResults(output_file, exit_code);
+
+ tests_.clear();
+ }
+
+ void ProcessTestResults(const base::FilePath& output_file, int exit_code) {
+ std::vector<TestResult> test_results;
+ bool have_test_results = ProcessGTestOutput(output_file, &test_results);
+
+ if (have_test_results) {
+ // TODO(phajdan.jr): Check for duplicates and mismatches between
+ // the results we got from XML file and tests we intended to run.
+ std::map<std::string, bool> results_map;
+ for (size_t i = 0; i < test_results.size(); i++)
+ results_map[test_results[i].GetFullName()] = test_results[i].success;
+
+ for (size_t i = 0; i < tests_.size(); i++) {
+ TestResult test_result;
+ test_result.test_case_name = tests_[i].test_case_name;
+ test_result.test_name = tests_[i].test_name;
+ test_result.success = results_map[tests_[i].GetFullName()];
+ tests_[i].callback.Run(test_result);
+ }
+
+ // TODO(phajdan.jr): Handle the case where the exit code is non-zero
+ // but results file indicates that all tests passed (e.g. crash during
+ // shutdown).
+ } else {
+ // We do not have reliable details about test results (parsing test
+ // stdout is known to be unreliable), apply the executable exit code
+ // to all tests.
+ // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
+ // individually.
+ for (size_t i = 0; i < tests_.size(); i++) {
+ TestResult test_result;
+ test_result.test_case_name = tests_[i].test_case_name;
+ test_result.test_name = tests_[i].test_name;
+ test_result.success = (exit_code == 0);
+ tests_[i].callback.Run(test_result);
+ }
+ }
+ }
+
+ std::vector<TestLaunchInfo> tests_;
+};
+
+} // namespace
+
+int LaunchUnitTests(int argc,
+ char** argv,
+ const RunTestSuiteCallback& run_test_suite) {
+ CommandLine::Init(argc, argv);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
+ !CommandLine::ForCurrentProcess()->HasSwitch(kBraveNewTestLauncherFlag)) {
+ return run_test_suite.Run();
+ }
+
+ base::TimeTicks start_time(base::TimeTicks::Now());
+
+ fprintf(stdout,
+ "Starting tests...\n"
+ "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their own \n"
+ "process. For debugging a test inside a debugger, use the\n"
+ "--gtest_filter=<your_test_name> flag along with \n"
+ "--single-process-tests.\n");
+ fflush(stdout);
+
+ testing::InitGoogleTest(&argc, argv);
+ TestTimeouts::Initialize();
+
+ base::UnitTestLauncherDelegate delegate;
+ int exit_code = base::LaunchTests(&delegate, argc, argv);
+
+ fprintf(stdout,
+ "Tests took %" PRId64 " seconds.\n",
+ (base::TimeTicks::Now() - start_time).InSeconds());
+ fflush(stdout);
+
+ return exit_code;
+}
+
+} // namespace base
« no previous file with comments | « base/test/unit_test_launcher.h ('k') | base/test/unit_test_launcher_ios.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698