blob: 41bb6e02382ded632f8cbac45912144e77ef34e2 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <vector>
#include "apps/test/app_window_waiter.h"
#include "ash/public/interfaces/login_screen_test_api.test-mojom-test-utils.h"
#include "ash/public/interfaces/wallpaper.mojom.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/json/json_reader.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/app_mode/fake_cws.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h"
#include "chrome/browser/chromeos/login/app_launch_controller.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
#include "chrome/browser/chromeos/login/test/js_checker.h"
#include "chrome/browser/chromeos/login/test/network_portal_detector_mixin.h"
#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
#include "chrome/browser/chromeos/login/test/test_condition_waiter.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/login/ui/login_display_host_webui.h"
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/ownership/fake_owner_settings_service.h"
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.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/chromeos/settings/scoped_cros_settings_test_helper.h"
#include "chrome/browser/extensions/browsertest_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile_impl.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/ash/wallpaper_controller_client.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h"
#include "chromeos/constants/chromeos_switches.h"
#include "chromeos/dbus/cryptohome/cryptohome_client.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "chromeos/settings/cros_settings_provider.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/scoped_user_manager.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/browser/web_ui.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/manifest.h"
#include "extensions/common/switches.h"
#include "extensions/components/native_app_window/native_app_window_views.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_switches.h"
#include "google_apis/gaia/gaia_urls.h"
#include "media/audio/test_audio_thread.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/audio/public/cpp/fake_system_info.h"
#include "services/audio/public/cpp/sounds/audio_stream_handler.h"
#include "services/audio/public/cpp/sounds/sounds_manager.h"
#include "services/identity/public/cpp/identity_manager.h"
#include "services/service_manager/public/cpp/connector.h"
#include "ui/aura/window.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/keyboard/public/keyboard_switches.h"
namespace em = enterprise_management;
namespace chromeos {
namespace {
// This is a simple test app that creates an app window and immediately closes
// it again. Webstore data json is in
// chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
// detail/ggaeimfdpnmlhdhpcikgoblffmkckdmn
const char kTestKioskApp[] = "ggaeimfdpnmlhdhpcikgoblffmkckdmn";
// This app creates a window and declares usage of the identity API in its
// manifest, so we can test device robot token minting via the identity API.
// Webstore data json is in
// chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
// detail/gcpjojfkologpegommokeppihdbcnahn
const char kTestEnterpriseKioskApp[] = "gcpjojfkologpegommokeppihdbcnahn";
// An offline enable test app. Webstore data json is in
// chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
// detail/iiigpodgfihagabpagjehoocpakbnclp
// 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[] = "iiigpodgfihagabpagjehoocpakbnclp";
// 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/abbjjkefakmllanciinhgjgjamdmlbdg
const char kTestLocalFsKioskApp[] = "abbjjkefakmllanciinhgjgjamdmlbdg";
// An app to test local access to file systems via the
// chrome.fileSystem.requestFileSystem API.
// Webstore data json is in
// chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
// detail/enelnimkndkcejhjnpaofdlbbfmdnagi
const char kTestGetVolumeListKioskApp[] = "enelnimkndkcejhjnpaofdlbbfmdnagi";
// An app to test Kiosk virtual keyboard API chrome.virtualKeyboard.* .
// Source files are in
// chrome/test/data/chromeos/app_mode/virtual_keyboard/src/
const char kTestVirtualKeyboardKioskApp[] = "bbkdjgcbpfjanhcdljmpddplpeehopdo";
// Testing apps for testing kiosk multi-app feature. All the crx files are in
// chrome/test/data/chromeos/app_mode/webstore/downloads.
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/primary_app
const char kTestPrimaryKioskApp[] = "fclmjfpgiaifbnbnlpmdjhicolkapihc";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_1
const char kTestSecondaryApp1[] = "elbhpkeieolijdlflcplbbabceggjknh";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_2
const char kTestSecondaryApp2[] = "coamgmmgmjeeaodkbpdajekljacgfhkc";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app_3
const char kTestSecondaryApp3[] = "miccbahcahimnejpdoaafjeolookhoem";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
// secondary_extensions_1
const char kTestSecondaryExtension[] = "pegeblegnlhnpgghhjblhchdllfijodp";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
// shared_module_primary_app
const char kTestSharedModulePrimaryApp[] = "kidkeddeanfhailinhfokehpolmfdppa";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/secondary_app
const char kTestSecondaryApp[] = "ffceghmcpipkneddgikbgoagnheejdbf";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/shared_module
const char kTestSharedModuleId[] = "hpanhkopkhnkpcmnedlnjmkfafmlamak";
// Source files are in
// chrome/test/data/chromeos/app_mode/multi_app_kiosk/src/
// secondary_extension
const char kTestSecondaryExt[] = "meaknlbicgahoejcchpnkenkmbekcddf";
// Fake usb stick mount path.
const char kFakeUsbMountPathUpdatePass[] =
"chromeos/app_mode/external_update/update_pass";
const char kFakeUsbMountPathNoManifest[] =
"chromeos/app_mode/external_update/no_manifest";
const char kFakeUsbMountPathBadManifest[] =
"chromeos/app_mode/external_update/bad_manifest";
const char kFakeUsbMountPathLowerAppVersion[] =
"chromeos/app_mode/external_update/lower_app_version";
const char kFakeUsbMountPathLowerCrxVersion[] =
"chromeos/app_mode/external_update/lower_crx_version";
const char kFakeUsbMountPathBadCrx[] =
"chromeos/app_mode/external_update/bad_crx";
// Timeout while waiting for network connectivity during tests.
const int kTestNetworkTimeoutSeconds = 1;
// Email of owner account for test.
const char kTestOwnerEmail[] = "owner@example.com";
const char kTestEnterpriseAccountId[] = "enterprise-kiosk-app@localhost";
const char kTestEnterpriseServiceAccountId[] = "service_account@example.com";
const char kTestRefreshToken[] = "fake-refresh-token";
const char kTestUserinfoToken[] = "fake-userinfo-token";
const char kTestLoginToken[] = "fake-login-token";
const char kTestAccessToken[] = "fake-access-token";
const char kTestClientId[] = "fake-client-id";
const char kTestAppScope[] = "https://www.googleapis.com/auth/userinfo.profile";
// Helper function for GetConsumerKioskAutoLaunchStatusCallback.
void ConsumerKioskAutoLaunchStatusCheck(
KioskAppManager::ConsumerKioskAutoLaunchStatus* out_status,
const base::Closure& runner_quit_task,
KioskAppManager::ConsumerKioskAutoLaunchStatus in_status) {
LOG(INFO) << "KioskAppManager::ConsumerKioskModeStatus = " << in_status;
*out_status = in_status;
runner_quit_task.Run();
}
// Helper KioskAppManager::EnableKioskModeCallback implementation.
void ConsumerKioskModeAutoStartLockCheck(bool* out_locked,
const base::Closure& runner_quit_task,
bool in_locked) {
LOG(INFO) << "kiosk locked = " << in_locked;
*out_locked = in_locked;
runner_quit_task.Run();
}
// Helper function for WaitForNetworkTimeOut.
void OnNetworkWaitTimedOut(const base::Closure& runner_quit_task) {
runner_quit_task.Run();
}
bool IsAppInstalled(const std::string& app_id, const std::string& version) {
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
DCHECK(app_profile);
const extensions::Extension* app =
extensions::ExtensionSystem::Get(app_profile)
->extension_service()
->GetInstalledExtension(app_id);
return app != nullptr && version == app->version().GetString();
}
extensions::Manifest::Type GetAppType(const std::string& app_id) {
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
DCHECK(app_profile);
const extensions::Extension* app =
extensions::ExtensionSystem::Get(app_profile)
->extension_service()
->GetInstalledExtension(app_id);
DCHECK(app);
return app->GetType();
}
void SetPlatformVersion(const std::string& platform_version) {
const std::string lsb_release = base::StringPrintf(
"CHROMEOS_RELEASE_VERSION=%s", platform_version.c_str());
base::SysInfo::SetChromeOSVersionInfoForTest(lsb_release, base::Time::Now());
}
class KioskSessionInitializedWaiter : public KioskAppManagerObserver {
public:
KioskSessionInitializedWaiter() : scoped_observer_(this) {
scoped_observer_.Add(KioskAppManager::Get());
}
~KioskSessionInitializedWaiter() override = default;
void Wait() {
if (KioskAppManager::Get()->app_session())
return;
run_loop_.Run();
}
// KioskAppManagerObserver:
void OnKioskSessionInitialized() override { run_loop_.Quit(); }
private:
ScopedObserver<KioskAppManager, KioskAppManagerObserver> scoped_observer_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(KioskSessionInitializedWaiter);
};
// Helper functions for CanConfigureNetwork mock.
class ScopedCanConfigureNetwork {
public:
ScopedCanConfigureNetwork(bool can_configure, bool needs_owner_auth)
: can_configure_(can_configure),
needs_owner_auth_(needs_owner_auth),
can_configure_network_callback_(
base::Bind(&ScopedCanConfigureNetwork::CanConfigureNetwork,
base::Unretained(this))),
needs_owner_auth_callback_(base::Bind(
&ScopedCanConfigureNetwork::NeedsOwnerAuthToConfigureNetwork,
base::Unretained(this))) {
AppLaunchController::SetCanConfigureNetworkCallbackForTesting(
&can_configure_network_callback_);
AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
&needs_owner_auth_callback_);
}
~ScopedCanConfigureNetwork() {
AppLaunchController::SetCanConfigureNetworkCallbackForTesting(NULL);
AppLaunchController::SetNeedOwnerAuthToConfigureNetworkCallbackForTesting(
NULL);
}
bool CanConfigureNetwork() { return can_configure_; }
bool NeedsOwnerAuthToConfigureNetwork() { return needs_owner_auth_; }
private:
bool can_configure_;
bool needs_owner_auth_;
AppLaunchController::ReturnBoolCallback can_configure_network_callback_;
AppLaunchController::ReturnBoolCallback needs_owner_auth_callback_;
DISALLOW_COPY_AND_ASSIGN(ScopedCanConfigureNetwork);
};
class KioskFakeDiskMountManager : public file_manager::FakeDiskMountManager {
public:
KioskFakeDiskMountManager() {}
~KioskFakeDiskMountManager() override {}
void set_usb_mount_path(const std::string& usb_mount_path) {
usb_mount_path_ = usb_mount_path;
}
void MountUsbStick() {
DCHECK(!usb_mount_path_.empty());
MountPath(usb_mount_path_, "", "", {}, chromeos::MOUNT_TYPE_DEVICE,
chromeos::MOUNT_ACCESS_MODE_READ_ONLY);
}
void UnMountUsbStick() {
DCHECK(!usb_mount_path_.empty());
UnmountPath(usb_mount_path_, UNMOUNT_OPTIONS_NONE,
disks::DiskMountManager::UnmountPathCallback());
}
private:
std::string usb_mount_path_;
DISALLOW_COPY_AND_ASSIGN(KioskFakeDiskMountManager);
};
class AppDataLoadWaiter : public KioskAppManagerObserver {
public:
AppDataLoadWaiter(KioskAppManager* manager,
const std::string& app_id,
const std::string& version)
: runner_(NULL),
manager_(manager),
wait_type_(WAIT_FOR_CRX_CACHE),
loaded_(false),
quit_(false),
app_id_(app_id),
version_(version) {
manager_->AddObserver(this);
}
~AppDataLoadWaiter() override { manager_->RemoveObserver(this); }
void Wait() {
wait_type_ = WAIT_FOR_CRX_CACHE;
if (quit_)
return;
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
void WaitForAppData() {
wait_type_ = WAIT_FOR_APP_DATA;
if (quit_ || IsAppDataLoaded())
return;
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
bool loaded() const { return loaded_; }
private:
enum WaitType {
WAIT_FOR_CRX_CACHE,
WAIT_FOR_APP_DATA,
};
// KioskAppManagerObserver overrides:
void OnKioskAppDataChanged(const std::string& app_id) override {
if (wait_type_ != WAIT_FOR_APP_DATA || app_id != app_id_ ||
!IsAppDataLoaded()) {
return;
}
loaded_ = true;
quit_ = true;
if (runner_.get())
runner_->Quit();
}
void OnKioskAppDataLoadFailure(const std::string& app_id) override {
if (wait_type_ != WAIT_FOR_APP_DATA || app_id != app_id_)
return;
loaded_ = false;
quit_ = true;
if (runner_.get())
runner_->Quit();
}
void OnKioskExtensionLoadedInCache(const std::string& app_id) override {
if (wait_type_ != WAIT_FOR_CRX_CACHE)
return;
std::string cached_version;
base::FilePath file_path;
if (!manager_->GetCachedCrx(app_id_, &file_path, &cached_version))
return;
if (version_ != cached_version)
return;
loaded_ = true;
quit_ = true;
if (runner_.get())
runner_->Quit();
}
void OnKioskExtensionDownloadFailed(const std::string& app_id) override {
if (wait_type_ != WAIT_FOR_CRX_CACHE)
return;
loaded_ = false;
quit_ = true;
if (runner_.get())
runner_->Quit();
}
bool IsAppDataLoaded() {
KioskAppManager::App app;
return manager_->GetApp(app_id_, &app) && !app.is_loading;
}
scoped_refptr<content::MessageLoopRunner> runner_;
KioskAppManager* manager_;
WaitType wait_type_;
bool loaded_;
bool quit_;
std::string app_id_;
std::string version_;
DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter);
};
} // namespace
class KioskTest : public OobeBaseTest {
public:
KioskTest() : settings_helper_(false), fake_cws_(new FakeCWS) {
set_exit_when_last_browser_closes(false);
// This test does not operate any real App, so App data does not exist.
// Depending on timing, the asynchronous check for app data may or may not
// complete before test checks pass. And if the check does complete, it will
// mark app status KioskAppData::STATUS_ERROR, and exclude it from the list
// of populated apps.
//
// Then, any Update UI event (asynchronous) (like
// LoginDisplayHostCommon::OnStartSignInScreenCommon() will invoke
// SendKioskApps() and destroy test configuration.
//
// We default to ignore test data, as most of test cases use app ids only,
// So individual checks should revert it to default when needed.
//
// TODO(https://crbug.com/937244): Remove this.
KioskAppData::SetIgnoreKioskAppDataLoadFailuresForTesting(true);
}
~KioskTest() override {}
protected:
void SetUp() override {
test_app_id_ = kTestKioskApp;
set_test_app_version("1.0.0");
set_test_crx_file(test_app_id() + ".crx");
needs_background_networking_ = true;
mock_user_manager_.reset(new MockUserManager);
ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(true);
AppLaunchController::SkipSplashWaitForTesting();
AppLaunchController::SetNetworkWaitForTesting(kTestNetworkTimeoutSeconds);
OobeBaseTest::SetUp();
}
void TearDown() override {
ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(false);
OobeBaseTest::TearDown();
}
void SetUpOnMainThread() override {
OobeBaseTest::SetUpOnMainThread();
// Needed to avoid showing Gaia screen instead of owner signin for
// consumer network down test cases.
StartupUtils::MarkDeviceRegistered(base::Closure());
settings_helper_.ReplaceDeviceSettingsProviderWithStub();
owner_settings_service_ = settings_helper_.CreateOwnerSettingsService(
ProfileManager::GetPrimaryUserProfile());
// Set up local cache for app update check.
extensions::browsertest_util::CreateAndInitializeLocalCache();
}
void TearDownOnMainThread() override {
settings_helper_.RestoreRealDeviceSettingsProvider();
AppLaunchController::SetNetworkTimeoutCallbackForTesting(NULL);
AppLaunchSigninScreen::SetUserManagerForTesting(NULL);
OobeBaseTest::TearDownOnMainThread();
// Clean up while main thread still runs.
// See http://crbug.com/176659.
KioskAppManager::Get()->CleanUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
OobeBaseTest::SetUpCommandLine(command_line);
fake_cws_->Init(embedded_test_server());
if (use_consumer_kiosk_mode_)
command_line->AppendSwitch(switches::kEnableConsumerKiosk);
}
bool LaunchApp(const std::string& app_id, bool diagnostic_mode) {
// TODO(https://crbug.com/932323): Implement or remove diagnostic mode.
if (diagnostic_mode)
return false;
ash::mojom::LoginScreenTestApiPtr test_api_;
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->BindInterface(ash::mojom::kServiceName, &test_api_);
ash::mojom::LoginScreenTestApiAsyncWaiter login_screen(test_api_.get());
bool found;
login_screen.LaunchApp(app_id, &found);
return found;
}
void ReloadKioskApps() {
SetupTestAppUpdateCheck();
// Remove then add to ensure NOTIFICATION_KIOSK_APPS_LOADED fires.
KioskAppManager::Get()->RemoveApp(test_app_id_,
owner_settings_service_.get());
KioskAppManager::Get()->AddApp(test_app_id_, owner_settings_service_.get());
}
void FireKioskAppSettingsChanged() {
KioskAppManager::Get()->UpdateAppData();
}
void SetupTestAppUpdateCheck() {
if (test_app_version().empty())
return;
fake_cws_->SetUpdateCrx(test_app_id(), test_crx_file(), test_app_version());
}
void ReloadAutolaunchKioskApps() {
SetupTestAppUpdateCheck();
KioskAppManager::Get()->AddApp(test_app_id_, owner_settings_service_.get());
KioskAppManager::Get()->SetAutoLaunchApp(test_app_id_,
owner_settings_service_.get());
}
void StartUIForAppLaunch() {
if (use_consumer_kiosk_mode_)
EnableConsumerKioskMode();
// Start UI
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
if (wizard_controller)
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
}
void PrepareAppLaunch() {
// Start UI
StartUIForAppLaunch();
// 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(
NetworkPortalDetector::CaptivePortalStatus network_status) {
PrepareAppLaunch();
network_portal_detector_.SimulateDefaultNetworkState(network_status);
EXPECT_TRUE(LaunchApp(test_app_id(), false));
}
const extensions::Extension* GetInstalledApp() {
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
return extensions::ExtensionSystem::Get(app_profile)
->extension_service()
->GetInstalledExtension(test_app_id_);
}
const base::Version& GetInstalledAppVersion() {
return GetInstalledApp()->version();
}
extensions::Manifest::Location GetInstalledAppLocation() {
return GetInstalledApp()->location();
}
void WaitForAppLaunchWithOptions(bool check_launch_data, bool terminate_app) {
ExtensionTestMessageListener launch_data_check_listener(
"launchData.isKioskSession = true", false);
// Wait for the Kiosk App to launch.
KioskSessionInitializedWaiter().Wait();
// Default profile switches to app profile after app is launched.
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());
// Check if the kiosk webapp is really installed for the default profile.
const extensions::Extension* app =
extensions::ExtensionSystem::Get(app_profile)
->extension_service()
->GetInstalledExtension(test_app_id_);
EXPECT_TRUE(app);
// App should appear with its window.
extensions::AppWindowRegistry* app_window_registry =
extensions::AppWindowRegistry::Get(app_profile);
extensions::AppWindow* window =
apps::AppWindowWaiter(app_window_registry, test_app_id_).Wait();
EXPECT_TRUE(window);
// Login screen should be gone or fading out.
LoginDisplayHost* login_display_host = LoginDisplayHost::default_host();
EXPECT_TRUE(
login_display_host == NULL ||
login_display_host->GetNativeWindow()->layer()->GetTargetOpacity() ==
0.0f);
// Terminate the app.
if (terminate_app)
window->GetBaseWindow()->Close();
// Wait until the app terminates if it is still running.
if (!app_window_registry->GetAppWindowsForApp(test_app_id_).empty())
RunUntilBrowserProcessQuits();
// Check that the app had been informed that it is running in a kiosk
// session.
if (check_launch_data)
EXPECT_TRUE(launch_data_check_listener.was_satisfied());
}
void WaitForAppLaunchSuccess() {
WaitForAppLaunchWithOptions(true /* check_launch_data */,
true /* terminate_app */);
}
void WaitForAppLaunchNetworkTimeout() {
if (GetAppLaunchController()->network_wait_timedout())
return;
scoped_refptr<content::MessageLoopRunner> runner =
new content::MessageLoopRunner;
base::Closure callback =
base::Bind(&OnNetworkWaitTimedOut, runner->QuitClosure());
AppLaunchController::SetNetworkTimeoutCallbackForTesting(&callback);
runner->Run();
CHECK(GetAppLaunchController()->network_wait_timedout());
AppLaunchController::SetNetworkTimeoutCallbackForTesting(NULL);
}
void EnableConsumerKioskMode() {
bool locked = false;
scoped_refptr<content::MessageLoopRunner> runner =
new content::MessageLoopRunner;
KioskAppManager::Get()->EnableConsumerKioskAutoLaunch(base::Bind(
&ConsumerKioskModeAutoStartLockCheck, &locked, runner->QuitClosure()));
runner->Run();
EXPECT_TRUE(locked);
}
KioskAppManager::ConsumerKioskAutoLaunchStatus GetConsumerKioskModeStatus() {
KioskAppManager::ConsumerKioskAutoLaunchStatus status =
static_cast<KioskAppManager::ConsumerKioskAutoLaunchStatus>(-1);
scoped_refptr<content::MessageLoopRunner> runner =
new content::MessageLoopRunner;
KioskAppManager::Get()->GetConsumerKioskAutoLaunchStatus(base::Bind(
&ConsumerKioskAutoLaunchStatusCheck, &status, runner->QuitClosure()));
runner->Run();
CHECK_NE(status,
static_cast<KioskAppManager::ConsumerKioskAutoLaunchStatus>(-1));
return status;
}
void RunAppLaunchNetworkDownTest() {
mock_user_manager()->SetActiveUser(test_owner_account_id_);
AppLaunchSigninScreen::SetUserManagerForTesting(mock_user_manager());
// 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(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
splash_waiter.Wait();
WaitForAppLaunchNetworkTimeout();
// Configure network link should be visible.
test::OobeJS().ExpectVisible("splash-config-network");
// Set up fake user manager with an owner for the test.
LoginDisplayHost::default_host()->GetOobeUI()->ShowOobeUI(false);
// Configure network should bring up lock screen for owner.
OobeScreenWaiter lock_screen_waiter(OobeScreen::SCREEN_ACCOUNT_PICKER);
static_cast<AppLaunchSplashScreenView::Delegate*>(GetAppLaunchController())
->OnConfigureNetwork();
lock_screen_waiter.Wait();
// There should be only one owner pod on this screen.
test::OobeJS().ExpectTrue("$('pod-row').alwaysFocusSinglePod");
// A network error screen should be shown after authenticating.
OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
static_cast<AppLaunchSigninScreen::Delegate*>(GetAppLaunchController())
->OnOwnerSigninSuccess();
error_screen_waiter.Wait();
ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
SimulateNetworkOnline();
WaitForAppLaunchSuccess();
}
// Waits for a message sent from DOM automation to |message_queue|.
// The message is expected to be in JSON format:
// {'name': <msg_name>, 'data': <extra_msg_data>}.
// This will wait until a message with name set to |message_name| is seen, and
// it will return the value set as the message's data. It is acceptable for
// the DOM message not to specify 'data' property, in which case this will
// return empty value.
base::Value WaitForDOMMessage(content::DOMMessageQueue* message_queue,
const std::string& message_name) {
std::string message;
while (message_queue->WaitForMessage(&message)) {
base::Optional<base::Value> message_value =
base::JSONReader::Read(message);
if (!message_value.has_value() || !message_value.value().is_dict())
continue;
const std::string* name = message_value.value().FindStringKey("name");
if (!name || *name != message_name)
continue;
const base::Value* data = message_value->FindKey("data");
return data ? data->Clone() : base::Value();
}
ADD_FAILURE() << "Message wait failed " << message_name;
return base::Value();
}
void SimulateNetworkOnline() {
network_portal_detector_.SimulateDefaultNetworkState(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
}
void SimulateNetworkOffline() {
network_portal_detector_.SimulateDefaultNetworkState(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
}
AppLaunchController* GetAppLaunchController() {
return LoginDisplayHost::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_; }
void set_test_app_version(const std::string& version) {
test_app_version_ = version;
}
const std::string& test_app_version() const { return test_app_version_; }
void set_test_crx_file(const std::string& filename) {
test_crx_file_ = filename;
}
const std::string& test_crx_file() const { return test_crx_file_; }
FakeCWS* fake_cws() { return fake_cws_.get(); }
void set_use_consumer_kiosk_mode(bool use) { use_consumer_kiosk_mode_ = use; }
ScopedCrosSettingsTestHelper settings_helper_;
std::unique_ptr<FakeOwnerSettingsService> owner_settings_service_;
const AccountId test_owner_account_id_ =
AccountId::FromUserEmail(kTestOwnerEmail);
NetworkPortalDetectorMixin network_portal_detector_{&mixin_host_};
private:
bool use_consumer_kiosk_mode_ = true;
std::string test_app_id_;
std::string test_app_version_;
std::string test_crx_file_;
std::unique_ptr<FakeCWS> fake_cws_;
std::unique_ptr<MockUserManager> mock_user_manager_;
DISALLOW_COPY_AND_ASSIGN(KioskTest);
};
IN_PROC_BROWSER_TEST_F(KioskTest, InstallAndLaunchApp) {
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
WaitForAppLaunchSuccess();
KioskAppManager::App app;
ASSERT_TRUE(KioskAppManager::Get()->GetApp(test_app_id(), &app));
EXPECT_FALSE(app.was_auto_launched_with_zero_delay);
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
IN_PROC_BROWSER_TEST_F(KioskTest, ZoomSupport) {
ExtensionTestMessageListener app_window_loaded_listener("appWindowLoaded",
false);
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
EXPECT_TRUE(app_window_loaded_listener.WaitUntilSatisfied());
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
ASSERT_TRUE(app_profile);
extensions::AppWindowRegistry* app_window_registry =
extensions::AppWindowRegistry::Get(app_profile);
extensions::AppWindow* window =
apps::AppWindowWaiter(app_window_registry, test_app_id()).Wait();
ASSERT_TRUE(window);
int original_width;
ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
window->web_contents(),
"window.domAutomationController.send(window.innerWidth);",
&original_width));
content::DOMMessageQueue message_queue;
// Inject window size observer that should notify this test when the app
// window size changes during zoom operations.
test::JSChecker(window->web_contents())
.Evaluate(
"window.addEventListener('resize', function() {"
" window.domAutomationController.send({"
" 'name': 'size_changed',"
" 'data': window.innerWidth"
" });"
"});");
native_app_window::NativeAppWindowViews* native_app_window_views =
static_cast<native_app_window::NativeAppWindowViews*>(
window->GetBaseWindow());
ui::AcceleratorTarget* accelerator_target =
static_cast<ui::AcceleratorTarget*>(native_app_window_views);
// Zoom in. Text is bigger and content window width becomes smaller.
accelerator_target->AcceleratorPressed(
ui::Accelerator(ui::VKEY_ADD, ui::EF_CONTROL_DOWN));
base::Value width_zoomed_in =
WaitForDOMMessage(&message_queue, "size_changed");
ASSERT_TRUE(width_zoomed_in.is_int());
ASSERT_LT(width_zoomed_in.GetInt(), original_width);
// Go back to normal. Window width is restored.
accelerator_target->AcceleratorPressed(
ui::Accelerator(ui::VKEY_0, ui::EF_CONTROL_DOWN));
base::Value width_zoom_normal =
WaitForDOMMessage(&message_queue, "size_changed");
ASSERT_TRUE(width_zoom_normal.is_int());
ASSERT_EQ(width_zoom_normal.GetInt(), original_width);
// Zoom out. Text is smaller and content window width becomes larger.
accelerator_target->AcceleratorPressed(
ui::Accelerator(ui::VKEY_SUBTRACT, ui::EF_CONTROL_DOWN));
base::Value width_zoomed_out =
WaitForDOMMessage(&message_queue, "size_changed");
ASSERT_TRUE(width_zoomed_out.is_int());
ASSERT_GT(width_zoomed_out.GetInt(), original_width);
// Terminate the app.
window->GetBaseWindow()->Close();
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(KioskTest, NotSignedInWithGAIAAccount) {
// Tests that the kiosk session is not considered to be logged in with a GAIA
// account.
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
WaitForAppLaunchSuccess();
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
ASSERT_TRUE(app_profile);
EXPECT_FALSE(
IdentityManagerFactory::GetForProfile(app_profile)->HasPrimaryAccount());
}
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) {
// Tests the network down case for launching an existing app that is
// installed in PRE_LaunchAppNetworkDown.
RunAppLaunchNetworkDownTest();
}
IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppWithNetworkConfigAccelerator) {
ScopedCanConfigureNetwork can_configure_network(true, false);
// Block app loading until the welcome screen is shown.
AppLaunchController::SetBlockAppLaunchForTesting(true);
// Start app launch and wait for network connectivity timeout.
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
splash_waiter.Wait();
// A network error screen should be shown after authenticating.
OobeScreenWaiter error_screen_waiter(OobeScreen::SCREEN_ERROR_MESSAGE);
// Simulate Ctrl+Alt+N accelerator.
GetLoginUI()->CallJavascriptFunctionUnsafe(
"cr.ui.Oobe.handleAccelerator", base::Value("app_launch_network_config"));
error_screen_waiter.Wait();
ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
// Continue button should be visible since we are online.
test::OobeJS().ExpectVisible("error-message-md-continue-button");
// Let app launching resume.
AppLaunchController::SetBlockAppLaunchForTesting(false);
// Click on [Continue] button.
test::OobeJS().TapOn("error-message-md-continue-button");
WaitForAppLaunchSuccess();
}
IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkDownConfigureNotAllowed) {
// Mock network could not be configured.
ScopedCanConfigureNetwork can_configure_network(false, true);
// Start app launch and wait for network connectivity timeout.
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
splash_waiter.Wait();
WaitForAppLaunchNetworkTimeout();
// Configure network link should not be visible.
test::OobeJS().ExpectHidden("splash-config-network");
// Network becomes online and app launch is resumed.
SimulateNetworkOnline();
WaitForAppLaunchSuccess();
}
IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppNetworkPortal) {
// Mock network could be configured without the owner password.
ScopedCanConfigureNetwork can_configure_network(true, false);
// Start app launch with network portal state.
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL);
OobeScreenWaiter app_splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
app_splash_waiter.set_no_assert_last_screen();
app_splash_waiter.Wait();
WaitForAppLaunchNetworkTimeout();
// Network error should show up automatically since this test does not
// require owner auth to configure network.
OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
ASSERT_TRUE(GetAppLaunchController()->showing_network_dialog());
SimulateNetworkOnline();
WaitForAppLaunchSuccess();
}
IN_PROC_BROWSER_TEST_F(KioskTest, LaunchAppUserCancel) {
// Make fake_cws_ return empty update response.
set_test_app_version("");
OobeScreenWaiter splash_waiter(OobeScreen::SCREEN_APP_LAUNCH_SPLASH);
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE);
splash_waiter.Wait();
settings_helper_.SetBoolean(
kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, true);
content::WindowedNotificationObserver signal(
chrome::NOTIFICATION_APP_TERMINATING,
content::NotificationService::AllSources());
GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
base::Value("app_launch_bailout"));
signal.Wait();
EXPECT_EQ(chromeos::KioskAppLaunchError::USER_CANCEL,
chromeos::KioskAppLaunchError::Get());
}
// TODO: https://crbug.com/932323
IN_PROC_BROWSER_TEST_F(KioskTest, DISABLED_LaunchInDiagnosticMode) {
const char kCheckDiagnosticModeOldAPI[] =
"$('show-apps-button').confirmDiagnosticMode_";
PrepareAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(kTestKioskApp, true));
test::OobeJS().CreateWaiter(kCheckDiagnosticModeOldAPI)->Wait();
std::string diagnosticMode(kCheckDiagnosticModeOldAPI);
test::OobeJS().Evaluate(
"(function() {"
"var e = new Event('click');" +
diagnosticMode +
"."
"okButton_.dispatchEvent(e);"
"})();");
WaitForAppLaunchSuccess();
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
IN_PROC_BROWSER_TEST_F(KioskTest, AutolaunchWarningCancel) {
EnableConsumerKioskMode();
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
CHECK(wizard_controller);
// Start login screen after configuring auto launch app since the warning
// is triggered when switching to login screen.
wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
ReloadAutolaunchKioskApps();
EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
// Wait for the auto launch warning come up.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.AutolaunchScreen.confirmAutoLaunchForTesting", base::Value(false));
// Wait for the auto launch warning to go away.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
content::NotificationService::AllSources())
.Wait();
EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
}
IN_PROC_BROWSER_TEST_F(KioskTest, AutolaunchWarningConfirm) {
EnableConsumerKioskMode();
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
CHECK(wizard_controller);
// Start login screen after configuring auto launch app since the warning
// is triggered when switching to login screen.
wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
ReloadAutolaunchKioskApps();
EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
// Wait for the auto launch warning come up.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.AutolaunchScreen.confirmAutoLaunchForTesting", base::Value(true));
// Wait for the auto launch warning to go away.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
content::NotificationService::AllSources())
.Wait();
EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
EXPECT_TRUE(KioskAppManager::Get()->IsAutoLaunchEnabled());
WaitForAppLaunchSuccess();
KioskAppManager::App app;
ASSERT_TRUE(KioskAppManager::Get()->GetApp(test_app_id(), &app));
EXPECT_TRUE(app.was_auto_launched_with_zero_delay);
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableCancel) {
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
CHECK(wizard_controller);
// Check Kiosk mode status.
EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
GetConsumerKioskModeStatus());
// Wait for the login UI to come up and switch to the kiosk_enable screen.
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
base::Value("kiosk_enable"));
// Wait for the kiosk_enable screen to show and cancel the screen.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.KioskEnableScreen.enableKioskForTesting", base::Value(false));
// Wait for the kiosk_enable screen to disappear.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
content::NotificationService::AllSources())
.Wait();
// Check that the status still says configurable.
EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
GetConsumerKioskModeStatus());
}
IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableConfirmed) {
// Start UI, find menu entry for this app and launch it.
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
CHECK(wizard_controller);
// Check Kiosk mode status.
EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
GetConsumerKioskModeStatus());
// Wait for the login UI to come up and switch to the kiosk_enable screen.
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
base::Value("kiosk_enable"));
// Wait for the kiosk_enable screen to show and cancel the screen.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.KioskEnableScreen.enableKioskForTesting", base::Value(true));
// Wait for the signal that indicates Kiosk Mode is enabled.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLED,
content::NotificationService::AllSources())
.Wait();
EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED,
GetConsumerKioskModeStatus());
}
IN_PROC_BROWSER_TEST_F(KioskTest, KioskEnableAfter2ndSigninScreen) {
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
CHECK(wizard_controller);
// Check Kiosk mode status.
EXPECT_EQ(KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE,
GetConsumerKioskModeStatus());
// Wait for the login UI to come up and switch to the kiosk_enable screen.
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
base::Value("kiosk_enable"));
// Wait for the kiosk_enable screen to show and cancel the screen.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.KioskEnableScreen.enableKioskForTesting", base::Value(false));
// Wait for the kiosk_enable screen to disappear.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
content::NotificationService::AllSources())
.Wait();
// Show signin screen again.
LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
// Show kiosk enable screen again.
GetLoginUI()->CallJavascriptFunctionUnsafe("cr.ui.Oobe.handleAccelerator",
base::Value("kiosk_enable"));
// And it should show up.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
}
// crbug.com/766169
#if defined(ADDRESS_SANITIZER)
#define MAYBE_DoNotLaunchWhenUntrusted DISABLED_DoNotLaunchWhenUntrusted
#else
// TODO(https://crbug.com/934109): Fix kiosk launch when the device is
// untrusted.
#define MAYBE_DoNotLaunchWhenUntrusted DISABLED_DoNotLaunchWhenUntrusted
#endif
IN_PROC_BROWSER_TEST_F(KioskTest, MAYBE_DoNotLaunchWhenUntrusted) {
PrepareAppLaunch();
SimulateNetworkOnline();
// Make cros settings untrusted.
settings_helper_.SetTrustedStatus(
CrosSettingsProvider::PERMANENTLY_UNTRUSTED);
// Check that the attempt to start a kiosk app fails with an error.
EXPECT_TRUE(LaunchApp(test_app_id(), false));
bool ignored = false;
EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
GetLoginUI()->GetWebContents(),
"if (cr.ui.Oobe.getInstance().errorMessageWasShownForTesting_) {"
" window.domAutomationController.send(true);"
"} else {"
" cr.ui.Oobe.showSignInError = function("
" loginAttempts, message, link, helpId) {"
" window.domAutomationController.send(true);"
" };"
"}",
&ignored));
}
// crbug.com/766169
#if defined(ADDRESS_SANITIZER)
#define MAYBE_NoConsumerAutoLaunchWhenUntrusted \
DISABLED_NoConsumerAutoLaunchWhenUntrusted
#else
#define MAYBE_NoConsumerAutoLaunchWhenUntrusted \
NoConsumerAutoLaunchWhenUntrusted
#endif
// Verifies that a consumer device does not auto-launch kiosk mode when cros
// settings are untrusted.
IN_PROC_BROWSER_TEST_F(KioskTest, MAYBE_NoConsumerAutoLaunchWhenUntrusted) {
EnableConsumerKioskMode();
// Wait for and confirm the auto-launch warning.
chromeos::WizardController::SkipPostLoginScreensForTesting();
chromeos::WizardController* wizard_controller =
chromeos::WizardController::default_controller();
ASSERT_TRUE(wizard_controller);
wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
ReloadAutolaunchKioskApps();
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
GetLoginUI()->CallJavascriptFunctionUnsafe(
"login.AutolaunchScreen.confirmAutoLaunchForTesting", base::Value(true));
// Make cros settings untrusted.
settings_helper_.SetTrustedStatus(
CrosSettingsProvider::PERMANENTLY_UNTRUSTED);
// Check that the attempt to auto-launch a kiosk app fails with an error.
OobeScreenWaiter(OobeScreen::SCREEN_ERROR_MESSAGE).Wait();
}
// Verifies available volumes for kiosk apps in kiosk session.
IN_PROC_BROWSER_TEST_F(KioskTest, GetVolumeList) {
set_test_app_id(kTestGetVolumeListKioskApp);
set_test_app_version("0.1");
set_test_crx_file(test_app_id() + ".crx");
extensions::ResultCatcher catcher;
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// Verifies that an enterprise device does not auto-launch kiosk mode when cros
// settings are untrusted.
IN_PROC_BROWSER_TEST_F(KioskTest, NoEnterpriseAutoLaunchWhenUntrusted) {
PrepareAppLaunch();
SimulateNetworkOnline();
// Make cros settings untrusted.
settings_helper_.SetTrustedStatus(
CrosSettingsProvider::PERMANENTLY_UNTRUSTED);
// Trigger the code that handles auto-launch on enterprise devices. This would
// normally be called from ShowLoginWizard(), which runs so early that it is
// not possible to inject an auto-launch policy before it runs.
LoginDisplayHost* login_display_host = LoginDisplayHost::default_host();
ASSERT_TRUE(login_display_host);
login_display_host->StartAppLaunch(test_app_id(), false, true);
// Check that no launch has started.
EXPECT_FALSE(login_display_host->GetAppLaunchController());
}
class KioskUpdateTest : public KioskTest {
public:
KioskUpdateTest() {}
~KioskUpdateTest() override {}
struct TestAppInfo {
std::string id;
std::string version;
std::string crx_filename;
extensions::Manifest::Type type;
TestAppInfo() {}
TestAppInfo(const std::string& id,
const std::string& version,
const std::string& crx_filename,
extensions::Manifest::Type type)
: id(id), version(version), crx_filename(crx_filename), type(type) {}
~TestAppInfo() {}
};
protected:
void SetUp() override {
fake_disk_mount_manager_ = new KioskFakeDiskMountManager();
disks::DiskMountManager::InitializeForTesting(fake_disk_mount_manager_);
KioskTest::SetUp();
}
void TearDown() override {
disks::DiskMountManager::Shutdown();
KioskTest::TearDown();
}
void SetUpOnMainThread() override {
// For update tests, we cache the app in the PRE part, and then we load it
// in the test, so we need to both store the apps list on teardown (so that
// the app manager would accept existing files in its extension cache on the
// next startup) and copy the list to our stub settings provider as well.
settings_helper_.CopyStoredValue(kAccountsPrefDeviceLocalAccounts);
KioskTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
settings_helper_.StoreCachedDeviceSetting(kAccountsPrefDeviceLocalAccounts);
KioskTest::TearDownOnMainThread();
}
void PreCacheApp(const std::string& app_id,
const std::string& version,
const std::string& crx_file,
bool wait_for_app_data) {
set_test_app_id(app_id);
set_test_app_version(version);
set_test_crx_file(crx_file);
KioskAppManager* manager = KioskAppManager::Get();
AppDataLoadWaiter waiter(manager, app_id, version);
ReloadKioskApps();
if (wait_for_app_data)
waiter.WaitForAppData();
else
waiter.Wait();
EXPECT_TRUE(waiter.loaded());
std::string cached_version;
base::FilePath file_path;
EXPECT_TRUE(manager->GetCachedCrx(app_id, &file_path, &cached_version));
EXPECT_EQ(version, cached_version);
}
void UpdateExternalCache(const std::string& version,
const std::string& crx_file) {
set_test_app_version(version);
set_test_crx_file(crx_file);
SetupTestAppUpdateCheck();
KioskAppManager* manager = KioskAppManager::Get();
AppDataLoadWaiter waiter(manager, test_app_id(), version);
KioskAppManager::Get()->UpdateExternalCache();
waiter.Wait();
EXPECT_TRUE(waiter.loaded());
std::string cached_version;
base::FilePath file_path;
EXPECT_TRUE(
manager->GetCachedCrx(test_app_id(), &file_path, &cached_version));
EXPECT_EQ(version, cached_version);
}
void SetupFakeDiskMountManagerMountPath(const std::string& mount_path) {
base::FilePath test_data_dir;
base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
test_data_dir = test_data_dir.AppendASCII(mount_path);
fake_disk_mount_manager_->set_usb_mount_path(test_data_dir.value());
}
void SimulateUpdateAppFromUsbStick(const std::string& usb_mount_path,
bool* app_update_notified,
bool* update_success) {
SetupFakeDiskMountManagerMountPath(usb_mount_path);
KioskAppExternalUpdateWaiter waiter(KioskAppManager::Get(), test_app_id());
fake_disk_mount_manager_->MountUsbStick();
waiter.Wait();
fake_disk_mount_manager_->UnMountUsbStick();
*update_success = waiter.update_success();
*app_update_notified = waiter.app_update_notified();
}
void PreCacheAndLaunchApp(const std::string& app_id,
const std::string& version,
const std::string& crx_file) {
set_test_app_id(app_id);
set_test_app_version(version);
set_test_crx_file(crx_file);
PrepareAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ(version, GetInstalledAppVersion().GetString());
}
void LaunchKioskWithSecondaryApps(
const TestAppInfo& primary_app,
const std::vector<TestAppInfo>& secondary_apps) {
// Pre-cache the primary app.
PreCacheApp(primary_app.id, primary_app.version, primary_app.crx_filename,
/*wait_for_app_data=*/false);
set_test_app_id(primary_app.id);
fake_cws()->SetNoUpdate(primary_app.id);
for (const auto& app : secondary_apps) {
fake_cws()->SetUpdateCrx(app.id, app.crx_filename, app.version);
}
// Launch the primary app.
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchWithOptions(false, true);
// Verify the primary app and the secondary apps are all installed.
EXPECT_TRUE(IsAppInstalled(primary_app.id, primary_app.version));
for (const auto& app : secondary_apps) {
EXPECT_TRUE(IsAppInstalled(app.id, app.version));
EXPECT_EQ(GetAppType(app.id), app.type);
}
}
void LaunchTestKioskAppWithTwoSecondaryApps() {
TestAppInfo primary_app(kTestPrimaryKioskApp, "1.0.0",
std::string(kTestPrimaryKioskApp) + "-1.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
std::vector<TestAppInfo> secondary_apps;
TestAppInfo secondary_app_1(kTestSecondaryApp1, "1.0.0",
std::string(kTestSecondaryApp1) + "-1.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
secondary_apps.push_back(secondary_app_1);
TestAppInfo secondary_app_2(kTestSecondaryApp2, "1.0.0",
std::string(kTestSecondaryApp2) + "-1.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
secondary_apps.push_back(secondary_app_2);
LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
}
void LaunchTestKioskAppWithSeconadayExtension() {
TestAppInfo primary_app(kTestPrimaryKioskApp, "24.0.0",
std::string(kTestPrimaryKioskApp) + "-24.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
std::vector<TestAppInfo> secondary_apps;
TestAppInfo secondary_extension(
kTestSecondaryExtension, "1.0.0",
std::string(kTestSecondaryExtension) + "-1.0.0.crx",
extensions::Manifest::TYPE_EXTENSION);
secondary_apps.push_back(secondary_extension);
LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
}
void LaunchAppWithSharedModuleAndSecondaryApp() {
TestAppInfo primary_app(
kTestSharedModulePrimaryApp, "1.0.0",
std::string(kTestSharedModulePrimaryApp) + "-1.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
std::vector<TestAppInfo> secondary_apps;
TestAppInfo secondary_app(kTestSecondaryApp, "1.0.0",
std::string(kTestSecondaryApp) + "-1.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
secondary_apps.push_back(secondary_app);
// Setting up FakeCWS for shared module is the same for shared module as
// for kiosk secondary apps.
TestAppInfo shared_module(kTestSharedModuleId, "1.0.0",
std::string(kTestSharedModuleId) + "-1.0.0.crx",
extensions::Manifest::TYPE_SHARED_MODULE);
secondary_apps.push_back(shared_module);
LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
EXPECT_TRUE(IsAppInstalled(shared_module.id, shared_module.version));
}
void LaunchAppWithSharedModule() {
TestAppInfo primary_app(
kTestSharedModulePrimaryApp, "2.0.0",
std::string(kTestSharedModulePrimaryApp) + "-2.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
std::vector<TestAppInfo> secondary_apps;
// Setting up FakeCWS for shared module is the same for shared module as
// for kiosk secondary apps.
TestAppInfo shared_module(kTestSharedModuleId, "1.0.0",
std::string(kTestSharedModuleId) + "-1.0.0.crx",
extensions::Manifest::TYPE_SHARED_MODULE);
secondary_apps.push_back(shared_module);
LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
}
bool PrimaryAppUpdateIsPending() const {
Profile* app_profile = ProfileManager::GetPrimaryUserProfile();
return !!extensions::ExtensionSystem::Get(app_profile)
->extension_service()
->GetPendingExtensionUpdate(test_app_id());
}
private:
class KioskAppExternalUpdateWaiter : public KioskAppManagerObserver {
public:
KioskAppExternalUpdateWaiter(KioskAppManager* manager,
const std::string& app_id)
: runner_(NULL),
manager_(manager),
app_id_(app_id),
quit_(false),
update_success_(false),
app_update_notified_(false) {
manager_->AddObserver(this);
}
~KioskAppExternalUpdateWaiter() override { manager_->RemoveObserver(this); }
void Wait() {
if (quit_)
return;
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
bool update_success() const { return update_success_; }
bool app_update_notified() const { return app_update_notified_; }
private:
// KioskAppManagerObserver overrides:
void OnKioskAppCacheUpdated(const std::string& app_id) override {
if (app_id_ != app_id)
return;
app_update_notified_ = true;
}
void OnKioskAppExternalUpdateComplete(bool success) override {
quit_ = true;
update_success_ = success;
if (runner_.get())
runner_->Quit();
}
scoped_refptr<content::MessageLoopRunner> runner_;
KioskAppManager* manager_;
const std::string app_id_;
bool quit_;
bool update_success_;
bool app_update_notified_;
DISALLOW_COPY_AND_ASSIGN(KioskAppExternalUpdateWaiter);
};
// Owned by DiskMountManager.
KioskFakeDiskMountManager* fake_disk_mount_manager_;
DISALLOW_COPY_AND_ASSIGN(KioskUpdateTest);
};
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchOfflineEnabledAppNoNetwork) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchOfflineEnabledAppNoNetwork) {
set_test_app_id(kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOffline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
PRE_LaunchCachedOfflineEnabledAppNoNetwork) {
PreCacheApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx",
/*wait_for_app_data=*/true);
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
LaunchCachedOfflineEnabledAppNoNetwork) {
set_test_app_id(kTestOfflineEnabledKioskApp);
EXPECT_TRUE(
KioskAppManager::Get()->HasCachedCrx(kTestOfflineEnabledKioskApp));
StartUIForAppLaunch();
SimulateNetworkOffline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
// Network offline, app v1.0 has run before, has cached v2.0 crx and v2.0 should
// be installed and launched during next launch.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
PRE_LaunchCachedNewVersionOfflineEnabledAppNoNetwork) {
// Install and launch v1 app.
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
// Update cache for v2 app.
UpdateExternalCache("2.0.0",
std::string(kTestOfflineEnabledKioskApp) + ".crx");
// The installed app is still in v1.
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
LaunchCachedNewVersionOfflineEnabledAppNoNetwork) {
set_test_app_id(kTestOfflineEnabledKioskApp);
EXPECT_TRUE(KioskAppManager::Get()->HasCachedCrx(test_app_id()));
StartUIForAppLaunch();
SimulateNetworkOffline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
// v2 app should have been installed.
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchOfflineEnabledAppNoUpdate) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchOfflineEnabledAppNoUpdate) {
set_test_app_id(kTestOfflineEnabledKioskApp);
fake_cws()->SetNoUpdate(test_app_id());
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
// TODO(crbug.com/949490): LaunchOfflineEnabledAppHasUpdate is flaky ChromeOS rel (timeout).
#if defined(OS_CHROMEOS) && defined(NDEBUG)
#define MAYBE_PRE_LaunchOfflineEnabledAppHasUpdate DISABLED_PRE_LaunchOfflineEnabledAppHasUpdate
#define MAYBE_LaunchOfflineEnabledAppHasUpdate DISABLED_LaunchOfflineEnabledAppHasUpdate
#else
#define MAYBE_PRE_LaunchOfflineEnabledAppHasUpdate PRE_LaunchOfflineEnabledAppHasUpdate
#define MAYBE_LaunchOfflineEnabledAppHasUpdate LaunchOfflineEnabledAppHasUpdate
#endif
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, MAYBE_PRE_LaunchOfflineEnabledAppHasUpdate) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, MAYBE_LaunchOfflineEnabledAppHasUpdate) {
set_test_app_id(kTestOfflineEnabledKioskApp);
fake_cws()->SetUpdateCrx(test_app_id(),
"iiigpodgfihagabpagjehoocpakbnclp.crx", "2.0.0");
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
EXPECT_EQ(extensions::Manifest::EXTERNAL_PREF, GetInstalledAppLocation());
}
// Pre-cache v1 kiosk app, then launch the app without network,
// plug in usb stick with a v2 app for offline updating.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_UsbStickUpdateAppNoNetwork) {
PreCacheApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx",
/*wait_for_app_data=*/true);
set_test_app_id(kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOffline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v2 app on the stick.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathUpdatePass,
&app_update_notified, &update_success);
EXPECT_TRUE(update_success);
EXPECT_TRUE(app_update_notified);
// The v2 kiosk app is loaded into external cache, but won't be installed
// until next time the device is started.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("2.0.0", cached_version);
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
}
// Restart the device, verify the app has been updated to v2.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppNoNetwork) {
// Verify the kiosk app has been updated to v2.
set_test_app_id(kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOffline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
}
// Usb stick is plugged in without a manifest file on it.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppNoManifest) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v2 app on the stick.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathNoManifest,
&app_update_notified, &update_success);
EXPECT_FALSE(update_success);
// Kiosk app is not updated.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("1.0.0", cached_version);
}
// Usb stick is plugged in with a bad manifest file on it.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppBadManifest) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v2 app on the stick.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathBadManifest,
&app_update_notified, &update_success);
EXPECT_FALSE(update_success);
// Kiosk app is not updated.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("1.0.0", cached_version);
}
// Usb stick is plugged in with a lower version of crx file specified in
// manifest.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppLowerAppVersion) {
// Precache v2 version of app.
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "2.0.0",
std::string(kTestOfflineEnabledKioskApp) + ".crx");
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v1 app on the stick.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathLowerAppVersion,
&app_update_notified, &update_success);
EXPECT_FALSE(update_success);
// Kiosk app is NOT updated to the lower version.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("2.0.0", cached_version);
}
// Usb stick is plugged in with a v1 crx file, although the manifest says
// this is a v3 version.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppLowerCrxVersion) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "2.0.0",
std::string(kTestOfflineEnabledKioskApp) + ".crx");
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v1 crx file on the stick, although
// the manifest says it is v3 app.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathLowerCrxVersion,
&app_update_notified, &update_success);
EXPECT_FALSE(update_success);
// Kiosk app is NOT updated to the lower version.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("2.0.0", cached_version);
}
// Usb stick is plugged in with a bad crx file.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppBadCrx) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
// Simulate mounting of usb stick with v1 crx file on the stick, although
// the manifest says it is v3 app.
bool update_success;
bool app_update_notified;
SimulateUpdateAppFromUsbStick(kFakeUsbMountPathBadCrx, &app_update_notified,
&update_success);
EXPECT_FALSE(update_success);
// Kiosk app is NOT updated.
base::FilePath crx_path;
std::string cached_version;
EXPECT_TRUE(KioskAppManager::Get()->GetCachedCrx(test_app_id(), &crx_path,
&cached_version));
EXPECT_EQ("1.0.0", cached_version);
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_PermissionChange) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "2.0.0",
std::string(kTestOfflineEnabledKioskApp) + ".crx");
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PermissionChange) {
set_test_app_id(kTestOfflineEnabledKioskApp);
set_test_app_version("2.0.0");
set_test_crx_file(test_app_id() + "_v2_permission_change.crx");
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_PreserveLocalData) {
// Installs v1 app and writes some local data.
set_test_app_id(kTestLocalFsKioskApp);
set_test_app_version("1.0.0");
set_test_crx_file(test_app_id() + ".crx");
extensions::ResultCatcher catcher;
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
WaitForAppLaunchWithOptions(true /* check_launch_data */,
false /* terminate_app */);
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PreserveLocalData) {
// Update existing v1 app installed in PRE_PreserveLocalData to v2
// that reads and verifies the local data.
set_test_app_id(kTestLocalFsKioskApp);
set_test_app_version("2.0.0");
set_test_crx_file(test_app_id() + "_v2_read_and_verify_data.crx");
extensions::ResultCatcher catcher;
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
WaitForAppLaunchWithOptions(true /* check_launch_data */,
false /* terminate_app */);
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// Tests the primary app install with required platform version. The test
// has three runs:
// 1. Install an app.
// 2. App update is delayed because the required platform version is not
// compliant.
// 3. Platform version changed and the new app is installed because it is
// compliant now.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
PRE_PRE_IncompliantPlatformDelayInstall) {
PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, "1.0.0",
std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_IncompliantPlatformDelayInstall) {
SetPlatformVersion("1233.0.0");
set_test_app_id(kTestOfflineEnabledKioskApp);
set_test_app_version("2.0.0");
set_test_crx_file(test_app_id() + "_v2_required_platform_version_added.crx");
// Fake auto launch.
ReloadAutolaunchKioskApps();
KioskAppManager::Get()->SetEnableAutoLaunch(true);
KioskAppManager::Get()->SetAppWasAutoLaunchedWithZeroDelay(
kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
EXPECT_TRUE(PrimaryAppUpdateIsPending());
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, IncompliantPlatformDelayInstall) {
SetPlatformVersion("1234.0.0");
set_test_app_id(kTestOfflineEnabledKioskApp);
set_test_app_version("2.0.0");
set_test_crx_file(test_app_id() + "_v2_required_platform_version_added.crx");
// Fake auto launch.
ReloadAutolaunchKioskApps();
KioskAppManager::Get()->SetEnableAutoLaunch(true);
KioskAppManager::Get()->SetAppWasAutoLaunchedWithZeroDelay(
kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
EXPECT_FALSE(PrimaryAppUpdateIsPending());
}
// Tests that app is installed for the first time even on an incompliant
// platform.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, IncompliantPlatformFirstInstall) {
SetPlatformVersion("1233.0.0");
set_test_app_id(kTestOfflineEnabledKioskApp);
set_test_app_version("2.0.0");
set_test_crx_file(test_app_id() + "_v2_required_platform_version_added.crx");
// Fake auto launch.
ReloadAutolaunchKioskApps();
KioskAppManager::Get()->SetEnableAutoLaunch(true);
KioskAppManager::Get()->SetAppWasAutoLaunchedWithZeroDelay(
kTestOfflineEnabledKioskApp);
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchSuccess();
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
EXPECT_FALSE(PrimaryAppUpdateIsPending());
}
/* ***** Test Kiosk multi-app feature ***** */
// Launch a primary kiosk app which has two secondary apps.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
LaunchTestKioskAppWithTwoSecondaryApps) {
LaunchTestKioskAppWithTwoSecondaryApps();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_UpdateMultiAppKioskRemoveOneApp) {
LaunchTestKioskAppWithTwoSecondaryApps();
}
// Update the primary app to version 2 which removes one of the secondary app
// from its manifest.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UpdateMultiAppKioskRemoveOneApp) {
set_test_app_id(kTestPrimaryKioskApp);
fake_cws()->SetUpdateCrx(kTestPrimaryKioskApp,
std::string(kTestPrimaryKioskApp) + "-2.0.0.crx",
"2.0.0");
fake_cws()->SetNoUpdate(kTestSecondaryApp1);
fake_cws()->SetNoUpdate(kTestSecondaryApp2);
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchWithOptions(false, true);
// Verify the secondary app kTestSecondaryApp1 is removed.
EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2, "1.0.0"));
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_UpdateMultiAppKioskAddOneApp) {
LaunchTestKioskAppWithTwoSecondaryApps();
}
// Update the primary app to version 3 which adds a new secondary app in its
// manifest.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UpdateMultiAppKioskAddOneApp) {
set_test_app_id(kTestPrimaryKioskApp);
fake_cws()->SetUpdateCrx(kTestPrimaryKioskApp,
std::string(kTestPrimaryKioskApp) + "-3.0.0.crx",
"3.0.0");
fake_cws()->SetNoUpdate(kTestSecondaryApp1);
fake_cws()->SetNoUpdate(kTestSecondaryApp2);
fake_cws()->SetUpdateCrx(kTestSecondaryApp3,
std::string(kTestSecondaryApp3) + "-1.0.0.crx",
"1.0.0");
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchWithOptions(false, true);
// Verify the secondary app kTestSecondaryApp3 is installed.
EXPECT_EQ("3.0.0", GetInstalledAppVersion().GetString());
EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp2, "1.0.0"));
EXPECT_TRUE(IsAppInstalled(kTestSecondaryApp3, "1.0.0"));
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchKioskAppWithSecondaryExtension) {
LaunchTestKioskAppWithSeconadayExtension();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
LaunchAppWithSharedModuleAndSecondaryApp) {
LaunchAppWithSharedModuleAndSecondaryApp();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
PRE_UpdateAppWithSharedModuleRemoveAllSecondaryApps) {
LaunchAppWithSharedModuleAndSecondaryApp();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
UpdateAppWithSharedModuleRemoveAllSecondaryApps) {
set_test_app_id(kTestSharedModulePrimaryApp);
fake_cws()->SetUpdateCrx(
kTestSharedModulePrimaryApp,
std::string(kTestSharedModulePrimaryApp) + "-2.0.0.crx", "2.0.0");
fake_cws()->SetNoUpdate(kTestSecondaryApp1);
fake_cws()->SetNoUpdate(kTestSharedModuleId);
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchWithOptions(false, true);
// Verify the secondary app is removed.
EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "1.0.0"));
EXPECT_FALSE(IsAppInstalled(kTestSecondaryApp1, "1.0.0"));
}
// This simulates the stand-alone ARC kiosk app case. The primary app has a
// shared ARC runtime but no secondary apps.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchAppWithSharedModuleNoSecondary) {
LaunchAppWithSharedModule();
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchAppWithUpdatedModule) {
LaunchAppWithSharedModule();
// Verify the shared module is installed with version 1.0.0.
EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "1.0.0"));
}
// This simulates the case the shared module is updated to a newer version.
// See crbug.com/555083.
IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchAppWithUpdatedModule) {
// No update for primary app, while the shared module is set up to a new
// version on cws.
set_test_app_id(kTestSharedModulePrimaryApp);
fake_cws()->SetNoUpdate(kTestSharedModulePrimaryApp);
fake_cws()->SetUpdateCrx(kTestSharedModuleId,
std::string(kTestSharedModuleId) + "-2.0.0.crx",
"2.0.0");
StartUIForAppLaunch();
SimulateNetworkOnline();
EXPECT_TRUE(LaunchApp(test_app_id(), false));
WaitForAppLaunchWithOptions(false, true);
// Verify the shared module is updated to the new version after primary app
// is launched.
EXPECT_TRUE(IsAppInstalled(kTestSharedModuleId, "2.0.0"));
}
IN_PROC_BROWSER_TEST_F(KioskUpdateTest,
LaunchAppWithSecondaryArcLikeAppAndExtension) {
TestAppInfo primary_app(
kTestSharedModulePrimaryApp, "3.0.0",
std::string(kTestSharedModulePrimaryApp) + "-3.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
std::vector<TestAppInfo> secondary_apps;
// Setting up FakeCWS for shared module is the same for shared module as
// for kiosk secondary apps.
TestAppInfo shared_module(kTestSharedModuleId, "1.0.0",
std::string(kTestSharedModuleId) + "-1.0.0.crx",
extensions::Manifest::TYPE_SHARED_MODULE);
secondary_apps.push_back(shared_module);
// The secondary app has a shared module, which is similar to an ARC app.
TestAppInfo secondary_app(kTestSecondaryApp, "2.0.0",
std::string(kTestSecondaryApp) + "-2.0.0.crx",
extensions::Manifest::TYPE_PLATFORM_APP);
secondary_apps.push_back(secondary_app);
TestAppInfo secondary_ext(kTestSecondaryExt, "1.0.0",
std::string(kTestSecondaryExt) + "-1.0.0.crx",
extensions::Manifest::TYPE_EXTENSION);
secondary_apps.push_back(secondary_ext);
LaunchKioskWithSecondaryApps(primary_app, secondary_apps);
}
class KioskEnterpriseTest : public KioskTest {
protected:
KioskEnterpriseTest() { set_use_consumer_kiosk_mode(false); }
void SetUpInProcessBrowserTestFixture() override {
policy::DevicePolicyCrosTestHelper::MarkAsEnterpriseOwnedBy(
test_owner_account_id_.GetUserEmail());
settings_helper_.SetCurrentUserIsOwner(false);
KioskTest::SetUpInProcessBrowserTestFixture();
}
void SetUpOnMainThread() override {
KioskTest::SetUpOnMainThread();
// Configure OAuth authentication.
GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
// This token satisfies the userinfo.email request from
// DeviceOAuth2TokenService used in token validation.
FakeGaia::AccessTokenInfo userinfo_token_info;
userinfo_token_info.token = kTestUserinfoToken;
userinfo_token_info.scopes.insert(
"https://www.googleapis.com/auth/userinfo.email");
userinfo_token_info.audience = gaia_urls->oauth2_chrome_client_id();
userinfo_token_info.email = kTestEnterpriseServiceAccountId;
fake_gaia_.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_.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;
access_token_info.token = kTestAccessToken;
access_token_info.scopes.insert(kTestAppScope);
access_token_info.audience = kTestClientId;
access_token_info.email = kTestEnterpriseServiceAccountId;
fake_gaia_.fake_gaia()->IssueOAuthToken(kTestLoginToken, access_token_info);
DeviceOAuth2TokenService* token_service =
DeviceOAuth2TokenServiceFactory::Get();
token_service->SetAndSaveRefreshToken(
kTestRefreshToken, DeviceOAuth2TokenService::StatusCallback());
base::RunLoop().RunUntilIdle();
}
void ConfigureKioskAppInPolicy(const std::string& account_id,
const std::string& app_id,
const std::string& update_url) {
settings_helper_.SetCurrentUserIsOwner(true);
std::vector<policy::DeviceLocalAccount> accounts;
accounts.push_back(
policy::DeviceLocalAccount(policy::DeviceLocalAccount::TYPE_KIOSK_APP,
account_id, app_id, update_url));
policy::SetDeviceLocalAccounts(owner_settings_service_.get(), accounts);
settings_helper_.SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
account_id);
settings_helper_.SetString(kServiceAccountIdentity,
kTestEnterpriseServiceAccountId);
settings_helper_.SetCurrentUserIsOwner(false);
}
private:
FakeGaiaMixin fake_gaia_{&mixin_host_, embedded_test_server()};
DISALLOW_COPY_AND_ASSIGN(KioskEnterpriseTest);
};
IN_PROC_BROWSER_TEST_F(KioskEnterpriseTest, EnterpriseKioskApp) {
// Prepare Fake CWS to serve app crx.
set_test_app_id(kTestEnterpriseKioskApp);
set_test_app_version("1.0.0");
set_test_crx_file(test_app_id() + ".crx");
SetupTestAppUpdateCheck();
// Configure kTestEnterpriseKioskApp in device policy.
ConfigureKioskAppInPolicy(kTestEnterpriseAccountId, kTestEnterpriseKioskApp,
"");
PrepareAppLaunch();
EXPECT_TRUE(LaunchApp(kTestEnterpriseKioskApp, false));
KioskSessionInitializedWaiter().Wait();
// Check installer status.
EXPECT_EQ(chromeos::KioskAppLaunchError::NONE,
chromeos::KioskAppLaunchError::Get());
EXPECT_EQ(extensions::Manifest::EXTERNAL_POLICY, GetInstalledAppLocation());
// Wait for the window to appear.
extensions::AppWindow* window =
apps::AppWindowWaiter(extensions::AppWindowRegistry::Get(
ProfileManager::GetPrimaryUserProfile()),
kTestEnterpriseKioskApp)
.Wait();
ASSERT_TRUE(window);
content::WaitForLoadStop(window->web_contents());
// Check whether the app can retrieve an OAuth2 access token.
std::string result;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
window->web_contents(),
"chrome.identity.getAuthToken({ 'interactive': false }, function(token) {"
" window.domAutomationController.send(token);"
"});",
&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(
IdentityManagerFactory::GetForProfile(app_profile)->HasPrimaryAccount());
// Terminate the app.
window->GetBaseWindow()->Close();
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(KioskEnterpriseTest, PrivateStore) {
set_test_app_id(kTestEnterpriseKioskApp);
const char kPrivateStoreUpdate[] = "/private_store_update";
net::EmbeddedTestServer private_server;
// |private_server| serves crx from test data dir.
base::FilePath test_data_dir;
base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
private_server.ServeFilesFromDirectory(test_data_dir);
ASSERT_TRUE(private_server.InitializeAndListen());
FakeCWS private_store;
private_store.InitAsPrivateStore(&private_server, kPrivateStoreUpdate);
private_store.SetUpdateCrx(kTestEnterpriseKioskApp,
std::string(kTestEnterpriseKioskApp) + ".crx",
"1.0.0");
private_server.StartAcceptingConnections();
// Configure kTestEnterpriseKioskApp in device policy.
ConfigureKioskAppInPolicy(kTestEnterpriseAccountId, kTestEnterpriseKioskApp,
private_server.GetURL(kPrivateStoreUpdate).spec());
// Meta should be able to be extracted from crx before launching.
KioskAppManager* manager = KioskAppManager::Get();
AppDataLoadWaiter waiter(manager, kTestEnterpriseKioskApp, std::string());
waiter.WaitForAppData();
PrepareAppLaunch();
EXPECT_TRUE(LaunchApp(kTestEnterpriseKioskApp, false));
WaitForAppLaunchWithOptions(false /* check_launch_data */,
true /* terminate_app */);
// Private store should serve crx and CWS should not.
DCHECK_GT(private_store.GetUpdateCheckCountAndReset(), 0);
DCHECK_EQ(0, fake_cws()->GetUpdateCheckCountAndReset());
EXPECT_EQ(extensions::Manifest::EXTERNAL_POLICY, GetInstalledAppLocation());
}
// A custom SoundsManagerTestImpl implements Initialize and Play only.
// The difference with audio::SoundsManagerImpl is AudioStreamHandler is
// only initialized upon Play is called, so the most recent AudioManager
// instance could be used, to make sure of using MockAudioManager to play
// bundled sounds.
// It's not a nested class under KioskVirtualKeyboardTest because forward
// declaration of a nested class is not possible.
// TODO(crbug.com/805319): remove this fake impl for test.
class KioskVirtualKeyboardTestSoundsManagerTestImpl
: public audio::SoundsManager {
public:
KioskVirtualKeyboardTestSoundsManagerTestImpl() {}
bool Initialize(SoundKey key, const base::StringPiece& data) override {
sound_data_[key] = data.as_string();
return true;
}
bool Play(SoundKey key) override {
auto iter = sound_data_.find(key);
if (iter == sound_data_.end()) {
LOG(WARNING) << "Playing non-existent key = " << key;
return false;
}
auto handler = std::make_unique<audio::AudioStreamHandler>(
content::ServiceManagerConnection::GetForProcess()
->GetConnector()
->Clone(),
iter->second);
if (!handler->IsInitialized()) {
LOG(WARNING) << "Can't initialize AudioStreamHandler for key = " << key;
return false;
}
return handler->Play();
}
bool Stop(SoundKey key) override {
NOTIMPLEMENTED();
return false;
}
base::TimeDelta GetDuration(SoundKey key) override {
NOTIMPLEMENTED();
return base::TimeDelta();
}
private:
std::map<SoundKey, std::string> sound_data_;
DISALLOW_COPY_AND_ASSIGN(KioskVirtualKeyboardTestSoundsManagerTestImpl);
};
// Specialized test fixture for testing kiosk mode where virtual keyboard is
// enabled.
class KioskVirtualKeyboardTest : public KioskTest,
public audio::FakeSystemInfo {
public:
KioskVirtualKeyboardTest() {
audio::FakeSystemInfo::OverrideGlobalBinderForAudioService(this);
}
~KioskVirtualKeyboardTest() override {
audio::FakeSystemInfo::ClearGlobalBinderForAudioService();
}
protected:
// KioskVirtualKeyboardTest overrides:
void SetUp() override {
audio::SoundsManager::InitializeForTesting(
new KioskVirtualKeyboardTestSoundsManagerTestImpl());
KioskTest::SetUp();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
KioskTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
extensions::switches::kWhitelistedExtensionID,
kTestVirtualKeyboardKioskApp);
command_line->AppendSwitch(keyboard::switches::kEnableVirtualKeyboard);
}
// audio::FakeSystemInfo override.
void HasInputDevices(HasInputDevicesCallback callback) override {
std::move(callback).Run(true);
}
private:
DISALLOW_COPY_AND_ASSIGN(KioskVirtualKeyboardTest);
};
// Verifies that chrome.virtualKeyboard.restrictFeatures and related private
// APIs work.
IN_PROC_BROWSER_TEST_F(KioskVirtualKeyboardTest, RestrictFeatures) {
set_test_app_id(kTestVirtualKeyboardKioskApp);
set_test_app_version("0.1");
set_test_crx_file(test_app_id() + ".crx");
extensions::ResultCatcher catcher;
StartAppLaunchFromLoginScreen(
NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
// Specialized test fixture for testing kiosk mode on the
// hidden WebUI initialization flow for slow hardware.
class KioskHiddenWebUITest : public KioskTest,
public ash::mojom::WallpaperObserver {
public:
KioskHiddenWebUITest() : wallpaper_loaded_(false), observer_binding_(this) {}
void SetUpOnMainThread() override {
LoginDisplayHostWebUI::DisableRestrictiveProxyCheckForTest();
KioskTest::SetUpOnMainThread();
ash::mojom::WallpaperObserverAssociatedPtrInfo ptr_info;
observer_binding_.Bind(mojo::MakeRequest(&ptr_info));
WallpaperControllerClient::Get()->AddObserver(std::move(ptr_info));
}
void TearDownOnMainThread() override {
KioskTest::TearDownOnMainThread();
}
void WaitForWallpaper() {
if (!wallpaper_loaded_) {
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
}
bool wallpaper_loaded() const { return wallpaper_loaded_; }
// ash::mojom::WallpaperObserver:
void OnWallpaperChanged(uint32_t image_id) override {
wallpaper_loaded_ = true;
if (runner_.get())
runner_->Quit();
}
void OnWallpaperColorsChanged(
const std::vector<SkColor>& prominent_colors) override {}
void OnWallpaperBlurChanged(bool blurred) override {}
bool wallpaper_loaded_;
scoped_refptr<content::MessageLoopRunner> runner_;
private:
// The binding this instance uses to implement ash::mojom::WallpaperObserver.
mojo::AssociatedBinding<ash::mojom::WallpaperObserver> observer_binding_;
DISALLOW_COPY_AND_ASSIGN(KioskHiddenWebUITest);
};
IN_PROC_BROWSER_TEST_F(KioskHiddenWebUITest, AutolaunchWarning) {
// Add a device owner.
FakeChromeUserManager* user_manager = new FakeChromeUserManager();
user_manager->AddUser(test_owner_account_id_);
user_manager::ScopedUserManager enabler(base::WrapUnique(user_manager));
// Set kiosk app to autolaunch.
EnableConsumerKioskMode();
WizardController::SkipPostLoginScreensForTesting();
WizardController* wizard_controller = WizardController::default_controller();
CHECK(wizard_controller);
// Start login screen after configuring auto launch app since the warning
// is triggered when switching to login screen.
wizard_controller->AdvanceToScreen(OobeScreen::SCREEN_OOBE_WELCOME);
ReloadAutolaunchKioskApps();
wizard_controller->SkipToLoginForTesting(LoginScreenContext());
EXPECT_FALSE(KioskAppManager::Get()->GetAutoLaunchApp().empty());
EXPECT_FALSE(KioskAppManager::Get()->IsAutoLaunchEnabled());
// Wait for the auto launch warning come up.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
content::NotificationService::AllSources())
.Wait();
// Wait for the wallpaper to load.
WaitForWallpaper();
EXPECT_TRUE(wallpaper_loaded());
}
} // namespace chromeos