remote_desktop_browsertest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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#include "chrome/test/remoting/remote_desktop_browsertest.h" 6 7#include "base/command_line.h" 8#include "chrome/browser/extensions/extension_service.h" 9#include "chrome/browser/extensions/unpacked_installer.h" 10#include "chrome/browser/ui/extensions/application_launch.h" 11#include "chrome/common/chrome_switches.h" 12#include "chrome/common/extensions/extension_file_util.h" 13#include "chrome/test/remoting/key_code_conv.h" 14#include "chrome/test/remoting/page_load_notification_observer.h" 15#include "chrome/test/remoting/waiter.h" 16#include "content/public/browser/native_web_keyboard_event.h" 17#include "content/public/browser/render_view_host.h" 18#include "content/public/test/test_utils.h" 19#include "extensions/common/constants.h" 20#include "extensions/common/extension.h" 21#include "ui/base/window_open_disposition.h" 22 23namespace remoting { 24 25RemoteDesktopBrowserTest::RemoteDesktopBrowserTest() 26 : extension_(NULL) { 27} 28 29RemoteDesktopBrowserTest::~RemoteDesktopBrowserTest() {} 30 31void RemoteDesktopBrowserTest::SetUp() { 32 ParseCommandLine(); 33 PlatformAppBrowserTest::SetUp(); 34} 35 36void RemoteDesktopBrowserTest::SetUpOnMainThread() { 37 PlatformAppBrowserTest::SetUpOnMainThread(); 38 39 // Pushing the initial WebContents instance onto the stack before 40 // RunTestOnMainThread() and after |InProcessBrowserTest::browser_| 41 // is initialized in InProcessBrowserTest::RunTestOnMainThreadLoop() 42 web_contents_stack_.push_back( 43 browser()->tab_strip_model()->GetActiveWebContents()); 44} 45 46// Change behavior of the default host resolver to avoid DNS lookup errors, 47// so we can make network calls. 48void RemoteDesktopBrowserTest::SetUpInProcessBrowserTestFixture() { 49 // The resolver object lifetime is managed by sync_test_setup, not here. 50 EnableDNSLookupForThisTest( 51 new net::RuleBasedHostResolverProc(host_resolver())); 52} 53 54void RemoteDesktopBrowserTest::TearDownInProcessBrowserTestFixture() { 55 DisableDNSLookupForThisTest(); 56} 57 58void RemoteDesktopBrowserTest::VerifyInternetAccess() { 59 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( 60 browser(), GURL("http://www.google.com"), 1); 61 62 EXPECT_EQ(GetCurrentURL().host(), "www.google.com"); 63} 64 65bool RemoteDesktopBrowserTest::HtmlElementVisible(const std::string& name) { 66 _ASSERT_TRUE(HtmlElementExists(name)); 67 68 ExecuteScript( 69 "function isElementVisible(name) {" 70 " var element = document.getElementById(name);" 71 " /* The existence of the element has already been ASSERTed. */" 72 " do {" 73 " if (element.hidden) {" 74 " return false;" 75 " }" 76 " element = element.parentNode;" 77 " } while (element != null);" 78 " return true;" 79 "};"); 80 81 return ExecuteScriptAndExtractBool( 82 "isElementVisible(\"" + name + "\")"); 83} 84 85void RemoteDesktopBrowserTest::InstallChromotingAppCrx() { 86 ASSERT_TRUE(!is_unpacked()); 87 88 base::FilePath install_dir(WebAppCrxPath()); 89 scoped_refptr<const Extension> extension(InstallExtensionWithUIAutoConfirm( 90 install_dir, 1, browser())); 91 92 EXPECT_FALSE(extension.get() == NULL); 93 94 extension_ = extension.get(); 95} 96 97void RemoteDesktopBrowserTest::InstallChromotingAppUnpacked() { 98 ASSERT_TRUE(is_unpacked()); 99 100 scoped_refptr<extensions::UnpackedInstaller> installer = 101 extensions::UnpackedInstaller::Create(extension_service()); 102 installer->set_prompt_for_plugins(false); 103 104 content::WindowedNotificationObserver observer( 105 chrome::NOTIFICATION_EXTENSION_LOADED, 106 content::NotificationService::AllSources()); 107 108 installer->Load(webapp_unpacked_); 109 110 observer.Wait(); 111} 112 113void RemoteDesktopBrowserTest::UninstallChromotingApp() { 114 UninstallExtension(ChromotingID()); 115 extension_ = NULL; 116} 117 118void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) { 119 const ExtensionSet* extensions = extension_service()->extensions(); 120 scoped_refptr<const extensions::Extension> extension; 121 ExtensionSet::const_iterator iter; 122 bool installed = false; 123 124 for (iter = extensions->begin(); iter != extensions->end(); ++iter) { 125 extension = *iter; 126 // Is there a better way to recognize the chromoting extension 127 // than name comparison? 128 if (extension->name() == "Chromoting" || 129 extension->name() == "Chrome Remote Desktop") { 130 installed = true; 131 break; 132 } 133 } 134 135 if (installed) { 136 if (extension_) 137 EXPECT_EQ(extension, extension_); 138 else 139 extension_ = extension.get(); 140 141 // Either a V1 (TYPE_LEGACY_PACKAGED_APP) or a V2 (TYPE_PLATFORM_APP ) app. 142 extensions::Manifest::Type type = extension->GetType(); 143 EXPECT_TRUE(type == extensions::Manifest::TYPE_PLATFORM_APP || 144 type == extensions::Manifest::TYPE_LEGACY_PACKAGED_APP); 145 146 EXPECT_TRUE(extension->ShouldDisplayInAppLauncher()); 147 } 148 149 EXPECT_EQ(installed, expected); 150} 151 152void RemoteDesktopBrowserTest::LaunchChromotingApp() { 153 ASSERT_TRUE(extension_); 154 155 GURL chromoting_main = Chromoting_Main_URL(); 156 // We cannot simply wait for any page load because the first page 157 // loaded could be the generated background page. We need to wait 158 // till the chromoting main page is loaded. 159 PageLoadNotificationObserver observer(chromoting_main); 160 161 OpenApplication(AppLaunchParams( 162 browser()->profile(), 163 extension_, 164 is_platform_app() ? extensions::LAUNCH_NONE : extensions::LAUNCH_TAB, 165 is_platform_app() ? NEW_WINDOW : CURRENT_TAB)); 166 167 observer.Wait(); 168 169 170 // The active WebContents instance should be the source of the LOAD_STOP 171 // notification. 172 content::NavigationController* controller = 173 content::Source<content::NavigationController>(observer.source()).ptr(); 174 175 content::WebContents* web_contents = controller->GetWebContents(); 176 if (web_contents != active_web_contents()) 177 web_contents_stack_.push_back(web_contents); 178 179 if (is_platform_app()) { 180 EXPECT_EQ(GetFirstShellWindowWebContents(), active_web_contents()); 181 } else { 182 // For apps v1 only, the DOMOperationObserver is not ready at the LOAD_STOP 183 // event. A half second wait is necessary for the subsequent javascript 184 // injection to work. 185 // TODO(weitaosu): Find out whether there is a more appropriate notification 186 // to wait for so we can get rid of this wait. 187 ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromMilliseconds(500)).Wait()); 188 } 189 190 EXPECT_EQ(Chromoting_Main_URL(), GetCurrentURL()); 191} 192 193void RemoteDesktopBrowserTest::Authorize() { 194 // The chromoting extension should be installed. 195 ASSERT_TRUE(extension_); 196 197 // The chromoting main page should be loaded in the current tab 198 // and isAuthenticated() should be false (auth dialog visible). 199 ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL()); 200 ASSERT_FALSE(IsAuthenticated()); 201 202 // The second observer monitors the loading of the Google login page. 203 // Unfortunately we cannot specify a source in this observer because 204 // we can't get a handle of the new window until the first observer 205 // has finished waiting. But we will assert that the source of the 206 // load stop event is indeed the newly created browser window. 207 content::WindowedNotificationObserver observer( 208 content::NOTIFICATION_LOAD_STOP, 209 content::NotificationService::AllSources()); 210 211 ClickOnControl("auth-button"); 212 213 observer.Wait(); 214 215 content::NavigationController* controller = 216 content::Source<content::NavigationController>(observer.source()).ptr(); 217 218 web_contents_stack_.push_back(controller->GetWebContents()); 219 220 // Verify the active tab is at the "Google Accounts" login page. 221 EXPECT_EQ("accounts.google.com", GetCurrentURL().host()); 222 EXPECT_TRUE(HtmlElementExists("Email")); 223 EXPECT_TRUE(HtmlElementExists("Passwd")); 224} 225 226void RemoteDesktopBrowserTest::Authenticate() { 227 // The chromoting extension should be installed. 228 ASSERT_TRUE(extension_); 229 230 // The active tab should have the "Google Accounts" login page loaded. 231 ASSERT_EQ("accounts.google.com", GetCurrentURL().host()); 232 ASSERT_TRUE(HtmlElementExists("Email")); 233 ASSERT_TRUE(HtmlElementExists("Passwd")); 234 235 // Now log in using the username and password passed in from the command line. 236 ExecuteScriptAndWaitForAnyPageLoad( 237 "document.getElementById(\"Email\").value = \"" + username_ + "\";" + 238 "document.getElementById(\"Passwd\").value = \"" + password_ +"\";" + 239 "document.forms[\"gaia_loginform\"].submit();"); 240 241 // TODO(weitaosu): Is there a better way to verify we are on the 242 // "Request for Permission" page? 243 // V2 app won't ask for approval here because the chromoting test account 244 // has already been granted permissions. 245 if (!is_platform_app()) { 246 EXPECT_EQ(GetCurrentURL().host(), "accounts.google.com"); 247 EXPECT_TRUE(HtmlElementExists("submit_approve_access")); 248 } 249} 250 251void RemoteDesktopBrowserTest::Approve() { 252 // The chromoting extension should be installed. 253 ASSERT_TRUE(extension_); 254 255 if (is_platform_app()) { 256 // Popping the login window off the stack to return to the chromoting 257 // window. 258 web_contents_stack_.pop_back(); 259 260 // There is nothing for the V2 app to approve because the chromoting test 261 // account has already been granted permissions. 262 // TODO(weitaosu): Revoke the permission at the beginning of the test so 263 // that we can test first-time experience here. 264 ConditionalTimeoutWaiter waiter( 265 base::TimeDelta::FromSeconds(3), 266 base::TimeDelta::FromSeconds(1), 267 base::Bind( 268 &RemoteDesktopBrowserTest::IsAuthenticatedInWindow, 269 active_web_contents())); 270 271 ASSERT_TRUE(waiter.Wait()); 272 } else { 273 ASSERT_EQ("accounts.google.com", GetCurrentURL().host()); 274 275 // Is there a better way to verify we are on the "Request for Permission" 276 // page? 277 ASSERT_TRUE(HtmlElementExists("submit_approve_access")); 278 279 const GURL chromoting_main = Chromoting_Main_URL(); 280 281 // active_web_contents() is still the login window but the observer 282 // should be set up to observe the chromoting window because that is 283 // where we'll receive the message from the login window and reload the 284 // chromoting app. 285 content::WindowedNotificationObserver observer( 286 content::NOTIFICATION_LOAD_STOP, 287 base::Bind( 288 &RemoteDesktopBrowserTest::IsAuthenticatedInWindow, 289 browser()->tab_strip_model()->GetActiveWebContents())); 290 291 ExecuteScript( 292 "lso.approveButtonAction();" 293 "document.forms[\"connect-approve\"].submit();"); 294 295 observer.Wait(); 296 297 // Popping the login window off the stack to return to the chromoting 298 // window. 299 web_contents_stack_.pop_back(); 300 } 301 302 ASSERT_TRUE(GetCurrentURL() == Chromoting_Main_URL()); 303 304 EXPECT_TRUE(IsAuthenticated()); 305} 306 307void RemoteDesktopBrowserTest::ExpandMe2Me() { 308 // The chromoting extension should be installed. 309 ASSERT_TRUE(extension_); 310 311 // The active tab should have the chromoting app loaded. 312 ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL()); 313 EXPECT_TRUE(IsAuthenticated()); 314 315 // The Me2Me host list should be hidden. 316 ASSERT_FALSE(HtmlElementVisible("me2me-content")); 317 // The Me2Me "Get Start" button should be visible. 318 ASSERT_TRUE(HtmlElementVisible("get-started-me2me")); 319 320 // Starting Me2Me. 321 ExecuteScript("remoting.showMe2MeUiAndSave();"); 322 323 EXPECT_TRUE(HtmlElementVisible("me2me-content")); 324 EXPECT_FALSE(HtmlElementVisible("me2me-first-run")); 325 326 // Wait until localHost is initialized. This can take a while. 327 ConditionalTimeoutWaiter waiter( 328 base::TimeDelta::FromSeconds(3), 329 base::TimeDelta::FromSeconds(1), 330 base::Bind(&RemoteDesktopBrowserTest::IsLocalHostReady, this)); 331 EXPECT_TRUE(waiter.Wait()); 332 333 EXPECT_TRUE(ExecuteScriptAndExtractBool( 334 "remoting.hostList.localHost_.hostName && " 335 "remoting.hostList.localHost_.hostId && " 336 "remoting.hostList.localHost_.status && " 337 "remoting.hostList.localHost_.status == 'ONLINE'")); 338} 339 340void RemoteDesktopBrowserTest::DisconnectMe2Me() { 341 // The chromoting extension should be installed. 342 ASSERT_TRUE(extension_); 343 344 // The active tab should have the chromoting app loaded. 345 ASSERT_EQ(Chromoting_Main_URL(), GetCurrentURL()); 346 ASSERT_TRUE(RemoteDesktopBrowserTest::IsSessionConnected()); 347 348 ClickOnControl("toolbar-stub"); 349 350 EXPECT_TRUE(HtmlElementVisible("session-toolbar")); 351 352 ClickOnControl("toolbar-disconnect"); 353 354 EXPECT_TRUE(HtmlElementVisible("client-dialog")); 355 EXPECT_TRUE(HtmlElementVisible("client-reconnect-button")); 356 EXPECT_TRUE(HtmlElementVisible("client-finished-me2me-button")); 357 358 ClickOnControl("client-finished-me2me-button"); 359 360 EXPECT_FALSE(HtmlElementVisible("client-dialog")); 361} 362 363void RemoteDesktopBrowserTest::SimulateKeyPressWithCode( 364 ui::KeyboardCode keyCode, 365 const char* code) { 366 SimulateKeyPressWithCode(keyCode, code, false, false, false, false); 367} 368 369void RemoteDesktopBrowserTest::SimulateKeyPressWithCode( 370 ui::KeyboardCode keyCode, 371 const char* code, 372 bool control, 373 bool shift, 374 bool alt, 375 bool command) { 376 content::SimulateKeyPressWithCode( 377 active_web_contents(), 378 keyCode, 379 code, 380 control, 381 shift, 382 alt, 383 command); 384} 385 386void RemoteDesktopBrowserTest::SimulateCharInput(char c) { 387 const char* code; 388 ui::KeyboardCode keyboard_code; 389 bool shift; 390 GetKeyValuesFromChar(c, &code, &keyboard_code, &shift); 391 ASSERT_TRUE(code != NULL); 392 SimulateKeyPressWithCode(keyboard_code, code, false, shift, false, false); 393} 394 395void RemoteDesktopBrowserTest::SimulateStringInput(const std::string& input) { 396 for (size_t i = 0; i < input.length(); ++i) 397 SimulateCharInput(input[i]); 398} 399 400void RemoteDesktopBrowserTest::SimulateMouseLeftClickAt(int x, int y) { 401 SimulateMouseClickAt(0, blink::WebMouseEvent::ButtonLeft, x, y); 402} 403 404void RemoteDesktopBrowserTest::SimulateMouseClickAt( 405 int modifiers, blink::WebMouseEvent::Button button, int x, int y) { 406 // TODO(weitaosu): The coordinate translation doesn't work correctly for 407 // apps v2. 408 ExecuteScript( 409 "var clientPluginElement = " 410 "document.getElementById('session-client-plugin');" 411 "var clientPluginRect = clientPluginElement.getBoundingClientRect();"); 412 413 int top = ExecuteScriptAndExtractInt("clientPluginRect.top"); 414 int left = ExecuteScriptAndExtractInt("clientPluginRect.left"); 415 int width = ExecuteScriptAndExtractInt("clientPluginRect.width"); 416 int height = ExecuteScriptAndExtractInt("clientPluginRect.height"); 417 418 ASSERT_GT(x, 0); 419 ASSERT_LT(x, width); 420 ASSERT_GT(y, 0); 421 ASSERT_LT(y, height); 422 423 content::SimulateMouseClickAt( 424 browser()->tab_strip_model()->GetActiveWebContents(), 425 modifiers, 426 button, 427 gfx::Point(left + x, top + y)); 428} 429 430void RemoteDesktopBrowserTest::Install() { 431 if (!NoInstall()) { 432 VerifyChromotingLoaded(false); 433 if (is_unpacked()) 434 InstallChromotingAppUnpacked(); 435 else 436 InstallChromotingAppCrx(); 437 } 438 439 VerifyChromotingLoaded(true); 440} 441 442void RemoteDesktopBrowserTest::Cleanup() { 443 // TODO(weitaosu): Remove this hack by blocking on the appropriate 444 // notification. 445 // The browser may still be loading images embedded in the webapp. If we 446 // uinstall it now those load will fail. 447 ASSERT_TRUE(TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait()); 448 449 if (!NoCleanup()) { 450 UninstallChromotingApp(); 451 VerifyChromotingLoaded(false); 452 } 453} 454 455void RemoteDesktopBrowserTest::Auth() { 456 Authorize(); 457 Authenticate(); 458 Approve(); 459} 460 461void RemoteDesktopBrowserTest::ConnectToLocalHost(bool remember_pin) { 462 // Verify that the local host is online. 463 ASSERT_TRUE(ExecuteScriptAndExtractBool( 464 "remoting.hostList.localHost_.hostName && " 465 "remoting.hostList.localHost_.hostId && " 466 "remoting.hostList.localHost_.status && " 467 "remoting.hostList.localHost_.status == 'ONLINE'")); 468 469 // Connect. 470 ClickOnControl("this-host-connect"); 471 472 // Enter the pin # passed in from the command line. 473 EnterPin(me2me_pin(), remember_pin); 474 475 WaitForConnection(); 476} 477 478void RemoteDesktopBrowserTest::ConnectToRemoteHost( 479 const std::string& host_name, bool remember_pin) { 480 std::string host_id = ExecuteScriptAndExtractString( 481 "remoting.hostList.getHostIdForName('" + host_name + "')"); 482 483 EXPECT_FALSE(host_id.empty()); 484 std::string element_id = "host_" + host_id; 485 486 // Verify the host is online. 487 std::string host_div_class = ExecuteScriptAndExtractString( 488 "document.getElementById('" + element_id + "').parentNode.className"); 489 EXPECT_NE(std::string::npos, host_div_class.find("host-online")); 490 491 ClickOnControl(element_id); 492 493 // Enter the pin # passed in from the command line. 494 EnterPin(me2me_pin(), remember_pin); 495 496 WaitForConnection(); 497} 498 499void RemoteDesktopBrowserTest::EnableDNSLookupForThisTest( 500 net::RuleBasedHostResolverProc* host_resolver) { 501 // mock_host_resolver_override_ takes ownership of the resolver. 502 scoped_refptr<net::RuleBasedHostResolverProc> resolver = 503 new net::RuleBasedHostResolverProc(host_resolver); 504 resolver->AllowDirectLookup("*.google.com"); 505 // On Linux, we use Chromium's NSS implementation which uses the following 506 // hosts for certificate verification. Without these overrides, running the 507 // integration tests on Linux causes errors as we make external DNS lookups. 508 resolver->AllowDirectLookup("*.thawte.com"); 509 resolver->AllowDirectLookup("*.geotrust.com"); 510 resolver->AllowDirectLookup("*.gstatic.com"); 511 resolver->AllowDirectLookup("*.googleapis.com"); 512 mock_host_resolver_override_.reset( 513 new net::ScopedDefaultHostResolverProc(resolver.get())); 514} 515 516void RemoteDesktopBrowserTest::DisableDNSLookupForThisTest() { 517 mock_host_resolver_override_.reset(); 518} 519 520void RemoteDesktopBrowserTest::ParseCommandLine() { 521 CommandLine* command_line = CommandLine::ForCurrentProcess(); 522 523 // The test framework overrides any command line user-data-dir 524 // argument with a /tmp/.org.chromium.Chromium.XXXXXX directory. 525 // That happens in the ChromeTestLauncherDelegate, and affects 526 // all unit tests (no opt out available). It intentionally erases 527 // any --user-data-dir switch if present and appends a new one. 528 // Re-override the default data dir if override-user-data-dir 529 // is specified. 530 if (command_line->HasSwitch(kOverrideUserDataDir)) { 531 const base::FilePath& override_user_data_dir = 532 command_line->GetSwitchValuePath(kOverrideUserDataDir); 533 534 ASSERT_FALSE(override_user_data_dir.empty()); 535 536 command_line->AppendSwitchPath(switches::kUserDataDir, 537 override_user_data_dir); 538 } 539 540 username_ = command_line->GetSwitchValueASCII(kUsername); 541 password_ = command_line->GetSwitchValueASCII(kkPassword); 542 me2me_pin_ = command_line->GetSwitchValueASCII(kMe2MePin); 543 remote_host_name_ = command_line->GetSwitchValueASCII(kRemoteHostName); 544 545 no_cleanup_ = command_line->HasSwitch(kNoCleanup); 546 no_install_ = command_line->HasSwitch(kNoInstall); 547 548 if (!no_install_) { 549 webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx); 550 webapp_unpacked_ = command_line->GetSwitchValuePath(kWebAppUnpacked); 551 // One and only one of these two arguments should be provided. 552 ASSERT_NE(webapp_crx_.empty(), webapp_unpacked_.empty()); 553 } 554} 555 556void RemoteDesktopBrowserTest::ExecuteScript(const std::string& script) { 557 ASSERT_TRUE(content::ExecuteScript(active_web_contents(), script)); 558} 559 560void RemoteDesktopBrowserTest::ExecuteScriptAndWaitForAnyPageLoad( 561 const std::string& script) { 562 content::WindowedNotificationObserver observer( 563 content::NOTIFICATION_LOAD_STOP, 564 content::Source<content::NavigationController>( 565 &active_web_contents()-> 566 GetController())); 567 568 ExecuteScript(script); 569 570 observer.Wait(); 571} 572 573// static 574bool RemoteDesktopBrowserTest::ExecuteScriptAndExtractBool( 575 content::WebContents* web_contents, const std::string& script) { 576 bool result; 577 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( 578 web_contents, 579 "window.domAutomationController.send(" + script + ");", 580 &result)); 581 582 return result; 583} 584 585// static 586int RemoteDesktopBrowserTest::ExecuteScriptAndExtractInt( 587 content::WebContents* web_contents, const std::string& script) { 588 int result; 589 _ASSERT_TRUE(content::ExecuteScriptAndExtractInt( 590 web_contents, 591 "window.domAutomationController.send(" + script + ");", 592 &result)); 593 594 return result; 595} 596 597// static 598std::string RemoteDesktopBrowserTest::ExecuteScriptAndExtractString( 599 content::WebContents* web_contents, const std::string& script) { 600 std::string result; 601 _ASSERT_TRUE(content::ExecuteScriptAndExtractString( 602 web_contents, 603 "window.domAutomationController.send(" + script + ");", 604 &result)); 605 606 return result; 607} 608 609void RemoteDesktopBrowserTest::ClickOnControl(const std::string& name) { 610 ASSERT_TRUE(HtmlElementVisible(name)); 611 612 ExecuteScript("document.getElementById(\"" + name + "\").click();"); 613} 614 615void RemoteDesktopBrowserTest::EnterPin(const std::string& pin, 616 bool remember_pin) { 617 // Wait for the pin-form to be displayed. This can take a while. 618 // We also need to dismiss the host-needs-update dialog if it comes up. 619 // TODO(weitaosu) 1: Instead of polling, can we register a callback to be 620 // called when the pin-form is ready? 621 // TODO(weitaosu) 2: Instead of blindly dismiss the host-needs-update dialog, 622 // we should verify that it only pops up at the right circumstance. That 623 // probably belongs in a separate test case though. 624 ConditionalTimeoutWaiter waiter( 625 base::TimeDelta::FromSeconds(5), 626 base::TimeDelta::FromSeconds(1), 627 base::Bind(&RemoteDesktopBrowserTest::IsPinFormVisible, this)); 628 EXPECT_TRUE(waiter.Wait()); 629 630 ExecuteScript( 631 "document.getElementById(\"pin-entry\").value = \"" + pin + "\";"); 632 633 if (remember_pin) { 634 EXPECT_TRUE(HtmlElementVisible("remember-pin")); 635 EXPECT_FALSE(ExecuteScriptAndExtractBool( 636 "document.getElementById('remember-pin-checkbox').checked")); 637 ClickOnControl("remember-pin"); 638 EXPECT_TRUE(ExecuteScriptAndExtractBool( 639 "document.getElementById('remember-pin-checkbox').checked")); 640 } 641 642 ClickOnControl("pin-connect-button"); 643} 644 645void RemoteDesktopBrowserTest::WaitForConnection() { 646 // Wait until the client has connected to the server. 647 // This can take a while. 648 // TODO(weitaosu): Instead of polling, can we register a callback to 649 // remoting.clientSession.onStageChange_? 650 ConditionalTimeoutWaiter waiter( 651 base::TimeDelta::FromSeconds(4), 652 base::TimeDelta::FromSeconds(1), 653 base::Bind(&RemoteDesktopBrowserTest::IsSessionConnected, this)); 654 EXPECT_TRUE(waiter.Wait()); 655 656 // The client is not yet ready to take input when the session state becomes 657 // CONNECTED. Wait for 2 seconds for the client to become ready. 658 // TODO(weitaosu): Find a way to detect when the client is truly ready. 659 TimeoutWaiter(base::TimeDelta::FromSeconds(2)).Wait(); 660} 661 662bool RemoteDesktopBrowserTest::IsLocalHostReady() { 663 // TODO(weitaosu): Instead of polling, can we register a callback to 664 // remoting.hostList.setLocalHost_? 665 return ExecuteScriptAndExtractBool("remoting.hostList.localHost_ != null"); 666} 667 668bool RemoteDesktopBrowserTest::IsSessionConnected() { 669 // If some form of PINless authentication is enabled, the host version 670 // warning may appear while waiting for the session to connect. 671 DismissHostVersionWarningIfVisible(); 672 673 return ExecuteScriptAndExtractBool( 674 "remoting.clientSession != null && " 675 "remoting.clientSession.getState() == " 676 "remoting.ClientSession.State.CONNECTED"); 677} 678 679bool RemoteDesktopBrowserTest::IsPinFormVisible() { 680 DismissHostVersionWarningIfVisible(); 681 return HtmlElementVisible("pin-form"); 682} 683 684void RemoteDesktopBrowserTest::DismissHostVersionWarningIfVisible() { 685 if (HtmlElementVisible("host-needs-update-connect-button")) 686 ClickOnControl("host-needs-update-connect-button"); 687} 688 689// static 690bool RemoteDesktopBrowserTest::IsAuthenticatedInWindow( 691 content::WebContents* web_contents) { 692 return ExecuteScriptAndExtractBool( 693 web_contents, "remoting.identity.isAuthenticated()"); 694} 695 696} // namespace remoting 697