1 // Copyright (c) 2009 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 #ifndef BASE_TEST_TEST_SUITE_H_ 6 #define BASE_TEST_TEST_SUITE_H_ 7 8 // Defines a basic test suite framework for running gtest based tests. You can 9 // instantiate this class in your main function and call its Run method to run 10 // any gtest based tests that are linked into your executable. 11 12 #include "base/at_exit.h" 13 #include "base/base_paths.h" 14 #include "base/debug_on_start.h" 15 #include "base/i18n/icu_util.h" 16 #include "base/multiprocess_test.h" 17 #include "base/nss_util.h" 18 #include "base/path_service.h" 19 #include "base/process_util.h" 20 #include "base/scoped_nsautorelease_pool.h" 21 #include "base/scoped_ptr.h" 22 #include "base/time.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/multiprocess_func_list.h" 25 26 #if defined(OS_POSIX) && !defined(OS_MACOSX) 27 #include <gtk/gtk.h> 28 #endif 29 30 // Match function used by the GetTestCount method. 31 typedef bool (*TestMatch)(const testing::TestInfo&); 32 33 // By setting up a shadow AtExitManager, this test event listener ensures that 34 // no state is carried between tests (like singletons, lazy instances, etc). 35 // Of course it won't help if the code under test corrupts memory. 36 class TestIsolationEnforcer : public testing::EmptyTestEventListener { 37 public: OnTestStart(const testing::TestInfo & test_info)38 virtual void OnTestStart(const testing::TestInfo& test_info) { 39 ASSERT_FALSE(exit_manager_.get()); 40 exit_manager_.reset(new base::ShadowingAtExitManager()); 41 } 42 OnTestEnd(const testing::TestInfo & test_info)43 virtual void OnTestEnd(const testing::TestInfo& test_info) { 44 ASSERT_TRUE(exit_manager_.get()); 45 exit_manager_.reset(); 46 } 47 48 private: 49 scoped_ptr<base::ShadowingAtExitManager> exit_manager_; 50 }; 51 52 class TestSuite { 53 public: TestSuite(int argc,char ** argv)54 TestSuite(int argc, char** argv) { 55 base::EnableTerminationOnHeapCorruption(); 56 CommandLine::Init(argc, argv); 57 testing::InitGoogleTest(&argc, argv); 58 #if defined(OS_POSIX) && !defined(OS_MACOSX) 59 g_thread_init(NULL); 60 gtk_init_check(&argc, &argv); 61 #endif // defined(OS_LINUX) 62 // Don't add additional code to this constructor. Instead add it to 63 // Initialize(). See bug 6436. 64 } 65 ~TestSuite()66 virtual ~TestSuite() { 67 CommandLine::Reset(); 68 } 69 70 // Returns true if a string starts with FLAKY_. IsFlaky(const char * name)71 static bool IsFlaky(const char* name) { 72 return strncmp(name, "FLAKY_", 6) == 0; 73 } 74 75 // Returns true if the test is marked as flaky. FlakyTest(const testing::TestInfo & test)76 static bool FlakyTest(const testing::TestInfo& test) { 77 return IsFlaky(test.name()) || IsFlaky(test.test_case_name()); 78 } 79 80 // Returns true if the test failed and is not marked as flaky. NonFlakyFailures(const testing::TestInfo & test)81 static bool NonFlakyFailures(const testing::TestInfo& test) { 82 return test.should_run() && test.result()->Failed() && !FlakyTest(test); 83 } 84 85 // Returns the number of tests where the match function returns true. GetTestCount(TestMatch test_match)86 int GetTestCount(TestMatch test_match) { 87 testing::UnitTest* instance = testing::UnitTest::GetInstance(); 88 int count = 0; 89 90 for (int i = 0; i < instance->total_test_case_count(); ++i) { 91 const testing::TestCase& test_case = *instance->GetTestCase(i); 92 for (int j = 0; j < test_case.total_test_count(); ++j) { 93 if (test_match(*test_case.GetTestInfo(j))) { 94 count++; 95 } 96 } 97 } 98 99 return count; 100 } 101 102 // TODO(phajdan.jr): Enforce isolation for all tests once it's stable. EnforceTestIsolation()103 void EnforceTestIsolation() { 104 testing::TestEventListeners& listeners = 105 testing::UnitTest::GetInstance()->listeners(); 106 listeners.Append(new TestIsolationEnforcer); 107 } 108 109 // Don't add additional code to this method. Instead add it to 110 // Initialize(). See bug 6436. Run()111 int Run() { 112 base::ScopedNSAutoreleasePool scoped_pool; 113 114 Initialize(); 115 std::wstring client_func = 116 CommandLine::ForCurrentProcess()->GetSwitchValue(kRunClientProcess); 117 // Check to see if we are being run as a client process. 118 if (!client_func.empty()) { 119 // Convert our function name to a usable string for GetProcAddress. 120 std::string func_name(client_func.begin(), client_func.end()); 121 122 return multi_process_function_list::InvokeChildProcessTest(func_name); 123 } 124 int result = RUN_ALL_TESTS(); 125 126 // Reset the result code if only flaky test failed. 127 if (result != 0 && GetTestCount(&TestSuite::NonFlakyFailures) == 0) { 128 result = 0; 129 } 130 131 // Display the number of flaky tests. 132 int flaky_count = GetTestCount(&TestSuite::FlakyTest); 133 if (flaky_count) { 134 printf(" YOU HAVE %d FLAKY %s\n\n", flaky_count, 135 flaky_count == 1 ? "TEST" : "TESTS"); 136 } 137 138 // This MUST happen before Shutdown() since Shutdown() tears down 139 // objects (such as NotificationService::current()) that Cocoa 140 // objects use to remove themselves as observers. 141 scoped_pool.Recycle(); 142 143 Shutdown(); 144 145 return result; 146 } 147 148 protected: 149 #if defined(OS_WIN) 150 // TODO(phajdan.jr): Clean up the windows-specific hacks. 151 // See http://crbug.com/29997 152 153 // By default, base::LogMessage::~LogMessage calls DebugUtil::BreakDebugger() 154 // when severity is LOG_FATAL. On Windows, this results in error dialogs 155 // which are not friendly to buildbots. 156 // To avoid these problems, we override the LogMessage behaviour by 157 // replacing the assert handler with UnitTestAssertHandler. UnitTestAssertHandler(const std::string & str)158 static void UnitTestAssertHandler(const std::string& str) { 159 // FAIL is a googletest macro, it marks the current test as failed. 160 // If throw_on_failure is set to true, it also ends the process. 161 ::testing::FLAGS_gtest_throw_on_failure = true; 162 FAIL() << str; 163 } 164 165 // Disable crash dialogs so that it doesn't gum up the buildbot SuppressErrorDialogs()166 virtual void SuppressErrorDialogs() { 167 UINT new_flags = SEM_FAILCRITICALERRORS | 168 SEM_NOGPFAULTERRORBOX | 169 SEM_NOOPENFILEERRORBOX; 170 171 // Preserve existing error mode, as discussed at 172 // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx 173 UINT existing_flags = SetErrorMode(new_flags); 174 SetErrorMode(existing_flags | new_flags); 175 } 176 #endif // defined(OS_WIN) 177 178 // Override these for custom initialization and shutdown handling. Use these 179 // instead of putting complex code in your constructor/destructor. 180 Initialize()181 virtual void Initialize() { 182 // Initialize logging. 183 FilePath exe; 184 PathService::Get(base::FILE_EXE, &exe); 185 FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log")); 186 logging::InitLogging(log_filename.value().c_str(), 187 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, 188 logging::LOCK_LOG_FILE, 189 logging::DELETE_OLD_LOG_FILE); 190 // We want process and thread IDs because we may have multiple processes. 191 // Note: temporarily enabled timestamps in an effort to catch bug 6361. 192 logging::SetLogItems(true, true, true, true); 193 194 CHECK(base::EnableInProcessStackDumping()); 195 #if defined(OS_WIN) 196 // Make sure we run with high resolution timer to minimize differences 197 // between production code and test code. 198 bool result = base::Time::UseHighResolutionTimer(true); 199 CHECK(result); 200 201 // In some cases, we do not want to see standard error dialogs. 202 if (!IsDebuggerPresent() && 203 !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) { 204 SuppressErrorDialogs(); 205 #if !defined(PURIFY) 206 // When the code in this file moved around, bug 6436 resurfaced. 207 // As a hack workaround, just #ifdef out this code for Purify builds. 208 logging::SetLogAssertHandler(UnitTestAssertHandler); 209 #endif // !defined(PURIFY) 210 } 211 #endif // defined(OS_WIN) 212 213 icu_util::Initialize(); 214 215 #if defined(USE_NSS) 216 // Trying to repeatedly initialize and cleanup NSS and NSPR may result in 217 // a deadlock. Such repeated initialization will happen when using test 218 // isolation. Prevent problems by initializing NSS here, so that the cleanup 219 // will be done only on process exit. 220 base::EnsureNSSInit(); 221 #endif // defined(USE_NSS) 222 } 223 Shutdown()224 virtual void Shutdown() { 225 } 226 227 // Make sure that we setup an AtExitManager so Singleton objects will be 228 // destroyed. 229 base::AtExitManager at_exit_manager_; 230 }; 231 232 #endif // BASE_TEST_TEST_SUITE_H_ 233