Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / kiosk_browsertest.cc
index 2dedf75..328e643 100644 (file)
@@ -2,12 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "apps/shell_window.h"
-#include "apps/shell_window_registry.h"
+#include "apps/app_window.h"
+#include "apps/app_window_registry.h"
 #include "apps/ui/native_app_window.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/desktop_background/desktop_background_controller_observer.h"
 #include "ash/shell.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/login/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/oobe_base_test.h"
+#include "chrome/browser/chromeos/login/startup_utils.h"
+#include "chrome/browser/chromeos/login/test/app_window_waiter.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/profiles/profile_impl.h"
+#include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/cryptohome_client.h"
+#include "components/signin/core/common/signin_pref_names.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/test/browser_test_utils.h"
+#include "crypto/sha2.h"
+#include "extensions/browser/extension_system.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_switches.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+
+using net::test_server::BasicHttpResponse;
+using net::test_server::HttpRequest;
+using net::test_server::HttpResponse;
 
 namespace em = enterprise_management;
 
@@ -55,6 +77,22 @@ const char kTestKioskApp[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe";
 //       detail/ibjkkfdnfcaoapcpheeijckmpcfkifob
 const char kTestEnterpriseKioskApp[] = "ibjkkfdnfcaoapcpheeijckmpcfkifob";
 
+// An offline enable test app. Webstore data json is in
+//   chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
+//       detail/ajoggoflpgplnnjkjamcmbepjdjdnpdp
+// An app profile with version 1.0.0 installed is in
+//   chrome/test/data/chromeos/app_mode/offline_enabled_app_profile
+// The version 2.0.0 crx is in
+//   chrome/test/data/chromeos/app_mode/webstore/downloads/
+const char kTestOfflineEnabledKioskApp[] = "ajoggoflpgplnnjkjamcmbepjdjdnpdp";
+
+// An app to test local fs data persistence across app update. V1 app writes
+// data into local fs. V2 app reads and verifies the data.
+// Webstore data json is in
+//   chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
+//       detail/bmbpicmpniaclbbpdkfglgipkkebnbjf
+const char kTestLocalFsKioskApp[] = "bmbpicmpniaclbbpdkfglgipkkebnbjf";
+
 // Timeout while waiting for network connectivity during tests.
 const int kTestNetworkTimeoutSeconds = 1;
 
@@ -71,18 +109,28 @@ const char kTestClientId[] = "fake-client-id";
 const char kTestAppScope[] =
     "https://www.googleapis.com/auth/userinfo.profile";
 
-// Helper function for GetConsumerKioskModeStatusCallback.
-void ConsumerKioskModeStatusCheck(
-    KioskAppManager::ConsumerKioskModeStatus* out_status,
+// Test JS API.
+const char kLaunchAppForTestNewAPI[] =
+    "login.AccountPickerScreen.runAppForTesting";
+const char kLaunchAppForTestOldAPI[] =
+    "login.AppsMenuButton.runAppForTesting";
+const char kCheckDiagnosticModeNewAPI[] =
+    "$('oobe').confirmDiagnosticMode_";
+const char kCheckDiagnosticModeOldAPI[] =
+    "$('show-apps-button').confirmDiagnosticMode_";
+
+// Helper function for GetConsumerKioskAutoLaunchStatusCallback.
+void ConsumerKioskAutoLaunchStatusCheck(
+    KioskAppManager::ConsumerKioskAutoLaunchStatus* out_status,
     const base::Closure& runner_quit_task,
-    KioskAppManager::ConsumerKioskModeStatus in_status) {
+    KioskAppManager::ConsumerKioskAutoLaunchStatus in_status) {
   LOG(INFO) << "KioskAppManager::ConsumerKioskModeStatus = " << in_status;
   *out_status = in_status;
   runner_quit_task.Run();
 }
 
 // Helper KioskAppManager::EnableKioskModeCallback implementation.
-void ConsumerKioskModeLockCheck(
+void ConsumerKioskModeAutoStartLockCheck(
     bool* out_locked,
     const base::Closure& runner_quit_task,
     bool in_locked) {
@@ -96,12 +144,6 @@ void OnNetworkWaitTimedOut(const base::Closure& runner_quit_task) {
   runner_quit_task.Run();
 }
 
-// Helper function for DeviceOAuth2TokenServiceFactory::Get().
-void CopyTokenService(DeviceOAuth2TokenService** out_token_service,
-                      DeviceOAuth2TokenService* in_token_service) {
-  *out_token_service = in_token_service;
-}
-
 // Helper functions for CanConfigureNetwork mock.
 class ScopedCanConfigureNetwork {
  public:
@@ -141,53 +183,55 @@ class ScopedCanConfigureNetwork {
   DISALLOW_COPY_AND_ASSIGN(ScopedCanConfigureNetwork);
 };
 
-}  // namespace
-
-// Helper class that monitors app windows to wait for a window to appear.
-class ShellWindowObserver : public apps::ShellWindowRegistry::Observer {
+// Helper class to wait until a js condition becomes true.
+class JsConditionWaiter {
  public:
-  ShellWindowObserver(apps::ShellWindowRegistry* registry,
-                      const std::string& app_id)
-      : registry_(registry), app_id_(app_id), window_(NULL), running_(false) {
-    registry_->AddObserver(this);
-  }
-  virtual ~ShellWindowObserver() {
-    registry_->RemoveObserver(this);
-  }
-
-  apps::ShellWindow* Wait() {
-    running_ = true;
-    message_loop_runner_ = new content::MessageLoopRunner;
-    message_loop_runner_->Run();
-    EXPECT_TRUE(window_);
-    return window_;
+  JsConditionWaiter(content::WebContents* web_contents,
+                    const std::string& js)
+      : web_contents_(web_contents),
+        js_(js) {
   }
 
-  // ShellWindowRegistry::Observer
-  virtual void OnShellWindowAdded(apps::ShellWindow* shell_window) OVERRIDE {
-    if (!running_)
+  void Wait() {
+    if (CheckJs())
       return;
 
-    if (shell_window->extension_id() == app_id_) {
-      window_ = shell_window;
-      message_loop_runner_->Quit();
-      running_ = false;
-    }
+    base::RepeatingTimer<JsConditionWaiter> check_timer;
+    check_timer.Start(
+        FROM_HERE,
+        base::TimeDelta::FromMilliseconds(10),
+        this,
+        &JsConditionWaiter::OnTimer);
+
+    runner_ = new content::MessageLoopRunner;
+    runner_->Run();
   }
-  virtual void OnShellWindowIconChanged(
-      apps::ShellWindow* shell_window) OVERRIDE {}
-  virtual void OnShellWindowRemoved(apps::ShellWindow* shell_window) OVERRIDE {}
 
  private:
-  apps::ShellWindowRegistry* registry_;
-  std::string app_id_;
-  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
-  apps::ShellWindow* window_;
-  bool running_;
+  bool CheckJs() {
+    bool result;
+    CHECK(content::ExecuteScriptAndExtractBool(
+        web_contents_,
+        "window.domAutomationController.send(!!(" + js_ + "));",
+        &result));
+    return result;
+  }
 
-  DISALLOW_COPY_AND_ASSIGN(ShellWindowObserver);
+  void OnTimer() {
+    DCHECK(runner_);
+    if (CheckJs())
+      runner_->Quit();
+  }
+
+  content::WebContents* web_contents_;
+  const std::string js_;
+  scoped_refptr<content::MessageLoopRunner> runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsConditionWaiter);
 };
 
+}  // namespace
+
 class KioskTest : public OobeBaseTest {
  public:
   KioskTest() {
@@ -197,8 +241,8 @@ class KioskTest : public OobeBaseTest {
   virtual ~KioskTest() {}
 
  protected:
-
   virtual void SetUp() OVERRIDE {
+    test_app_id_ = kTestKioskApp;
     mock_user_manager_.reset(new MockUserManager);
     AppLaunchController::SkipSplashWaitForTesting();
     AppLaunchController::SetNetworkWaitForTesting(kTestNetworkTimeoutSeconds);
@@ -223,11 +267,7 @@ class KioskTest : public OobeBaseTest {
     // Create gaia and webstore URL from test server url but using different
     // host names. This is to avoid gaia response being tagged as from
     // webstore in chrome_resource_dispatcher_host_delegate.cc.
-    const GURL& server_url = embedded_test_server()->base_url();
-    std::string webstore_host("webstore");
-    GURL::Replacements replace_webstore_host;
-    replace_webstore_host.SetHostStr(webstore_host);
-    GURL webstore_url = server_url.ReplaceComponents(replace_webstore_host);
+    GURL webstore_url = GetTestWebstoreUrl();
     command_line->AppendSwitchASCII(
         ::switches::kAppsGalleryURL,
         webstore_url.Resolve("/chromeos/app_mode/webstore").spec());
@@ -237,47 +277,84 @@ class KioskTest : public OobeBaseTest {
             "/chromeos/app_mode/webstore/downloads/%s.crx").spec());
   }
 
+  GURL GetTestWebstoreUrl() {
+    const GURL& server_url = embedded_test_server()->base_url();
+    std::string webstore_host("webstore");
+    GURL::Replacements replace_webstore_host;
+    replace_webstore_host.SetHostStr(webstore_host);
+    return server_url.ReplaceComponents(replace_webstore_host);
+  }
+
+  void LaunchApp(const std::string& app_id, bool diagnostic_mode) {
+    bool new_kiosk_ui = KioskAppMenuHandler::EnableNewKioskUI();
+    GetLoginUI()->CallJavascriptFunction(new_kiosk_ui ?
+        kLaunchAppForTestNewAPI : kLaunchAppForTestOldAPI,
+        base::StringValue(app_id),
+        base::FundamentalValue(diagnostic_mode));
+  }
+
   void ReloadKioskApps() {
-    KioskAppManager::Get()->AddApp(kTestKioskApp);
+    // Remove then add to ensure NOTIFICATION_KIOSK_APPS_LOADED fires.
+    KioskAppManager::Get()->RemoveApp(test_app_id_);
+    KioskAppManager::Get()->AddApp(test_app_id_);
   }
 
   void ReloadAutolaunchKioskApps() {
-    KioskAppManager::Get()->AddApp(kTestKioskApp);
-    KioskAppManager::Get()->SetAutoLaunchApp(kTestKioskApp);
+    KioskAppManager::Get()->AddApp(test_app_id_);
+    KioskAppManager::Get()->SetAutoLaunchApp(test_app_id_);
   }
 
-  void StartAppLaunchFromLoginScreen(const base::Closure& network_setup_cb) {
+  void PrepareAppLaunch() {
     EnableConsumerKioskMode();
 
-    // Start UI, find menu entry for this app and launch it.
+    // Start UI
     content::WindowedNotificationObserver login_signal(
-      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
-      content::NotificationService::AllSources());
+        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+        content::NotificationService::AllSources());
     chromeos::WizardController::SkipPostLoginScreensForTesting();
     chromeos::WizardController* wizard_controller =
         chromeos::WizardController::default_controller();
-    CHECK(wizard_controller);
-    wizard_controller->SkipToLoginForTesting(LoginScreenContext());
-    login_signal.Wait();
+    if (wizard_controller) {
+      wizard_controller->SkipToLoginForTesting(LoginScreenContext());
+      login_signal.Wait();
+    } else {
+      // No wizard and running with an existing profile and it should land
+      // on account picker when new kiosk UI is enabled. Otherwise, just
+      // wait for the login signal from Gaia.
+      if (KioskAppMenuHandler::EnableNewKioskUI())
+        OobeScreenWaiter(OobeDisplay::SCREEN_ACCOUNT_PICKER).Wait();
+      else
+        login_signal.Wait();
+    }
 
-    // Wait for the Kiosk App configuration to reload, then launch the app.
+    // Wait for the Kiosk App configuration to reload.
     content::WindowedNotificationObserver apps_loaded_signal(
         chrome::NOTIFICATION_KIOSK_APPS_LOADED,
         content::NotificationService::AllSources());
     ReloadKioskApps();
     apps_loaded_signal.Wait();
+  }
+
+  void StartAppLaunchFromLoginScreen(const base::Closure& network_setup_cb) {
+    PrepareAppLaunch();
 
     if (!network_setup_cb.is_null())
       network_setup_cb.Run();
 
-    GetLoginUI()->CallJavascriptFunction(
-        "login.AppsMenuButton.runAppForTesting",
-        base::StringValue(kTestKioskApp));
+    LaunchApp(test_app_id(), false);
   }
 
-  void WaitForAppLaunchSuccess() {
-    SimulateNetworkOnline();
+  const extensions::Extension* GetInstalledApp() {
+    Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
+    return extensions::ExtensionSystem::Get(app_profile)->
+        extension_service()->GetInstalledExtension(test_app_id_);
+  }
 
+  const Version& GetInstalledAppVersion() {
+    return *GetInstalledApp()->version();
+  }
+
+  void WaitForAppLaunchSuccess() {
     ExtensionTestMessageListener
         launch_data_check_listener("launchData.isKioskSession = true", false);
 
@@ -290,6 +367,10 @@ class KioskTest : public OobeBaseTest {
     Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
     ASSERT_TRUE(app_profile);
 
+    // Check ChromeOS preference is initialized.
+    EXPECT_TRUE(
+        static_cast<ProfileImpl*>(app_profile)->chromeos_preferences_);
+
     // Check installer status.
     EXPECT_EQ(chromeos::KioskAppLaunchError::NONE,
               chromeos::KioskAppLaunchError::Get());
@@ -297,14 +378,14 @@ class KioskTest : public OobeBaseTest {
     // Check if the kiosk webapp is really installed for the default profile.
     const extensions::Extension* app =
         extensions::ExtensionSystem::Get(app_profile)->
-        extension_service()->GetInstalledExtension(kTestKioskApp);
+        extension_service()->GetInstalledExtension(test_app_id_);
     EXPECT_TRUE(app);
 
     // App should appear with its window.
-    apps::ShellWindowRegistry* shell_window_registry =
-        apps::ShellWindowRegistry::Get(app_profile);
-    apps::ShellWindow* window =
-        ShellWindowObserver(shell_window_registry, kTestKioskApp).Wait();
+    apps::AppWindowRegistry* app_window_registry =
+        apps::AppWindowRegistry::Get(app_profile);
+    apps::AppWindow* window =
+        AppWindowWaiter(app_window_registry, test_app_id_).Wait();
     EXPECT_TRUE(window);
 
     // Login screen should be gone or fading out.
@@ -316,7 +397,7 @@ class KioskTest : public OobeBaseTest {
             0.0f);
 
     // Wait until the app terminates if it is still running.
-    if (!shell_window_registry->GetShellWindowsForApp(kTestKioskApp).empty())
+    if (!app_window_registry->GetAppWindowsForApp(test_app_id_).empty())
       content::RunMessageLoop();
 
     // Check that the app had been informed that it is running in a kiosk
@@ -345,34 +426,120 @@ class KioskTest : public OobeBaseTest {
     scoped_ptr<bool> locked(new bool(false));
     scoped_refptr<content::MessageLoopRunner> runner =
         new content::MessageLoopRunner;
-    KioskAppManager::Get()->EnableConsumerModeKiosk(
-        base::Bind(&ConsumerKioskModeLockCheck,
+    KioskAppManager::Get()->EnableConsumerKioskAutoLaunch(
+        base::Bind(&ConsumerKioskModeAutoStartLockCheck,
                    locked.get(),
                    runner->QuitClosure()));
     runner->Run();
     EXPECT_TRUE(*locked.get());
   }
 
-  KioskAppManager::ConsumerKioskModeStatus GetConsumerKioskModeStatus() {
-    KioskAppManager::ConsumerKioskModeStatus status =
-        static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1);
+  KioskAppManager::ConsumerKioskAutoLaunchStatus
+  GetConsumerKioskModeStatus() {
+    KioskAppManager::ConsumerKioskAutoLaunchStatus status =
+        static_cast<KioskAppManager::ConsumerKioskAutoLaunchStatus>(-1);
     scoped_refptr<content::MessageLoopRunner> runner =
         new content::MessageLoopRunner;
-    KioskAppManager::Get()->GetConsumerKioskModeStatus(
-        base::Bind(&ConsumerKioskModeStatusCheck,
+    KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(
+        base::Bind(&ConsumerKioskAutoLaunchStatusCheck,
                    &status,
                    runner->QuitClosure()));
     runner->Run();
-    CHECK_NE(status, static_cast<KioskAppManager::ConsumerKioskModeStatus>(-1));
+    CHECK_NE(status,
+             static_cast<KioskAppManager::ConsumerKioskAutoLaunchStatus>(-1));
     return status;
   }
 
+  // Copies the app profile from |relative_app_profile_dir| from test directory
+  // to the app profile directory (assuming "user") under testing profile. This
+  // is for that needs to have a kiosk app already installed from a previous
+  // run. Note this must be called before app profile is loaded.
+  void SetupAppProfile(const std::string& relative_app_profile_dir) {
+    base::FilePath app_profile_dir;
+    if (CommandLine::ForCurrentProcess()->HasSwitch(
+            ::switches::kMultiProfiles)) {
+      KioskAppManager::App app_data;
+      CHECK(KioskAppManager::Get()->GetApp(test_app_id(), &app_data));
+      std::string app_user_id_hash =
+          CryptohomeClient::GetStubSanitizedUsername(app_data.user_id);
+      app_profile_dir =
+          ProfileHelper::GetProfilePathByUserIdHash(app_user_id_hash);
+    } else {
+      ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &app_profile_dir));
+      app_profile_dir = app_profile_dir.Append(
+          ProfileHelper::GetProfileDirByLegacyLoginProfileSwitch());
+    }
+    ASSERT_TRUE(base::CreateDirectory(app_profile_dir));
+
+    base::FilePath test_data_dir;
+    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+    test_data_dir = test_data_dir.AppendASCII(relative_app_profile_dir);
+    ASSERT_TRUE(
+        base::CopyFile(test_data_dir.Append(chrome::kPreferencesFilename),
+                       app_profile_dir.Append(chrome::kPreferencesFilename)));
+    ASSERT_TRUE(
+        base::CopyDirectory(test_data_dir.AppendASCII("Extensions"),
+                            app_profile_dir,
+                            true));
+  }
+
+  void RunAppLaunchNetworkDownTest() {
+    // Mock network could be configured with owner's password.
+    ScopedCanConfigureNetwork can_configure_network(true, true);
+
+    // Start app launch and wait for network connectivity timeout.
+    StartAppLaunchFromLoginScreen(SimulateNetworkOfflineClosure());
+    OobeScreenWaiter splash_waiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH);
+    splash_waiter.Wait();
+    WaitForAppLaunchNetworkTimeout();
+
+    // Configure network link should be visible.
+    JsExpect("$('splash-config-network').hidden == false");
+
+    // Set up fake user manager with an owner for the test.
+    mock_user_manager()->SetActiveUser(kTestOwnerEmail);
+    AppLaunchSigninScreen::SetUserManagerForTesting(mock_user_manager());
+    static_cast<LoginDisplayHostImpl*>(LoginDisplayHostImpl::default_host())
+        ->GetOobeUI()->ShowOobeUI(false);
+
+    // Configure network should bring up lock screen for owner.
+    OobeScreenWaiter lock_screen_waiter(OobeDisplay::SCREEN_ACCOUNT_PICKER);
+    static_cast<AppLaunchSplashScreenActor::Delegate*>(GetAppLaunchController())
+        ->OnConfigureNetwork();
+    lock_screen_waiter.Wait();
+
+    // There should be only one owner pod on this screen.
+    JsExpect("$('pod-row').isSinglePod");
+
+    // A network error screen should be shown after authenticating.
+    OobeScreenWaiter error_screen_waiter(OobeDisplay::SCREEN_ERROR_MESSAGE);
+    static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
+        ->OnOwnerSigninSuccess();
+    error_screen_waiter.Wait();
+
+    ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
+
+    SimulateNetworkOnline();
+    WaitForAppLaunchSuccess();
+  }
+
   AppLaunchController* GetAppLaunchController() {
     return chromeos::LoginDisplayHostImpl::default_host()
         ->GetAppLaunchController();
   }
 
+  MockUserManager* mock_user_manager() { return mock_user_manager_.get(); }
+
+  void set_test_app_id(const std::string& test_app_id) {
+    test_app_id_ = test_app_id;
+  }
+  const std::string& test_app_id() const { return test_app_id_; }
+
+ private:
+  std::string test_app_id_;
   scoped_ptr<MockUserManager> mock_user_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskTest);
 };
 
 IN_PROC_BROWSER_TEST_F(KioskTest, InstallAndLaunchApp) {
@@ -380,39 +547,59 @@ IN_PROC_BROWSER_TEST_F(KioskTest, InstallAndLaunchApp) {
   WaitForAppLaunchSuccess();
 }
 
+IN_PROC_BROWSER_TEST_F(KioskTest, NotSignedInWithGAIAAccount) {
+  // Tests that the kiosk session is not considered to be logged in with a GAIA
+  // account.
+  StartAppLaunchFromLoginScreen(SimulateNetworkOnlineClosure());
+  WaitForAppLaunchSuccess();
+
+  Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
+  ASSERT_TRUE(app_profile);
+  EXPECT_FALSE(app_profile->GetPrefs()->HasPrefPath(
+      prefs::kGoogleServicesUsername));
+}
+
+IN_PROC_BROWSER_TEST_F(KioskTest, PRE_LaunchAppNetworkDown) {
+  // Tests the network down case for the initial app download and launch.
+  RunAppLaunchNetworkDownTest();
+}
+
 IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDown) {
-  // Mock network could be configured with owner's password.
-  ScopedCanConfigureNetwork can_configure_network(true, true);
+  // Tests the network down case for launching an existing app that is
+  // installed in PRE_LaunchAppNetworkDown.
+  RunAppLaunchNetworkDownTest();
+}
+
+// TODO(zelidrag): Figure out why this test is flaky on bbots.
+IN_PROC_BROWSER_TEST_F(KioskTest,
+                       DISABLED_LaunchAppWithNetworkConfigAccelerator) {
+  ScopedCanConfigureNetwork can_configure_network(true, false);
 
   // Start app launch and wait for network connectivity timeout.
-  StartAppLaunchFromLoginScreen(SimulateNetworkOfflineClosure());
+  StartAppLaunchFromLoginScreen(SimulateNetworkOnlineClosure());
   OobeScreenWaiter splash_waiter(OobeDisplay::SCREEN_APP_LAUNCH_SPLASH);
   splash_waiter.Wait();
-  WaitForAppLaunchNetworkTimeout();
-
-  // Configure network link should be visible.
-  JsExpect("$('splash-config-network').hidden == false");
-
-  // Set up fake user manager with an owner for the test.
-  mock_user_manager_->SetActiveUser(kTestOwnerEmail);
-  AppLaunchSigninScreen::SetUserManagerForTesting(mock_user_manager_.get());
-  static_cast<LoginDisplayHostImpl*>(LoginDisplayHostImpl::default_host())
-      ->GetOobeUI()->ShowOobeUI(false);
-
-  // Configure network should bring up lock screen for owner.
-  OobeScreenWaiter lock_screen_waiter(OobeDisplay::SCREEN_ACCOUNT_PICKER);
-  static_cast<AppLaunchSplashScreenActor::Delegate*>(GetAppLaunchController())
-    ->OnConfigureNetwork();
-  lock_screen_waiter.Wait();
 
   // A network error screen should be shown after authenticating.
   OobeScreenWaiter error_screen_waiter(OobeDisplay::SCREEN_ERROR_MESSAGE);
-  static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
-      ->OnOwnerSigninSuccess();
+  // Simulate Ctrl+Alt+N accelerator.
+  GetLoginUI()->CallJavascriptFunction(
+      "cr.ui.Oobe.handleAccelerator",
+      base::StringValue("app_launch_network_config"));
   error_screen_waiter.Wait();
-
   ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
 
+  // Continue button should be visible since we are online.
+  JsExpect("$('continue-network-config-btn').hidden == false");
+
+  // Click on [Continue] button.
+  ASSERT_TRUE(content::ExecuteScript(
+      GetLoginUI()->GetWebContents(),
+      "(function() {"
+      "var e = new Event('click');"
+      "$('continue-network-config-btn').dispatchEvent(e);"
+      "})();"));
+
   WaitForAppLaunchSuccess();
 }
 
@@ -430,10 +617,12 @@ IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDownConfigureNotAllowed) {
   JsExpect("$('splash-config-network').hidden == true");
 
   // Network becomes online and app launch is resumed.
+  SimulateNetworkOnline();
   WaitForAppLaunchSuccess();
 }
 
-IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkPortal) {
+// Flaky on bots. http://crbug.com/365507
+IN_PROC_BROWSER_TEST_F(KioskTest, DISABLED_LaunchAppNetworkPortal) {
   // Mock network could be configured without the owner password.
   ScopedCanConfigureNetwork can_configure_network(true, false);
 
@@ -448,6 +637,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkPortal) {
   OobeScreenWaiter(OobeDisplay::SCREEN_ERROR_MESSAGE).Wait();
 
   ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
+  SimulateNetworkOnline();
   WaitForAppLaunchSuccess();
 }
 
@@ -468,6 +658,31 @@ IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppUserCancel) {
             chromeos::KioskAppLaunchError::Get());
 }
 
+IN_PROC_BROWSER_TEST_F(KioskTest, LaunchInDiagnosticMode) {
+  PrepareAppLaunch();
+  SimulateNetworkOnline();
+
+  LaunchApp(kTestKioskApp, true);
+
+  content::WebContents* login_contents = GetLoginUI()->GetWebContents();
+
+  bool new_kiosk_ui = KioskAppMenuHandler::EnableNewKioskUI();
+  JsConditionWaiter(login_contents, new_kiosk_ui ?
+      kCheckDiagnosticModeNewAPI : kCheckDiagnosticModeOldAPI).Wait();
+
+  std::string diagnosticMode(new_kiosk_ui ?
+      kCheckDiagnosticModeNewAPI : kCheckDiagnosticModeOldAPI);
+  ASSERT_TRUE(content::ExecuteScript(
+      login_contents,
+      "(function() {"
+         "var e = new Event('click');" +
+         diagnosticMode + "."
+             "okButton_.dispatchEvent(e);"
+      "})();"));
+
+  WaitForAppLaunchSuccess();
+}
+
 IN_PROC_BROWSER_TEST_F(KioskTest, AutolaunchWarningCancel) {
   EnableConsumerKioskMode();
   // Start UI, find menu entry for this app and launch it.
@@ -536,7 +751,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableCancel) {
   CHECK(wizard_controller);
 
   // Check Kiosk mode status.
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
             GetConsumerKioskModeStatus());
 
   // Wait for the login UI to come up and switch to the kiosk_enable screen.
@@ -561,7 +776,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableCancel) {
       content::NotificationService::AllSources()).Wait();
 
   // Check that the status still says configurable.
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
             GetConsumerKioskModeStatus());
 }
 
@@ -573,7 +788,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableConfirmed) {
   CHECK(wizard_controller);
 
   // Check Kiosk mode status.
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
             GetConsumerKioskModeStatus());
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
 
@@ -597,7 +812,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableConfirmed) {
   content::WindowedNotificationObserver(
       chrome::NOTIFICATION_KIOSK_ENABLED,
       content::NotificationService::AllSources()).Wait();
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_ENABLED,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED,
             GetConsumerKioskModeStatus());
 }
 
@@ -618,7 +833,7 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableAbortedWithAutoEnrollment) {
   CHECK(wizard_controller);
 
   // Check Kiosk mode status.
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
             GetConsumerKioskModeStatus());
   wizard_controller->SkipToLoginForTesting(LoginScreenContext());
 
@@ -639,22 +854,13 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableAbortedWithAutoEnrollment) {
 }
 
 IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableAfter2ndSigninScreen) {
-  // Fake an auto enrollment is not going to be enforced.
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kEnterpriseEnrollmentInitialModulus, "1");
-  CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kEnterpriseEnrollmentModulusLimit, "2");
-  g_browser_process->local_state()->SetBoolean(prefs::kShouldAutoEnroll, false);
-  g_browser_process->local_state()->SetInteger(
-      prefs::kAutoEnrollmentPowerLimit, -1);
-
   chromeos::WizardController::SkipPostLoginScreensForTesting();
   chromeos::WizardController* wizard_controller =
       chromeos::WizardController::default_controller();
   CHECK(wizard_controller);
 
   // Check Kiosk mode status.
