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