| OLD | NEW |
| (Empty) |
| 1 // Copyright 2007-2010 Google Inc. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 // ======================================================================== | |
| 15 | |
| 16 #include "omaha/testing/omaha_unittest.h" | |
| 17 #include <atlpath.h> | |
| 18 #include <atlstr.h> | |
| 19 #include "base/basictypes.h" | |
| 20 #include "omaha/base/app_util.h" | |
| 21 #include "omaha/base/debug.h" | |
| 22 #include "omaha/base/file.h" | |
| 23 #include "omaha/base/logging.h" | |
| 24 #include "omaha/base/omaha_version.h" | |
| 25 #include "omaha/base/scoped_any.h" | |
| 26 #include "omaha/base/vistautil.h" | |
| 27 #include "omaha/testing/unit_test.h" | |
| 28 | |
| 29 namespace omaha { | |
| 30 | |
| 31 namespace { | |
| 32 | |
| 33 // | |
| 34 // Subset of Google Test arguments. | |
| 35 // | |
| 36 const TCHAR* const kUnitTestBreakOnFailure = _T("--gtest_break_on_failure"); | |
| 37 const TCHAR* const kUnitTestFilter = _T("--gtest_filter"); | |
| 38 const TCHAR* const kUnitTestListTests = _T("--gtest_list_tests"); | |
| 39 | |
| 40 // | |
| 41 // Omaha-specifc arguments. | |
| 42 // | |
| 43 const TCHAR* const kOmahaArgIsBuildSystem = _T("--omaha_buildsystem"); | |
| 44 const TCHAR* const kOmahaArgPsexecDir = _T("--omaha_psexec_dir"); | |
| 45 // Only use kOmahaArgAcceptPsexecEula for automated testing when you have | |
| 46 // already read and agreed to the EULA terms. | |
| 47 // If present both are present, kOmahaArgAcceptPsexecEula must appear after | |
| 48 // kOmahaArgPsexecDir on the command line. | |
| 49 const TCHAR* const kOmahaArgAcceptPsexecEula = _T("--omaha_accept_psexec_eula"); | |
| 50 | |
| 51 // Logs the start, end, and failures of each test in the Omaha log. | |
| 52 // TODO(omaha): Consider adding a logging category for tests. | |
| 53 class TestLogger : public ::testing::EmptyTestEventListener { | |
| 54 // Called before a test starts. | |
| 55 virtual void OnTestStart(const ::testing::TestInfo& test_info) { | |
| 56 OPT_LOG(L3, (_T("*** TEST %s.%s starting."), | |
| 57 CString(CA2W(test_info.test_case_name())), | |
| 58 CString(CA2W(test_info.name())))); | |
| 59 } | |
| 60 | |
| 61 // Called after a failed assertion or a SUCCESS(). | |
| 62 virtual void OnTestPartResult( | |
| 63 const ::testing::TestPartResult& test_part_result) { | |
| 64 OPT_LOG(L3, (_T("%s in %s:%d\n%s"), | |
| 65 (test_part_result.failed() ? _T("*** TEST Failure") : | |
| 66 _T("TEST Success")), | |
| 67 CString(CA2W(test_part_result.file_name())), | |
| 68 test_part_result.line_number(), | |
| 69 CString(CA2W(test_part_result.summary())))); | |
| 70 } | |
| 71 | |
| 72 // Called after a test ends. | |
| 73 virtual void OnTestEnd(const ::testing::TestInfo& test_info) { | |
| 74 OPT_LOG(L3, (_T("*** TEST %s.%s ending."), | |
| 75 CString(CA2W(test_info.test_case_name())), | |
| 76 CString(CA2W(test_info.name())))); | |
| 77 } | |
| 78 }; | |
| 79 | |
| 80 void LogCommandLineAndEnvironment(int argc, TCHAR** argv) { | |
| 81 ASSERT1(1 <= argc); | |
| 82 ASSERT1(argv); | |
| 83 | |
| 84 CString command_line = argv[0]; | |
| 85 for (int i = 1; i < argc; ++i) { | |
| 86 command_line.AppendFormat(_T(" %s"), argv[i]); | |
| 87 } | |
| 88 OPT_LOG(L1, (_T("[Omaha unit test command line][%s]"), command_line)); | |
| 89 | |
| 90 TCHAR* env_vars = ::GetEnvironmentStrings(); | |
| 91 if (env_vars == NULL) { | |
| 92 ASSERT1(false); | |
| 93 return; | |
| 94 } | |
| 95 | |
| 96 // Iterate through the environment variables string. The format of the string | |
| 97 // is Name1=Value1\0Name2=Value2\0Name3=Value3\0\0. | |
| 98 const TCHAR* const kPartialMatchToIgnore = _T("PASSW"); | |
| 99 const TCHAR* current = env_vars; | |
| 100 CString environment_variables; | |
| 101 while (*current) { | |
| 102 size_t sub_length = _tcslen(current) + 1; | |
| 103 if (!_tcsstr(current, kPartialMatchToIgnore)) { | |
| 104 environment_variables.AppendFormat(_T("\t%s\r\n"), current); | |
| 105 } | |
| 106 current += sub_length; | |
| 107 } | |
| 108 | |
| 109 OPT_LOG(L3, (_T("[Omaha unit test environment][\r\n%s]"), | |
| 110 environment_variables)); | |
| 111 } | |
| 112 | |
| 113 // Sets values based on environment variables. | |
| 114 void ProcessEnvironmentVariables() { | |
| 115 if (IsEnvironmentVariableSet(_T("OMAHA_TEST_BUILD_SYSTEM"))) { | |
| 116 SetIsBuildSystem(); | |
| 117 } | |
| 118 | |
| 119 TCHAR psexec_dir[MAX_PATH] = {0}; | |
| 120 if (::GetEnvironmentVariable(_T("OMAHA_PSEXEC_DIR"), | |
| 121 psexec_dir, | |
| 122 arraysize(psexec_dir))) { | |
| 123 SetPsexecDir(psexec_dir); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 bool ParseOmahaArgPsexecDir(const CString& arg) { | |
| 128 CString psexec_dir_arg_begin; | |
| 129 psexec_dir_arg_begin.Format(_T("%s="), kOmahaArgPsexecDir); | |
| 130 | |
| 131 if (arg.Left(psexec_dir_arg_begin.GetLength()) != psexec_dir_arg_begin) { | |
| 132 return false; | |
| 133 } | |
| 134 | |
| 135 SetPsexecDir(arg.Mid(psexec_dir_arg_begin.GetLength())); | |
| 136 return true; | |
| 137 } | |
| 138 | |
| 139 // Must be called after ParseOmahaArgPsexecDir(). | |
| 140 bool ParseOmahaArgAcceptPsexecEula(const TCHAR* arg) { | |
| 141 ASSERT1(arg); | |
| 142 if (_tcsicmp(arg, kOmahaArgAcceptPsexecEula)) { | |
| 143 return false; | |
| 144 } | |
| 145 | |
| 146 EXPECT_TRUE(AcceptPsexecEula()) | |
| 147 << _T("Make sure '") << kOmahaArgPsexecDir << _T("' appears after '") | |
| 148 << kOmahaArgAcceptPsexecEula << _T("' on the command line and that ") | |
| 149 << _T("psexec.exe is in the specified location."); | |
| 150 return true; | |
| 151 } | |
| 152 | |
| 153 bool ParseOmahaArgIsBuildMachine(const TCHAR* arg) { | |
| 154 ASSERT1(arg); | |
| 155 if (_tcsicmp(arg, kOmahaArgIsBuildSystem)) { | |
| 156 return false; | |
| 157 } | |
| 158 SetIsBuildSystem(); | |
| 159 return true; | |
| 160 } | |
| 161 | |
| 162 // Parse args. Print help message if invalid arguments. | |
| 163 bool ParseUnitTestArgs(int argc, TCHAR** argv) { | |
| 164 testing::InitGoogleTest(&argc, argv); | |
| 165 | |
| 166 if (argc > 1) { | |
| 167 // One or more args were unparsed by the Google Test parser. Handle | |
| 168 // Omaha-specific arguments that may be present. Code is based on | |
| 169 // ParseGoogleTestFlagsOnlyImpl. | |
| 170 for (int i = 1; i < argc; i++) { | |
| 171 if (ParseOmahaArgPsexecDir(argv[i]) || | |
| 172 ParseOmahaArgAcceptPsexecEula(argv[i]) || | |
| 173 ParseOmahaArgIsBuildMachine(argv[i])) { | |
| 174 // Yes. Shift the remainder of the argv list left by one. Note | |
| 175 // that argv has (*argc + 1) elements, the last one always being | |
| 176 // NULL. The following loop moves the trailing NULL element as | |
| 177 // well. | |
| 178 for (int j = i; j != argc; j++) { | |
| 179 argv[j] = argv[j + 1]; | |
| 180 } | |
| 181 | |
| 182 // Decrements the argument count. | |
| 183 argc--; | |
| 184 | |
| 185 // We also need to decrement the iterator as we just removed | |
| 186 // an element. | |
| 187 i--; | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 if (argc <= 1) { | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 _tprintf(_T("ERROR: Invalid Command line!\n"), argv[1]); | |
| 197 _tprintf(_T(" First invalid command option: %s\n\n"), argv[1]); | |
| 198 _tprintf(_T("Valid options:\n")); | |
| 199 _tprintf(_T("%25s Cause an av when a test fails (for use with debugger)\n"), | |
| 200 kUnitTestBreakOnFailure); | |
| 201 _tprintf(_T("%25s Sets a filter on the unit tests.\n") | |
| 202 _T("%25s Format: %s=Filter[:Filter] where\n") | |
| 203 _T("%25s Filter is TestCase[.Test] and * is a wildcard.\n"), | |
| 204 kUnitTestFilter, _T(""), kUnitTestFilter, _T("")); | |
| 205 _tprintf(_T("%25s Lists all tests\n"), | |
| 206 kUnitTestListTests); | |
| 207 return false; | |
| 208 } | |
| 209 | |
| 210 } // namespace | |
| 211 | |
| 212 // If a test launches or checks other processes, uses shared resources, or uses | |
| 213 // the network, it is a medium or larger test. | |
| 214 // COM is always initialized. | |
| 215 int RunTests(bool is_medium_or_large_test, | |
| 216 bool load_resources, | |
| 217 int argc, | |
| 218 TCHAR** argv) { | |
| 219 ASSERT1(!is_medium_or_large_test || load_resources); | |
| 220 | |
| 221 // TODO(omaha): Add executable name. | |
| 222 OPT_LOG(L1, (_T("[Starting Omaha unit tests]"))); | |
| 223 LogCommandLineAndEnvironment(argc, argv); | |
| 224 | |
| 225 // Process the environment variables before the args to allow the args to take | |
| 226 // precedence. | |
| 227 ProcessEnvironmentVariables(); | |
| 228 | |
| 229 if (!ParseUnitTestArgs(argc, argv)) { | |
| 230 return -1; | |
| 231 } | |
| 232 FailOnAssert fail_on_assert; | |
| 233 | |
| 234 InitializeVersionFromModule(NULL); | |
| 235 | |
| 236 scoped_co_init co_init(COINIT_MULTITHREADED); | |
| 237 VERIFY1(SUCCEEDED(co_init.hresult())); | |
| 238 | |
| 239 const bool is_build_system = IsBuildSystem(); | |
| 240 | |
| 241 if (is_build_system) { | |
| 242 // Some tests only run as admin. We want to know if the build system is no | |
| 243 // longer running unit tests as admin. | |
| 244 if (!vista_util::IsUserAdmin()) { | |
| 245 _tprintf(_T("\nUser is not an admin. All tests may not run.\n")); | |
| 246 } | |
| 247 | |
| 248 // TODO(omaha): Remove this and the app_util.h, file.h, and atlpath.h | |
| 249 // includes once the test system does this for us. | |
| 250 const TCHAR* const kDllRequiredForCoverageRuns = _T("VSCover80.dll"); | |
| 251 CPath source_path(app_util::GetCurrentModuleDirectory()); | |
| 252 source_path.Append(kDllRequiredForCoverageRuns); | |
| 253 if (File::Exists(source_path)) { | |
| 254 CPath target_path(app_util::GetSystemDir()); | |
| 255 target_path.Append(kDllRequiredForCoverageRuns); | |
| 256 _tprintf(_T("\nCopying '%s' to '%s'.\n"), source_path, target_path); | |
| 257 VERIFY1(SUCCEEDED(File::Copy(source_path, target_path, false))); | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 if (is_medium_or_large_test) { | |
| 262 TerminateAllGoogleUpdateProcesses(); | |
| 263 } | |
| 264 | |
| 265 int result = InitializeNetwork(); | |
| 266 if (result) { | |
| 267 return result; | |
| 268 } | |
| 269 | |
| 270 if (load_resources) { | |
| 271 // Load a resource DLL so that strings can be loaded during tests and add it | |
| 272 // to the list of modules used for CString.LoadString and CreateDialog | |
| 273 // calls. The unittest executable includes unittest-specific resources. | |
| 274 HMODULE resource_dll = ::LoadLibraryEx(_T("goopdateres_en.dll"), | |
| 275 NULL, | |
| 276 LOAD_LIBRARY_AS_DATAFILE); | |
| 277 ASSERT1(resource_dll); | |
| 278 _AtlBaseModule.AddResourceInstance(resource_dll); | |
| 279 } | |
| 280 | |
| 281 // A COM module is required to create COM objects. | |
| 282 // Create it regardless of whether COM is actually used by this executable. | |
| 283 CComModule module; | |
| 284 | |
| 285 // Add an event listener. Google Test takes the ownership. | |
| 286 ::testing::TestEventListeners& listeners = | |
| 287 ::testing::UnitTest::GetInstance()->listeners(); | |
| 288 listeners.Append(new TestLogger); | |
| 289 | |
| 290 result = RUN_ALL_TESTS(); | |
| 291 | |
| 292 DeinitializeNetwork(); | |
| 293 | |
| 294 if (is_build_system && is_medium_or_large_test) { | |
| 295 TerminateAllGoogleUpdateProcesses(); | |
| 296 } | |
| 297 | |
| 298 return result; | |
| 299 } | |
| 300 | |
| 301 int g_assert_count = 0; | |
| 302 | |
| 303 } // namespace omaha | |
| OLD | NEW |