-  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_MODE_CONFIGURABLE,
+  EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
             GetConsumerKioskModeStatus());
 
   // Wait for the login UI to come up and switch to the kiosk_enable screen.
@@ -693,6 +899,199 @@ IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableAfter2ndSigninScreen) {
       content::NotificationService::AllSources()).Wait();
 }
 
+class KioskUpdateTest : public KioskTest,
+                        public testing::WithParamInterface<bool> {
+ public:
+  KioskUpdateTest() {}
+  virtual ~KioskUpdateTest() {}
+
+ protected:
+  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+    // Needs background networking so that ExtensionDownloader works.
+    needs_background_networking_ = true;
+
+    KioskTest::SetUpCommandLine(command_line);
+    if (GetParam())
+      command_line->AppendSwitch(::switches::kMultiProfiles);
+  }
+
+  virtual void SetUpOnMainThread() OVERRIDE {
+    KioskTest::SetUpOnMainThread();
+
+    GURL webstore_url = GetTestWebstoreUrl();
+    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        ::switches::kAppsGalleryUpdateURL,
+        webstore_url.Resolve("/update_check.xml").spec());
+
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&KioskUpdateTest::HandleRequest,
+                   base::Unretained(this)));
+  }
+
+  void SetNoUpdate() {
+    SetUpdateCheckContent(
+        "chromeos/app_mode/webstore/update_check/no_update.xml",
+        GURL(),
+        "",
+        "",
+        "");
+  }
+
+  void SetUpdateCrx(const std::string& crx_file, const std::string& version) {
+    GURL webstore_url = GetTestWebstoreUrl();
+    GURL crx_download_url = webstore_url.Resolve(
+        "/chromeos/app_mode/webstore/downloads/" + crx_file);
+    base::FilePath test_data_dir;
+    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+    base::FilePath crx_file_path =
+        test_data_dir.AppendASCII("chromeos/app_mode/webstore/downloads")
+            .AppendASCII(crx_file);
+
+    std::string crx_content;
+    ASSERT_TRUE(base::ReadFileToString(crx_file_path, &crx_content));
+
+    const std::string sha256 = crypto::SHA256HashString(crx_content);
+    const std::string sha256_hex =
+        base::HexEncode(sha256.c_str(), sha256.size());
+
+    SetUpdateCheckContent(
+        "chromeos/app_mode/webstore/update_check/has_update.xml",
+        crx_download_url,
+        sha256_hex,
+        base::UintToString(crx_content.size()),
+        version);
+  }
+
+ private:
+  void SetUpdateCheckContent(const std::string& update_check_file,
+                             const GURL& crx_download_url,
+                             const std::string& crx_fp,
+                             const std::string& crx_size,
+                             const std::string& version) {
+    base::FilePath test_data_dir;
+    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+    base::FilePath update_file =
+        test_data_dir.AppendASCII(update_check_file.c_str());
+    ASSERT_TRUE(base::ReadFileToString(update_file, &update_check_content_));
+
+    ReplaceSubstringsAfterOffset(
+        &update_check_content_, 0, "$AppId", test_app_id());
+    ReplaceSubstringsAfterOffset(
+        &update_check_content_, 0, "$CrxDownloadUrl", crx_download_url.spec());
+    ReplaceSubstringsAfterOffset(&update_check_content_, 0, "$FP", crx_fp);
+    ReplaceSubstringsAfterOffset(&update_check_content_, 0, "$Size", crx_size);
+    ReplaceSubstringsAfterOffset(
+        &update_check_content_, 0, "$Version", version);
+  }
+
+  scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
+    GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
+    std::string request_path = request_url.path();
+    if (!update_check_content_.empty() &&
+        request_path == "/update_check.xml") {
+      scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
+      http_response->set_code(net::HTTP_OK);
+      http_response->set_content_type("text/xml");
+      http_response->set_content(update_check_content_);
+      return http_response.PassAs<HttpResponse>();
+    }
+
+    return scoped_ptr<HttpResponse>();
+  }
+
+  std::string update_check_content_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskUpdateTest);
+};
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, LaunchOfflineEnabledAppNoNetwork) {
+  set_test_app_id(kTestOfflineEnabledKioskApp);
+
+  PrepareAppLaunch();
+  SimulateNetworkOffline();
+  SetupAppProfile("chromeos/app_mode/offline_enabled_app_profile");
+
+  LaunchApp(test_app_id(), false);
+  WaitForAppLaunchSuccess();
+}
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, LaunchOfflineEnabledAppNoUpdate) {
+  set_test_app_id(kTestOfflineEnabledKioskApp);
+
+  SetNoUpdate();
+
+  PrepareAppLaunch();
+  SimulateNetworkOnline();
+  SetupAppProfile("chromeos/app_mode/offline_enabled_app_profile");
+
+  LaunchApp(test_app_id(), false);
+  WaitForAppLaunchSuccess();
+
+  EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
+}
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, LaunchOfflineEnabledAppHasUpdate) {
+  set_test_app_id(kTestOfflineEnabledKioskApp);
+
+  SetUpdateCrx("ajoggoflpgplnnjkjamcmbepjdjdnpdp.crx", "2.0.0");
+
+  PrepareAppLaunch();
+  SimulateNetworkOnline();
+  SetupAppProfile("chromeos/app_mode/offline_enabled_app_profile");
+
+  LaunchApp(test_app_id(), false);
+  WaitForAppLaunchSuccess();
+
+  EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
+}
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, PermissionChange) {
+  set_test_app_id(kTestOfflineEnabledKioskApp);
+
+  SetUpdateCrx("ajoggoflpgplnnjkjamcmbepjdjdnpdp_v2_permission_change.crx",
+               "2.0.0");
+
+  PrepareAppLaunch();
+  SimulateNetworkOnline();
+  SetupAppProfile("chromeos/app_mode/offline_enabled_app_profile");
+
+  LaunchApp(test_app_id(), false);
+  WaitForAppLaunchSuccess();
+
+  EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
+}
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, PRE_PreserveLocalData) {
+  // Installs v1 app and writes some local data.
+  set_test_app_id(kTestLocalFsKioskApp);
+
+  ResultCatcher catcher;
+  StartAppLaunchFromLoginScreen(SimulateNetworkOnlineClosure());
+  WaitForAppLaunchSuccess();
+  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+IN_PROC_BROWSER_TEST_P(KioskUpdateTest, PreserveLocalData) {
+  // Update existing v1 app installed in PRE_PreserveLocalData to v2
+  // that reads and verifies the local data.
+  set_test_app_id(kTestLocalFsKioskApp);
+
+  SetUpdateCrx("bmbpicmpniaclbbpdkfglgipkkebnbjf_v2_read_and_verify_data.crx",
+               "2.0.0");
+
+  ResultCatcher catcher;
+  StartAppLaunchFromLoginScreen(SimulateNetworkOnlineClosure());
+  WaitForAppLaunchSuccess();
+
+  EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
+  ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+// TODO(xiyuan): Remove this after multi profile is turned on by default.
+INSTANTIATE_TEST_CASE_P(KioskUpdateTestInstantiation,
+                        KioskUpdateTest,
+                        testing::Bool());
+
 class KioskEnterpriseTest : public KioskTest {
  protected:
   KioskEnterpriseTest() {}
@@ -720,9 +1119,13 @@ class KioskEnterpriseTest : public KioskTest {
         device_policy_test_helper_.device_policy()->policy_data();
     policy_data.set_service_account_identity(kTestEnterpriseServiceAccountId);
     device_policy_test_helper_.device_policy()->Build();
+
+    base::RunLoop run_loop;
     DBusThreadManager::Get()->GetSessionManagerClient()->StoreDevicePolicy(
         device_policy_test_helper_.device_policy()->GetBlob(),
-        base::Bind(&KioskEnterpriseTest::StorePolicyCallback));
+        base::Bind(&KioskEnterpriseTest::StorePolicyCallback,
+                   run_loop.QuitClosure()));
+    run_loop.Run();
 
     DeviceSettingsService::Get()->Load();
 
@@ -737,14 +1140,14 @@ class KioskEnterpriseTest : public KioskTest {
         "https://www.googleapis.com/auth/userinfo.email");
     userinfo_token_info.audience = gaia_urls->oauth2_chrome_client_id();
     userinfo_token_info.email = kTestEnterpriseServiceAccountId;
-    fake_gaia_.IssueOAuthToken(kTestRefreshToken, userinfo_token_info);
+    fake_gaia_->IssueOAuthToken(kTestRefreshToken, userinfo_token_info);
 
     // The any-api access token for accessing the token minting endpoint.
     FakeGaia::AccessTokenInfo login_token_info;
     login_token_info.token = kTestLoginToken;
     login_token_info.scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
     login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
-    fake_gaia_.IssueOAuthToken(kTestRefreshToken, login_token_info);
+    fake_gaia_->IssueOAuthToken(kTestRefreshToken, login_token_info);
 
     // This is the access token requested by the app via the identity API.
     FakeGaia::AccessTokenInfo access_token_info;
@@ -752,18 +1155,18 @@ class KioskEnterpriseTest : public KioskTest {
     access_token_info.scopes.insert(kTestAppScope);
     access_token_info.audience = kTestClientId;
     access_token_info.email = kTestEnterpriseServiceAccountId;
-    fake_gaia_.IssueOAuthToken(kTestLoginToken, access_token_info);
+    fake_gaia_->IssueOAuthToken(kTestLoginToken, access_token_info);
 
-    DeviceOAuth2TokenService* token_service = NULL;
-    DeviceOAuth2TokenServiceFactory::Get(
-        base::Bind(&CopyTokenService, &token_service));
+    DeviceOAuth2TokenService* token_service =
+        DeviceOAuth2TokenServiceFactory::Get();
+    token_service->SetAndSaveRefreshToken(
+        kTestRefreshToken, DeviceOAuth2TokenService::StatusCallback());
     base::RunLoop().RunUntilIdle();
-    ASSERT_TRUE(token_service);
-    token_service->SetAndSaveRefreshToken(kTestRefreshToken);
   }
 
-  static void StorePolicyCallback(bool result) {
+  static void StorePolicyCallback(const base::Closure& callback, bool result) {
     ASSERT_TRUE(result);
+    callback.Run();
   }
 
   policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
@@ -786,9 +1189,7 @@ IN_PROC_BROWSER_TEST_F(KioskEnterpriseTest, EnterpriseKioskApp) {
                  base::Unretained(KioskAppManager::Get()),
                  kTestEnterpriseKioskApp, &app)).Wait();
 
-  GetLoginUI()->CallJavascriptFunction(
-      "login.AppsMenuButton.runAppForTesting",
-      base::StringValue(kTestEnterpriseKioskApp));
+  LaunchApp(kTestEnterpriseKioskApp, false);
 
   // Wait for the Kiosk App to launch.
   content::WindowedNotificationObserver(
@@ -800,9 +1201,10 @@ IN_PROC_BROWSER_TEST_F(KioskEnterpriseTest, EnterpriseKioskApp) {
             chromeos::KioskAppLaunchError::Get());
 
   // Wait for the window to appear.
-  apps::ShellWindow* window = ShellWindowObserver(
-      apps::ShellWindowRegistry::Get(ProfileManager::GetPrimaryUserProfile()),
-      kTestEnterpriseKioskApp).Wait();
+  apps::AppWindow* window =
+      AppWindowWaiter(
+          apps::AppWindowRegistry::Get(ProfileManager::GetPrimaryUserProfile()),
+          kTestEnterpriseKioskApp).Wait();
   ASSERT_TRUE(window);
 
   // Check whether the app can retrieve an OAuth2 access token.
@@ -816,6 +1218,13 @@ IN_PROC_BROWSER_TEST_F(KioskEnterpriseTest, EnterpriseKioskApp) {
       &result));
   EXPECT_EQ(kTestAccessToken, result);
 
+  // Verify that the session is not considered to be logged in with a GAIA
+  // account.
+  Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
+  ASSERT_TRUE(app_profile);
+  EXPECT_FALSE(app_profile->GetPrefs()->HasPrefPath(
+      prefs::kGoogleServicesUsername));
+
   // Terminate the app.
   window->GetBaseWindow()->Close();
   content::RunAllPendingInMessageLoop();
@@ -831,15 +1240,14 @@ class KioskHiddenWebUITest : public KioskTest,
   // KioskTest overrides:
   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     KioskTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII(switches::kDeviceRegistered, "1");
     command_line->AppendSwitch(switches::kDisableBootAnimation);
-    command_line->AppendSwitch(switches::kDisableOobeAnimation);
   }
 
   virtual void SetUpOnMainThread() OVERRIDE {
     KioskTest::SetUpOnMainThread();
     ash::Shell::GetInstance()->desktop_background_controller()
         ->AddObserver(this);
+    StartupUtils::MarkDeviceRegistered();
   }
 
   virtual void TearDownOnMainThread() OVERRIDE {