Chromium Code Reviews| 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 |