Commit 02f9f701 authored by Alan Cutter's avatar Alan Cutter Committed by Commit Bot

Refactor ExternalWebAppManager config loading flow

This CL splits ExternalWebAppManager's config loading flow into discrete
steps and removes the various testing entry points that omit or
duplicate logic used by the real thing.

Tests can now inject data (file_utils, config_dir, configs) into the
config loading pipeline instead of having separate mini pipelines just
for them.

This change is in preparation for adding a new "FilterExtensionIds" step
to the config loading flow. Without this refactor there would be
duplication of logic between real and test code code paths that would be
prone to bitrot and missing real coverage.

Bug: 1128801
Change-Id: Ie5e87b26ab47782fab6589a4127df3ea5e876fec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2423823Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarGlen Robertson <glenrob@chromium.org>
Commit-Queue: Alan Cutter <alancutter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810025}
parent 210f1b4a
...@@ -53,29 +53,27 @@ const base::FilePath::CharType kWebAppsSubDirectory[] = ...@@ -53,29 +53,27 @@ const base::FilePath::CharType kWebAppsSubDirectory[] =
#endif #endif
bool g_skip_startup_for_testing_ = false; bool g_skip_startup_for_testing_ = false;
const base::FilePath* g_config_dir_for_testing = nullptr;
const std::vector<base::Value>* g_configs_for_testing = nullptr;
const FileUtilsWrapper* g_file_utils_for_testing = nullptr;
std::vector<ExternalInstallOptions> LoadInstallOptionsBlocking( struct LoadedConfig {
std::unique_ptr<FileUtilsWrapper> file_utils, base::Value contents;
const base::FilePath& dir, base::FilePath file;
const std::string& user_type) { };
std::vector<ExternalInstallOptions> install_options_list;
if (!base::FeatureList::IsEnabled(features::kDefaultWebAppInstallation))
return install_options_list;
int disabled_count = 0; struct LoadedConfigs {
std::vector<LoadedConfig> configs;
int error_count = 0; int error_count = 0;
};
// Load hard coded apps. LoadedConfigs LoadConfigsBlocking(const base::FilePath& config_dir) {
PreinstalledWebApps preinstalled_web_apps = GetPreinstalledWebApps();
for (ExternalInstallOptions& options : preinstalled_web_apps.options)
install_options_list.push_back(std::move(options));
disabled_count += preinstalled_web_apps.disabled_count;
// Load JSON config apps.
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK); base::BlockingType::MAY_BLOCK);
LoadedConfigs result;
base::FilePath::StringType extension(FILE_PATH_LITERAL(".json")); base::FilePath::StringType extension(FILE_PATH_LITERAL(".json"));
base::FileEnumerator json_files(dir, base::FileEnumerator json_files(config_dir,
false, // Recursive. false, // Recursive.
base::FileEnumerator::FILES); base::FileEnumerator::FILES);
for (base::FilePath file = json_files.Next(); !file.empty(); for (base::FilePath file = json_files.Next(); !file.empty();
...@@ -90,91 +88,49 @@ std::vector<ExternalInstallOptions> LoadInstallOptionsBlocking( ...@@ -90,91 +88,49 @@ std::vector<ExternalInstallOptions> LoadInstallOptionsBlocking(
deserializer.Deserialize(nullptr, &error_msg); deserializer.Deserialize(nullptr, &error_msg);
if (!app_config) { if (!app_config) {
LOG(ERROR) << file.value() << " was not valid JSON: " << error_msg; LOG(ERROR) << file.value() << " was not valid JSON: " << error_msg;
++error_count; ++result.error_count;
continue; continue;
} }
result.configs.push_back(
{.contents = std::move(*app_config), .file = file});
}
return result;
}
ExternalConfigParseResult result = struct ParsedConfigs {
ParseConfig(*file_utils, dir, file, user_type, *app_config); std::vector<ExternalInstallOptions> options_list;
switch (result.type) { int disabled_count = 0;
int error_count = 0;
};
ParsedConfigs ParseConfigsBlocking(const base::FilePath& config_dir,
const std::string& user_type,
LoadedConfigs loaded_configs) {
ParsedConfigs result;
result.error_count = loaded_configs.error_count;
auto file_utils = g_file_utils_for_testing
? g_file_utils_for_testing->Clone()
: std::make_unique<FileUtilsWrapper>();
for (const LoadedConfig& loaded_config : loaded_configs.configs) {
ExternalConfigParseResult parse_result =
ParseConfig(*file_utils, config_dir, loaded_config.file, user_type,
loaded_config.contents);
switch (parse_result.type) {
case ExternalConfigParseResult::kEnabled: case ExternalConfigParseResult::kEnabled:
install_options_list.push_back(std::move(result.options.value())); result.options_list.push_back(std::move(parse_result.options.value()));
break; break;
case ExternalConfigParseResult::kDisabled: case ExternalConfigParseResult::kDisabled:
++disabled_count; ++result.disabled_count;
break; break;
case ExternalConfigParseResult::kError: case ExternalConfigParseResult::kError:
++error_count; ++result.error_count;
break; break;
} }
} }
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramEnabledCount, return result;
install_options_list.size());
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramDisabledCount,
disabled_count);
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramConfigErrorCount,
error_count);
return install_options_list;
}
base::FilePath DetermineLoadDir(const Profile* profile) {
base::FilePath dir;
#if defined(OS_CHROMEOS)
// As of mid 2018, only Chrome OS has default/external web apps, and
// chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS is only defined for OS_LINUX,
// which includes OS_CHROMEOS.
if (chromeos::ProfileHelper::IsPrimaryProfile(profile)) {
// For manual testing, you can change s/STANDALONE/USER/, as writing to
// "$HOME/.config/chromium/test-user/.config/chromium/External
// Extensions/web_apps" does not require root ACLs, unlike
// "/usr/share/chromium/extensions/web_apps".
if (!base::PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
&dir)) {
LOG(ERROR) << "ExternalWebAppManager::LoadInstallOptions: "
"base::PathService::Get failed";
} else {
dir = dir.Append(kWebAppsSubDirectory);
}
}
#endif
return dir;
}
void OnExternalWebAppsSynchronized(
std::map<GURL, InstallResultCode> install_results,
std::map<GURL, bool> uninstall_results) {
RecordExternalAppInstallResultCode("Webapp.InstallResult.Default",
install_results);
}
std::vector<ExternalInstallOptions> SynchronizeAppsBlockingForTesting(
std::unique_ptr<FileUtilsWrapper> file_utils,
std::vector<std::string> app_configs,
const std::string& user_type) {
std::vector<ExternalInstallOptions> install_options_list;
for (const std::string& app_config_string : app_configs) {
base::Optional<base::Value> app_config =
base::JSONReader::Read(app_config_string);
DCHECK(app_config);
ExternalConfigParseResult result =
ParseConfig(*file_utils, base::FilePath(FILE_PATH_LITERAL("test_dir")),
base::FilePath(FILE_PATH_LITERAL("test_dir/test.json")),
user_type, *app_config);
if (result.type == ExternalConfigParseResult::kEnabled)
install_options_list.push_back(std::move(*result.options));
}
// TODO(crbug.com/1128801): Dedupe this with LoadInstallOptionsBlocking().
for (ExternalInstallOptions& options : GetPreinstalledWebApps().options)
install_options_list.push_back(std::move(options));
return install_options_list;
} }
} // namespace } // namespace
...@@ -186,6 +142,25 @@ const char* ExternalWebAppManager::kHistogramDisabledCount = ...@@ -186,6 +142,25 @@ const char* ExternalWebAppManager::kHistogramDisabledCount =
const char* ExternalWebAppManager::kHistogramConfigErrorCount = const char* ExternalWebAppManager::kHistogramConfigErrorCount =
"WebApp.Preinstalled.ConfigErrorCount"; "WebApp.Preinstalled.ConfigErrorCount";
void ExternalWebAppManager::SkipStartupForTesting() {
g_skip_startup_for_testing_ = true;
}
void ExternalWebAppManager::SetConfigDirForTesting(
const base::FilePath* config_dir) {
g_config_dir_for_testing = config_dir;
}
void ExternalWebAppManager::SetConfigsForTesting(
const std::vector<base::Value>* configs) {
g_configs_for_testing = configs;
}
void ExternalWebAppManager::SetFileUtilsForTesting(
const FileUtilsWrapper* file_utils) {
g_file_utils_for_testing = file_utils;
}
ExternalWebAppManager::ExternalWebAppManager(Profile* profile) ExternalWebAppManager::ExternalWebAppManager(Profile* profile)
: profile_(profile) {} : profile_(profile) {}
...@@ -197,71 +172,135 @@ void ExternalWebAppManager::SetSubsystems( ...@@ -197,71 +172,135 @@ void ExternalWebAppManager::SetSubsystems(
} }
void ExternalWebAppManager::Start() { void ExternalWebAppManager::Start() {
if (!g_skip_startup_for_testing_) { if (!g_skip_startup_for_testing_)
LoadInstallOptions(base::BindOnce( LoadAndSynchronize({});
&ExternalWebAppManager::SynchronizeExternalInstallOptions, }
weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&OnExternalWebAppsSynchronized))); void ExternalWebAppManager::LoadForTesting(ConsumeInstallOptions callback) {
} Load(std::move(callback));
} }
// static void ExternalWebAppManager::LoadAndSynchronizeForTesting(
std::vector<ExternalInstallOptions> SynchronizeCallback callback) {
ExternalWebAppManager::ReloadInstallOptionsForTesting( LoadAndSynchronize(std::move(callback));
std::unique_ptr<FileUtilsWrapper> file_utils,
const base::FilePath& dir,
Profile* profile) {
return LoadInstallOptionsBlocking(std::move(file_utils), dir,
apps::DetermineUserType(profile));
} }
void ExternalWebAppManager::LoadInstallOptions(LoadCallback callback) { void ExternalWebAppManager::LoadAndSynchronize(SynchronizeCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Load(base::BindOnce(&ExternalWebAppManager::Synchronize,
// Do a two-part callback dance, across different TaskRunners. weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
// }
// 1. Schedule LoadInstallOptionsBlocking to happen on a background thread, so
// that we don't block the UI thread. When that's done, void ExternalWebAppManager::Load(ConsumeInstallOptions callback) {
// base::PostTaskAndReplyWithResult will bounce us back to the originating if (!base::FeatureList::IsEnabled(features::kDefaultWebAppInstallation)) {
// thread (the UI thread). std::move(callback).Run({});
// return;
// 2. In |callback|, forward the vector of ExternalInstallOptions on to the }
// pending_app_manager_, which can only be called on the UI thread.
LoadConfigs(base::BindOnce(
&ExternalWebAppManager::ParseConfigs, weak_ptr_factory_.GetWeakPtr(),
base::BindOnce(&ExternalWebAppManager::PostProcessConfigs,
weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
void ExternalWebAppManager::LoadConfigs(ConsumeLoadedConfigs callback) {
if (g_configs_for_testing) {
LoadedConfigs loaded_configs;
for (const base::Value& config : *g_configs_for_testing) {
loaded_configs.configs.push_back(
{.contents = config.Clone(),
.file = base::FilePath(FILE_PATH_LITERAL("test.json"))});
}
std::move(callback).Run(std::move(loaded_configs));
return;
}
base::ThreadPool::PostTaskAndReplyWithResult( base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT, {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce( base::BindOnce(&LoadConfigsBlocking, GetConfigDir()),
&LoadInstallOptionsBlocking, std::make_unique<FileUtilsWrapper>(),
DetermineLoadDir(profile_), apps::DetermineUserType(profile_)),
std::move(callback)); std::move(callback));
} }
void ExternalWebAppManager::SkipStartupForTesting() { void ExternalWebAppManager::ParseConfigs(ConsumeParsedConfigs callback,
g_skip_startup_for_testing_ = true; LoadedConfigs loaded_configs) {
}
void ExternalWebAppManager::SynchronizeAppsForTesting(
std::unique_ptr<FileUtilsWrapper> file_utils,
std::vector<std::string> app_configs,
PendingAppManager::SynchronizeCallback callback) {
base::ThreadPool::PostTaskAndReplyWithResult( base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT, {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
base::BindOnce(&SynchronizeAppsBlockingForTesting, std::move(file_utils), base::BindOnce(&ParseConfigsBlocking, GetConfigDir(),
std::move(app_configs), apps::DetermineUserType(profile_)), apps::DetermineUserType(profile_),
base::BindOnce(&ExternalWebAppManager::SynchronizeExternalInstallOptions, std::move(loaded_configs)),
weak_ptr_factory_.GetWeakPtr(), std::move(callback))); std::move(callback));
}
void ExternalWebAppManager::PostProcessConfigs(ConsumeInstallOptions callback,
ParsedConfigs parsed_configs) {
PreinstalledWebApps preinstalled_web_apps = GetPreinstalledWebApps();
for (ExternalInstallOptions& options : preinstalled_web_apps.options)
parsed_configs.options_list.push_back(std::move(options));
parsed_configs.disabled_count += preinstalled_web_apps.disabled_count;
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramEnabledCount,
parsed_configs.options_list.size());
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramDisabledCount,
parsed_configs.disabled_count);
base::UmaHistogramCounts100(ExternalWebAppManager::kHistogramConfigErrorCount,
parsed_configs.error_count);
std::move(callback).Run(std::move(parsed_configs.options_list));
} }
void ExternalWebAppManager::SynchronizeExternalInstallOptions( void ExternalWebAppManager::Synchronize(
PendingAppManager::SynchronizeCallback callback, PendingAppManager::SynchronizeCallback callback,
std::vector<ExternalInstallOptions> desired_apps_install_options) { std::vector<ExternalInstallOptions> desired_apps_install_options) {
DCHECK(pending_app_manager_); DCHECK(pending_app_manager_);
pending_app_manager_->SynchronizeInstalledApps( pending_app_manager_->SynchronizeInstalledApps(
std::move(desired_apps_install_options), std::move(desired_apps_install_options),
ExternalInstallSource::kExternalDefault, std::move(callback)); ExternalInstallSource::kExternalDefault,
base::BindOnce(&ExternalWebAppManager::OnExternalWebAppsSynchronized,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void ExternalWebAppManager::OnExternalWebAppsSynchronized(
PendingAppManager::SynchronizeCallback callback,
std::map<GURL, InstallResultCode> install_results,
std::map<GURL, bool> uninstall_results) {
RecordExternalAppInstallResultCode("Webapp.InstallResult.Default",
install_results);
if (callback) {
std::move(callback).Run(std::move(install_results),
std::move(uninstall_results));
}
}
base::FilePath ExternalWebAppManager::GetConfigDir() {
base::FilePath dir;
#if defined(OS_CHROMEOS)
// As of mid 2018, only Chrome OS has default/external web apps, and
// chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS is only defined for OS_LINUX,
// which includes OS_CHROMEOS.
if (chromeos::ProfileHelper::IsPrimaryProfile(profile_)) {
if (g_config_dir_for_testing) {
dir = *g_config_dir_for_testing;
} else {
// For manual testing, you can change s/STANDALONE/USER/, as writing to
// "$HOME/.config/chromium/test-user/.config/chromium/External
// Extensions/web_apps" does not require root ACLs, unlike
// "/usr/share/chromium/extensions/web_apps".
if (!base::PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
&dir)) {
LOG(ERROR) << "base::PathService::Get failed";
} else {
dir = dir.Append(kWebAppsSubDirectory);
}
}
}
#endif
return dir;
} }
} // namespace web_app } // namespace web_app
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "chrome/browser/web_applications/components/external_install_options.h" #include "chrome/browser/web_applications/components/external_install_options.h"
#include "chrome/browser/web_applications/components/pending_app_manager.h" #include "chrome/browser/web_applications/components/pending_app_manager.h"
#include "chrome/browser/web_applications/file_utils_wrapper.h" #include "chrome/browser/web_applications/file_utils_wrapper.h"
...@@ -22,47 +23,65 @@ class Profile; ...@@ -22,47 +23,65 @@ class Profile;
namespace web_app { namespace web_app {
namespace {
struct LoadedConfigs;
struct ParsedConfigs;
} // namespace
class PendingAppManager; class PendingAppManager;
// Installs web apps to be preinstalled on the device (AKA default apps) during
// start up. Will keep the apps installed on the device in sync with the set of
// apps configured for preinstall, adding or removing as necessary. Works very
// similar to WebAppPolicyManager.
class ExternalWebAppManager { class ExternalWebAppManager {
public: public:
using ConsumeLoadedConfigs = base::OnceCallback<void(LoadedConfigs)>;
using ConsumeParsedConfigs = base::OnceCallback<void(ParsedConfigs)>;
using ConsumeInstallOptions =
base::OnceCallback<void(std::vector<ExternalInstallOptions>)>;
using SynchronizeCallback = PendingAppManager::SynchronizeCallback;
static const char* kHistogramEnabledCount; static const char* kHistogramEnabledCount;
static const char* kHistogramDisabledCount; static const char* kHistogramDisabledCount;
static const char* kHistogramConfigErrorCount; static const char* kHistogramConfigErrorCount;
static void SkipStartupForTesting();
static void SetConfigDirForTesting(const base::FilePath* config_dir);
static void SetConfigsForTesting(const std::vector<base::Value>* configs);
static void SetFileUtilsForTesting(const FileUtilsWrapper* file_utils);
explicit ExternalWebAppManager(Profile* profile); explicit ExternalWebAppManager(Profile* profile);
~ExternalWebAppManager(); ~ExternalWebAppManager();
void SetSubsystems(PendingAppManager* pending_app_manager); void SetSubsystems(PendingAppManager* pending_app_manager);
// Loads the preinstalled app configs and synchronizes them with the device's
// installed apps.
void Start(); void Start();
// Scans the given directory (non-recursively) for *.json files that define void LoadAndSynchronizeForTesting(SynchronizeCallback callback);
// "external web apps", the Web App analogs of "external extensions",
// described at https://developer.chrome.com/apps/external_extensions
//
// This function performs file I/O, and must not be scheduled on UI threads.
static std::vector<ExternalInstallOptions> ReloadInstallOptionsForTesting(
std::unique_ptr<FileUtilsWrapper> file_utils,
const base::FilePath& dir,
Profile* profile);
using LoadCallback =
base::OnceCallback<void(std::vector<ExternalInstallOptions>)>;
void LoadInstallOptions(LoadCallback callback); void LoadForTesting(ConsumeInstallOptions callback);
static void SkipStartupForTesting(); private:
void LoadAndSynchronize(SynchronizeCallback callback);
void SynchronizeAppsForTesting( void Load(ConsumeInstallOptions callback);
std::unique_ptr<FileUtilsWrapper> file_utils, void LoadConfigs(ConsumeLoadedConfigs callback);
std::vector<std::string> app_configs, void ParseConfigs(ConsumeParsedConfigs callback,
PendingAppManager::SynchronizeCallback callback); LoadedConfigs loaded_configs);
void PostProcessConfigs(ConsumeInstallOptions callback,
ParsedConfigs parsed_configs);
private: void Synchronize(SynchronizeCallback callback,
void SynchronizeExternalInstallOptions(
PendingAppManager::SynchronizeCallback callback,
std::vector<ExternalInstallOptions>); std::vector<ExternalInstallOptions>);
void OnExternalWebAppsSynchronized(
PendingAppManager::SynchronizeCallback callback,
std::map<GURL, InstallResultCode> install_results,
std::map<GURL, bool> uninstall_results);
base::FilePath GetConfigDir();
PendingAppManager* pending_app_manager_ = nullptr; PendingAppManager* pending_app_manager_ = nullptr;
Profile* const profile_; Profile* const profile_;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "chrome/browser/web_applications/external_web_app_manager.h" #include "chrome/browser/web_applications/external_web_app_manager.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
...@@ -41,34 +42,48 @@ class ExternalWebAppManagerBrowserTest ...@@ -41,34 +42,48 @@ class ExternalWebAppManagerBrowserTest
// Mocks "icon.png" as available in the config's directory. // Mocks "icon.png" as available in the config's directory.
InstallResultCode SyncDefaultAppConfig(const GURL& install_url, InstallResultCode SyncDefaultAppConfig(const GURL& install_url,
std::string app_config_string) { std::string app_config_string) {
base::FilePath test_config_dir(FILE_PATH_LITERAL("test_dir"));
ExternalWebAppManager::SetConfigDirForTesting(&test_config_dir);
base::FilePath source_root_dir; base::FilePath source_root_dir;
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir)); CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir));
base::FilePath test_icon_path = base::FilePath test_icon_path =
source_root_dir.Append(GetChromeTestDataDir()) source_root_dir.Append(GetChromeTestDataDir())
.AppendASCII("web_apps/blue-192.png"); .AppendASCII("web_apps/blue-192.png");
TestFileUtils file_utils(
{{base::FilePath(FILE_PATH_LITERAL("test_dir/icon.png")),
test_icon_path}});
ExternalWebAppManager::SetFileUtilsForTesting(&file_utils);
std::vector<base::Value> app_configs;
app_configs.push_back(*base::JSONReader::Read(app_config_string));
ExternalWebAppManager::SetConfigsForTesting(&app_configs);
base::Optional<InstallResultCode> code; base::Optional<InstallResultCode> code;
base::RunLoop sync_run_loop; base::RunLoop sync_run_loop;
WebAppProvider::Get(browser()->profile()) WebAppProvider::Get(browser()->profile())
->external_web_app_manager_for_testing() ->external_web_app_manager_for_testing()
.SynchronizeAppsForTesting( .LoadAndSynchronizeForTesting(base::BindLambdaForTesting(
TestFileUtils::Create(
{{base::FilePath(FILE_PATH_LITERAL("test_dir/icon.png")),
test_icon_path}}),
{app_config_string},
base::BindLambdaForTesting(
[&](std::map<GURL, InstallResultCode> install_results, [&](std::map<GURL, InstallResultCode> install_results,
std::map<GURL, bool> uninstall_results) { std::map<GURL, bool> uninstall_results) {
code = install_results.at(install_url); code = install_results.at(install_url);
sync_run_loop.Quit(); sync_run_loop.Quit();
})); }));
sync_run_loop.Run(); sync_run_loop.Run();
ExternalWebAppManager::SetConfigDirForTesting(nullptr);
ExternalWebAppManager::SetFileUtilsForTesting(nullptr);
ExternalWebAppManager::SetConfigsForTesting(nullptr);
return *code; return *code;
} }
~ExternalWebAppManagerBrowserTest() override = default; ~ExternalWebAppManagerBrowserTest() override = default;
}; };
// This JSON config functionality is only available on Chrome OS.
#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) { IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
Profile* profile = browser()->profile(); Profile* profile = browser()->profile();
...@@ -102,10 +117,6 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) { ...@@ -102,10 +117,6 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
EXPECT_EQ(app, uninstalled_app.get()); EXPECT_EQ(app, uninstalled_app.get());
} }
// TODO(crbug.com/1119710): Loading icon.png fails on Windows.
// This JSON config functionality is only used on Chrome OS.
#if !defined(OS_WIN)
// Check that offline fallback installs work offline. // Check that offline fallback installs work offline.
IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
OfflineFallbackManifestSiteOffline) { OfflineFallbackManifestSiteOffline) {
...@@ -286,6 +297,6 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, ...@@ -286,6 +297,6 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
SK_ColorBLUE); SK_ColorBLUE);
} }
#endif // !defined(OS_WIN) #endif // defined(OS_CHROMEOS)
} // namespace web_app } // namespace web_app
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/test/bind_test_util.h"
#include "base/test/metrics/histogram_tester.h" #include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/test/scoped_path_override.h" #include "base/test/scoped_path_override.h"
...@@ -39,11 +40,10 @@ namespace web_app { ...@@ -39,11 +40,10 @@ namespace web_app {
namespace { namespace {
constexpr char kGoodJsonTestDir[] = "good_json";
constexpr char kWebAppDefaultApps[] = "web_app_default_apps";
constexpr char kUserTypesTestDir[] = "user_types"; constexpr char kUserTypesTestDir[] = "user_types";
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
constexpr char kGoodJsonTestDir[] = "good_json";
constexpr char kAppAllUrl[] = "https://www.google.com/all"; constexpr char kAppAllUrl[] = "https://www.google.com/all";
constexpr char kAppChildUrl[] = "https://www.google.com/child"; constexpr char kAppChildUrl[] = "https://www.google.com/child";
constexpr char kAppGuestUrl[] = "https://www.google.com/guest"; constexpr char kAppGuestUrl[] = "https://www.google.com/guest";
...@@ -52,20 +52,6 @@ constexpr char kAppSupervisedUrl[] = "https://www.google.com/supervised"; ...@@ -52,20 +52,6 @@ constexpr char kAppSupervisedUrl[] = "https://www.google.com/supervised";
constexpr char kAppUnmanagedUrl[] = "https://www.google.com/unmanaged"; constexpr char kAppUnmanagedUrl[] = "https://www.google.com/unmanaged";
#endif #endif
// Returns the chrome/test/data/web_app_default_apps/sub_dir directory that
// holds the *.json data files from which ScanDirForExternalWebAppsForTesting
// should extract URLs from.
static base::FilePath GetTestDir(const std::string& sub_dir) {
base::FilePath dir;
if (!base::PathService::Get(chrome::DIR_TEST_DATA, &dir)) {
ADD_FAILURE()
<< "base::PathService::Get could not resolve chrome::DIR_TEST_DATA";
}
return dir.AppendASCII(kWebAppDefaultApps).AppendASCII(sub_dir);
}
using InstallOptionsList = std::vector<ExternalInstallOptions>;
} // namespace } // namespace
class ExternalWebAppManagerTest : public testing::Test { class ExternalWebAppManagerTest : public testing::Test {
...@@ -90,35 +76,44 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -90,35 +76,44 @@ class ExternalWebAppManagerTest : public testing::Test {
} }
protected: protected:
// Helper that makes blocking call to std::vector<ExternalInstallOptions> LoadApps(const char* test_dir,
// |ExternalWebAppManager::LoadInstallOptions| and returns read app infos. Profile* profile = nullptr) {
static InstallOptionsList LoadApps(Profile* profile, std::unique_ptr<TestingProfile> testing_profile;
const base::FilePath& test_dir) { if (!profile) {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
base::ScopedPathOverride path_override( testing_profile = CreateProfileAndLogin();
chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS, test_dir); profile = testing_profile.get();
#else
NOTREACHED();
#endif #endif
}
// Uses the chrome/test/data/web_app_default_apps/test_dir directory that
// holds the *.json data files from which tests should parse as app configs.
base::FilePath config_dir;
if (!base::PathService::Get(chrome::DIR_TEST_DATA, &config_dir)) {
ADD_FAILURE()
<< "base::PathService::Get could not resolve chrome::DIR_TEST_DATA";
}
config_dir =
config_dir.AppendASCII("web_app_default_apps").AppendASCII(test_dir);
ExternalWebAppManager::SetConfigDirForTesting(&config_dir);
auto external_web_app_manager = auto external_web_app_manager =
std::make_unique<ExternalWebAppManager>(profile); std::make_unique<ExternalWebAppManager>(profile);
InstallOptionsList result; std::vector<ExternalInstallOptions> result;
base::RunLoop run_loop; base::RunLoop run_loop;
external_web_app_manager->LoadInstallOptions(base::BindOnce( external_web_app_manager->LoadForTesting(base::BindLambdaForTesting(
[](base::RunLoop* run_loop, InstallOptionsList* result, [&](std::vector<ExternalInstallOptions> install_options_list) {
InstallOptionsList install_options_list) { result = install_options_list;
*result = install_options_list; run_loop.Quit();
run_loop->Quit(); }));
},
&run_loop, &result));
run_loop.Run(); run_loop.Run();
return result;
}
std::vector<ExternalInstallOptions> ReloadInstallOptions( ExternalWebAppManager::SetConfigDirForTesting(nullptr);
const std::string& dir) {
return ExternalWebAppManager::ReloadInstallOptionsForTesting( return result;
std::make_unique<FileUtilsWrapper>(), GetTestDir(dir),
CreateProfile().get());
} }
// Helper that creates simple test profile. // Helper that creates simple test profile.
...@@ -127,6 +122,7 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -127,6 +122,7 @@ class ExternalWebAppManagerTest : public testing::Test {
return profile_builder.Build(); return profile_builder.Build();
} }
#if defined(OS_CHROMEOS)
// Helper that creates simple test guest profile. // Helper that creates simple test guest profile.
std::unique_ptr<TestingProfile> CreateGuestProfile() { std::unique_ptr<TestingProfile> CreateGuestProfile() {
TestingProfile::Builder profile_builder; TestingProfile::Builder profile_builder;
...@@ -134,7 +130,6 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -134,7 +130,6 @@ class ExternalWebAppManagerTest : public testing::Test {
return profile_builder.Build(); return profile_builder.Build();
} }
#if defined(OS_CHROMEOS)
// Helper that creates simple test profile and logs it into user manager. // Helper that creates simple test profile and logs it into user manager.
// This makes profile appears as a primary profile in ChromeOS. // This makes profile appears as a primary profile in ChromeOS.
std::unique_ptr<TestingProfile> CreateProfileAndLogin() { std::unique_ptr<TestingProfile> CreateProfileAndLogin() {
...@@ -156,8 +151,7 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -156,8 +151,7 @@ class ExternalWebAppManagerTest : public testing::Test {
} }
void VerifySetOfApps(Profile* profile, const std::set<GURL>& expectations) { void VerifySetOfApps(Profile* profile, const std::set<GURL>& expectations) {
const auto install_options_list = const auto install_options_list = LoadApps(kUserTypesTestDir, profile);
LoadApps(profile, GetTestDir(kUserTypesTestDir));
ASSERT_EQ(expectations.size(), install_options_list.size()); ASSERT_EQ(expectations.size(), install_options_list.size());
for (const auto& install_options : install_options_list) for (const auto& install_options : install_options_list)
ASSERT_EQ(1u, expectations.count(install_options.install_url)); ASSERT_EQ(1u, expectations.count(install_options.install_url));
...@@ -182,7 +176,7 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -182,7 +176,7 @@ class ExternalWebAppManagerTest : public testing::Test {
user_manager::UserManager::Get()); user_manager::UserManager::Get());
} }
// To supprot primary/non-primary users. // To support primary/non-primary users.
std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_; std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
#endif #endif
...@@ -192,8 +186,10 @@ class ExternalWebAppManagerTest : public testing::Test { ...@@ -192,8 +186,10 @@ class ExternalWebAppManagerTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(ExternalWebAppManagerTest); DISALLOW_COPY_AND_ASSIGN(ExternalWebAppManagerTest);
}; };
// Only Chrome OS parses config files.
#if defined(OS_CHROMEOS)
TEST_F(ExternalWebAppManagerTest, GoodJson) { TEST_F(ExternalWebAppManagerTest, GoodJson) {
const auto install_options_list = ReloadInstallOptions(kGoodJsonTestDir); const auto install_options_list = LoadApps(kGoodJsonTestDir);
// The good_json directory contains two good JSON files: // The good_json directory contains two good JSON files:
// chrome_platform_status.json and google_io_2016.json. // chrome_platform_status.json and google_io_2016.json.
...@@ -234,7 +230,7 @@ TEST_F(ExternalWebAppManagerTest, GoodJson) { ...@@ -234,7 +230,7 @@ TEST_F(ExternalWebAppManagerTest, GoodJson) {
} }
TEST_F(ExternalWebAppManagerTest, BadJson) { TEST_F(ExternalWebAppManagerTest, BadJson) {
const auto app_infos = ReloadInstallOptions("bad_json"); const auto app_infos = LoadApps("bad_json");
// The bad_json directory contains one (malformed) JSON file. // The bad_json directory contains one (malformed) JSON file.
EXPECT_EQ(0u, app_infos.size()); EXPECT_EQ(0u, app_infos.size());
...@@ -242,7 +238,7 @@ TEST_F(ExternalWebAppManagerTest, BadJson) { ...@@ -242,7 +238,7 @@ TEST_F(ExternalWebAppManagerTest, BadJson) {
} }
TEST_F(ExternalWebAppManagerTest, TxtButNoJson) { TEST_F(ExternalWebAppManagerTest, TxtButNoJson) {
const auto app_infos = ReloadInstallOptions("txt_but_no_json"); const auto app_infos = LoadApps("txt_but_no_json");
// The txt_but_no_json directory contains one file, and the contents of that // The txt_but_no_json directory contains one file, and the contents of that
// file is valid JSON, but that file's name does not end with ".json". // file is valid JSON, but that file's name does not end with ".json".
...@@ -251,7 +247,7 @@ TEST_F(ExternalWebAppManagerTest, TxtButNoJson) { ...@@ -251,7 +247,7 @@ TEST_F(ExternalWebAppManagerTest, TxtButNoJson) {
} }
TEST_F(ExternalWebAppManagerTest, MixedJson) { TEST_F(ExternalWebAppManagerTest, MixedJson) {
const auto app_infos = ReloadInstallOptions("mixed_json"); const auto app_infos = LoadApps("mixed_json");
// The mixed_json directory contains one empty JSON file, one malformed JSON // The mixed_json directory contains one empty JSON file, one malformed JSON
// file and one good JSON file. ScanDirForExternalWebAppsForTesting should // file and one good JSON file. ScanDirForExternalWebAppsForTesting should
...@@ -265,7 +261,7 @@ TEST_F(ExternalWebAppManagerTest, MixedJson) { ...@@ -265,7 +261,7 @@ TEST_F(ExternalWebAppManagerTest, MixedJson) {
} }
TEST_F(ExternalWebAppManagerTest, MissingAppUrl) { TEST_F(ExternalWebAppManagerTest, MissingAppUrl) {
const auto app_infos = ReloadInstallOptions("missing_app_url"); const auto app_infos = LoadApps("missing_app_url");
// The missing_app_url directory contains one JSON file which is correct // The missing_app_url directory contains one JSON file which is correct
// except for a missing "app_url" field. // except for a missing "app_url" field.
...@@ -274,7 +270,7 @@ TEST_F(ExternalWebAppManagerTest, MissingAppUrl) { ...@@ -274,7 +270,7 @@ TEST_F(ExternalWebAppManagerTest, MissingAppUrl) {
} }
TEST_F(ExternalWebAppManagerTest, EmptyAppUrl) { TEST_F(ExternalWebAppManagerTest, EmptyAppUrl) {
const auto app_infos = ReloadInstallOptions("empty_app_url"); const auto app_infos = LoadApps("empty_app_url");
// The empty_app_url directory contains one JSON file which is correct // The empty_app_url directory contains one JSON file which is correct
// except for an empty "app_url" field. // except for an empty "app_url" field.
...@@ -283,7 +279,7 @@ TEST_F(ExternalWebAppManagerTest, EmptyAppUrl) { ...@@ -283,7 +279,7 @@ TEST_F(ExternalWebAppManagerTest, EmptyAppUrl) {
} }
TEST_F(ExternalWebAppManagerTest, InvalidAppUrl) { TEST_F(ExternalWebAppManagerTest, InvalidAppUrl) {
const auto app_infos = ReloadInstallOptions("invalid_app_url"); const auto app_infos = LoadApps("invalid_app_url");
// The invalid_app_url directory contains one JSON file which is correct // The invalid_app_url directory contains one JSON file which is correct
// except for an invalid "app_url" field. // except for an invalid "app_url" field.
...@@ -292,7 +288,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidAppUrl) { ...@@ -292,7 +288,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidAppUrl) {
} }
TEST_F(ExternalWebAppManagerTest, TrueHideFromUser) { TEST_F(ExternalWebAppManagerTest, TrueHideFromUser) {
const auto app_infos = ReloadInstallOptions("true_hide_from_user"); const auto app_infos = LoadApps("true_hide_from_user");
EXPECT_EQ(1u, app_infos.size()); EXPECT_EQ(1u, app_infos.size());
const auto& app = app_infos[0]; const auto& app = app_infos[0];
...@@ -303,7 +299,7 @@ TEST_F(ExternalWebAppManagerTest, TrueHideFromUser) { ...@@ -303,7 +299,7 @@ TEST_F(ExternalWebAppManagerTest, TrueHideFromUser) {
} }
TEST_F(ExternalWebAppManagerTest, InvalidHideFromUser) { TEST_F(ExternalWebAppManagerTest, InvalidHideFromUser) {
const auto app_infos = ReloadInstallOptions("invalid_hide_from_user"); const auto app_infos = LoadApps("invalid_hide_from_user");
// The invalid_hide_from_user directory contains on JSON file which is correct // The invalid_hide_from_user directory contains on JSON file which is correct
// except for an invalid "hide_from_user" field. // except for an invalid "hide_from_user" field.
...@@ -312,7 +308,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidHideFromUser) { ...@@ -312,7 +308,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidHideFromUser) {
} }
TEST_F(ExternalWebAppManagerTest, InvalidCreateShortcuts) { TEST_F(ExternalWebAppManagerTest, InvalidCreateShortcuts) {
const auto app_infos = ReloadInstallOptions("invalid_create_shortcuts"); const auto app_infos = LoadApps("invalid_create_shortcuts");
// The invalid_create_shortcuts directory contains one JSON file which is // The invalid_create_shortcuts directory contains one JSON file which is
// correct except for an invalid "create_shortcuts" field. // correct except for an invalid "create_shortcuts" field.
...@@ -321,7 +317,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidCreateShortcuts) { ...@@ -321,7 +317,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidCreateShortcuts) {
} }
TEST_F(ExternalWebAppManagerTest, MissingLaunchContainer) { TEST_F(ExternalWebAppManagerTest, MissingLaunchContainer) {
const auto app_infos = ReloadInstallOptions("missing_launch_container"); const auto app_infos = LoadApps("missing_launch_container");
// The missing_launch_container directory contains one JSON file which is // The missing_launch_container directory contains one JSON file which is
// correct except for a missing "launch_container" field. // correct except for a missing "launch_container" field.
...@@ -330,7 +326,7 @@ TEST_F(ExternalWebAppManagerTest, MissingLaunchContainer) { ...@@ -330,7 +326,7 @@ TEST_F(ExternalWebAppManagerTest, MissingLaunchContainer) {
} }
TEST_F(ExternalWebAppManagerTest, InvalidLaunchContainer) { TEST_F(ExternalWebAppManagerTest, InvalidLaunchContainer) {
const auto app_infos = ReloadInstallOptions("invalid_launch_container"); const auto app_infos = LoadApps("invalid_launch_container");
// The invalid_launch_container directory contains one JSON file which is // The invalid_launch_container directory contains one JSON file which is
// correct except for an invalid "launch_container" field. // correct except for an invalid "launch_container" field.
...@@ -339,7 +335,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidLaunchContainer) { ...@@ -339,7 +335,7 @@ TEST_F(ExternalWebAppManagerTest, InvalidLaunchContainer) {
} }
TEST_F(ExternalWebAppManagerTest, InvalidUninstallAndReplace) { TEST_F(ExternalWebAppManagerTest, InvalidUninstallAndReplace) {
const auto app_infos = ReloadInstallOptions("invalid_uninstall_and_replace"); const auto app_infos = LoadApps("invalid_uninstall_and_replace");
// The invalid_uninstall_and_replace directory contains 2 JSON files which are // The invalid_uninstall_and_replace directory contains 2 JSON files which are
// correct except for invalid "uninstall_and_replace" fields. // correct except for invalid "uninstall_and_replace" fields.
...@@ -351,7 +347,7 @@ TEST_F(ExternalWebAppManagerTest, DefaultWebAppInstallDisabled) { ...@@ -351,7 +347,7 @@ TEST_F(ExternalWebAppManagerTest, DefaultWebAppInstallDisabled) {
base::test::ScopedFeatureList scoped_feature_list; base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndDisableFeature( scoped_feature_list.InitAndDisableFeature(
features::kDefaultWebAppInstallation); features::kDefaultWebAppInstallation);
const auto app_infos = ReloadInstallOptions(kGoodJsonTestDir); const auto app_infos = LoadApps(kGoodJsonTestDir);
EXPECT_EQ(0u, app_infos.size()); EXPECT_EQ(0u, app_infos.size());
histograms_.ExpectTotalCount( histograms_.ExpectTotalCount(
...@@ -366,7 +362,7 @@ TEST_F(ExternalWebAppManagerTest, EnabledByFinch) { ...@@ -366,7 +362,7 @@ TEST_F(ExternalWebAppManagerTest, EnabledByFinch) {
base::AutoReset<bool> testing_scope = base::AutoReset<bool> testing_scope =
SetExternalAppInstallFeatureAlwaysEnabledForTesting(); SetExternalAppInstallFeatureAlwaysEnabledForTesting();
const auto app_infos = ReloadInstallOptions("enabled_by_finch"); const auto app_infos = LoadApps("enabled_by_finch");
// The enabled_by_finch directory contains two JSON file containing apps // The enabled_by_finch directory contains two JSON file containing apps
// that have field trials. As the matching feature is enabled, they should be // that have field trials. As the matching feature is enabled, they should be
...@@ -376,7 +372,7 @@ TEST_F(ExternalWebAppManagerTest, EnabledByFinch) { ...@@ -376,7 +372,7 @@ TEST_F(ExternalWebAppManagerTest, EnabledByFinch) {
} }
TEST_F(ExternalWebAppManagerTest, NotEnabledByFinch) { TEST_F(ExternalWebAppManagerTest, NotEnabledByFinch) {
const auto app_infos = ReloadInstallOptions("enabled_by_finch"); const auto app_infos = LoadApps("enabled_by_finch");
// The enabled_by_finch directory contains two JSON file containing apps // The enabled_by_finch directory contains two JSON file containing apps
// that have field trials. As the matching feature isn't enabled, they should // that have field trials. As the matching feature isn't enabled, they should
...@@ -385,7 +381,6 @@ TEST_F(ExternalWebAppManagerTest, NotEnabledByFinch) { ...@@ -385,7 +381,6 @@ TEST_F(ExternalWebAppManagerTest, NotEnabledByFinch) {
ExpectHistograms(/*enabled=*/0, /*disabled=*/2, /*errors=*/0); ExpectHistograms(/*enabled=*/0, /*disabled=*/2, /*errors=*/0);
} }
#if defined(OS_CHROMEOS)
TEST_F(ExternalWebAppManagerTest, ChildUser) { TEST_F(ExternalWebAppManagerTest, ChildUser) {
const auto profile = CreateProfileAndLogin(); const auto profile = CreateProfileAndLogin();
profile->SetSupervisedUserId(supervised_users::kChildAccountSUID); profile->SetSupervisedUserId(supervised_users::kChildAccountSUID);
...@@ -415,15 +410,13 @@ TEST_F(ExternalWebAppManagerTest, UnmanagedUser) { ...@@ -415,15 +410,13 @@ TEST_F(ExternalWebAppManagerTest, UnmanagedUser) {
} }
TEST_F(ExternalWebAppManagerTest, NonPrimaryProfile) { TEST_F(ExternalWebAppManagerTest, NonPrimaryProfile) {
EXPECT_TRUE( EXPECT_TRUE(LoadApps(kUserTypesTestDir, CreateProfile().get()).empty());
LoadApps(CreateProfile().get(), GetTestDir(kUserTypesTestDir)).empty());
} }
#else #else // defined(OS_CHROMEOS)
// No app is expected for non-ChromeOS builds. // No app is expected for non-ChromeOS builds.
TEST_F(ExternalWebAppManagerTest, NoApp) { TEST_F(ExternalWebAppManagerTest, NoApp) {
EXPECT_TRUE( EXPECT_TRUE(LoadApps(kUserTypesTestDir, CreateProfile().get()).empty());
LoadApps(CreateProfile().get(), GetTestDir(kUserTypesTestDir)).empty());
} }
#endif #endif // defined(OS_CHROMEOS)
} // namespace web_app } // namespace web_app
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
...@@ -176,9 +177,9 @@ class ExternalWebAppMigrationBrowserTest : public InProcessBrowserTest { ...@@ -176,9 +177,9 @@ class ExternalWebAppMigrationBrowserTest : public InProcessBrowserTest {
run_loop.Quit(); run_loop.Quit();
}); });
std::vector<std::string> configs; std::vector<base::Value> app_configs;
if (pass_config) { if (pass_config) {
std::string external_web_app_config = base::ReplaceStringPlaceholders( std::string app_config_string = base::ReplaceStringPlaceholders(
R"({ R"({
"app_url": "$1", "app_url": "$1",
"launch_container": "window", "launch_container": "window",
...@@ -187,15 +188,17 @@ class ExternalWebAppMigrationBrowserTest : public InProcessBrowserTest { ...@@ -187,15 +188,17 @@ class ExternalWebAppMigrationBrowserTest : public InProcessBrowserTest {
"uninstall_and_replace": ["$3"] "uninstall_and_replace": ["$3"]
})", })",
{GetWebAppUrl().spec(), kMigrationFlag, kExtensionId}, nullptr); {GetWebAppUrl().spec(), kMigrationFlag, kExtensionId}, nullptr);
configs.push_back(std::move(external_web_app_config)); app_configs.push_back(*base::JSONReader::Read(app_config_string));
} }
ExternalWebAppManager::SetConfigsForTesting(&app_configs);
WebAppProvider::Get(profile()) WebAppProvider::Get(profile())
->external_web_app_manager_for_testing() ->external_web_app_manager_for_testing()
.SynchronizeAppsForTesting(std::make_unique<FileUtilsWrapper>(), .LoadAndSynchronizeForTesting(std::move(callback));
configs, std::move(callback));
run_loop.Run(); run_loop.Run();
ExternalWebAppManager::SetConfigsForTesting(nullptr);
} }
bool IsWebAppInstalled() { bool IsWebAppInstalled() {
...@@ -444,15 +447,12 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppMigrationBrowserTest, ...@@ -444,15 +447,12 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppMigrationBrowserTest,
EXPECT_FALSE(IsWebAppInstalled()); EXPECT_FALSE(IsWebAppInstalled());
EXPECT_TRUE(IsExtensionAppInstalled()); EXPECT_TRUE(IsExtensionAppInstalled());
// TODO(crbug.com/1128801): Use the normal LoadInstallOptions() code path histograms.ExpectUniqueSample(ExternalWebAppManager::kHistogramEnabledCount,
// such that metrics are recorded. 0, 1);
// histograms.ExpectUniqueSample( histograms.ExpectUniqueSample(
// ExternalWebAppManager::kHistogramEnabledCount, ExternalWebAppManager::kHistogramDisabledCount, 1, 1);
// 0, 1); histograms.ExpectUniqueSample(
// histograms.ExpectUniqueSample( ExternalWebAppManager::kHistogramConfigErrorCount, 0, 1);
// ExternalWebAppManager::kHistogramDisabledCount, 1, 1);
// histograms.ExpectUniqueSample(
// ExternalWebAppManager::kHistogramConfigErrorCount, 0, 1);
} }
// Migrate extension app to web app. // Migrate extension app to web app.
...@@ -481,14 +481,12 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppMigrationBrowserTest, ...@@ -481,14 +481,12 @@ IN_PROC_BROWSER_TEST_F(ExternalWebAppMigrationBrowserTest,
EXPECT_EQ(uninstalled_app->id(), kExtensionId); EXPECT_EQ(uninstalled_app->id(), kExtensionId);
EXPECT_FALSE(IsExtensionAppInstalled()); EXPECT_FALSE(IsExtensionAppInstalled());
// TODO(crbug.com/1128801): Use the normal LoadInstallOptions() code path histograms.ExpectUniqueSample(
// such that metrics are recorded. ExternalWebAppManager::kHistogramEnabledCount, 1, 1);
// histograms.ExpectUniqueSample( histograms.ExpectUniqueSample(
// ExternalWebAppManager::kHistogramEnabledCount, 1, 1); ExternalWebAppManager::kHistogramDisabledCount, 0, 1);
// histograms.ExpectUniqueSample( histograms.ExpectUniqueSample(
// ExternalWebAppManager::kHistogramDisabledCount, 0, 1); ExternalWebAppManager::kHistogramConfigErrorCount, 0, 1);
// histograms.ExpectUniqueSample(
// ExternalWebAppManager::kHistogramConfigErrorCount, 0, 1);
} }
} }
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
namespace web_app { namespace web_app {
std::unique_ptr<FileUtilsWrapper> FileUtilsWrapper::Clone() { std::unique_ptr<FileUtilsWrapper> FileUtilsWrapper::Clone() const {
return std::make_unique<FileUtilsWrapper>(); return std::make_unique<FileUtilsWrapper>();
} }
......
...@@ -34,7 +34,7 @@ class FileUtilsWrapper { ...@@ -34,7 +34,7 @@ class FileUtilsWrapper {
virtual ~FileUtilsWrapper() = default; virtual ~FileUtilsWrapper() = default;
// Create a copy to use in IO task. // Create a copy to use in IO task.
virtual std::unique_ptr<FileUtilsWrapper> Clone(); virtual std::unique_ptr<FileUtilsWrapper> Clone() const;
bool PathExists(const base::FilePath& path); bool PathExists(const base::FilePath& path);
......
...@@ -23,7 +23,7 @@ TestFileUtils::TestFileUtils(const TestFileUtils&) = default; ...@@ -23,7 +23,7 @@ TestFileUtils::TestFileUtils(const TestFileUtils&) = default;
TestFileUtils::~TestFileUtils() = default; TestFileUtils::~TestFileUtils() = default;
std::unique_ptr<FileUtilsWrapper> TestFileUtils::Clone() { std::unique_ptr<FileUtilsWrapper> TestFileUtils::Clone() const {
return std::make_unique<TestFileUtils>(*this); return std::make_unique<TestFileUtils>(*this);
} }
......
...@@ -28,7 +28,7 @@ class TestFileUtils : public FileUtilsWrapper { ...@@ -28,7 +28,7 @@ class TestFileUtils : public FileUtilsWrapper {
~TestFileUtils() override; ~TestFileUtils() override;
// FileUtilsWrapper: // FileUtilsWrapper:
std::unique_ptr<FileUtilsWrapper> Clone() override; std::unique_ptr<FileUtilsWrapper> Clone() const override;
int WriteFile(const base::FilePath& filename, int WriteFile(const base::FilePath& filename,
const char* data, const char* data,
int size) override; int size) override;
......
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