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

Side by Side 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 unified diff | 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 »
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/unit_test_launcher.h"
6
7 #include "base/command_line.h"
8 #include "base/compiler_specific.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/file_util.h"
11 #include "base/format_macros.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_util.h"
14 #include "base/test/gtest_xml_util.h"
15 #include "base/test/test_launcher.h"
16 #include "base/test/test_timeouts.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace base {
20
21 namespace {
22
23 // This constant controls how many tests are run in a single batch.
24 const size_t kTestBatchLimit = 10;
25
26 // Flag to enable the new launcher logic.
27 // TODO(phajdan.jr): Remove it, http://crbug.com/236893 .
28 const char kBraveNewTestLauncherFlag[] = "brave-new-test-launcher";
29
30 // Flag to run all tests in a single process.
31 const char kSingleProcessTestsFlag[] = "single-process-tests";
32
33 // Returns command line for child GTest process based on the command line
34 // of current process. |test_names| is a vector of test full names
35 // (e.g. "A.B"), |output_file| is path to the GTest XML output file.
36 CommandLine GetCommandLineForChildGTestProcess(
37 const std::vector<std::string>& test_names,
38 const base::FilePath& output_file) {
39 CommandLine new_cmd_line(CommandLine::ForCurrentProcess()->GetProgram());
40 CommandLine::SwitchMap switches =
41 CommandLine::ForCurrentProcess()->GetSwitches();
42
43 switches.erase(kGTestOutputFlag);
44 new_cmd_line.AppendSwitchPath(
45 kGTestOutputFlag,
46 base::FilePath(FILE_PATH_LITERAL("xml:") + output_file.value()));
47
48 for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
49 iter != switches.end(); ++iter) {
50 new_cmd_line.AppendSwitchNative(iter->first, iter->second);
51 }
52
53 new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
54 JoinString(test_names, ":"));
55 new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
56 new_cmd_line.AppendSwitch(kBraveNewTestLauncherFlag);
57
58 return new_cmd_line;
59 }
60
61 class UnitTestLauncherDelegate : public TestLauncherDelegate {
62 private:
63 struct TestLaunchInfo {
64 std::string GetFullName() const {
65 return test_case_name + "." + test_name;
66 }
67
68 std::string test_case_name;
69 std::string test_name;
70 TestResultCallback callback;
71 };
72
73 virtual bool ShouldRunTest(const testing::TestCase* test_case,
74 const testing::TestInfo* test_info) OVERRIDE {
75 // There is no additional logic to disable specific tests.
76 return true;
77 }
78
79 virtual void RunTest(const testing::TestCase* test_case,
80 const testing::TestInfo* test_info,
81 const TestResultCallback& callback) OVERRIDE {
82 TestLaunchInfo launch_info;
83 launch_info.test_case_name = test_case->name();
84 launch_info.test_name = test_info->name();
85 launch_info.callback = callback;
86 tests_.push_back(launch_info);
87
88 // Run tests in batches no larger than the limit.
89 if (tests_.size() >= kTestBatchLimit)
90 RunRemainingTests();
91 }
92
93 virtual void RunRemainingTests() OVERRIDE {
94 if (tests_.empty())
95 return;
96
97 // Create a dedicated temporary directory to store the xml result data
98 // per run to ensure clean state and make it possible to launch multiple
99 // processes in parallel.
100 base::FilePath output_file;
101 base::ScopedTempDir temp_dir;
102 CHECK(temp_dir.CreateUniqueTempDir());
103 output_file = temp_dir.path().AppendASCII("test_results.xml");
104
105 std::vector<std::string> test_names;
106 for (size_t i = 0; i < tests_.size(); i++)
107 test_names.push_back(tests_[i].GetFullName());
108
109 CommandLine cmd_line(
110 GetCommandLineForChildGTestProcess(test_names, output_file));
111
112 // Adjust the timeout depending on how many tests we're running
113 // (note that e.g. the last batch of tests will be smaller).
114 // TODO(phajdan.jr): Consider an adaptive timeout, which can change
115 // depending on how many tests ran and how many remain.
116 // Note: do NOT parse child's stdout to do that, it's known to be
117 // unreliable (e.g. buffering issues can mix up the output).
118 base::TimeDelta timeout =
119 test_names.size() * TestTimeouts::action_timeout();
120
121 // TODO(phajdan.jr): Distinguish between test failures and crashes.
122 bool was_timeout = false;
123 int exit_code = LaunchChildGTestProcess(cmd_line,
124 std::string(),
125 timeout,
126 &was_timeout);
127
128 ProcessTestResults(output_file, exit_code);
129
130 tests_.clear();
131 }
132
133 void ProcessTestResults(const base::FilePath& output_file, int exit_code) {
134 std::vector<TestResult> test_results;
135 bool have_test_results = ProcessGTestOutput(output_file, &test_results);
136
137 if (have_test_results) {
138 // TODO(phajdan.jr): Check for duplicates and mismatches between
139 // the results we got from XML file and tests we intended to run.
140 std::map<std::string, bool> results_map;
141 for (size_t i = 0; i < test_results.size(); i++)
142 results_map[test_results[i].GetFullName()] = test_results[i].success;
143
144 for (size_t i = 0; i < tests_.size(); i++) {
145 TestResult test_result;
146 test_result.test_case_name = tests_[i].test_case_name;
147 test_result.test_name = tests_[i].test_name;
148 test_result.success = results_map[tests_[i].GetFullName()];
149 tests_[i].callback.Run(test_result);
150 }
151
152 // TODO(phajdan.jr): Handle the case where the exit code is non-zero
153 // but results file indicates that all tests passed (e.g. crash during
154 // shutdown).
155 } else {
156 // We do not have reliable details about test results (parsing test
157 // stdout is known to be unreliable), apply the executable exit code
158 // to all tests.
159 // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
160 // individually.
161 for (size_t i = 0; i < tests_.size(); i++) {
162 TestResult test_result;
163 test_result.test_case_name = tests_[i].test_case_name;
164 test_result.test_name = tests_[i].test_name;
165 test_result.success = (exit_code == 0);
166 tests_[i].callback.Run(test_result);
167 }
168 }
169 }
170
171 std::vector<TestLaunchInfo> tests_;
172 };
173
174 } // namespace
175
176 int LaunchUnitTests(int argc,
177 char** argv,
178 const RunTestSuiteCallback& run_test_suite) {
179 CommandLine::Init(argc, argv);
180 if (CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
181 !CommandLine::ForCurrentProcess()->HasSwitch(kBraveNewTestLauncherFlag)) {
182 return run_test_suite.Run();
183 }
184
185 base::TimeTicks start_time(base::TimeTicks::Now());
186
187 fprintf(stdout,
188 "Starting tests...\n"
189 "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their own \n"
190 "process. For debugging a test inside a debugger, use the\n"
191 "--gtest_filter=<your_test_name> flag along with \n"
192 "--single-process-tests.\n");
193 fflush(stdout);
194
195 testing::InitGoogleTest(&argc, argv);
196 TestTimeouts::Initialize();
197
198 base::UnitTestLauncherDelegate delegate;
199 int exit_code = base::LaunchTests(&delegate, argc, argv);
200
201 fprintf(stdout,
202 "Tests took %" PRId64 " seconds.\n",
203 (base::TimeTicks::Now() - start_time).InSeconds());
204 fflush(stdout);
205
206 return exit_code;
207 }
208
209 } // namespace base
OLDNEW
« 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