Commit 6971ebbf authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Introduce ExtensionForceInstallMixin for tests

Create a test mixin ExtensionForceInstallMixin that helps in testing of
force-installed extensions.

In this initial version, only device policy faked via
DevicePolicyCrosTestHelper is supported; the extension has to be already
packed into a CRX file. The mixin hosts the CRX file in an embedded test
server, generates and hosts an update manifest XML and configures the
device policy.

Also partially migrate signin_profile_extensions_policy_browsertest.cc
to the new mixin.

Bug: 1090941
Change-Id: Ic2b82dc15d0bfcf18e68d267d78312ce2311789f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2277812Reviewed-by: default avatarOmar Morsi <omorsi@google.com>
Reviewed-by: default avatarAlexander Hendrich <hendrich@chromium.org>
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Cr-Commit-Position: refs/heads/master@{#785327}
parent 6d56e768
......@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/version.h"
......@@ -15,8 +16,10 @@
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/policy/extension_force_install_mixin.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/notification_details.h"
......@@ -54,8 +57,8 @@ namespace {
// * The manual testing app which is whitelisted for running in the sign-in
// profile:
const char kWhitelistedAppId[] = "bjaiihebfngildkcjkjckolinodhliff";
const char kWhitelistedAppUpdateManifestPath[] =
"/extensions/signin_screen_manual_test_app/crx/update_manifest.xml";
const char kWhitelistedAppCrxPath[] =
"extensions/signin_screen_manual_test_app/app_signed_by_webstore.crx";
// * A trivial test app which is NOT whitelisted for running in the sign-in
// profile:
const char kNotWhitelistedAppId[] = "mockapnacjbcdncmpkjngjalkhphojek";
......@@ -64,8 +67,9 @@ const char kNotWhitelistedUpdateManifestPath[] =
// * A trivial test extension which is whitelisted for running in the sign-in
// profile:
const char kWhitelistedExtensionId[] = "ngjobkbdodapjbbncmagbccommkggmnj";
const char kWhitelistedExtensionUpdateManifestPath[] =
"/extensions/signin_screen_manual_test_extension/update_manifest.xml";
const char kWhitelistedExtensionCrxPath[] =
"extensions/signin_screen_manual_test_extension/"
"extension_signed_by_webstore.crx";
// * A trivial test extension which is NOT whitelisted for running in the
// sign-in profile:
const char kNotWhitelistedExtensionId[] = "mockepjebcnmhmhcahfddgfcdgkdifnc";
......@@ -212,10 +216,25 @@ class SigninProfileExtensionsPolicyTest
SigninProfileExtensionsPolicyTest()
: SigninProfileExtensionsPolicyTestBase(version_info::Channel::STABLE) {}
void SetUpOnMainThread() override {
SigninProfileExtensionsPolicyTestBase::SetUpOnMainThread();
extension_force_install_mixin_.InitWithDevicePolicyCrosTestHelper(
GetInitialProfile(), policy_helper());
}
ExtensionForceInstallMixin extension_force_install_mixin_{&mixin_host_};
private:
DISALLOW_COPY_AND_ASSIGN(SigninProfileExtensionsPolicyTest);
};
base::FilePath GetTestDataDir() {
base::FilePath test_data_dir;
EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
return test_data_dir;
}
} // namespace
// Tests that a whitelisted app gets installed.
......@@ -226,8 +245,8 @@ IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest,
extensions::TestExtensionRegistryObserver registry_observer(
extensions::ExtensionRegistry::Get(profile), kWhitelistedAppId);
AddExtensionForForceInstallation(kWhitelistedAppId,
kWhitelistedAppUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedAppCrxPath)));
registry_observer.WaitForExtensionLoaded();
const extensions::Extension* extension =
......@@ -262,8 +281,8 @@ IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest,
extensions::TestExtensionRegistryObserver registry_observer(
extensions::ExtensionRegistry::Get(profile), kWhitelistedExtensionId);
AddExtensionForForceInstallation(kWhitelistedExtensionId,
kWhitelistedExtensionUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedExtensionCrxPath)));
registry_observer.WaitForExtensionLoaded();
const extensions::Extension* extension =
......@@ -302,8 +321,8 @@ IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest, BackgroundPage) {
EXPECT_FALSE(
chromeos::ProfileHelper::SigninProfileHasLoginScreenExtensions());
ExtensionBackgroundPageReadyObserver page_observer(kWhitelistedAppId);
AddExtensionForForceInstallation(kWhitelistedAppId,
kWhitelistedAppUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedAppCrxPath)));
page_observer.Wait();
EXPECT_TRUE(chromeos::ProfileHelper::SigninProfileHasLoginScreenExtensions());
}
......@@ -318,10 +337,10 @@ IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest,
extensions::TestExtensionRegistryObserver registry_observer2(
extensions::ExtensionRegistry::Get(profile), kWhitelistedExtensionId);
AddExtensionForForceInstallation(kWhitelistedAppId,
kWhitelistedAppUpdateManifestPath);
AddExtensionForForceInstallation(kWhitelistedExtensionId,
kWhitelistedExtensionUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedAppCrxPath)));
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedExtensionCrxPath)));
registry_observer1.WaitForExtensionLoaded();
registry_observer2.WaitForExtensionLoaded();
......@@ -337,10 +356,10 @@ IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest,
ExtensionBackgroundPageReadyObserver page_observer_for_extension(
kWhitelistedExtensionId);
AddExtensionForForceInstallation(kWhitelistedAppId,
kWhitelistedAppUpdateManifestPath);
AddExtensionForForceInstallation(kWhitelistedExtensionId,
kWhitelistedExtensionUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedAppCrxPath)));
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedExtensionCrxPath)));
page_observer_for_app.Wait();
page_observer_for_extension.Wait();
......@@ -376,8 +395,8 @@ class SigninProfileExtensionsPolicyOfflineLaunchTest
extensions::ExtensionRegistry::Get(GetInitialProfile()),
kWhitelistedAppId);
AddExtensionForForceInstallation(kWhitelistedAppId,
kWhitelistedAppUpdateManifestPath);
EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
GetTestDataDir().AppendASCII(kWhitelistedAppCrxPath)));
// In the non-PRE test, this simulates inability to make network requests
// for fetching the extension update manifest and CRX files. In the PRE test
......
This diff is collapsed.
// Copyright 2020 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.
#ifndef CHROME_BROWSER_POLICY_EXTENSION_FORCE_INSTALL_MIXIN_H_
#define CHROME_BROWSER_POLICY_EXTENSION_FORCE_INSTALL_MIXIN_H_
#include "base/files/scoped_temp_dir.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "extensions/common/extension_id.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
class GURL;
class Profile;
namespace base {
class FilePath;
class Version;
} // namespace base
#if defined(OS_CHROMEOS)
namespace policy {
class DevicePolicyCrosTestHelper;
} // namespace policy
#endif // OS_CHROMEOS
// A mixin that allows to force-install an extension/app via the device policy.
//
// Encapsulates the following operations:
// * generating an update manifest,
// * hosting the update manifest and the CRX via an embedded test server,
// * configuring the force installation in the device policy.
//
// Example usage (for force-installing into the sign-in profile using the device
// policy):
//
// class MyTestFixture : ... {
// protected:
// void SetUpOnMainThread() override {
// ...
// force_install_mixin_.InitWithDevicePolicyCrosTestHelper(...);
// }
// void ForceInstall() {
// EXPECT_TRUE(force_install_mixin_.ForceInstallFromCrx(...));
// }
// ExtensionForceInstallMixin force_install_mixin_{&mixin_host_};
// };
//
// TODO(crbug.com/1090941): Add user policy, CRX packing, awaiting, auto update.
class ExtensionForceInstallMixin final : public InProcessBrowserTestMixin {
public:
explicit ExtensionForceInstallMixin(InProcessBrowserTestMixinHost* host);
ExtensionForceInstallMixin(const ExtensionForceInstallMixin&) = delete;
ExtensionForceInstallMixin& operator=(const ExtensionForceInstallMixin&) =
delete;
~ExtensionForceInstallMixin() override;
// Use one of the Init*() methods to initialize the object before calling any
// other method:
#if defined(OS_CHROMEOS)
void InitWithDevicePolicyCrosTestHelper(
Profile* profile,
policy::DevicePolicyCrosTestHelper* device_policy_cros_test_helper);
#endif // OS_CHROMEOS
// Force-installs the CRX file |crx_path|; under the hood, generates an update
// manifest and serves it and the CRX file by the embedded test server.
// |extension_id| - if non-null, will be set to the installed extension ID.
bool ForceInstallFromCrx(const base::FilePath& crx_path,
extensions::ExtensionId* extension_id = nullptr);
// InProcessBrowserTestMixin:
void SetUpOnMainThread() override;
private:
// Returns the directory whose contents are served by the embedded test
// server.
base::FilePath GetServedDirPath() const;
// Returns the URL of the update manifest pointing to the embedded test
// server.
GURL GetServedUpdateManifestUrl(
const extensions::ExtensionId& extension_id) const;
// Returns the URL of the CRX file pointing to the embedded test server.
GURL GetServedCrxUrl(const extensions::ExtensionId& extension_id,
const base::Version& extension_version) const;
// Makes the given |source_crx_path| file served by the embedded test server.
bool ServeExistingCrx(const base::FilePath& source_crx_path,
const extensions::ExtensionId& extension_id,
const base::Version& extension_version);
// Creates an update manifest with the CRX URL pointing to the embedded test
// server.
bool CreateAndServeUpdateManifestFile(
const extensions::ExtensionId& extension_id,
const base::Version& extension_version);
// Sets the policy to force-install the given extension from the given update
// manifest URL.
bool UpdatePolicy(const extensions::ExtensionId& extension_id,
const GURL& update_manifest_url);
base::ScopedTempDir temp_dir_;
net::EmbeddedTestServer embedded_test_server_;
Profile* profile_ = nullptr;
#if defined(OS_CHROMEOS)
policy::DevicePolicyCrosTestHelper* device_policy_cros_test_helper_ = nullptr;
#endif
};
#endif // CHROME_BROWSER_POLICY_EXTENSION_FORCE_INSTALL_MIXIN_H_
......@@ -1847,6 +1847,8 @@ if (!is_android) {
"../browser/extensions/window_open_apitest.cc",
"../browser/extensions/worker_apitest.cc",
"../browser/notifications/notification_permission_context_apitest.cc",
"../browser/policy/extension_force_install_mixin.cc",
"../browser/policy/extension_force_install_mixin.h",
"../browser/policy/extension_policy_browsertest.cc",
"../browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc",
"../browser/safe_browsing/chrome_cleaner/chrome_cleaner_reboot_dialog_controller_impl_browsertest_win.cc",
......
......@@ -2,8 +2,8 @@ This app is primarily intended to be used for the manual testing of the apps on
the Chrome OS sign-in screen. The sources are located under the ./app/
directory.
The ./crx/app_signed_by_webstore.crx package must be a file signed by WebStore,
in order for the app to have the expected ID which is whitelisted in Chrome -
The ./app_signed_by_webstore.crx package must be a file signed by WebStore, in
order for the app to have the expected ID which is whitelisted in Chrome -
"bjaiihebfngildkcjkjckolinodhliff".
In case a new version of the test app has to be published on WebStore, please
......
<?xml version='1.0' encoding='UTF-8'?>
<!--
This update manifest points to the ./app_signed_by_webstore.crx file.
"mock.http" is a placeholder that gets substituted with the test server
address in runtime.
-->
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='bjaiihebfngildkcjkjckolinodhliff'>
<updatecheck
codebase='http://mock.http/extensions/signin_screen_manual_test_app/crx/app_signed_by_webstore.crx'
version='4.0' />
</app>
</gupdate>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment