| 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 <fstream> | |
| 6 #include <string> | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "base/command_line.h" | |
| 10 #include "base/environment.h" | |
| 11 #include "base/file_util.h" | |
| 12 #include "base/file_version_info.h" | |
| 13 #include "base/files/file_enumerator.h" | |
| 14 #include "base/files/file_path.h" | |
| 15 #include "base/i18n/time_formatting.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/path_service.h" | |
| 18 #include "base/rand_util.h" | |
| 19 #include "base/strings/string_number_conversions.h" | |
| 20 #include "base/strings/string_split.h" | |
| 21 #include "base/strings/string_util.h" | |
| 22 #include "base/strings/stringprintf.h" | |
| 23 #include "base/threading/platform_thread.h" | |
| 24 #include "base/time/time.h" | |
| 25 #include "chrome/app/chrome_command_ids.h" | |
| 26 #include "chrome/browser/browser_process.h" | |
| 27 #include "chrome/browser/character_encoding.h" | |
| 28 #include "chrome/browser/ui/view_ids.h" | |
| 29 #include "chrome/common/chrome_paths.h" | |
| 30 #include "chrome/common/chrome_version_info.h" | |
| 31 #include "chrome/common/env_vars.h" | |
| 32 #include "chrome/common/url_constants.h" | |
| 33 #include "chrome/test/automation/automation_proxy.h" | |
| 34 #include "chrome/test/automation/browser_proxy.h" | |
| 35 #include "chrome/test/automation/tab_proxy.h" | |
| 36 #include "chrome/test/automation/window_proxy.h" | |
| 37 #include "chrome/test/reliability/automated_ui_tests.h" | |
| 38 #include "chrome/test/ui/ui_test.h" | |
| 39 #include "ui/events/keycodes/keyboard_codes.h" | |
| 40 #include "url/gurl.h" | |
| 41 | |
| 42 #if defined(TOOLKIT_VIEWS) | |
| 43 #include "ui/views/view.h" | |
| 44 #endif | |
| 45 | |
| 46 namespace { | |
| 47 | |
| 48 const char kReproSwitch[] = "key"; | |
| 49 | |
| 50 const char kReproRepeatSwitch[] = "num-reproductions"; | |
| 51 | |
| 52 const char kInputFilePathSwitch[] = "input"; | |
| 53 | |
| 54 const char kOutputFilePathSwitch[] = "output"; | |
| 55 | |
| 56 const char kDebugModeSwitch[] = "debug"; | |
| 57 | |
| 58 const char kWaitSwitch[] = "wait-after-action"; | |
| 59 | |
| 60 const char kTestLogFilePathSwitch[] = "testlog"; | |
| 61 | |
| 62 const base::FilePath::CharType* const kDefaultInputFilePath = | |
| 63 FILE_PATH_LITERAL("automated_ui_tests.txt"); | |
| 64 | |
| 65 const base::FilePath::CharType* const kDefaultOutputFilePath = | |
| 66 FILE_PATH_LITERAL("automated_ui_tests_error_report.txt"); | |
| 67 | |
| 68 const base::FilePath::CharType* const kDefaultTestLogFilePath = | |
| 69 FILE_PATH_LITERAL("automated_ui_tests_log.txt"); | |
| 70 | |
| 71 const int kDebuggingTimeoutMsec = 5000; | |
| 72 | |
| 73 // How many commands to run when testing a dialog box. | |
| 74 const int kTestDialogActionsToRun = 7; | |
| 75 | |
| 76 // String name of local chrome dll for looking up file information. | |
| 77 const wchar_t kChromeDll[] = L"chrome.dll"; | |
| 78 | |
| 79 void SilentRuntimeReportHandler(const std::string& str) { | |
| 80 } | |
| 81 | |
| 82 base::FilePath GetInputFilePath() { | |
| 83 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 84 if (parsed_command_line.HasSwitch(kInputFilePathSwitch)) { | |
| 85 return parsed_command_line.GetSwitchValuePath(kInputFilePathSwitch); | |
| 86 } else { | |
| 87 return base::FilePath(kDefaultInputFilePath); | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 base::FilePath GetOutputFilePath() { | |
| 92 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 93 if (parsed_command_line.HasSwitch(kOutputFilePathSwitch)) { | |
| 94 return parsed_command_line.GetSwitchValuePath(kOutputFilePathSwitch); | |
| 95 } else { | |
| 96 return base::FilePath(kDefaultOutputFilePath); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 base::FilePath GetTestLogFilePath() { | |
| 101 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 102 if (parsed_command_line.HasSwitch(kTestLogFilePathSwitch)) { | |
| 103 return parsed_command_line.GetSwitchValuePath(kTestLogFilePathSwitch); | |
| 104 } else { | |
| 105 return base::FilePath(kDefaultTestLogFilePath); | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 std::string GetChromeRevision() { | |
| 110 // Get Chrome version | |
| 111 std::string last_change; | |
| 112 #if defined(OS_WIN) | |
| 113 // Check file version info for chrome dll. | |
| 114 scoped_ptr<FileVersionInfo> file_info; | |
| 115 file_info.reset( | |
| 116 FileVersionInfo::CreateFileVersionInfo(base::FilePath(kChromeDll))); | |
| 117 last_change = WideToASCII(file_info->last_change()); | |
| 118 #elif defined(OS_POSIX) | |
| 119 chrome::VersionInfo version_info; | |
| 120 last_change = version_info.LastChange(); | |
| 121 #endif // !defined(OS_WIN) | |
| 122 return last_change; | |
| 123 } | |
| 124 | |
| 125 void InitTestLog(base::Time start_time) { | |
| 126 base::FilePath path = GetTestLogFilePath(); | |
| 127 std::ofstream test_log_file; | |
| 128 if (!path.empty()) | |
| 129 test_log_file.open(path.value().c_str(), std::ios::out); | |
| 130 | |
| 131 const std::string time = | |
| 132 UTF16ToASCII(base::TimeFormatFriendlyDateAndTime(start_time)); | |
| 133 | |
| 134 test_log_file << "Last Change: " << GetChromeRevision() << std::endl; | |
| 135 test_log_file << "Test Start: " << time << std::endl; | |
| 136 test_log_file.close(); | |
| 137 } | |
| 138 | |
| 139 void AppendToTestLog(const std::string& append_string) { | |
| 140 base::FilePath path = GetTestLogFilePath(); | |
| 141 std::ofstream test_log_file; | |
| 142 if (!path.empty()) { | |
| 143 test_log_file.open(path.value().c_str(), | |
| 144 std::ios::out | std::ios_base::app); | |
| 145 } | |
| 146 | |
| 147 test_log_file << append_string << std::endl; | |
| 148 test_log_file.close(); | |
| 149 } | |
| 150 | |
| 151 double CalculateTestDuration(base::Time start_time) { | |
| 152 base::Time time_now = base::Time::Now(); | |
| 153 return time_now.ToDoubleT() - start_time.ToDoubleT(); | |
| 154 } | |
| 155 | |
| 156 } // namespace | |
| 157 | |
| 158 // This subset of commands is used to test dialog boxes, which aren't likely | |
| 159 // to respond to most other commands. | |
| 160 const std::string kTestDialogPossibleActions[] = { | |
| 161 // See FuzzyTestDialog for details on why Enter and SpaceBar must appear first | |
| 162 // in this list. | |
| 163 "PressEnterKey", | |
| 164 "PressSpaceBar", | |
| 165 "PressTabKey", | |
| 166 "DownArrow" | |
| 167 }; | |
| 168 | |
| 169 // The list of dialogs that can be shown. | |
| 170 const std::string kDialogs[] = { | |
| 171 "About", | |
| 172 "Options", | |
| 173 "TaskManager", | |
| 174 "JavaScriptConsole", | |
| 175 "ClearBrowsingData", | |
| 176 "ImportSettings", | |
| 177 "EditSearchEngines", | |
| 178 "ViewPasswords" | |
| 179 }; | |
| 180 | |
| 181 AutomatedUITest::AutomatedUITest() | |
| 182 : test_start_time_(base::Time::NowFromSystemTime()), | |
| 183 total_crashes_(0), | |
| 184 debug_logging_enabled_(false), | |
| 185 post_action_delay_(0) { | |
| 186 show_window_ = true; | |
| 187 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 188 if (parsed_command_line.HasSwitch(kDebugModeSwitch)) | |
| 189 debug_logging_enabled_ = true; | |
| 190 if (parsed_command_line.HasSwitch(kWaitSwitch)) { | |
| 191 std::string str = parsed_command_line.GetSwitchValueASCII(kWaitSwitch); | |
| 192 if (str.empty()) { | |
| 193 post_action_delay_ = 1; | |
| 194 } else { | |
| 195 base::StringToInt(str, &post_action_delay_); | |
| 196 } | |
| 197 } | |
| 198 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
| 199 if (env->HasVar(env_vars::kHeadless)) | |
| 200 logging::SetLogReportHandler(SilentRuntimeReportHandler); | |
| 201 } | |
| 202 | |
| 203 AutomatedUITest::~AutomatedUITest() {} | |
| 204 | |
| 205 void AutomatedUITest::RunReproduction() { | |
| 206 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 207 | |
| 208 InitTestLog(test_start_time_); | |
| 209 xml_writer_.StartWriting(); | |
| 210 xml_writer_.StartElement("Report"); | |
| 211 std::string action_string = | |
| 212 parsed_command_line.GetSwitchValueASCII(kReproSwitch); | |
| 213 | |
| 214 int64 num_reproductions = 1; | |
| 215 if (parsed_command_line.HasSwitch(kReproRepeatSwitch)) { | |
| 216 base::StringToInt64( | |
| 217 parsed_command_line.GetSwitchValueASCII(kReproRepeatSwitch), | |
| 218 &num_reproductions); | |
| 219 } | |
| 220 std::vector<std::string> actions; | |
| 221 base::SplitString(action_string, ',', &actions); | |
| 222 bool did_crash = false; | |
| 223 bool command_complete = false; | |
| 224 | |
| 225 for (int64 i = 0; i < num_reproductions && !did_crash; ++i) { | |
| 226 bool did_teardown = false; | |
| 227 xml_writer_.StartElement("Executed"); | |
| 228 for (size_t j = 0; j < actions.size(); ++j) { | |
| 229 DoAction(actions[j]); | |
| 230 if (DidCrash(true)) { | |
| 231 did_crash = true; | |
| 232 if (j >= (actions.size() - 1)) | |
| 233 command_complete = true; | |
| 234 break; | |
| 235 } | |
| 236 if (LowerCaseEqualsASCII(actions[j], "teardown")) | |
| 237 did_teardown = true; | |
| 238 } | |
| 239 | |
| 240 // Force proper teardown after each run, if it didn't already happen. But | |
| 241 // don't teardown after crashes. | |
| 242 if (!did_teardown && !did_crash) | |
| 243 DoAction("TearDown"); | |
| 244 | |
| 245 xml_writer_.EndElement(); // End "Executed" element. | |
| 246 } | |
| 247 | |
| 248 if (did_crash) { | |
| 249 base::FilePath crash_dump = GetMostRecentCrashDump(); | |
| 250 base::FilePath::StringType result = | |
| 251 FILE_PATH_LITERAL("*** Crash dump produced. ") | |
| 252 FILE_PATH_LITERAL("See result file for more details. Dump = "); | |
| 253 result.append(crash_dump.value()); | |
| 254 result.append(FILE_PATH_LITERAL(" ***\n")); | |
| 255 printf("%s", result.c_str()); | |
| 256 LogCrashResult(crash_dump, command_complete); | |
| 257 EXPECT_TRUE(false) << "Crash detected."; | |
| 258 } else { | |
| 259 printf("*** No crashes. See result file for more details. ***\n"); | |
| 260 LogSuccessResult(); | |
| 261 } | |
| 262 | |
| 263 AppendToTestLog(base::StringPrintf("total_duration_seconds=%f", | |
| 264 CalculateTestDuration(test_start_time_))); | |
| 265 WriteReportToFile(); | |
| 266 } | |
| 267 | |
| 268 | |
| 269 void AutomatedUITest::RunAutomatedUITest() { | |
| 270 InitTestLog(test_start_time_); | |
| 271 | |
| 272 ASSERT_TRUE(InitXMLReader()) << "Error initializing XMLReader"; | |
| 273 xml_writer_.StartWriting(); | |
| 274 xml_writer_.StartElement("Report"); | |
| 275 | |
| 276 while (init_reader_.Read()) { | |
| 277 init_reader_.SkipToElement(); | |
| 278 std::string node_name = init_reader_.NodeName(); | |
| 279 if (LowerCaseEqualsASCII(node_name, "command")) { | |
| 280 bool no_errors = true; | |
| 281 xml_writer_.StartElement("Executed"); | |
| 282 std::string command_number; | |
| 283 if (init_reader_.NodeAttribute("number", &command_number)) { | |
| 284 xml_writer_.AddAttribute("command_number", command_number); | |
| 285 } | |
| 286 xml_writer_.StopIndenting(); | |
| 287 | |
| 288 // Starts the browser, logging it as an action. | |
| 289 DoAction("SetUp"); | |
| 290 | |
| 291 // Record the depth of the root of the command subtree, then advance to | |
| 292 // the first element in preparation for parsing. | |
| 293 int start_depth = init_reader_.Depth(); | |
| 294 ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file."; | |
| 295 init_reader_.SkipToElement(); | |
| 296 | |
| 297 // Check for a crash right after startup. | |
| 298 if (DidCrash(true)) { | |
| 299 LogCrashResult(GetMostRecentCrashDump(), false); | |
| 300 // Try and start up again. | |
| 301 CloseBrowserAndServer(); | |
| 302 LaunchBrowserAndServer(); | |
| 303 set_active_browser(automation()->GetBrowserWindow(0).get()); | |
| 304 if (DidCrash(true)) { | |
| 305 no_errors = false; | |
| 306 // We crashed again, so skip to the end of the this command. | |
| 307 while (init_reader_.Depth() != start_depth) { | |
| 308 ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file."; | |
| 309 } | |
| 310 } else { | |
| 311 // We didn't crash, so end the old element, logging a crash for that. | |
| 312 // Then start a new element to log this command. | |
| 313 xml_writer_.StartIndenting(); | |
| 314 xml_writer_.EndElement(); | |
| 315 xml_writer_.StartElement("Executed"); | |
| 316 xml_writer_.AddAttribute("command_number", command_number); | |
| 317 xml_writer_.StopIndenting(); | |
| 318 xml_writer_.StartElement("SetUp"); | |
| 319 xml_writer_.EndElement(); | |
| 320 } | |
| 321 } | |
| 322 // Parse the command, performing the specified actions and checking | |
| 323 // for a crash after each one. | |
| 324 while (init_reader_.Depth() != start_depth) { | |
| 325 node_name = init_reader_.NodeName(); | |
| 326 | |
| 327 DoAction(node_name); | |
| 328 | |
| 329 // Advance to the next element | |
| 330 ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file."; | |
| 331 init_reader_.SkipToElement(); | |
| 332 if (DidCrash(true)) { | |
| 333 no_errors = false; | |
| 334 // This was the last action if we've returned to the initial depth | |
| 335 // of the command subtree. | |
| 336 bool wasLastAction = init_reader_.Depth() == start_depth; | |
| 337 LogCrashResult(GetMostRecentCrashDump(), wasLastAction); | |
| 338 // Skip to the beginning of the next command. | |
| 339 while (init_reader_.Depth() != start_depth) { | |
| 340 ASSERT_TRUE(init_reader_.Read()) << "Malformed XML file."; | |
| 341 } | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 if (no_errors) { | |
| 346 // If there were no previous crashes, log our tear down and check for | |
| 347 // a crash, log success for the entire command if this doesn't crash. | |
| 348 DoAction("TearDown"); | |
| 349 if (DidCrash(true)) | |
| 350 LogCrashResult(GetMostRecentCrashDump(), true); | |
| 351 else | |
| 352 LogSuccessResult(); | |
| 353 } else { | |
| 354 // If there was a previous crash, just tear down without logging, so | |
| 355 // that we know what the last command was before we crashed. | |
| 356 CloseBrowserAndServer(); | |
| 357 } | |
| 358 | |
| 359 xml_writer_.StartIndenting(); | |
| 360 xml_writer_.EndElement(); // End "Executed" element. | |
| 361 } | |
| 362 } | |
| 363 | |
| 364 AppendToTestLog(base::StringPrintf("total_duration_seconds=%f", | |
| 365 CalculateTestDuration(test_start_time_))); | |
| 366 | |
| 367 // The test is finished so write our report. | |
| 368 WriteReportToFile(); | |
| 369 } | |
| 370 | |
| 371 bool AutomatedUITest::DoAction(const std::string& action) { | |
| 372 bool did_complete_action = false; | |
| 373 xml_writer_.StartElement(action); | |
| 374 if (debug_logging_enabled_) | |
| 375 AppendToOutputFile(action); | |
| 376 | |
| 377 if (LowerCaseEqualsASCII(action, "about")) { | |
| 378 did_complete_action = OpenAboutDialog(); | |
| 379 } else if (LowerCaseEqualsASCII(action, "back")) { | |
| 380 did_complete_action = BackButton(); | |
| 381 } else if (LowerCaseEqualsASCII(action, "changeencoding")) { | |
| 382 did_complete_action = ChangeEncoding(); | |
| 383 } else if (LowerCaseEqualsASCII(action, "closetab")) { | |
| 384 did_complete_action = CloseActiveTab(); | |
| 385 } else if (LowerCaseEqualsASCII(action, "clearbrowsingdata")) { | |
| 386 did_complete_action = OpenClearBrowsingDataDialog(); | |
| 387 } else if (LowerCaseEqualsASCII(action, "crash")) { | |
| 388 did_complete_action = ForceCrash(); | |
| 389 } else if (LowerCaseEqualsASCII(action, "dialog")) { | |
| 390 did_complete_action = ExerciseDialog(); | |
| 391 } else if (LowerCaseEqualsASCII(action, "downloads")) { | |
| 392 did_complete_action = ShowDownloads(); | |
| 393 } else if (LowerCaseEqualsASCII(action, "duplicatetab")) { | |
| 394 did_complete_action = DuplicateTab(); | |
| 395 } else if (LowerCaseEqualsASCII(action, "editsearchengines")) { | |
| 396 did_complete_action = OpenEditSearchEnginesDialog(); | |
| 397 } else if (LowerCaseEqualsASCII(action, "findinpage")) { | |
| 398 did_complete_action = FindInPage(); | |
| 399 } else if (LowerCaseEqualsASCII(action, "forward")) { | |
| 400 did_complete_action = ForwardButton(); | |
| 401 } else if (LowerCaseEqualsASCII(action, "goofftherecord")) { | |
| 402 did_complete_action = GoOffTheRecord(); | |
| 403 } else if (LowerCaseEqualsASCII(action, "history")) { | |
| 404 did_complete_action = ShowHistory(); | |
| 405 } else if (LowerCaseEqualsASCII(action, "home")) { | |
| 406 did_complete_action = Home(); | |
| 407 } else if (LowerCaseEqualsASCII(action, "importsettings")) { | |
| 408 did_complete_action = OpenImportSettingsDialog(); | |
| 409 } else if (LowerCaseEqualsASCII(action, "javascriptconsole")) { | |
| 410 did_complete_action = JavaScriptConsole(); | |
| 411 } else if (LowerCaseEqualsASCII(action, "navigate")) { | |
| 412 std::string url = content::kAboutBlankURL; | |
| 413 if (init_reader_.NodeAttribute("url", &url)) { | |
| 414 xml_writer_.AddAttribute("url", url); | |
| 415 } | |
| 416 GURL test_url(url); | |
| 417 did_complete_action = Navigate(test_url); | |
| 418 } else if (LowerCaseEqualsASCII(action, "newtab")) { | |
| 419 did_complete_action = NewTab(); | |
| 420 } else if (LowerCaseEqualsASCII(action, "openwindow")) { | |
| 421 did_complete_action = OpenAndActivateNewBrowserWindow(NULL); | |
| 422 } else if (LowerCaseEqualsASCII(action, "options")) { | |
| 423 did_complete_action = Options(); | |
| 424 } else if (LowerCaseEqualsASCII(action, "reload")) { | |
| 425 did_complete_action = ReloadPage(); | |
| 426 } else if (LowerCaseEqualsASCII(action, "restoretab")) { | |
| 427 did_complete_action = RestoreTab(); | |
| 428 } else if (LowerCaseEqualsASCII(action, "selectnexttab")) { | |
| 429 did_complete_action = SelectNextTab(); | |
| 430 } else if (LowerCaseEqualsASCII(action, "selectprevtab")) { | |
| 431 did_complete_action = SelectPreviousTab(); | |
| 432 } else if (LowerCaseEqualsASCII(action, "setup")) { | |
| 433 AutomatedUITestBase::SetUp(); | |
| 434 did_complete_action = true; | |
| 435 } else if (LowerCaseEqualsASCII(action, "sleep")) { | |
| 436 // This is for debugging, it probably shouldn't be used real tests. | |
| 437 base::PlatformThread::Sleep( | |
| 438 base::TimeDelta::FromMilliseconds(kDebuggingTimeoutMsec)); | |
| 439 did_complete_action = true; | |
| 440 } else if (LowerCaseEqualsASCII(action, "star")) { | |
| 441 did_complete_action = StarPage(); | |
| 442 } else if (LowerCaseEqualsASCII(action, "taskmanager")) { | |
| 443 did_complete_action = OpenTaskManagerDialog(); | |
| 444 } else if (LowerCaseEqualsASCII(action, "teardown")) { | |
| 445 CloseBrowserAndServer(); | |
| 446 did_complete_action = true; | |
| 447 } else if (LowerCaseEqualsASCII(action, "testaboutchrome")) { | |
| 448 did_complete_action = TestAboutChrome(); | |
| 449 } else if (LowerCaseEqualsASCII(action, "testclearbrowsingdata")) { | |
| 450 did_complete_action = TestClearBrowsingData(); | |
| 451 } else if (LowerCaseEqualsASCII(action, "testeditsearchengines")) { | |
| 452 did_complete_action = TestEditSearchEngines(); | |
| 453 } else if (LowerCaseEqualsASCII(action, "testimportsettings")) { | |
| 454 did_complete_action = TestImportSettings(); | |
| 455 } else if (LowerCaseEqualsASCII(action, "testoptions")) { | |
| 456 did_complete_action = TestOptions(); | |
| 457 } else if (LowerCaseEqualsASCII(action, "testtaskmanager")) { | |
| 458 did_complete_action = TestTaskManager(); | |
| 459 } else if (LowerCaseEqualsASCII(action, "testviewpasswords")) { | |
| 460 did_complete_action = TestViewPasswords(); | |
| 461 } else if (LowerCaseEqualsASCII(action, "viewpasswords")) { | |
| 462 did_complete_action = OpenViewPasswordsDialog(); | |
| 463 } else if (LowerCaseEqualsASCII(action, "viewsource")) { | |
| 464 did_complete_action = ViewSource(); | |
| 465 } else if (LowerCaseEqualsASCII(action, "zoomplus")) { | |
| 466 did_complete_action = ZoomPlus(); | |
| 467 } else if (LowerCaseEqualsASCII(action, "zoomminus")) { | |
| 468 did_complete_action = ZoomMinus(); | |
| 469 } else { | |
| 470 NOTREACHED() << "Unknown command passed into DoAction: " | |
| 471 << action.c_str(); | |
| 472 } | |
| 473 | |
| 474 EXPECT_TRUE(did_complete_action) << action; | |
| 475 | |
| 476 if (!did_complete_action) | |
| 477 xml_writer_.AddAttribute("failed_to_complete", "yes"); | |
| 478 xml_writer_.EndElement(); | |
| 479 | |
| 480 if (post_action_delay_) { | |
| 481 base::PlatformThread::Sleep( | |
| 482 base::TimeDelta::FromSeconds(post_action_delay_)); | |
| 483 } | |
| 484 | |
| 485 return did_complete_action; | |
| 486 } | |
| 487 | |
| 488 bool AutomatedUITest::ChangeEncoding() { | |
| 489 // Get the encoding list that is used to populate the UI (encoding menu) | |
| 490 std::string cur_locale = g_browser_process->GetApplicationLocale(); | |
| 491 const std::vector<CharacterEncoding::EncodingInfo>* encodings = | |
| 492 CharacterEncoding::GetCurrentDisplayEncodings( | |
| 493 cur_locale, "ISO-8859-1,windows-1252", std::string()); | |
| 494 DCHECK(encodings); | |
| 495 DCHECK(!encodings->empty()); | |
| 496 unsigned len = static_cast<unsigned>(encodings->size()); | |
| 497 | |
| 498 // The vector will contain mostly IDC values for encoding commands plus a few | |
| 499 // menu separators (0 values). If we hit a separator we just retry. | |
| 500 int index = base::RandInt(0, len); | |
| 501 while ((*encodings)[index].encoding_id == 0) { | |
| 502 index = base::RandInt(0, len); | |
| 503 } | |
| 504 | |
| 505 return RunCommandAsync((*encodings)[index].encoding_id); | |
| 506 } | |
| 507 | |
| 508 bool AutomatedUITest::JavaScriptConsole() { | |
| 509 return RunCommandAsync(IDC_DEV_TOOLS); | |
| 510 } | |
| 511 | |
| 512 bool AutomatedUITest::OpenAboutDialog() { | |
| 513 return RunCommandAsync(IDC_ABOUT); | |
| 514 } | |
| 515 | |
| 516 bool AutomatedUITest::OpenClearBrowsingDataDialog() { | |
| 517 return RunCommandAsync(IDC_CLEAR_BROWSING_DATA); | |
| 518 } | |
| 519 | |
| 520 bool AutomatedUITest::OpenEditSearchEnginesDialog() { | |
| 521 return RunCommandAsync(IDC_EDIT_SEARCH_ENGINES); | |
| 522 } | |
| 523 | |
| 524 bool AutomatedUITest::OpenImportSettingsDialog() { | |
| 525 return RunCommandAsync(IDC_IMPORT_SETTINGS); | |
| 526 } | |
| 527 | |
| 528 bool AutomatedUITest::OpenTaskManagerDialog() { | |
| 529 return RunCommandAsync(IDC_TASK_MANAGER); | |
| 530 } | |
| 531 | |
| 532 bool AutomatedUITest::OpenViewPasswordsDialog() { | |
| 533 return RunCommandAsync(IDC_VIEW_PASSWORDS); | |
| 534 } | |
| 535 | |
| 536 bool AutomatedUITest::Options() { | |
| 537 return RunCommandAsync(IDC_OPTIONS); | |
| 538 } | |
| 539 | |
| 540 bool AutomatedUITest::StarPage() { | |
| 541 return RunCommandAsync(IDC_BOOKMARK_PAGE); | |
| 542 } | |
| 543 | |
| 544 bool AutomatedUITest::ViewSource() { | |
| 545 return RunCommandAsync(IDC_VIEW_SOURCE); | |
| 546 } | |
| 547 | |
| 548 bool AutomatedUITest::ZoomMinus() { | |
| 549 return RunCommandAsync(IDC_ZOOM_MINUS); | |
| 550 } | |
| 551 | |
| 552 bool AutomatedUITest::ZoomPlus() { | |
| 553 return RunCommandAsync(IDC_ZOOM_PLUS); | |
| 554 } | |
| 555 | |
| 556 bool AutomatedUITest::TestAboutChrome() { | |
| 557 DoAction("About"); | |
| 558 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 559 } | |
| 560 | |
| 561 bool AutomatedUITest::TestClearBrowsingData() { | |
| 562 DoAction("ClearBrowsingData"); | |
| 563 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 564 } | |
| 565 | |
| 566 bool AutomatedUITest::TestEditSearchEngines() { | |
| 567 DoAction("EditSearchEngines"); | |
| 568 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 569 } | |
| 570 | |
| 571 bool AutomatedUITest::TestImportSettings() { | |
| 572 DoAction("ImportSettings"); | |
| 573 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 574 } | |
| 575 | |
| 576 bool AutomatedUITest::TestTaskManager() { | |
| 577 DoAction("TaskManager"); | |
| 578 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 579 } | |
| 580 | |
| 581 bool AutomatedUITest::TestOptions() { | |
| 582 DoAction("Options"); | |
| 583 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 584 } | |
| 585 | |
| 586 bool AutomatedUITest::TestViewPasswords() { | |
| 587 DoAction("ViewPasswords"); | |
| 588 return FuzzyTestDialog(kTestDialogActionsToRun); | |
| 589 } | |
| 590 | |
| 591 bool AutomatedUITest::ExerciseDialog() { | |
| 592 int index = base::RandInt(0, arraysize(kDialogs) - 1); | |
| 593 return DoAction(kDialogs[index]) && FuzzyTestDialog(kTestDialogActionsToRun); | |
| 594 } | |
| 595 | |
| 596 bool AutomatedUITest::FuzzyTestDialog(int num_actions) { | |
| 597 bool return_value = true; | |
| 598 | |
| 599 for (int i = 0; i < num_actions; i++) { | |
| 600 // We want to make sure the first action performed on the dialog is not | |
| 601 // Space or Enter because focus is likely on the Close button. Both Space | |
| 602 // and Enter would close the dialog without performing more actions. We | |
| 603 // rely on the fact that those two actions are first in the array and set | |
| 604 // the lower bound to 2 if i == 0 to skip those two actions. | |
| 605 int action_index = base::RandInt(i == 0 ? 2 : 0, | |
| 606 arraysize(kTestDialogPossibleActions) | |
| 607 - 1); | |
| 608 return_value = return_value && | |
| 609 DoAction(kTestDialogPossibleActions[action_index]); | |
| 610 if (DidCrash(false)) | |
| 611 break; | |
| 612 } | |
| 613 return DoAction("PressEscapeKey") && return_value; | |
| 614 } | |
| 615 | |
| 616 bool AutomatedUITest::ForceCrash() { | |
| 617 scoped_refptr<TabProxy> tab(GetActiveTab()); | |
| 618 GURL test_url(content::kChromeUICrashURL); | |
| 619 AutomationMsg_NavigationResponseValues result = tab->NavigateToURL(test_url); | |
| 620 if (result != AUTOMATION_MSG_NAVIGATION_SUCCESS) { | |
| 621 AddErrorAttribute("navigation_failed"); | |
| 622 return false; | |
| 623 } | |
| 624 return true; | |
| 625 } | |
| 626 | |
| 627 bool AutomatedUITest::InitXMLReader() { | |
| 628 base::FilePath input_path = GetInputFilePath(); | |
| 629 | |
| 630 if (!base::ReadFileToString(input_path, &xml_init_file_)) | |
| 631 return false; | |
| 632 return init_reader_.Load(xml_init_file_); | |
| 633 } | |
| 634 | |
| 635 bool AutomatedUITest::WriteReportToFile() { | |
| 636 base::FilePath path = GetOutputFilePath(); | |
| 637 std::ofstream error_file; | |
| 638 if (!path.empty()) | |
| 639 error_file.open(path.value().c_str(), std::ios::out); | |
| 640 | |
| 641 // Closes all open elements and free the writer. This is required | |
| 642 // in order to retrieve the contents of the buffer. | |
| 643 xml_writer_.StopWriting(); | |
| 644 error_file << xml_writer_.GetWrittenString(); | |
| 645 error_file.close(); | |
| 646 return true; | |
| 647 } | |
| 648 | |
| 649 void AutomatedUITest::AppendToOutputFile(const std::string& append_string) { | |
| 650 base::FilePath path = GetOutputFilePath(); | |
| 651 std::ofstream error_file; | |
| 652 if (!path.empty()) | |
| 653 error_file.open(path.value().c_str(), std::ios::out | std::ios_base::app); | |
| 654 | |
| 655 error_file << append_string << " "; | |
| 656 error_file.close(); | |
| 657 } | |
| 658 | |
| 659 void AutomatedUITest::LogCrashResult(const base::FilePath& crash_dump, | |
| 660 bool command_completed) { | |
| 661 xml_writer_.StartElement("result"); | |
| 662 xml_writer_.AddAttribute("test_log_path", | |
| 663 GetTestLogFilePath().MaybeAsASCII()); | |
| 664 xml_writer_.AddAttribute("revision", GetChromeRevision()); | |
| 665 xml_writer_.StartElement("crash"); | |
| 666 #if defined(OS_WIN) | |
| 667 xml_writer_.AddAttribute("crash_dump", WideToASCII(crash_dump.value())); | |
| 668 #else | |
| 669 xml_writer_.AddAttribute("crash_dump", crash_dump.value()); | |
| 670 #endif | |
| 671 if (command_completed) | |
| 672 xml_writer_.AddAttribute("command_completed", "yes"); | |
| 673 else | |
| 674 xml_writer_.AddAttribute("command_completed", "no"); | |
| 675 xml_writer_.EndElement(); | |
| 676 xml_writer_.EndElement(); | |
| 677 } | |
| 678 | |
| 679 void AutomatedUITest::LogSuccessResult() { | |
| 680 xml_writer_.StartElement("result"); | |
| 681 xml_writer_.AddAttribute("test_log_path", | |
| 682 GetTestLogFilePath().MaybeAsASCII()); | |
| 683 xml_writer_.AddAttribute("revision", GetChromeRevision()); | |
| 684 xml_writer_.StartElement("success"); | |
| 685 xml_writer_.EndElement(); | |
| 686 xml_writer_.EndElement(); | |
| 687 } | |
| 688 | |
| 689 void AutomatedUITest::AddInfoAttribute(const std::string& info) { | |
| 690 xml_writer_.AddAttribute("info", info); | |
| 691 } | |
| 692 | |
| 693 void AutomatedUITest::AddWarningAttribute(const std::string& warning) { | |
| 694 xml_writer_.AddAttribute("warning", warning); | |
| 695 } | |
| 696 | |
| 697 void AutomatedUITest::AddErrorAttribute(const std::string& error) { | |
| 698 xml_writer_.AddAttribute("error", error); | |
| 699 } | |
| 700 | |
| 701 void AutomatedUITest::LogErrorMessage(const std::string& error) { | |
| 702 AddErrorAttribute(error); | |
| 703 } | |
| 704 | |
| 705 void AutomatedUITest::LogWarningMessage(const std::string& warning) { | |
| 706 AddWarningAttribute(warning); | |
| 707 } | |
| 708 | |
| 709 void AutomatedUITest::LogInfoMessage(const std::string& info) { | |
| 710 AddWarningAttribute(info); | |
| 711 } | |
| 712 | |
| 713 base::FilePath AutomatedUITest::GetMostRecentCrashDump() { | |
| 714 base::FilePath crash_dump_path; | |
| 715 base::FilePath most_recent_file_name; | |
| 716 PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_path); | |
| 717 base::Time most_recent_file_time; | |
| 718 | |
| 719 bool first_file = true; | |
| 720 | |
| 721 base::FileEnumerator enumerator(crash_dump_path, | |
| 722 false, // not recursive | |
| 723 base::FileEnumerator::FILES); | |
| 724 for (base::FilePath path = enumerator.Next(); !path.value().empty(); | |
| 725 path = enumerator.Next()) { | |
| 726 base::PlatformFileInfo file_info; | |
| 727 file_util::GetFileInfo(path, &file_info); | |
| 728 if (first_file) { | |
| 729 most_recent_file_time = file_info.last_modified; | |
| 730 most_recent_file_name = path.BaseName(); | |
| 731 first_file = false; | |
| 732 } else if (file_info.last_modified >= most_recent_file_time) { | |
| 733 most_recent_file_time = file_info.last_modified; | |
| 734 most_recent_file_name = path.BaseName(); | |
| 735 } | |
| 736 } | |
| 737 if (most_recent_file_name.empty()) { | |
| 738 return base::FilePath(); | |
| 739 } else { | |
| 740 crash_dump_path = crash_dump_path.Append(most_recent_file_name); | |
| 741 return crash_dump_path; | |
| 742 } | |
| 743 } | |
| 744 | |
| 745 bool AutomatedUITest::DidCrash(bool update_total_crashes) { | |
| 746 int actual_crashes = GetCrashCount(); | |
| 747 | |
| 748 // If there are more crash dumps than the total dumps which we have recorded | |
| 749 // then this is a new crash. | |
| 750 if (actual_crashes > total_crashes_) { | |
| 751 if (update_total_crashes) | |
| 752 total_crashes_ = actual_crashes; | |
| 753 return true; | |
| 754 } else { | |
| 755 return false; | |
| 756 } | |
| 757 } | |
| 758 | |
| 759 TEST_F(AutomatedUITest, TheOneAndOnlyTest) { | |
| 760 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
| 761 if (parsed_command_line.HasSwitch(kReproSwitch)) | |
| 762 RunReproduction(); | |
| 763 else | |
| 764 RunAutomatedUITest(); | |
| 765 } | |
| OLD | NEW |