1// Copyright 2013 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#ifndef CHROME_TEST_REMOTING_REMOTE_DESKTOP_BROWSERTEST_H_
6#define CHROME_TEST_REMOTING_REMOTE_DESKTOP_BROWSERTEST_H_
7
8#include "base/debug/stack_trace.h"
9#include "chrome/browser/apps/app_browsertest_util.h"
10#include "chrome/browser/chrome_notification_types.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/test/base/ui_test_utils.h"
13#include "content/public/browser/notification_service.h"
14#include "content/public/test/browser_test_utils.h"
15#include "net/dns/mock_host_resolver.h"
16
17namespace {
18// Command line arguments specific to the chromoting browser tests.
19const char kOverrideUserDataDir[] = "override-user-data-dir";
20const char kNoCleanup[] = "no-cleanup";
21const char kNoInstall[] = "no-install";
22const char kWebAppCrx[] = "webapp-crx";
23const char kWebAppUnpacked[] = "webapp-unpacked";
24const char kUsername[] = "username";
25const char kkPassword[] = "password";
26const char kMe2MePin[] = "me2me-pin";
27const char kRemoteHostName[] = "remote-host-name";
28const char kExtensionName[] = "extension-name";
29const char kHttpServer[] = "http-server";
30
31// ASSERT_TRUE can only be used in void returning functions. This version
32// should be used in non-void-returning functions.
33inline void _ASSERT_TRUE(bool condition) {
34  if (!condition) {
35    // ASSERT_TRUE only prints the first call frame in the error message.
36    // In our case, this is the _ASSERT_TRUE wrapper function, which is not
37    // useful.  To help with debugging, we will dump the full callstack.
38    LOG(ERROR) << "Assertion failed.";
39    LOG(ERROR) << base::debug::StackTrace().ToString();
40  }
41  ASSERT_TRUE(condition);
42  return;
43}
44
45}  // namespace
46
47using extensions::Extension;
48
49namespace remoting {
50
51class RemoteDesktopBrowserTest : public extensions::PlatformAppBrowserTest {
52 public:
53  RemoteDesktopBrowserTest();
54  virtual ~RemoteDesktopBrowserTest();
55
56  // InProcessBrowserTest Overrides
57  virtual void SetUp() OVERRIDE;
58  virtual void SetUpOnMainThread() OVERRIDE;
59
60 protected:
61  // InProcessBrowserTest Overrides
62  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE;
63
64  // InProcessBrowserTest Overrides
65  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE;
66
67  // The following helpers each perform a simple task.
68
69  // Verify the test has access to the internet (specifically google.com)
70  void VerifyInternetAccess();
71
72  // Open the client page for the browser test to get status of host actions
73  void OpenClientBrowserPage();
74
75  // Install the chromoting extension from a crx file.
76  void InstallChromotingAppCrx();
77
78  // Install the unpacked chromoting extension.
79  void InstallChromotingAppUnpacked();
80
81  // Uninstall the chromoting extension.
82  void UninstallChromotingApp();
83
84  // Test whether the chromoting extension is installed.
85  void VerifyChromotingLoaded(bool expected);
86
87  // Launch the chromoting app.
88  void LaunchChromotingApp();
89
90  // Authorize: grant extended access permission to the user's computer.
91  void Authorize();
92
93  // Authenticate: sign in to google using the credentials provided.
94  void Authenticate();
95
96  // Approve: grant the chromoting app necessary permissions.
97  void Approve();
98
99  // Click on "Get Started" in the Me2Me section and show the host list.
100  void ExpandMe2Me();
101
102  // Disconnect the active Me2Me session.
103  void DisconnectMe2Me();
104
105  // Simulate a key event.
106  void SimulateKeyPressWithCode(ui::KeyboardCode keyCode, const char* code);
107
108  void SimulateKeyPressWithCode(ui::KeyboardCode keyCode,
109                                const char* code,
110                                bool control,
111                                bool shift,
112                                bool alt,
113                                bool command);
114
115  // Simulate typing a character
116  void SimulateCharInput(char c);
117
118  // Simulate typing a string
119  void SimulateStringInput(const std::string& input);
120
121  // Helper to simulate a left button mouse click.
122  void SimulateMouseLeftClickAt(int x, int y);
123
124  // Helper to simulate a mouse click.
125  void SimulateMouseClickAt(
126      int modifiers, blink::WebMouseEvent::Button button, int x, int y);
127
128  // The following helpers each perform a composite task.
129
130  // Install the chromoting extension
131  void Install();
132
133  // Perform all necessary steps (installation, authorization, authentication,
134  // expanding the me2me section) so that the app is ready for a me2me
135  // connection.
136  void SetUpTestForMe2Me();
137
138  // Clean up after the test.
139  void Cleanup();
140
141  // Perform all the auth steps: authorization, authentication, etc.
142  // It starts from the chromoting main page unauthenticated and ends up back
143  // on the chromoting main page authenticated and ready to go.
144  void Auth();
145
146  // Ensures that the host is started locally with |me2me_pin()|.
147  // Browser_test.js must be loaded before calling this function.
148  void EnsureRemoteConnectionEnabled();
149
150  // Connect to the local host through Me2Me.
151  void ConnectToLocalHost(bool remember_pin);
152
153  // Connect to a remote host through Me2Me.
154  void ConnectToRemoteHost(const std::string& host_name, bool remember_pin);
155
156  // Enter the pin number and connect.
157  void EnterPin(const std::string& name, bool remember_pin);
158
159  // Helper to get the pin number used for me2me authentication.
160  std::string me2me_pin() { return me2me_pin_; }
161
162  // Helper to get the name of the remote host to connect to.
163  std::string remote_host_name() { return remote_host_name_; }
164
165  // Helper to get the test controller URL.
166  std::string http_server() { return http_server_; }
167
168  // Change behavior of the default host resolver to allow DNS lookup
169  // to proceed instead of being blocked by the test infrastructure.
170  void EnableDNSLookupForThisTest(
171    net::RuleBasedHostResolverProc* host_resolver);
172
173  // We need to reset the DNS lookup when we finish, or the test will fail.
174  void DisableDNSLookupForThisTest();
175
176  void ParseCommandLine();
177
178  // Accessor methods.
179
180  // Helper to get the path to the crx file of the webapp to be tested.
181  base::FilePath WebAppCrxPath() { return webapp_crx_; }
182
183  // Helper to get the extension ID of the installed chromoting webapp.
184  std::string ChromotingID() { return extension_->id(); }
185
186  // Is this a appsv2 web app?
187  bool is_platform_app() {
188    return extension_->GetType() == extensions::Manifest::TYPE_PLATFORM_APP;
189  }
190
191  // Are we testing an unpacked extension?
192  bool is_unpacked() {
193    return !webapp_unpacked_.empty();
194  }
195
196  // The "active" WebContents instance the test needs to interact with.
197  content::WebContents* active_web_contents() {
198    DCHECK(!web_contents_stack_.empty());
199    return web_contents_stack_.back();
200  }
201
202  // The client WebContents instance the test needs to interact with.
203  content::WebContents* client_web_content() {
204    return client_web_content_;
205  }
206
207  content::WebContents* app_web_content() {
208    return app_web_content_;
209  }
210
211  // Whether to perform the cleanup tasks (uninstalling chromoting, etc).
212  // This is useful for diagnostic purposes.
213  bool NoCleanup() { return no_cleanup_; }
214
215  // Whether to install the chromoting extension before running the test cases.
216  // This is useful for diagnostic purposes.
217  bool NoInstall() { return no_install_; }
218
219  // Helper to construct the starting URL of the installed chromoting webapp.
220  GURL Chromoting_Main_URL() {
221    return GURL("chrome-extension://" + ChromotingID() + "/main.html");
222  }
223
224  // Helper to retrieve the current URL in the active WebContents.
225  GURL GetCurrentURL() {
226    return active_web_contents()->GetURL();
227  }
228
229  // Helpers to execute JavaScript code on a web page.
230
231  // Helper to execute a JavaScript code snippet in the active WebContents.
232  void ExecuteScript(const std::string& script);
233
234  // Helper to execute a JavaScript code snippet in the active WebContents
235  // and wait for page load to complete.
236  void ExecuteScriptAndWaitForAnyPageLoad(const std::string& script);
237
238  // Helper to execute a JavaScript code snippet in the active WebContents
239  // and extract the boolean result.
240  bool ExecuteScriptAndExtractBool(const std::string& script) {
241    return ExecuteScriptAndExtractBool(active_web_contents(), script);
242  }
243
244  // Helper to execute a JavaScript code snippet and extract the boolean result.
245  static bool ExecuteScriptAndExtractBool(content::WebContents* web_contents,
246                                          const std::string& script);
247
248  // Helper to execute a JavaScript code snippet in the active WebContents
249  // and extract the int result.
250  int ExecuteScriptAndExtractInt(const std::string& script) {
251    return ExecuteScriptAndExtractInt(active_web_contents(), script);
252  }
253
254  // Helper to execute a JavaScript code snippet and extract the int result.
255  static int ExecuteScriptAndExtractInt(content::WebContents* web_contents,
256                                        const std::string& script);
257
258  // Helper to execute a JavaScript code snippet in the active WebContents
259  // and extract the string result.
260  std::string ExecuteScriptAndExtractString(const std::string& script) {
261    return ExecuteScriptAndExtractString(active_web_contents(), script);
262  }
263
264  // Helper to execute a JavaScript code snippet and extract the string result.
265  static std::string ExecuteScriptAndExtractString(
266      content::WebContents* web_contents, const std::string& script);
267
268  // Helper to load a JavaScript file from |path| and inject it to
269  // current web_content.  The variable |path| is relative to the directory of
270  // the |browsertest| executable.
271  static bool LoadScript(content::WebContents* web_contents,
272                         const base::FilePath::StringType& path);
273
274  // Helper to execute a JavaScript browser test.  It creates an object using
275  // the |browserTest.testName| ctor and calls |run| on the created object with
276  // |testData|, which can be any arbitrary object literal. The script
277  // browser_test.js must be loaded (using LoadScript) before calling this
278  // function.
279  void RunJavaScriptTest(content::WebContents* web_contents,
280                         const std::string& testName,
281                         const std::string& testData);
282
283  // Helper to check whether an html element with the given name exists in
284  // the active WebContents.
285  bool HtmlElementExists(const std::string& name) {
286    return ExecuteScriptAndExtractBool(
287        "document.getElementById(\"" + name + "\") != null");
288  }
289
290  // Helper to check whether a html element with the given name is visible in
291  // the active WebContents.
292  bool HtmlElementVisible(const std::string& name);
293
294  // Click on the named HTML control in the active WebContents.
295  void ClickOnControl(const std::string& name);
296
297  // Wait for the me2me connection to be established.
298  void WaitForConnection();
299
300  // Checking whether the localHost has been initialized.
301  bool IsLocalHostReady();
302
303  // Callback used by EnterPin to check whether the pin form is visible
304  // and to dismiss the host-needs-update dialog.
305  bool IsPinFormVisible();
306
307  // Callback used by WaitForConnection to check whether the connection
308  // has been established.
309  bool IsSessionConnected();
310
311  // Callback used by Approve to check whether the chromoting app has
312  // successfully authenticated with the Google services.
313  bool IsAuthenticated() {
314      return IsAuthenticatedInWindow(active_web_contents());
315  }
316
317  // Callback used by Approve to check whether the Accept button is enabled
318  // and ready to receive a click.
319  static bool IsEnabled(
320      content::WebContents* web_contents, const std::string& name);
321
322  // If the "Host version out-of-date" form is visible, dismiss it.
323  void DismissHostVersionWarningIfVisible();
324
325  // Callback used by Approve to check whether the chromoting app has
326  // successfully authenticated with the Google services.
327  static bool IsAuthenticatedInWindow(content::WebContents* web_contents);
328
329  // Callback used to check whether a host action is completed.
330  // Used by browser tests while conditionally waiting for host actions.
331  static bool IsHostActionComplete(
332      content::WebContents* client_web_content, std::string host_action_var);
333
334 private:
335  // Fields
336
337  // This test needs to make live DNS requests for access to
338  // GAIA and sync server URLs under google.com. We use a scoped version
339  // to override the default resolver while the test is active.
340  scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_;
341
342  // Stores all the WebContents instance in a stack so that we can easily
343  // return to the previous instance.
344  // The active WebContents instance is always stored at the top of the stack.
345  // Initially the stack contains the WebContents instance created by
346  // InProcessBrowserTest as the initial context to run test in.
347  // Whenever a WebContents instance is spawned and needs attention we
348  // push it onto the stack and that becomes the active instance.
349  // And once we are done with the current WebContents instance
350  // we pop it off the stack, returning to the previous instance.
351  std::vector<content::WebContents*> web_contents_stack_;
352
353  // WebContent of the client page that facilitates communication with
354  // the HTTP server. This is how the remoting browser tests
355  // will get acknowledgments of actions completed on the host.
356  content::WebContents* client_web_content_;
357
358  // WebContent of the landing page in the chromoting app.
359  content::WebContents* app_web_content_;
360
361  bool no_cleanup_;
362  bool no_install_;
363  const Extension* extension_;
364  base::FilePath webapp_crx_;
365  base::FilePath webapp_unpacked_;
366  std::string username_;
367  std::string password_;
368  std::string me2me_pin_;
369  std::string remote_host_name_;
370  std::string extension_name_;
371  std::string http_server_;
372};
373
374}  // namespace remoting
375
376#endif  // CHROME_TEST_REMOTING_REMOTE_DESKTOP_BROWSERTEST_H_
377