1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_TEST_UI_UI_TEST_H_
#define CHROME_TEST_UI_UI_TEST_H_
#pragma once
// This file provides a common base for running UI unit tests, which operate
// the entire browser application in a separate process for holistic
// functional testing.
//
// Tests should #include this file, subclass UITest, and use the TEST_F macro
// to declare individual test cases. This provides a running browser window
// during the test, accessible through the window_ member variable. The window
// will close when the test ends, regardless of whether the test passed.
//
// Tests which need to launch the browser with a particular set of command-line
// arguments should set the value of launch_arguments_ in their constructors.
#include <string>
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/process.h"
#include "base/test/test_timeouts.h"
#include "base/time.h"
#include "build/build_config.h"
// TODO(evanm): we should be able to just forward-declare
// AutomationProxy here, but many files that #include this one don't
// themselves #include automation_proxy.h.
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/proxy_launcher.h"
#include "testing/platform_test.h"
class AutomationProxy;
class BrowserProxy;
class DictionaryValue;
class FilePath;
class GURL;
class ScopedTempDir;
class TabProxy;
// Base class for UI Tests. This implements the core of the functions.
// This base class decouples all automation functionality from testing
// infrastructure, for use without gtest.
// If using gtest, you probably want to inherit from UITest (declared below)
// rather than UITestBase.
class UITestBase {
public:
// ********* Utility functions *********
// Launches the browser only.
void LaunchBrowser();
// Launches the browser and IPC testing connection in server mode.
void LaunchBrowserAndServer();
// Launches the IPC testing connection in client mode,
// which then attempts to connect to a browser.
void ConnectToRunningBrowser();
// Only for pyauto.
void set_command_execution_timeout_ms(int timeout);
// Overridable so that derived classes can provide their own ProxyLauncher.
virtual ProxyLauncher* CreateProxyLauncher();
// Closes the browser and IPC testing server.
void CloseBrowserAndServer();
// Launches the browser with the given command line.
// TODO(phajdan.jr): Make LaunchBrowser private. Tests should use
// LaunchAnotherBrowserBlockUntilClosed.
void LaunchBrowser(const CommandLine& cmdline, bool clear_profile);
#if !defined(OS_MACOSX)
// This function is deliberately not defined on the Mac because re-using an
// existing browser process when launching from the command line isn't a
// concept that we support on the Mac; AppleEvents are the Mac solution for
// the same need. Any test based on this function doesn't apply to the Mac.
// Launches an another browser process and waits for it to finish. Returns
// true on success.
bool LaunchAnotherBrowserBlockUntilClosed(const CommandLine& cmdline);
#endif
// Exits out browser instance.
void QuitBrowser();
// Tells the browser to navigate to the given URL in the active tab
// of the first app window.
// This method doesn't return until the navigation is complete.
void NavigateToURL(const GURL& url);
// Navigate to the given URL in the active tab of the given app window.
void NavigateToURL(const GURL& url, int window_index);
// Same as above, except in the given tab and window.
void NavigateToURL(const GURL& url, int window_index, int tab_index);
// Tells the browser to navigate to the given URL in the active tab
// of the first app window.
// This method doesn't return until the |number_of_navigations| navigations
// complete.
void NavigateToURLBlockUntilNavigationsComplete(const GURL& url,
int number_of_navigations);
// Same as above, except in the given tab and window.
void NavigateToURLBlockUntilNavigationsComplete(const GURL& url,
int number_of_navigations, int tab_index, int window_index);
// Returns the URL of the currently active tab. Only looks in the first
// window, for backward compatibility. If there is no active tab, or some
// other error, the returned URL will be empty.
GURL GetActiveTabURL() { return GetActiveTabURL(0); }
// Like above, but looks at the window at the given index.
GURL GetActiveTabURL(int window_index);
// Returns the title of the currently active tab. Only looks in the first
// window, for backward compatibility.
std::wstring GetActiveTabTitle() { return GetActiveTabTitle(0); }
// Like above, but looks at the window at the given index.
std::wstring GetActiveTabTitle(int window_index);
// Returns the tabstrip index of the currently active tab in the window at
// the given index, or -1 on error. Only looks in the first window, for
// backward compatibility.
int GetActiveTabIndex() { return GetActiveTabIndex(0); }
// Like above, but looks at the window at the given index.
int GetActiveTabIndex(int window_index);
// Returns true when the browser process is running, independent if any
// renderer process exists or not. It will returns false if an user closed the
// window or if the browser process died by itself.
bool IsBrowserRunning();
// Returns true when timeout_ms milliseconds have elapsed.
// Returns false if the browser process died while waiting.
bool CrashAwareSleep(int timeout_ms);
// Returns the number of tabs in the first window. If no windows exist,
// causes a test failure and returns 0.
int GetTabCount();
// Same as GetTabCount(), except with the window at the given index.
int GetTabCount(int window_index);
// Polls up to kWaitForActionMaxMsec ms to attain a specific tab count. Will
// assert that the tab count is valid at the end of the wait.
void WaitUntilTabCount(int tab_count);
// Wait for the browser process to shut down on its own (i.e. as a result of
// some action that your test has taken).
bool WaitForBrowserProcessToQuit(int timeout);
// Waits until the Bookmark bar has stopped animating and become fully visible
// (if |wait_for_open| is true) or fully hidden (if |wait_for_open| is false).
// This function can time out (in which case it returns false).
bool WaitForBookmarkBarVisibilityChange(BrowserProxy* browser,
bool wait_for_open);
// Sends the request to close the browser without blocking.
// This is so we can interact with dialogs opened on browser close,
// e.g. the beforeunload confirm dialog.
void CloseBrowserAsync(BrowserProxy* browser) const;
// Closes the specified browser. Returns true if the browser was closed.
// This call is blocking. |application_closed| is set to true if this was
// the last browser window (and therefore as a result of it closing the
// browser process terminated). Note that in that case this method returns
// after the browser process has terminated.
bool CloseBrowser(BrowserProxy* browser, bool* application_closed) const;
// Gets the directory for the currently active profile in the browser.
FilePath GetDownloadDirectory();
// Returns the directory name where the "typical" user data is that we use
// for testing.
static FilePath ComputeTypicalUserDataSource(
ProxyLauncher::ProfileType profile_type);
// Return the user data directory being used by the browser instance in
// UITest::SetUp().
FilePath user_data_dir() const {
return launcher_->user_data_dir();
}
// Called by some tests that wish to have a base profile to start from. This
// "user data directory" (containing one or more profiles) will be recursively
// copied into the user data directory for the test and the files will be
// evicted from the OS cache. To start with a blank profile, supply an empty
// string (the default).
const FilePath& template_user_data() const { return template_user_data_; }
void set_template_user_data(const FilePath& template_user_data) {
template_user_data_ = template_user_data;
}
// Get the handle of browser process connected to the automation. This
// function only returns a reference to the handle so the caller does not
// own the handle returned.
base::ProcessHandle process() const { return launcher_->process(); }
// Return the process id of the browser process (-1 on error).
base::ProcessId browser_process_id() const { return launcher_->process_id(); }
// Return the time when the browser was run.
base::TimeTicks browser_launch_time() const {
return launcher_->browser_launch_time();
}
// Return how long the shutdown took.
base::TimeDelta browser_quit_time() const {
return launcher_->browser_quit_time();
}
// Fetch the state which determines whether the profile will be cleared on
// next startup.
bool get_clear_profile() const {
return clear_profile_;
}
// Sets clear_profile_. Should be called before launching browser to have
// any effect.
void set_clear_profile(bool clear_profile) {
clear_profile_ = clear_profile;
}
// homepage_ accessor.
std::string homepage() {
return homepage_;
}
// Sets homepage_. Should be called before launching browser to have
// any effect.
void set_homepage(const std::string& homepage) {
homepage_ = homepage;
}
void set_test_name(const std::string& name) {
test_name_ = name;
}
// Sets the shutdown type, which defaults to WINDOW_CLOSE.
void set_shutdown_type(ProxyLauncher::ShutdownType value) {
launcher_->set_shutdown_type(value);
}
// Get the number of crash dumps we've logged since the test started.
int GetCrashCount();
// Use Chromium binaries from the given directory.
void SetBrowserDirectory(const FilePath& dir);
protected:
// String to display when a test fails because the crash service isn't
// running.
static const wchar_t kFailedNoCrashService[];
UITestBase();
explicit UITestBase(MessageLoop::Type msg_loop_type);
virtual ~UITestBase();
// Starts the browser using the arguments in launch_arguments_, and
// sets up member variables.
virtual void SetUp();
// Closes the browser window.
virtual void TearDown();
AutomationProxy* automation() const {
return launcher_->automation();
}
ProxyLauncher::LaunchState DefaultLaunchState() {
ProxyLauncher::LaunchState state =
{ clear_profile_, template_user_data_, profile_type_,
browser_directory_, launch_arguments_,
include_testing_id_, show_window_ };
return state;
}
virtual bool ShouldFilterInet();
// Extra command-line switches that need to be passed to the browser are
// added in this function. Add new command-line switches here.
void SetLaunchSwitches();
// Wait a certain amount of time for all the app processes to exit,
// forcibly killing them if they haven't exited by then.
// It has the side-effect of killing every browser window opened in your
// session, even those unrelated in the test.
void CleanupAppProcesses();
// Returns the proxy for the currently active tab, or NULL if there is no
// tab or there was some kind of error. Only looks at the first window, for
// backward compatibility. The returned pointer MUST be deleted by the
// caller if non-NULL.
scoped_refptr<TabProxy> GetActiveTab();
// Like above, but looks at the window at the given index.
scoped_refptr<TabProxy> GetActiveTab(int window_index);
// ********* Member variables *********
// Path to the browser executable.
FilePath browser_directory_;
// Path to the unit test data.
FilePath test_data_directory_;
// Command to launch the browser
CommandLine launch_arguments_;
// The number of errors expected during the run (generally 0).
size_t expected_errors_;
// The number of crashes expected during the run (generally 0).
int expected_crashes_;
// Homepage used for testing.
std::string homepage_;
// Name of currently running automated test passed to Chrome process.
std::string test_name_;
// Wait for initial loads to complete in SetUp() before running test body.
bool wait_for_initial_loads_;
// This can be set to true to have the test run the dom automation case.
bool dom_automation_enabled_;
// See set_template_user_data().
FilePath template_user_data_;
// Determines if the window is shown or hidden. Defaults to hidden.
bool show_window_;
// If true the profile is cleared before launching. Default is true.
bool clear_profile_;
// Should we supply the testing channel id
// on the command line? Default is true.
bool include_testing_id_;
// Enable file cookies, default is true.
bool enable_file_cookies_;
// Launches browser and AutomationProxy.
scoped_ptr<ProxyLauncher> launcher_;
// Are we using a profile with a complex theme?
ProxyLauncher::ProfileType profile_type_;
// PID file for websocket server.
FilePath websocket_pid_file_;
private:
// Time the test was started (so we can check for new crash dumps)
base::Time test_start_time_;
};
class UITest : public UITestBase, public PlatformTest {
protected:
UITest() {}
explicit UITest(MessageLoop::Type msg_loop_type)
: UITestBase(), PlatformTest(), message_loop_(msg_loop_type) {
}
virtual void SetUp();
virtual void TearDown();
virtual ProxyLauncher* CreateProxyLauncher();
// Synchronously launches local http server normally used to run LayoutTests.
void StartHttpServer(const FilePath& root_directory);
// Launches local http server on the specified port.
void StartHttpServerWithPort(const FilePath& root_directory, int port);
void StopHttpServer();
// Count the number of active browser processes launched by this test.
// The count includes browser sub-processes.
bool GetBrowserProcessCount(int* count) WARN_UNUSED_RESULT;
// Returns a copy of local state preferences. The caller is responsible for
// deleting the returned object. Returns NULL if there is an error.
DictionaryValue* GetLocalState();
// Returns a copy of the default profile preferences. The caller is
// responsible for deleting the returned object. Returns NULL if there is an
// error.
DictionaryValue* GetDefaultProfilePreferences();
// Waits for the test case to finish.
// ASSERTS if there are test failures.
void WaitForFinish(const std::string &name,
const std::string &id, const GURL &url,
const std::string& test_complete_cookie,
const std::string& expected_cookie_value,
const int wait_time);
// Wrapper around EvictFileFromSystemCache to retry 10 times in case of
// error.
// Apparently needed for Windows buildbots (to workaround an error when
// file is in use).
// TODO(phajdan.jr): Move to test_file_util if we need it in more places.
bool EvictFileFromSystemCacheWrapper(const FilePath& path);
// Wait for |generated_file| to be ready and then compare it with
// |original_file| to see if they're identical or not if |compare_file| is
// true. If |need_equal| is true, they need to be identical. Otherwise,
// they should be different. This function will delete the generated file if
// the parameter |delete_generated_file| is true.
void WaitForGeneratedFileAndCheck(const FilePath& generated_file,
const FilePath& original_file,
bool compare_files,
bool need_equal,
bool delete_generated_file);
// Polls the tab for a JavaScript condition and returns once one of the
// following conditions hold true:
// - The JavaScript condition evaluates to true (return true).
// - The browser process died (return false).
// - The timeout value has been exceeded (return false).
//
// The JavaScript expression is executed in the context of the frame that
// matches the provided xpath.
bool WaitUntilJavaScriptCondition(TabProxy* tab,
const std::wstring& frame_xpath,
const std::wstring& jscript,
int timeout_ms);
// Polls the tab for the cookie_name cookie and returns once one of the
// following conditions hold true:
// - The cookie is of expected_value.
// - The browser process died.
// - The timeout value has been exceeded.
bool WaitUntilCookieValue(TabProxy* tab, const GURL& url,
const char* cookie_name,
int timeout_ms,
const char* expected_value);
// Polls the tab for the cookie_name cookie and returns once one of the
// following conditions hold true:
// - The cookie is set to any value.
// - The browser process died.
// - The timeout value has been exceeded.
std::string WaitUntilCookieNonEmpty(TabProxy* tab,
const GURL& url,
const char* cookie_name,
int timeout_ms);
// Checks whether the download shelf is visible in the current browser, giving
// it a chance to appear (we don't know the exact timing) while finishing as
// soon as possible.
bool WaitForDownloadShelfVisible(BrowserProxy* browser);
// Checks whether the download shelf is invisible in the current browser,
// giving it a chance to appear (we don't know the exact timing) while
// finishing as soon as possible.
bool WaitForDownloadShelfInvisible(BrowserProxy* browser);
// Waits until the Find window has become fully visible (if |wait_for_open| is
// true) or fully hidden (if |wait_for_open| is false). This function can time
// out (return false) if the window doesn't appear within a specific time.
bool WaitForFindWindowVisibilityChange(BrowserProxy* browser,
bool wait_for_open);
// Terminates the browser, simulates end of session.
void TerminateBrowser();
// Tells the browser to navigate to the given URL in the active tab
// of the first app window.
// Does not wait for the navigation to complete to return.
// To avoid intermittent test failures, use NavigateToURL instead, if
// possible.
void NavigateToURLAsync(const GURL& url);
private:
// Waits for download shelf visibility or invisibility.
bool WaitForDownloadShelfVisibilityChange(BrowserProxy* browser,
bool wait_for_open);
MessageLoop message_loop_; // Enables PostTask to main thread.
};
// These exist only to support the gTest assertion macros, and
// shouldn't be used in normal program code.
#ifdef UNIT_TEST
std::ostream& operator<<(std::ostream& out, const std::wstring& wstr);
template<typename T>
std::ostream& operator<<(std::ostream& out, const ::scoped_ptr<T>& ptr) {
return out << ptr.get();
}
#endif // UNIT_TEST
#endif // CHROME_TEST_UI_UI_TEST_H_
|