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

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: fixes 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
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";
M-A Ruel 2013/08/15 01:59:14 I feel this flag could be easily confused with --s
Paweł Hajdan Jr. 2013/08/15 21:54:45 Right, I'm trying to at least improve things over
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);
M-A Ruel 2013/08/15 01:59:14 why not iter->first, iter->second?
Paweł Hajdan Jr. 2013/08/15 21:54:45 Done.
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 for each run to ensure clean
M-A Ruel 2013/08/15 01:59:14 // Create a dedicated temporary directory to store
Paweł Hajdan Jr. 2013/08/15 21:54:45 Done.
98 // state and make it possible to launch multiple processes in parallel.
99 base::FilePath output_file;
100 base::ScopedTempDir temp_dir;
101 // TODO(phajdan.jr): Handle the failure gracefully.
M-A Ruel 2013/08/15 01:59:14 I don't think it's worth, at that point it could b
Paweł Hajdan Jr. 2013/08/15 21:54:45 Done.
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).
M-A Ruel 2013/08/15 01:59:14 // TODO(phajdan.jr): Use timeout adaptative based
Paweł Hajdan Jr. 2013/08/15 21:54:45 Done.
114 base::TimeDelta timeout =
115 test_names.size() * TestTimeouts::action_timeout();
116
117 // TODO(phajdan.jr): Distinguish between test failures and crashes.
118 bool was_timeout = false;
119 int exit_code = LaunchChildGTestProcess(cmd_line,
120 std::string(),
121 timeout,
122 &was_timeout);
123
124 ProcessTestResults(output_file, exit_code);
125
126 tests_.clear();
127 }
128
129 void ProcessTestResults(const base::FilePath& output_file, int exit_code) {
130 std::vector<TestResult> test_results;
131 bool have_test_results = ProcessGTestOutput(output_file, &test_results);
132
133 if (have_test_results) {
134 // TODO(phajdan.jr): Check for duplicates and mismatches between
135 // the results we got from XML file and tests we intended to run.
136 std::map<std::string, bool> results_map;
137 for (size_t i = 0; i < test_results.size(); i++)
138 results_map[test_results[i].GetFullName()] = test_results[i].success;
139
140 for (size_t i = 0; i < tests_.size(); i++) {
141 TestResult test_result;
142 test_result.test_case_name = tests_[i].test_case_name;
143 test_result.test_name = tests_[i].test_name;
144 test_result.success = results_map[tests_[i].GetFullName()];
145 tests_[i].callback.Run(test_result);
146 }
147
148 // TODO(phajdan.jr): Handle the case where the exit code is non-zero
149 // but results file indicates that all tests passed (e.g. crash during
150 // shutdown).
151 } else {
152 // We do not have reliable details about test results (parsing test
153 // stdout is known to be unreliable), apply the executable exit code
154 // to all tests.
155 // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
156 // individually.
157 for (size_t i = 0; i < tests_.size(); i++) {
158 TestResult test_result;
159 test_result.test_case_name = tests_[i].test_case_name;
160 test_result.test_name = tests_[i].test_name;
161 test_result.success = (exit_code == 0);
162 tests_[i].callback.Run(test_result);
163 }
164 }
165 }
166
167 std::vector<TestLaunchInfo> tests_;
168 };
169
170 } // namespace
171
172 int LaunchUnitTests(int argc,
173 char** argv,
174 const RunTestSuiteCallback& run_test_suite) {
175 CommandLine::Init(argc, argv);
176 if (CommandLine::ForCurrentProcess()->HasSwitch(kSingleProcessTestsFlag) ||
177 !CommandLine::ForCurrentProcess()->HasSwitch(kBraveNewTestLauncherFlag)) {
178 return run_test_suite.Run();
179 }
180
181 base::TimeTicks start_time(base::TimeTicks::Now());
182
183 fprintf(stdout,
184 "Starting tests...\n"
185 "IMPORTANT DEBUGGING NOTE: batches of tests are run inside their own \n"
186 "process. For debugging a test inside a debugger, use the\n"
187 "--gtest_filter=<your_test_name> flag along with \n"
188 "--single-process-tests.\n");
189 fflush(stdout);
190
191 testing::InitGoogleTest(&argc, argv);
192 TestTimeouts::Initialize();
193
194 base::UnitTestLauncherDelegate delegate;
195 int exit_code = base::LaunchTests(&delegate, argc, argv);
196
197 fprintf(stdout,
198 "Tests took %" PRId64 " seconds.\n",
199 (base::TimeTicks::Now() - start_time).InSeconds());
200 fflush(stdout);
201
202 return exit_code;
203 }
204
205 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698