Roll src/third_party/skia d094908:ac8d8b8
[chromium-blink-merge.git] / chrome / test / remoting / remote_desktop_browsertest.cc
bloba18778a990d5598c1717992faba72e710ac70232
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.
5 #include "chrome/test/remoting/remote_desktop_browsertest.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/json/json_reader.h"
10 #include "base/path_service.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/unpacked_installer.h"
13 #include "chrome/browser/ui/extensions/app_launch_params.h"
14 #include "chrome/browser/ui/extensions/application_launch.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/test/remoting/key_code_conv.h"
17 #include "chrome/test/remoting/page_load_notification_observer.h"
18 #include "chrome/test/remoting/waiter.h"
19 #include "content/public/browser/native_web_keyboard_event.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "content/public/test/test_utils.h"
22 #include "extensions/browser/extension_registry.h"
23 #include "extensions/common/constants.h"
24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_set.h"
26 #include "extensions/common/switches.h"
27 #include "ui/base/window_open_disposition.h"
29 namespace remoting {
31 RemoteDesktopBrowserTest::RemoteDesktopBrowserTest()
32 : extension_(NULL) {
35 RemoteDesktopBrowserTest::~RemoteDesktopBrowserTest() {}
37 void RemoteDesktopBrowserTest::SetUp() {
38 ParseCommandLine();
39 PlatformAppBrowserTest::SetUp();
42 void RemoteDesktopBrowserTest::SetUpOnMainThread() {
43 PlatformAppBrowserTest::SetUpOnMainThread();
45 // Pushing the initial WebContents instance onto the stack before
46 // RunTestOnMainThread() and after |InProcessBrowserTest::browser_|
47 // is initialized in InProcessBrowserTest::RunTestOnMainThreadLoop()
48 web_contents_stack_.push_back(
49 browser()->tab_strip_model()->GetActiveWebContents());
52 // Change behavior of the default host resolver to avoid DNS lookup errors,
53 // so we can make network calls.
54 void RemoteDesktopBrowserTest::SetUpInProcessBrowserTestFixture() {
55 // The resolver object lifetime is managed by sync_test_setup, not here.
56 EnableDNSLookupForThisTest(
57 new net::RuleBasedHostResolverProc(host_resolver()));
60 void RemoteDesktopBrowserTest::TearDownInProcessBrowserTestFixture() {
61 DisableDNSLookupForThisTest();
64 void RemoteDesktopBrowserTest::VerifyInternetAccess() {
65 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
66 browser(), GURL("http://www.google.com"), 1);
68 EXPECT_EQ(GetCurrentURL().host(), "www.google.com");
71 void RemoteDesktopBrowserTest::OpenClientBrowserPage() {
72 // Open the client browser page in a new tab
73 ui_test_utils::NavigateToURLWithDisposition(
74 browser(),
75 GURL(http_server() + "/clientpage.html"),
76 NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
78 // Save this web content for later reference
79 client_web_content_ = browser()->tab_strip_model()->GetActiveWebContents();
81 // Go back to the previous tab that has chromoting opened
82 browser()->tab_strip_model()->SelectPreviousTab();
85 bool RemoteDesktopBrowserTest::HtmlElementVisible(const std::string& name) {
86 _ASSERT_TRUE(HtmlElementExists(name));
88 ExecuteScript(
89 "function isElementVisible(name) {"
90 " var element = document.getElementById(name);"
91 " /* The existence of the element has already been ASSERTed. */"
92 " do {"
93 " if (element.hidden) {"
94 " return false;"
95 " }"
96 " element = element.parentNode;"
97 " } while (element != null);"
98 " return true;"
99 "};");
101 return ExecuteScriptAndExtractBool(
102 "isElementVisible(\"" + name + "\")");
105 void RemoteDesktopBrowserTest::InstallChromotingAppCrx() {
106 ASSERT_TRUE(!is_unpacked());
108 base::FilePath install_dir(WebAppCrxPath());
109 scoped_refptr<const Extension> extension(InstallExtensionWithUIAutoConfirm(
110 install_dir, 1, browser()));
112 EXPECT_FALSE(extension.get() == NULL);
114 extension_ = extension.get();
117 void RemoteDesktopBrowserTest::InstallChromotingAppUnpacked() {
118 ASSERT_TRUE(is_unpacked());
120 scoped_refptr<extensions::UnpackedInstaller> installer =
121 extensions::UnpackedInstaller::Create(extension_service());
122 installer->set_prompt_for_plugins(false);
124 content::WindowedNotificationObserver observer(
125 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
126 content::NotificationService::AllSources());
128 installer->Load(webapp_unpacked_);
130 observer.Wait();
133 void RemoteDesktopBrowserTest::UninstallChromotingApp() {
134 UninstallExtension(ChromotingID());
135 extension_ = NULL;
138 void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
139 bool installed = false;
141 for (const scoped_refptr<const extensions::Extension>& extension :
142 extensions::ExtensionRegistry::Get(profile())->enabled_extensions()) {
143 // Is there a better way to recognize the chromoting extension
144 // than name comparison?
145 if (extension->name() == extension_name_) {
146 if (extension_) {
147 EXPECT_EQ(extension.get(), extension_);
148 } else {
149 extension_ = extension.get();
152 installed = true;
153 break;
157 if (installed) {
158 // Either a V1 (TYPE_LEGACY_PACKAGED_APP) or a V2 (TYPE_PLATFORM_APP ) app.
159 extensions::Manifest::Type type = extension_->GetType();
160 EXPECT_TRUE(type == extensions::Manifest::TYPE_PLATFORM_APP ||
161 type == extensions::Manifest::TYPE_LEGACY_PACKAGED_APP);
163 EXPECT_TRUE(extension_->ShouldDisplayInAppLauncher());
166 ASSERT_EQ(installed, expected);
169 void RemoteDesktopBrowserTest::LaunchChromotingApp(bool defer_start) {
170 ASSERT_TRUE(extension_);
172 GURL chromoting_main = Chromoting_Main_URL();
173 // We cannot simply wait for any page load because the first page
174 // loaded could be the generated background page. We need to wait
175 // till the chromoting main page is loaded.
176 PageLoadNotificationObserver observer(chromoting_main);
177 observer.set_ignore_url_parameters(true);
179 // If the app should be started in deferred mode, ensure that a "source" URL
180 // parameter; if not, ensure that no such parameter is present. The value of
181 // the parameter is determined by the AppLaunchParams ("test", in this case).
182 extensions::FeatureSwitch::ScopedOverride override_trace_app_source(
183 extensions::FeatureSwitch::trace_app_source(),
184 defer_start);
186 OpenApplication(AppLaunchParams(browser()->profile(), extension_,
187 is_platform_app()
188 ? extensions::LAUNCH_CONTAINER_NONE
189 : extensions::LAUNCH_CONTAINER_TAB,
190 is_platform_app() ? NEW_WINDOW : CURRENT_TAB,
191 extensions::SOURCE_TEST));
193 observer.Wait();
196 // The active WebContents instance should be the source of the LOAD_STOP
197 // notification.
198 content::NavigationController* controller =
199 content::Source<content::NavigationController>(observer.source()).ptr();
201 content::WebContents* web_contents = controller->GetWebContents();
202 if (web_contents != active_web_contents())
203 web_contents_stack_.push_back(web_contents);
205 app_web_content_ = web_contents;
207 if (is_platform_app()) {
208 EXPECT_EQ(GetFirstAppWindowWebContents(), active_web_contents());
209 } else {
210 // For apps v1 only, the DOMOperationObserver is not ready at the LOAD_STOP
211 // event. A half second wait is necessary for the subsequent javascript
212 // injection to work.
213 // TODO(weitaosu): Find out whether there is a more appropriate notification
214 // to wait for so we can get rid of this wait.
215 ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(5)).Wait());
218 EXPECT_EQ(Chromoting_Main_URL(), GetCurrentURL());
221 void RemoteDesktopBrowserTest::StartChromotingApp() {
222 ClickOnControl("browser-test-continue-init");
225 void RemoteDesktopBrowserTest::Authorize() {
226 // The chromoting extension should be installed.
227 ASSERT_TRUE(extension_);
229 // The chromoting main page should be loaded in the current tab
230 // and isAuthenticated() should be false (auth dialog visible).
231 ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL());
232 ASSERT_FALSE(IsAuthenticated());
234 // The second observer monitors the loading of the Google login page.
235 // Unfortunately we cannot specify a source in this observer because
236 // we can't get a handle of the new window until the first observer
237 // has finished waiting. But we will assert that the source of the
238 // load stop event is indeed the newly created browser window.
239 content::WindowedNotificationObserver observer(
240 content::NOTIFICATION_LOAD_STOP,
241 content::NotificationService::AllSources());
243 ClickOnControl("auth-button");
245 observer.Wait();
247 content::NavigationController* controller =
248 content::Source<content::NavigationController>(observer.source()).ptr();
250 web_contents_stack_.push_back(controller->GetWebContents());
252 // Verify the active tab is at the "Google Accounts" login page.
253 EXPECT_EQ("accounts.google.com", GetCurrentURL().host());
254 EXPECT_TRUE(HtmlElementExists("Email"));
255 EXPECT_TRUE(HtmlElementExists("Passwd"));
258 void RemoteDesktopBrowserTest::Authenticate() {
259 // The chromoting extension should be installed.
260 ASSERT_TRUE(extension_);
262 // The active tab should have the "Google Accounts" login page loaded.
263 ASSERT_EQ("accounts.google.com", GetCurrentURL().host());
264 ASSERT_TRUE(HtmlElementExists("Email"));
265 ASSERT_TRUE(HtmlElementExists("Passwd"));
267 // Now log in using the username and password passed in from the command line.
268 ExecuteScriptAndWaitForAnyPageLoad(
269 "document.getElementById(\"Email\").value = \"" + username_ + "\";" +
270 "document.getElementById(\"Passwd\").value = \"" + password_ +"\";" +
271 "document.forms[\"gaia_loginform\"].submit();");
273 // TODO(weitaosu): Is there a better way to verify we are on the
274 // "Request for Permission" page?
275 // V2 app won't ask for approval here because the chromoting test account
276 // has already been granted permissions.
277 if (!is_platform_app()) {
278 EXPECT_EQ(GetCurrentURL().host(), "accounts.google.com");
279 EXPECT_TRUE(HtmlElementExists("submit_approve_access"));
283 void RemoteDesktopBrowserTest::Approve() {
284 // The chromoting extension should be installed.
285 ASSERT_TRUE(extension_);
287 if (is_platform_app()) {
288 // Popping the login window off the stack to return to the chromoting
289 // window.
290 web_contents_stack_.pop_back();
292 // There is nothing for the V2 app to approve because the chromoting test
293 // account has already been granted permissions.
294 // TODO(weitaosu): Revoke the permission at the beginning of the test so
295 // that we can test first-time experience here.
296 ConditionalTimeoutWaiter waiter(
297 base::TimeDelta::FromSeconds(7),
298 base::TimeDelta::FromSeconds(1),
299 base::Bind(
300 &RemoteDesktopBrowserTest::IsAuthenticatedInWindow,
301 active_web_contents()));
303 ASSERT_TRUE(waiter.Wait());
304 } else {
305 ASSERT_EQ("accounts.google.com", GetCurrentURL().host());
307 // Is there a better way to verify we are on the "Request for Permission"
308 // page?
309 ASSERT_TRUE(HtmlElementExists("submit_approve_access"));
311 const GURL chromoting_main = Chromoting_Main_URL();
313 // active_web_contents() is still the login window but the observer
314 // should be set up to observe the chromoting window because that is
315 // where we'll receive the message from the login window and reload the
316 // chromoting app.
317 content::WindowedNotificationObserver observer(
318 content::NOTIFICATION_LOAD_STOP,
319 base::Bind(
320 &RemoteDesktopBrowserTest::IsAuthenticatedInWindow,
321 browser()->tab_strip_model()->GetActiveWebContents()));
323 // Click to Approve the web-app.
324 ClickOnControl("submit_approve_access");
326 observer.Wait();
328 // Popping the login window off the stack to return to the chromoting
329 // window.
330 web_contents_stack_.pop_back();
333 ASSERT_TRUE(GetCurrentURL() == Chromoting_Main_URL());
335 EXPECT_TRUE(IsAuthenticated());
338 void RemoteDesktopBrowserTest::ExpandMe2Me() {
339 // The chromoting extension should be installed.
340 ASSERT_TRUE(extension_);
342 // The active tab should have the chromoting app loaded.
343 ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL());
344 EXPECT_TRUE(IsAuthenticated());
346 // The Me2Me host list should be hidden.
347 ASSERT_FALSE(HtmlElementVisible("me2me-content"));
348 // The Me2Me "Get Start" button should be visible.
349 ASSERT_TRUE(HtmlElementVisible("get-started-me2me"));
351 // Starting Me2Me.
352 ExecuteScript("remoting.showMe2MeUiAndSave();");
354 EXPECT_TRUE(HtmlElementVisible("me2me-content"));
355 EXPECT_FALSE(HtmlElementVisible("me2me-first-run"));
358 void RemoteDesktopBrowserTest::DisconnectMe2Me() {
359 // The chromoting extension should be installed.
360 ASSERT_TRUE(extension_);
362 ASSERT_TRUE(RemoteDesktopBrowserTest::IsSessionConnected());
364 ExecuteScript("remoting.disconnect();");
366 EXPECT_TRUE(HtmlElementVisible("client-dialog"));
367 EXPECT_TRUE(HtmlElementVisible("client-reconnect-button"));
368 EXPECT_TRUE(HtmlElementVisible("client-finished-me2me-button"));
370 ClickOnControl("client-finished-me2me-button");
372 EXPECT_FALSE(HtmlElementVisible("client-dialog"));
375 void RemoteDesktopBrowserTest::SimulateKeyPressWithCode(
376 ui::KeyboardCode keyCode,
377 const char* code) {
378 SimulateKeyPressWithCode(keyCode, code, false, false, false, false);
381 void RemoteDesktopBrowserTest::SimulateKeyPressWithCode(
382 ui::KeyboardCode keyCode,
383 const char* code,
384 bool control,
385 bool shift,
386 bool alt,
387 bool command) {
388 content::SimulateKeyPressWithCode(
389 active_web_contents(),
390 keyCode,
391 code,
392 control,
393 shift,
394 alt,
395 command);
398 void RemoteDesktopBrowserTest::SimulateCharInput(char c) {
399 const char* code;
400 ui::KeyboardCode keyboard_code;
401 bool shift;
402 GetKeyValuesFromChar(c, &code, &keyboard_code, &shift);
403 ASSERT_TRUE(code != NULL);
404 SimulateKeyPressWithCode(keyboard_code, code, false, shift, false, false);
407 void RemoteDesktopBrowserTest::SimulateStringInput(const std::string& input) {
408 for (size_t i = 0; i < input.length(); ++i)
409 SimulateCharInput(input[i]);
412 void RemoteDesktopBrowserTest::SimulateMouseLeftClickAt(int x, int y) {
413 SimulateMouseClickAt(0, blink::WebMouseEvent::ButtonLeft, x, y);
416 void RemoteDesktopBrowserTest::SimulateMouseClickAt(
417 int modifiers, blink::WebMouseEvent::Button button, int x, int y) {
418 // TODO(weitaosu): The coordinate translation doesn't work correctly for
419 // apps v2.
420 ExecuteScript(
421 "var clientPluginElement = "
422 "document.getElementById('session-client-plugin');"
423 "var clientPluginRect = clientPluginElement.getBoundingClientRect();");
425 int top = ExecuteScriptAndExtractInt("clientPluginRect.top");
426 int left = ExecuteScriptAndExtractInt("clientPluginRect.left");
427 int width = ExecuteScriptAndExtractInt("clientPluginRect.width");
428 int height = ExecuteScriptAndExtractInt("clientPluginRect.height");
430 ASSERT_GT(x, 0);
431 ASSERT_LT(x, width);
432 ASSERT_GT(y, 0);
433 ASSERT_LT(y, height);
435 content::SimulateMouseClickAt(
436 browser()->tab_strip_model()->GetActiveWebContents(),
437 modifiers,
438 button,
439 gfx::Point(left + x, top + y));
442 void RemoteDesktopBrowserTest::Install() {
443 if (!NoInstall()) {
444 VerifyChromotingLoaded(false);
445 if (is_unpacked())
446 InstallChromotingAppUnpacked();
447 else
448 InstallChromotingAppCrx();
451 VerifyChromotingLoaded(true);
454 void RemoteDesktopBrowserTest::Cleanup() {
455 // TODO(weitaosu): Remove this hack by blocking on the appropriate
456 // notification.
457 // The browser may still be loading images embedded in the webapp. If we
458 // uinstall it now those load will fail.
459 ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait());
461 if (!NoCleanup()) {
462 UninstallChromotingApp();
463 VerifyChromotingLoaded(false);
466 // TODO(chaitali): Remove this additional timeout after we figure out
467 // why this is needed for the v1 app to work.
468 // Without this timeout the test fail with a "CloseWebContents called for
469 // tab not in our strip" error for the v1 app.
470 ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait());
473 void RemoteDesktopBrowserTest::SetUpTestForMe2Me() {
474 VerifyInternetAccess();
475 Install();
476 LaunchChromotingApp(false);
477 Auth();
478 LoadScript(app_web_content(), FILE_PATH_LITERAL("browser_test.js"));
479 ExpandMe2Me();
480 // The call to EnsureRemoteConnectionEnabled() does a PIN reset.
481 // This causes the test to fail because of a recent bug:
482 // crbug.com/430676
483 // TODO(anandc): Reactivate this call after above bug is fixed.
484 //EnsureRemoteConnectionEnabled();
487 void RemoteDesktopBrowserTest::Auth() {
488 // For this test, we must be given the user-name and password.
489 ASSERT_TRUE(!username_.empty() && !password_.empty());
491 Authorize();
492 Authenticate();
493 Approve();
496 void RemoteDesktopBrowserTest::EnsureRemoteConnectionEnabled() {
497 // browser_test.ensureRemoteConnectionEnabled is defined in
498 // browser_test.js, which must be loaded before calling this function.
499 // TODO(kelvinp): This function currently only works on linux when the user is
500 // already part of the chrome-remote-desktop group. Extend this functionality
501 // to Mac (https://crbug.com/397576) and Windows (https://crbug.com/397575).
502 bool result;
503 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
504 app_web_content(),
505 "browserTest.ensureRemoteConnectionEnabled(" + me2me_pin() + ")",
506 &result));
507 EXPECT_TRUE(result) << "Cannot start the host with Pin:" << me2me_pin();
510 void RemoteDesktopBrowserTest::ConnectToLocalHost(bool remember_pin) {
511 // Wait for local-host to be ready.
512 ConditionalTimeoutWaiter waiter(
513 base::TimeDelta::FromSeconds(5),
514 base::TimeDelta::FromMilliseconds(500),
515 base::Bind(&RemoteDesktopBrowserTest::IsLocalHostReady, this));
516 EXPECT_TRUE(waiter.Wait());
518 // Verify that the local host is online.
519 ASSERT_TRUE(ExecuteScriptAndExtractBool(
520 "remoting.hostList.localHost_.hostName && "
521 "remoting.hostList.localHost_.hostId && "
522 "remoting.hostList.localHost_.status && "
523 "remoting.hostList.localHost_.status == 'ONLINE'"));
525 // Connect.
526 ClickOnControl("this-host-connect");
528 // Enter the pin # passed in from the command line.
529 EnterPin(me2me_pin(), remember_pin);
531 WaitForConnection();
534 void RemoteDesktopBrowserTest::ConnectToRemoteHost(
535 const std::string& host_name, bool remember_pin) {
537 // Wait for hosts list to be fetched.
538 // This test typically runs with a clean user-profile, with no host-list
539 // cached. Waiting for the host-list to be null is sufficient to proceed.
540 ConditionalTimeoutWaiter waiter(
541 base::TimeDelta::FromSeconds(5),
542 base::TimeDelta::FromMilliseconds(500),
543 base::Bind(&RemoteDesktopBrowserTest::IsHostListReady, this));
544 EXPECT_TRUE(waiter.Wait());
546 std::string host_id = ExecuteScriptAndExtractString(
547 "remoting.hostList.getHostIdForName('" + host_name + "')");
549 EXPECT_FALSE(host_id.empty());
550 std::string element_id = "host_" + host_id;
552 // Verify the host is online.
553 std::string host_div_class = ExecuteScriptAndExtractString(
554 "document.getElementById('" + element_id + "').parentNode.className");
555 EXPECT_NE(std::string::npos, host_div_class.find("host-online"));
557 ClickOnControl(element_id);
559 // Enter the pin # passed in from the command line.
560 EnterPin(me2me_pin(), remember_pin);
562 WaitForConnection();
565 void RemoteDesktopBrowserTest::EnableDNSLookupForThisTest(
566 net::RuleBasedHostResolverProc* host_resolver) {
567 // mock_host_resolver_override_ takes ownership of the resolver.
568 scoped_refptr<net::RuleBasedHostResolverProc> resolver =
569 new net::RuleBasedHostResolverProc(host_resolver);
570 resolver->AllowDirectLookup("*.google.com");
571 // On Linux, we use Chromium's NSS implementation which uses the following
572 // hosts for certificate verification. Without these overrides, running the
573 // integration tests on Linux causes errors as we make external DNS lookups.
574 resolver->AllowDirectLookup("*.thawte.com");
575 resolver->AllowDirectLookup("*.geotrust.com");
576 resolver->AllowDirectLookup("*.gstatic.com");
577 resolver->AllowDirectLookup("*.googleapis.com");
578 mock_host_resolver_override_.reset(
579 new net::ScopedDefaultHostResolverProc(resolver.get()));
582 void RemoteDesktopBrowserTest::DisableDNSLookupForThisTest() {
583 mock_host_resolver_override_.reset();
586 void RemoteDesktopBrowserTest::ParseCommandLine() {
587 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
589 // The test framework overrides any command line user-data-dir
590 // argument with a /tmp/.org.chromium.Chromium.XXXXXX directory.
591 // That happens in the ChromeTestLauncherDelegate, and affects
592 // all unit tests (no opt out available). It intentionally erases
593 // any --user-data-dir switch if present and appends a new one.
594 // Re-override the default data dir if override-user-data-dir
595 // is specified.
596 if (command_line->HasSwitch(kOverrideUserDataDir)) {
597 const base::FilePath& override_user_data_dir =
598 command_line->GetSwitchValuePath(kOverrideUserDataDir);
600 ASSERT_FALSE(override_user_data_dir.empty());
602 command_line->AppendSwitchPath(switches::kUserDataDir,
603 override_user_data_dir);
606 base::CommandLine::StringType accounts_file =
607 command_line->GetSwitchValueNative(kAccountsFile);
608 std::string account_type = command_line->GetSwitchValueASCII(kAccountType);
609 if (!accounts_file.empty()) {
610 // We've been passed in a file containing accounts information.
611 // In this case, we'll obtain the user-name and password information from
612 // the specified file, even if user-name and password have been specified
613 // on the command-line.
614 base::FilePath accounts_file_path((base::FilePath(accounts_file)));
615 ASSERT_FALSE(account_type.empty());
616 ASSERT_TRUE(base::PathExists((base::FilePath(accounts_file))));
617 SetUserNameAndPassword((base::FilePath(accounts_file)), account_type);
618 } else {
619 // No file for accounts specified. Read user-name and password from command
620 // line.
621 username_ = command_line->GetSwitchValueASCII(kUserName);
622 password_ = command_line->GetSwitchValueASCII(kUserPassword);
625 me2me_pin_ = command_line->GetSwitchValueASCII(kMe2MePin);
626 remote_host_name_ = command_line->GetSwitchValueASCII(kRemoteHostName);
627 extension_name_ = command_line->GetSwitchValueASCII(kExtensionName);
628 http_server_ = command_line->GetSwitchValueASCII(kHttpServer);
630 no_cleanup_ = command_line->HasSwitch(kNoCleanup);
631 no_install_ = command_line->HasSwitch(kNoInstall);
633 if (!no_install_) {
634 webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx);
635 webapp_unpacked_ = command_line->GetSwitchValuePath(kWebAppUnpacked);
636 // One and only one of these two arguments should be provided.
637 ASSERT_NE(webapp_crx_.empty(), webapp_unpacked_.empty());
640 // Run with "enable-web-based-signin" flag to enforce web-based sign-in,
641 // rather than inline signin. This ensures we use the same authentication
642 // page, regardless of whether we are testing the v1 or v2 web-app.
643 command_line->AppendSwitch(switches::kEnableWebBasedSignin);
645 // Enable experimental extensions; this is to allow adding the LG extensions
646 command_line->AppendSwitch(
647 extensions::switches::kEnableExperimentalExtensionApis);
650 void RemoteDesktopBrowserTest::ExecuteScript(const std::string& script) {
651 ASSERT_TRUE(content::ExecuteScript(active_web_contents(), script));
654 void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForAnyPageLoad(
655 const std::string& script) {
656 content::WindowedNotificationObserver observer(
657 content::NOTIFICATION_LOAD_STOP,
658 content::Source<content::NavigationController>(
659 &active_web_contents()->
660 GetController()));
662 ExecuteScript(script);
664 observer.Wait();
667 // static
668 bool RemoteDesktopBrowserTest::ExecuteScriptAndExtractBool(
669 content::WebContents* web_contents, const std::string& script) {
670 bool result;
671 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
672 web_contents,
673 "window.domAutomationController.send(" + script + ");",
674 &result));
676 return result;
679 // static
680 int RemoteDesktopBrowserTest::ExecuteScriptAndExtractInt(
681 content::WebContents* web_contents, const std::string& script) {
682 int result;
683 _ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
684 web_contents,
685 "window.domAutomationController.send(" + script + ");",
686 &result));
688 return result;
691 // static
692 std::string RemoteDesktopBrowserTest::ExecuteScriptAndExtractString(
693 content::WebContents* web_contents, const std::string& script) {
694 std::string result;
695 _ASSERT_TRUE(content::ExecuteScriptAndExtractString(
696 web_contents,
697 "window.domAutomationController.send(" + script + ");",
698 &result));
700 return result;
703 // static
704 bool RemoteDesktopBrowserTest::LoadScript(
705 content::WebContents* web_contents,
706 const base::FilePath::StringType& path) {
707 std::string script;
708 base::FilePath src_dir;
709 _ASSERT_TRUE(PathService::Get(base::DIR_EXE, &src_dir));
710 base::FilePath script_path = src_dir.Append(path);
712 if (!base::ReadFileToString(script_path, &script)) {
713 LOG(ERROR) << "Failed to load script " << script_path.value();
714 return false;
717 return content::ExecuteScript(web_contents, script);
720 // static
721 void RemoteDesktopBrowserTest::RunJavaScriptTest(
722 content::WebContents* web_contents,
723 const std::string& testName,
724 const std::string& testData) {
725 std::string result;
726 std::string script = "browserTest.runTest(browserTest." + testName + ", " +
727 testData + ");";
729 DVLOG(1) << "Executing " << script;
731 ASSERT_TRUE(
732 content::ExecuteScriptAndExtractString(web_contents, script, &result));
734 // Read in the JSON
735 base::JSONReader reader;
736 scoped_ptr<base::Value> value;
737 value.reset(reader.Read(result, base::JSON_ALLOW_TRAILING_COMMAS));
739 // Convert to dictionary
740 base::DictionaryValue* dict_value = NULL;
741 ASSERT_TRUE(value->GetAsDictionary(&dict_value));
743 bool succeeded;
744 std::string error_message;
745 std::string stack_trace;
747 // Extract the fields
748 ASSERT_TRUE(dict_value->GetBoolean("succeeded", &succeeded));
749 ASSERT_TRUE(dict_value->GetString("error_message", &error_message));
750 ASSERT_TRUE(dict_value->GetString("stack_trace", &stack_trace));
752 EXPECT_TRUE(succeeded) << error_message << "\n" << stack_trace;
755 void RemoteDesktopBrowserTest::ClickOnControl(const std::string& name) {
756 ASSERT_TRUE(HtmlElementVisible(name));
758 std::string has_disabled_attribute =
759 "document.getElementById('" + name + "').hasAttribute('disabled')";
761 if (ExecuteScriptAndExtractBool(active_web_contents(),
762 has_disabled_attribute)) {
763 // This element has a disabled attribute. Wait for it become enabled.
764 ConditionalTimeoutWaiter waiter(
765 base::TimeDelta::FromSeconds(5),
766 base::TimeDelta::FromMilliseconds(500),
767 base::Bind(&RemoteDesktopBrowserTest::IsEnabled,
768 active_web_contents(), name));
769 ASSERT_TRUE(waiter.Wait());
772 ExecuteScript("document.getElementById(\"" + name + "\").click();");
775 void RemoteDesktopBrowserTest::EnterPin(const std::string& pin,
776 bool remember_pin) {
777 // Wait for the pin-form to be displayed. This can take a while.
778 // We also need to dismiss the host-needs-update dialog if it comes up.
779 // TODO(weitaosu) 1: Instead of polling, can we register a callback to be
780 // called when the pin-form is ready?
781 // TODO(weitaosu) 2: Instead of blindly dismiss the host-needs-update dialog,
782 // we should verify that it only pops up at the right circumstance. That
783 // probably belongs in a separate test case though.
784 ConditionalTimeoutWaiter waiter(
785 base::TimeDelta::FromSeconds(30),
786 base::TimeDelta::FromSeconds(1),
787 base::Bind(&RemoteDesktopBrowserTest::IsPinFormVisible, this));
788 EXPECT_TRUE(waiter.Wait());
790 ExecuteScript(
791 "document.getElementById(\"pin-entry\").value = \"" + pin + "\";");
793 if (remember_pin) {
794 EXPECT_TRUE(HtmlElementVisible("remember-pin"));
795 EXPECT_FALSE(ExecuteScriptAndExtractBool(
796 "document.getElementById('remember-pin-checkbox').checked"));
797 ClickOnControl("remember-pin");
798 EXPECT_TRUE(ExecuteScriptAndExtractBool(
799 "document.getElementById('remember-pin-checkbox').checked"));
802 ClickOnControl("pin-connect-button");
805 void RemoteDesktopBrowserTest::WaitForConnection() {
806 // Wait until the client has connected to the server.
807 // This can take a while.
808 // TODO(weitaosu): Instead of polling, can we register a callback to
809 // remoting.clientSession.onStageChange_?
810 ConditionalTimeoutWaiter waiter(
811 base::TimeDelta::FromSeconds(30),
812 base::TimeDelta::FromSeconds(1),
813 base::Bind(&RemoteDesktopBrowserTest::IsSessionConnected, this));
814 EXPECT_TRUE(waiter.Wait());
816 // The client is not yet ready to take input when the session state becomes
817 // CONNECTED. Wait for 2 seconds for the client to become ready.
818 // TODO(weitaosu): Find a way to detect when the client is truly ready.
819 TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait();
822 bool RemoteDesktopBrowserTest::IsLocalHostReady() {
823 // TODO(weitaosu): Instead of polling, can we register a callback to
824 // remoting.hostList.setLocalHost_?
825 return ExecuteScriptAndExtractBool("remoting.hostList.localHost_ != null");
828 bool RemoteDesktopBrowserTest::IsHostListReady() {
829 // Wait until hostList is not null.
830 // The connect-to-host tests are run on the waterfall using a new profile-dir.
831 // No hosts will be cached.
832 return ExecuteScriptAndExtractBool(
833 "remoting.hostList != null && remoting.hostList.hosts_ != null");
836 bool RemoteDesktopBrowserTest::IsSessionConnected() {
837 // If some form of PINless authentication is enabled, the host version
838 // warning may appear while waiting for the session to connect.
839 DismissHostVersionWarningIfVisible();
841 return ExecuteScriptAndExtractBool(
842 "remoting.clientSession != null && "
843 "remoting.clientSession.getState() == "
844 "remoting.ClientSession.State.CONNECTED");
847 bool RemoteDesktopBrowserTest::IsPinFormVisible() {
848 DismissHostVersionWarningIfVisible();
849 return HtmlElementVisible("pin-form");
852 void RemoteDesktopBrowserTest::DismissHostVersionWarningIfVisible() {
853 if (HtmlElementVisible("host-needs-update-connect-button"))
854 ClickOnControl("host-needs-update-connect-button");
857 void RemoteDesktopBrowserTest::SetUserNameAndPassword(
858 const base::FilePath &accounts_file_path, const std::string& account_type) {
860 // Read contents of accounts file, using its absolute path.
861 base::FilePath absolute_path = base::MakeAbsoluteFilePath(accounts_file_path);
862 std::string accounts_info;
863 ASSERT_TRUE(base::ReadFileToString(absolute_path, &accounts_info));
865 // Get the root dictionary from the input json file contents.
866 scoped_ptr<base::Value> root(
867 base::JSONReader::Read(accounts_info, base::JSON_ALLOW_TRAILING_COMMAS));
869 const base::DictionaryValue* root_dict = NULL;
870 ASSERT_TRUE(root.get() && root->GetAsDictionary(&root_dict));
872 // Now get the dictionary for the specified account type.
873 const base::DictionaryValue* account_dict = NULL;
874 ASSERT_TRUE(root_dict->GetDictionary(account_type, &account_dict));
875 ASSERT_TRUE(account_dict->GetString(kUserName, &username_));
876 ASSERT_TRUE(account_dict->GetString(kUserPassword, &password_));
879 // static
880 bool RemoteDesktopBrowserTest::IsAuthenticatedInWindow(
881 content::WebContents* web_contents) {
882 return ExecuteScriptAndExtractBool(
883 web_contents, "remoting.identity.isAuthenticated()");
886 // static
887 bool RemoteDesktopBrowserTest::IsHostActionComplete(
888 content::WebContents* client_web_content,
889 std::string host_action_var) {
890 return ExecuteScriptAndExtractBool(
891 client_web_content,
892 host_action_var);
895 // static
896 bool RemoteDesktopBrowserTest::IsEnabled(
897 content::WebContents* client_web_content,
898 const std::string& element_name) {
899 return !ExecuteScriptAndExtractBool(
900 client_web_content,
901 "document.getElementById(\"" + element_name + "\").disabled");
904 } // namespace remoting