OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome/test/base/test_log_collector_win.h" | |
6 | |
7 #include <windows.h> | |
8 | |
9 #include <algorithm> | |
10 #include <ios> // For std::hex | |
11 | |
12 #include "base/command_line.h" | |
13 #include "base/compiler_specific.h" | |
14 #include "base/file_path.h" | |
15 #include "base/file_util.h" | |
16 #include "base/lazy_instance.h" | |
17 #include "base/logging.h" | |
18 #include "base/memory/scoped_ptr.h" | |
19 #include "base/scoped_temp_dir.h" | |
20 #include "base/stringprintf.h" | |
21 #include "chrome/test/base/file_logger_win.h" | |
22 #include "chrome/test/base/test_switches.h" | |
23 #include "testing/gtest/include/gtest/gtest.h" | |
24 | |
25 namespace { | |
26 | |
27 const char kTraceLogExtension[] = ".etl"; | |
28 | |
29 class TestLogCollector { | |
30 public: | |
31 TestLogCollector(); | |
32 ~TestLogCollector(); | |
33 | |
34 void Initialize(testing::UnitTest* unit_test); | |
35 | |
36 void SetUp(); | |
37 void StartSessionForTest(const testing::TestInfo& test_info); | |
38 bool LogTestPartResult(const testing::TestPartResult& test_part_result); | |
39 void ProcessSessionForTest(const testing::TestInfo& test_info); | |
40 void TearDown(); | |
41 | |
42 private: | |
43 // An EventListener that generally delegates to a given default result | |
44 // printer with a few exceptions; see individual method comments for details. | |
45 class EventListener : public testing::TestEventListener { | |
46 public: | |
47 // Ownership of |default_result_printer| is taken by the new instance. | |
48 EventListener(TestLogCollector* test_log_collector, | |
49 testing::TestEventListener* default_result_printer); | |
50 virtual ~EventListener(); | |
51 | |
52 // Sets up the log collector. | |
53 virtual void OnTestProgramStart( | |
54 const testing::UnitTest& unit_test) OVERRIDE { | |
55 test_log_collector_->SetUp(); | |
56 default_result_printer_->OnTestProgramStart(unit_test); | |
57 } | |
58 | |
59 virtual void OnTestIterationStart(const testing::UnitTest& unit_test, | |
60 int iteration) OVERRIDE { | |
61 default_result_printer_->OnTestIterationStart(unit_test, iteration); | |
62 } | |
63 | |
64 virtual void OnEnvironmentsSetUpStart( | |
65 const testing::UnitTest& unit_test) OVERRIDE { | |
66 default_result_printer_->OnEnvironmentsSetUpStart(unit_test); | |
67 } | |
68 | |
69 virtual void OnEnvironmentsSetUpEnd( | |
70 const testing::UnitTest& unit_test) OVERRIDE { | |
71 default_result_printer_->OnEnvironmentsSetUpEnd(unit_test); | |
72 } | |
73 | |
74 virtual void OnTestCaseStart(const testing::TestCase& test_case) OVERRIDE { | |
75 default_result_printer_->OnTestCaseStart(test_case); | |
76 } | |
77 | |
78 // Calls back to the collector to start collecting logs for this test. | |
79 virtual void OnTestStart(const testing::TestInfo& test_info) OVERRIDE { | |
80 default_result_printer_->OnTestStart(test_info); | |
81 test_log_collector_->StartSessionForTest(test_info); | |
82 } | |
83 | |
84 // Calls back to the collector with the partial result. If the collector | |
85 // does not handle it, it is given to the default result printer. | |
86 virtual void OnTestPartResult( | |
87 const testing::TestPartResult& test_part_result) OVERRIDE { | |
88 if (!test_log_collector_->LogTestPartResult(test_part_result)) | |
89 default_result_printer_->OnTestPartResult(test_part_result); | |
90 } | |
91 | |
92 // Calls back to the collector to handle the collected log for the test that | |
93 // has just ended. | |
94 virtual void OnTestEnd(const testing::TestInfo& test_info) OVERRIDE { | |
95 test_log_collector_->ProcessSessionForTest(test_info); | |
96 default_result_printer_->OnTestEnd(test_info); | |
97 } | |
98 | |
99 virtual void OnTestCaseEnd(const testing::TestCase& test_case) OVERRIDE { | |
100 default_result_printer_->OnTestCaseEnd(test_case); | |
101 } | |
102 | |
103 virtual void OnEnvironmentsTearDownStart( | |
104 const testing::UnitTest& unit_test) OVERRIDE { | |
105 default_result_printer_->OnEnvironmentsTearDownStart(unit_test); | |
106 } | |
107 | |
108 virtual void OnEnvironmentsTearDownEnd( | |
109 const testing::UnitTest& unit_test) OVERRIDE { | |
110 default_result_printer_->OnEnvironmentsTearDownEnd(unit_test); | |
111 } | |
112 | |
113 virtual void OnTestIterationEnd(const testing::UnitTest& unit_test, | |
114 int iteration) OVERRIDE { | |
115 default_result_printer_->OnTestIterationEnd(unit_test, iteration); | |
116 } | |
117 | |
118 // Tears down the log collector. | |
119 virtual void OnTestProgramEnd(const testing::UnitTest& unit_test) OVERRIDE { | |
120 default_result_printer_->OnTestProgramEnd(unit_test); | |
121 test_log_collector_->TearDown(); | |
122 } | |
123 | |
124 private: | |
125 TestLogCollector* test_log_collector_; | |
126 scoped_ptr<testing::TestEventListener> default_result_printer_; | |
127 | |
128 DISALLOW_COPY_AND_ASSIGN(EventListener); | |
129 }; | |
130 | |
131 // The Google Test unit test into which the collector has been installed. | |
132 testing::UnitTest* unit_test_; | |
133 | |
134 // A temporary directory into which a log file is placed for the duration of | |
135 // each test. Created/destroyed at collector SetUp and TearDown. | |
136 ScopedTempDir log_temp_dir_; | |
137 | |
138 // The test logger. Initialized/Unintitialized at collector SetUp and | |
139 // TearDown. | |
140 FileLogger file_logger_; | |
141 | |
142 // The current log file. Valid only during a test. | |
143 FilePath log_file_; | |
144 | |
145 // True if --also-emit-success-logs was specified on the command line. | |
146 bool also_emit_success_logs_; | |
147 | |
148 DISALLOW_COPY_AND_ASSIGN(TestLogCollector); | |
149 }; | |
150 | |
151 base::LazyInstance<TestLogCollector> g_test_log_collector = | |
152 LAZY_INSTANCE_INITIALIZER; | |
153 | |
154 // TestLogCollector::EventListener implementation | |
155 | |
156 TestLogCollector::EventListener::EventListener( | |
157 TestLogCollector* test_log_collector, | |
158 testing::TestEventListener* default_result_printer) | |
159 : test_log_collector_(test_log_collector), | |
160 default_result_printer_(default_result_printer) { | |
161 } | |
162 | |
163 TestLogCollector::EventListener::~EventListener() { | |
164 } | |
165 | |
166 // TestLogCollector implementation | |
167 | |
168 TestLogCollector::TestLogCollector() | |
169 : unit_test_(NULL), also_emit_success_logs_(false) { | |
170 } | |
171 | |
172 TestLogCollector::~TestLogCollector() { | |
173 } | |
174 | |
175 void TestLogCollector::Initialize(testing::UnitTest* unit_test) { | |
176 if (unit_test_ != NULL) { | |
177 CHECK_EQ(unit_test, unit_test_) | |
178 << "Cannot install the test log collector in multiple unit tests."; | |
179 return; // Already initialized. | |
180 } | |
181 | |
182 // Remove the default result printer and install the collector's listener | |
183 // which delegates to the printer. If the default result printer has already | |
184 // been released, log an error and move on. | |
185 testing::TestEventListeners& listeners = unit_test->listeners(); | |
186 testing::TestEventListener* default_result_printer = | |
187 listeners.default_result_printer(); | |
188 if (default_result_printer == NULL) { | |
189 LOG(ERROR) << "Failed to initialize the test log collector on account of " | |
190 "another component having released the default result " | |
191 "printer."; | |
192 } else { | |
193 // Ownership of |default_release_printer| is passed to the new listener, and | |
194 // ownership of the new listener is passed to the unit test. | |
195 listeners.Append( | |
196 new EventListener(this, listeners.Release(default_result_printer))); | |
197 | |
198 also_emit_success_logs_ = CommandLine::ForCurrentProcess()->HasSwitch( | |
199 switches::kAlsoEmitSuccessLogs); | |
200 | |
201 unit_test_ = unit_test; | |
202 } | |
203 } | |
204 | |
205 // Invoked by the listener at test program start to create the temporary log | |
206 // directory and initialize the logger. | |
207 void TestLogCollector::SetUp() { | |
208 if (!log_temp_dir_.CreateUniqueTempDir()) { | |
209 LOG(ERROR) << "Failed to create temporary directory to hold log files."; | |
210 } else { | |
211 file_logger_.Initialize(); | |
212 } | |
213 } | |
214 | |
215 // Invoked by the listener at test start to begin collecting logs in a file. | |
216 void TestLogCollector::StartSessionForTest(const testing::TestInfo& test_info) { | |
217 if (log_temp_dir_.IsValid()) { | |
218 std::string log_file_name(test_info.name()); | |
219 std::replace(log_file_name.begin(), log_file_name.end(), '/', '_'); | |
robertshield
2012/03/02 22:37:41
can test names contain other invalid characters (\
grt (UTC plus 2)
2012/03/03 02:12:43
Nope, they're identifiers in the C/C++ sense.
| |
220 log_file_name.append(kTraceLogExtension); | |
221 log_file_ = log_temp_dir_.path().AppendASCII(log_file_name); | |
222 | |
223 file_logger_.StartLogging(log_file_); | |
224 } | |
225 } | |
226 | |
227 // Invoked by the listener when a test result is produced to log an event for | |
228 // the result. | |
229 bool TestLogCollector::LogTestPartResult( | |
230 const testing::TestPartResult& test_part_result) { | |
231 // Can't handle the event if no trace session. | |
232 if (!file_logger_.is_logging()) | |
233 return false; | |
234 | |
235 if (test_part_result.type() != testing::TestPartResult::kSuccess) { | |
236 // Approximate Google Test's message formatting. | |
237 LOG(ERROR) | |
238 << base::StringPrintf("%s(%d): error: %s", test_part_result.file_name(), | |
239 test_part_result.line_number(), | |
240 test_part_result.message()); | |
241 } | |
242 return true; | |
243 } | |
244 | |
245 // Invoked by the listener at test end to dump the collected log in case of | |
246 // error. | |
247 void TestLogCollector::ProcessSessionForTest( | |
248 const testing::TestInfo& test_info) { | |
249 if (file_logger_.is_logging()) { | |
250 file_logger_.StopLogging(); | |
251 | |
252 if (also_emit_success_logs_ || test_info.result()->Failed()) { | |
253 std::cerr << "----- log messages for " | |
254 << test_info.test_case_name() << "." << test_info.name() | |
255 << " above this line are repeated below -----" << std::endl; | |
256 // Dump the log to stderr. | |
257 file_logger_.DumpLogFile(log_file_, std::cerr); | |
258 } | |
259 | |
260 if (!file_util::Delete(log_file_, false)) | |
261 LOG(ERROR) << "Failed to delete log file " << log_file_.value(); | |
262 } | |
263 | |
264 log_file_.clear(); | |
265 } | |
266 | |
267 // Invoked by the listener at test program end to shut down the logger and | |
268 // delete the temporary log directory. | |
269 void TestLogCollector::TearDown() { | |
270 file_logger_.Uninitialize(); | |
271 | |
272 (void) log_temp_dir_.Delete(); | |
robertshield
2012/03/02 22:37:41
(void)? I guess you did this because Delete() is m
grt (UTC plus 2)
2012/03/03 02:12:43
Awesome, thanks!
| |
273 } | |
274 | |
275 } // namespace | |
276 | |
277 void InstallTestLogCollector(testing::UnitTest* unit_test) { | |
278 // Must be called before running any tests. | |
279 DCHECK(unit_test); | |
280 DCHECK(!unit_test->current_test_case()); | |
281 | |
282 g_test_log_collector.Get().Initialize(unit_test); | |
283 } | |
OLD | NEW |