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 |