kiosk_browsertest.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright (c) 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 "base/command_line.h" 6#include "base/memory/scoped_ptr.h" 7#include "base/message_loop/message_loop.h" 8#include "base/path_service.h" 9#include "base/strings/stringprintf.h" 10#include "chrome/browser/browser_process.h" 11#include "chrome/browser/chrome_browser_main.h" 12#include "chrome/browser/chrome_browser_main_extra_parts.h" 13#include "chrome/browser/chrome_content_browser_client.h" 14#include "chrome/browser/chrome_notification_types.h" 15#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" 16#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" 17#include "chrome/browser/chromeos/login/app_launch_controller.h" 18#include "chrome/browser/chromeos/login/existing_user_controller.h" 19#include "chrome/browser/chromeos/login/login_display_host_impl.h" 20#include "chrome/browser/chromeos/login/webui_login_display.h" 21#include "chrome/browser/chromeos/login/wizard_controller.h" 22#include "chrome/browser/extensions/extension_service.h" 23#include "chrome/browser/extensions/extension_system.h" 24#include "chrome/browser/lifetime/application_lifetime.h" 25#include "chrome/browser/prefs/scoped_user_pref_update.h" 26#include "chrome/browser/profiles/profile_manager.h" 27#include "chrome/browser/ui/browser.h" 28#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 29#include "chrome/common/chrome_paths.h" 30#include "chrome/common/chrome_switches.h" 31#include "chrome/common/extensions/extension.h" 32#include "chrome/test/base/in_process_browser_test.h" 33#include "chrome/test/base/interactive_test_utils.h" 34#include "chrome/test/base/ui_test_utils.h" 35#include "chromeos/chromeos_switches.h" 36#include "content/public/browser/notification_observer.h" 37#include "content/public/browser/notification_registrar.h" 38#include "content/public/browser/notification_service.h" 39#include "content/public/test/test_utils.h" 40#include "google_apis/gaia/gaia_switches.h" 41#include "net/base/host_port_pair.h" 42#include "net/dns/mock_host_resolver.h" 43#include "net/test/embedded_test_server/embedded_test_server.h" 44#include "net/test/embedded_test_server/http_request.h" 45#include "net/test/embedded_test_server/http_response.h" 46#include "testing/gmock/include/gmock/gmock.h" 47#include "testing/gtest/include/gtest/gtest.h" 48 49using namespace net::test_server; 50 51namespace chromeos { 52 53namespace { 54 55const char kWebstoreDomain[] = "cws.com"; 56const base::FilePath kServiceLogin("chromeos/service_login.html"); 57 58// Webstore data json is in 59// chrome/test/data/chromeos/app_mode/webstore/inlineinstall/ 60// detail/ggbflgnkafappblpkiflbgpmkfdpnhhe 61const char kTestKioskApp[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe"; 62 63// Helper function for GetConsumerKioskModeStatusCallback. 64void ConsumerKioskModeStatusCheck( 65 KioskAppManager::ConsumerKioskModeStatus* out_status, 66 const base::Closure& runner_quit_task, 67 KioskAppManager::ConsumerKioskModeStatus in_status) { 68 LOG(INFO) << "KioskAppManager::ConsumerKioskModeStatus = " << in_status; 69 *out_status = in_status; 70 runner_quit_task.Run(); 71} 72 73// Helper KioskAppManager::EnableKioskModeCallback implementation. 74void ConsumerKioskModeLockCheck( 75 bool* out_locked, 76 const base::Closure& runner_quit_task, 77 bool in_locked) { 78 LOG(INFO) << "kioks locked = " << in_locked; 79 *out_locked = in_locked; 80 runner_quit_task.Run(); 81} 82 83} // namespace 84 85class KioskTest : public InProcessBrowserTest, 86 // Param defining is multi-profiles enabled. 87 public testing::WithParamInterface<bool> { 88 public: 89 KioskTest() { 90 set_exit_when_last_browser_closes(false); 91 } 92 93 virtual ~KioskTest() {} 94 95 protected: 96 virtual void SetUpOnMainThread() OVERRIDE { 97 test_server_.reset(new EmbeddedTestServer( 98 content::BrowserThread::GetMessageLoopProxyForThread( 99 content::BrowserThread::IO))); 100 CHECK(test_server_->InitializeAndWaitUntilReady()); 101 test_server_->RegisterRequestHandler( 102 base::Bind(&KioskTest::HandleRequest, base::Unretained(this))); 103 LOG(INFO) << "Set up http server at " << test_server_->base_url(); 104 105 const GURL gaia_url("http://localhost:" + test_server_->base_url().port()); 106 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 107 ::switches::kGaiaUrl, gaia_url.spec()); 108 } 109 110 virtual void CleanUpOnMainThread() OVERRIDE { 111 // If the login display is still showing, exit gracefully. 112 if (LoginDisplayHostImpl::default_host()) { 113 base::MessageLoop::current()->PostTask(FROM_HERE, 114 base::Bind(&chrome::AttemptExit)); 115 content::RunMessageLoop(); 116 } 117 118 // Clean up while main thread still runs. 119 // See http://crbug.com/176659. 120 KioskAppManager::Get()->CleanUp(); 121 122 LOG(INFO) << "Stopping the http server."; 123 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); 124 test_server_.reset(); // Destructor wants UI thread. 125 } 126 127 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { 128 GURL url = test_server_->GetURL(request.relative_url); 129 LOG(INFO) << "Http request: " << url.spec(); 130 131 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse()); 132 if (url.path() == "/ServiceLogin") { 133 http_response->set_code(net::HTTP_OK); 134 http_response->set_content(service_login_response_); 135 http_response->set_content_type("text/html"); 136 } else if (url.path() == "/ServiceLoginAuth") { 137 LOG(INFO) << "Params: " << request.content; 138 static const char kContinueParam[] = "continue="; 139 int continue_arg_begin = request.content.find(kContinueParam) + 140 arraysize(kContinueParam) - 1; 141 int continue_arg_end = request.content.find("&", continue_arg_begin); 142 const std::string continue_url = request.content.substr( 143 continue_arg_begin, continue_arg_end - continue_arg_begin); 144 http_response->set_code(net::HTTP_OK); 145 const std::string redirect_js = 146 "document.location.href = unescape('" + continue_url + "');"; 147 http_response->set_content( 148 "<HTML><HEAD><SCRIPT>\n" + redirect_js + "\n</SCRIPT></HEAD></HTML>"); 149 http_response->set_content_type("text/html"); 150 } else { 151 LOG(ERROR) << "Unsupported url: " << url.path(); 152 } 153 return http_response.PassAs<HttpResponse>(); 154 } 155 156 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 157 if (GetParam()) { 158 command_line->AppendSwitch(::switches::kMultiProfiles); 159 } 160 command_line->AppendSwitch(chromeos::switches::kLoginManager); 161 command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests); 162 command_line->AppendSwitch( 163 chromeos::switches::kDisableChromeCaptivePortalDetector); 164 command_line->AppendSwitch(::switches::kDisableBackgroundNetworking); 165 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user"); 166 167 ASSERT_TRUE(test_server()->Start()); 168 net::HostPortPair host_port = test_server()->host_port_pair(); 169 std::string test_gallery_url = base::StringPrintf( 170 "http://%s:%d/files/chromeos/app_mode/webstore", 171 kWebstoreDomain, host_port.port()); 172 command_line->AppendSwitchASCII( 173 ::switches::kAppsGalleryURL, test_gallery_url); 174 175 std::string test_gallery_download_url = test_gallery_url; 176 test_gallery_download_url.append("/downloads/%s.crx"); 177 command_line->AppendSwitchASCII( 178 ::switches::kAppsGalleryDownloadURL, test_gallery_download_url); 179 } 180 181 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 182 base::FilePath test_data_dir; 183 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); 184 CHECK(file_util::ReadFileToString(test_data_dir.Append(kServiceLogin), 185 &service_login_response_)); 186 187 host_resolver()->AddRule(kWebstoreDomain, "127.0.0.1"); 188 } 189 190 void ReloadKioskApps() { 191 KioskAppManager::Get()->AddApp(kTestKioskApp); 192 } 193 194 void ReloadAutolaunchKioskApps() { 195 KioskAppManager::Get()->AddApp(kTestKioskApp); 196 KioskAppManager::Get()->SetAutoLaunchApp(kTestKioskApp); 197 } 198 199 void EnableConsumerKioskMode() { 200 scoped_ptr<bool> locked(new bool(false)); 201 scoped_refptr<content::MessageLoopRunner> runner = 202 new content::MessageLoopRunner; 203 KioskAppManager::Get()->EnableConsumerModeKiosk( 204 base::Bind(&ConsumerKioskModeLockCheck, 205 locked.get(), 206 runner->QuitClosure())); 207 runner->Run(); 208 EXPECT_TRUE(*locked.get()); 209 } 210 211 KioskAppManager::ConsumerKioskModeStatus GetConsumerKioskModeStatus() { 212 KioskAppManager::ConsumerKioskModeStatus status = 213 static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1); 214 scoped_refptr<content::MessageLoopRunner> runner = 215 new content::MessageLoopRunner; 216 KioskAppManager::Get()->GetConsumerKioskModeStatus( 217 base::Bind(&ConsumerKioskModeStatusCheck, 218 &status, 219 runner->QuitClosure())); 220 runner->Run(); 221 CHECK_NE(status, static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1)); 222 return status; 223 } 224 225 content::WebUI* GetLoginUI() { 226 return static_cast<chromeos::LoginDisplayHostImpl*>( 227 chromeos::LoginDisplayHostImpl::default_host())->GetOobeUI()->web_ui(); 228 } 229 230 std::string service_login_response_; 231 scoped_ptr<EmbeddedTestServer> test_server_; 232 }; 233 234IN_PROC_BROWSER_TEST_P(KioskTest, InstallAndLaunchApp) { 235 EnableConsumerKioskMode(); 236 chromeos::AppLaunchController::SkipSplashWaitForTesting(); 237 // Start UI, find menu entry for this app and launch it. 238 chromeos::WizardController::SkipPostLoginScreensForTesting(); 239 chromeos::WizardController* wizard_controller = 240 chromeos::WizardController::default_controller(); 241 CHECK(wizard_controller); 242 wizard_controller->SkipToLoginForTesting(); 243 244 ReloadKioskApps(); 245 246 // Wait for the Kiosk App configuration to reload, then launch the app. 247 content::WindowedNotificationObserver( 248 chrome::NOTIFICATION_KIOSK_APPS_LOADED, 249 content::NotificationService::AllSources()).Wait(); 250 GetLoginUI()->CallJavascriptFunction("login.AppsMenuButton.runAppForTesting", 251 base::StringValue(kTestKioskApp)); 252 253 // Wait for the Kiosk App to launch. 254 content::WindowedNotificationObserver( 255 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, 256 content::NotificationService::AllSources()).Wait(); 257 258 // Check installer status. 259 EXPECT_EQ(chromeos::KioskAppLaunchError::NONE, 260 chromeos::KioskAppLaunchError::Get()); 261 262 // Check if the kiosk webapp is really installed for the default profile. 263 ASSERT_TRUE(ProfileManager::GetDefaultProfile()); 264 const extensions::Extension* app = 265 extensions::ExtensionSystem::Get(ProfileManager::GetDefaultProfile())-> 266 extension_service()->GetInstalledExtension(kTestKioskApp); 267 EXPECT_TRUE(app); 268 269 // Wait until the app terminates. 270 content::RunMessageLoop(); 271} 272 273IN_PROC_BROWSER_TEST_P(KioskTest, AutolaunchWarningCancel) { 274 EnableConsumerKioskMode(); 275 // Start UI, find menu entry for this app and launch it. 276 chromeos::WizardController::SkipPostLoginScreensForTesting(); 277 chromeos::WizardController* wizard_controller = 278 chromeos::WizardController::default_controller(); 279 CHECK(wizard_controller); 280 ReloadAutolaunchKioskApps(); 281 wizard_controller->SkipToLoginForTesting(); 282 283 EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty()); 284 EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled()); 285 286 // Wait for the auto launch warning come up. 287 content::WindowedNotificationObserver( 288 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE, 289 content::NotificationService::AllSources()).Wait(); 290 GetLoginUI()->CallJavascriptFunction( 291 "login.AutolaunchScreen.confirmAutoLaunchForTesting", 292 base::FundamentalValue(false)); 293 294 // Wait for the auto launch warning to go away. 295 content::WindowedNotificationObserver( 296 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED, 297 content::NotificationService::AllSources()).Wait(); 298 299 EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled()); 300} 301 302IN_PROC_BROWSER_TEST_P(KioskTest, AutolaunchWarningConfirm) { 303 EnableConsumerKioskMode(); 304 // Start UI, find menu entry for this app and launch it. 305 chromeos::WizardController::SkipPostLoginScreensForTesting(); 306 chromeos::WizardController* wizard_controller = 307 chromeos::WizardController::default_controller(); 308 CHECK(wizard_controller); 309 wizard_controller->SkipToLoginForTesting(); 310 311 ReloadAutolaunchKioskApps(); 312 EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty()); 313 EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled()); 314 315 // Wait for the auto launch warning come up. 316 content::WindowedNotificationObserver( 317 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE, 318 content::NotificationService::AllSources()).Wait(); 319 GetLoginUI()->CallJavascriptFunction( 320 "login.AutolaunchScreen.confirmAutoLaunchForTesting", 321 base::FundamentalValue(true)); 322 323 // Wait for the auto launch warning to go away. 324 content::WindowedNotificationObserver( 325 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED, 326 content::NotificationService::AllSources()).Wait(); 327 328 EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty()); 329 EXPECT_TRUE(KioskAppManager::Get()->IsAutoLaunchEnabled()); 330 331 // Wait for the Kiosk App to launch. 332 content::WindowedNotificationObserver( 333 chrome::NOTIFICATION_KIOSK_APP_LAUNCHED, 334 content::NotificationService::AllSources()).Wait(); 335 336 // Check installer status. 337 EXPECT_EQ(chromeos::KioskAppLaunchError::NONE, 338 chromeos::KioskAppLaunchError::Get()); 339 340 // Check if the kiosk webapp is really installed for the default profile. 341 ASSERT_TRUE(ProfileManager::GetDefaultProfile()); 342 const extensions::Extension* app = 343 extensions::ExtensionSystem::Get(ProfileManager::GetDefaultProfile())-> 344 extension_service()->GetInstalledExtension(kTestKioskApp); 345 EXPECT_TRUE(app); 346 347 // Wait until the app terminates. 348 content::RunMessageLoop(); 349} 350 351IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableCancel) { 352 chromeos::WizardController::SkipPostLoginScreensForTesting(); 353 chromeos::WizardController* wizard_controller = 354 chromeos::WizardController::default_controller(); 355 CHECK(wizard_controller); 356 357 // Check Kiosk mode status. 358 EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE, 359 GetConsumerKioskModeStatus()); 360 361 // Wait for the login UI to come up and switch to the kiosk_enable screen. 362 wizard_controller->SkipToLoginForTesting(); 363 content::WindowedNotificationObserver( 364 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 365 content::NotificationService::AllSources()).Wait(); 366 GetLoginUI()->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator", 367 base::StringValue("kiosk_enable")); 368 369 // Wait for the kiosk_enable screen to show and cancel the screen. 370 content::WindowedNotificationObserver( 371 chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE, 372 content::NotificationService::AllSources()).Wait(); 373 GetLoginUI()->CallJavascriptFunction( 374 "login.KioskEnableScreen.enableKioskForTesting", 375 base::FundamentalValue(false)); 376 377 // Wait for the kiosk_enable screen to disappear. 378 content::WindowedNotificationObserver( 379 chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED, 380 content::NotificationService::AllSources()).Wait(); 381 382 // Check that the status still says configurable. 383 EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE, 384 GetConsumerKioskModeStatus()); 385} 386 387IN_PROC_BROWSER_TEST_P(KioskTest, KioskEnableConfirmed) { 388 // Start UI, find menu entry for this app and launch it. 389 chromeos::WizardController::SkipPostLoginScreensForTesting(); 390 chromeos::WizardController* wizard_controller = 391 chromeos::WizardController::default_controller(); 392 CHECK(wizard_controller); 393 394 // Check Kiosk mode status. 395 EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE, 396 GetConsumerKioskModeStatus()); 397 wizard_controller->SkipToLoginForTesting(); 398 399 // Wait for the login UI to come up and switch to the kiosk_enable screen. 400 wizard_controller->SkipToLoginForTesting(); 401 content::WindowedNotificationObserver( 402 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE, 403 content::NotificationService::AllSources()).Wait(); 404 GetLoginUI()->CallJavascriptFunction("cr.ui.Oobe.handleAccelerator", 405 base::StringValue("kiosk_enable")); 406 407 // Wait for the kiosk_enable screen to show and cancel the screen. 408 content::WindowedNotificationObserver( 409 chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE, 410 content::NotificationService::AllSources()).Wait(); 411 GetLoginUI()->CallJavascriptFunction( 412 "login.KioskEnableScreen.enableKioskForTesting", 413 base::FundamentalValue(true)); 414 415 // Wait for the signal that indicates Kiosk Mode is enabled. 416 content::WindowedNotificationObserver( 417 chrome::NOTIFICATION_KIOSK_ENABLED, 418 content::NotificationService::AllSources()).Wait(); 419 EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED, 420 GetConsumerKioskModeStatus()); 421} 422 423INSTANTIATE_TEST_CASE_P(KioskTestInstantiation, KioskTest, testing::Bool()); 424 425} // namespace chromeos 426