Home | History | Annotate | Download | only in reliability
      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/base/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 (!file_util::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 }
    766