blob: c77c39ec234782fd962adea57fdbf215450e529e [file] [log] [blame]
// Copyright 2018 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 "chrome/browser/web_applications/pending_app_manager_impl.h"
#include <map>
#include <memory>
#include <string>
#include <utility>
#include "base/barrier_closure.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/test/bind_test_util.h"
#include "base/timer/mock_timer.h"
#include "chrome/browser/web_applications/components/app_registrar.h"
#include "chrome/browser/web_applications/components/install_finalizer.h"
#include "chrome/browser/web_applications/components/pending_app_manager.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/pending_app_install_task.h"
#include "chrome/browser/web_applications/pending_app_registration_task.h"
#include "chrome/browser/web_applications/test/test_app_registrar.h"
#include "chrome/browser/web_applications/test/test_install_finalizer.h"
#include "chrome/browser/web_applications/test/test_web_app_provider.h"
#include "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
#include "chrome/browser/web_applications/test/test_web_app_url_loader.h"
#include "chrome/browser/web_applications/test/web_app_registration_waiter.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace web_app {
namespace {
using InstallAppsResults = std::vector<std::pair<GURL, InstallResultCode>>;
using UninstallAppsResults = std::vector<std::pair<GURL, bool>>;
// TODO(https://crbug.com/1042727): Fix test GURL scoping and remove this getter
// function.
GURL FooWebAppUrl() {
return GURL("https://foo.example");
}
GURL BarWebAppUrl() {
return GURL("https://bar.example");
}
GURL QuxWebAppUrl() {
return GURL("https://qux.example");
}
GURL FooLaunchUrl() {
return GURL("https://foo.example/launch");
}
GURL BarLaunchUrl() {
return GURL("https://bar.example/launch");
}
GURL QuxLaunchUrl() {
return GURL("https://qux.example/launch");
}
ExternalInstallOptions GetFooInstallOptions(
base::Optional<bool> override_previous_user_uninstall =
base::Optional<bool>()) {
ExternalInstallOptions options(FooWebAppUrl(), DisplayMode::kBrowser,
ExternalInstallSource::kExternalPolicy);
if (override_previous_user_uninstall.has_value())
options.override_previous_user_uninstall =
*override_previous_user_uninstall;
return options;
}
ExternalInstallOptions GetBarInstallOptions() {
ExternalInstallOptions options(BarWebAppUrl(), DisplayMode::kStandalone,
ExternalInstallSource::kExternalPolicy);
return options;
}
ExternalInstallOptions GetQuxInstallOptions() {
ExternalInstallOptions options(QuxWebAppUrl(), DisplayMode::kStandalone,
ExternalInstallSource::kExternalPolicy);
return options;
}
std::string GenerateFakeAppId(const GURL& url) {
return TestInstallFinalizer::GetAppIdForUrl(url);
}
class TestPendingAppManagerImpl : public PendingAppManagerImpl {
public:
TestPendingAppManagerImpl(Profile* profile,
TestAppRegistrar* test_app_registrar)
: PendingAppManagerImpl(profile),
test_app_registrar_(test_app_registrar) {}
~TestPendingAppManagerImpl() override {
DCHECK(next_installation_task_results_.empty());
DCHECK(next_installation_launch_urls_.empty());
DCHECK(!preempt_registration_callback_);
}
size_t install_run_count() { return install_run_count_; }
const std::vector<ExternalInstallOptions>& install_options_list() {
return install_options_list_;
}
size_t registration_run_count() { return registration_run_count_; }
const GURL& last_registered_launch_url() {
return last_registered_launch_url_;
}
void SetNextInstallationTaskResult(const GURL& app_url,
InstallResultCode result_code) {
DCHECK(!base::Contains(next_installation_task_results_, app_url));
next_installation_task_results_[app_url] = result_code;
}
void SetNextInstallationLaunchURL(const GURL& app_url,
const GURL& launch_url) {
DCHECK(!base::Contains(next_installation_launch_urls_, app_url));
next_installation_launch_urls_[app_url] = launch_url;
}
bool MaybePreemptRegistration() {
if (!preempt_registration_callback_)
return false;
base::Optional<base::OnceClosure> callback;
preempt_registration_callback_.swap(callback);
std::move(*callback).Run();
return true;
}
std::unique_ptr<PendingAppInstallTask> CreateInstallationTask(
ExternalInstallOptions install_options) override {
return std::make_unique<TestPendingAppInstallTask>(
this, profile(), std::move(install_options));
}
std::unique_ptr<PendingAppRegistrationTaskBase> StartRegistration(
GURL launch_url) override {
++registration_run_count_;
last_registered_launch_url_ = launch_url;
return std::make_unique<TestPendingAppRegistrationTask>(launch_url, this);
}
void OnInstallCalled(const ExternalInstallOptions& install_options) {
++install_run_count_;
install_options_list_.push_back(install_options);
}
InstallResultCode GetNextInstallationTaskResult(const GURL& url) {
DCHECK(base::Contains(next_installation_task_results_, url));
auto result = next_installation_task_results_.at(url);
next_installation_task_results_.erase(url);
return result;
}
GURL GetNextInstallationLaunchURL(const GURL& url) {
if (!base::Contains(next_installation_launch_urls_, url))
return GURL::EmptyGURL();
auto result = next_installation_launch_urls_.at(url);
next_installation_launch_urls_.erase(url);
return result;
}
void WaitForRegistrationAndCancel() {
DCHECK(!preempt_registration_callback_);
base::RunLoop run_loop;
preempt_registration_callback_ =
base::BindLambdaForTesting([&run_loop]() { run_loop.Quit(); });
run_loop.Run();
}
TestAppRegistrar* registrar() { return test_app_registrar_; }
private:
class TestPendingAppInstallTask : public PendingAppInstallTask {
public:
TestPendingAppInstallTask(
TestPendingAppManagerImpl* pending_app_manager_impl,
Profile* profile,
ExternalInstallOptions install_options)
: PendingAppInstallTask(
profile,
pending_app_manager_impl->registrar(),
pending_app_manager_impl->shortcut_manager(),
pending_app_manager_impl->file_handler_manager(),
pending_app_manager_impl->ui_manager(),
pending_app_manager_impl->finalizer(),
install_options),
pending_app_manager_impl_(pending_app_manager_impl),
externally_installed_app_prefs_(profile->GetPrefs()) {}
~TestPendingAppInstallTask() override = default;
void Install(content::WebContents* web_contents,
WebAppUrlLoader::Result url_loaded_result,
ResultCallback callback) override {
pending_app_manager_impl_->OnInstallCalled(install_options());
base::Optional<AppId> app_id;
const GURL& install_url = install_options().url;
auto result_code =
pending_app_manager_impl_->GetNextInstallationTaskResult(install_url);
if (result_code == InstallResultCode::kSuccessNewInstall) {
app_id = GenerateFakeAppId(install_url);
GURL launch_url =
pending_app_manager_impl_->GetNextInstallationLaunchURL(
install_url);
pending_app_manager_impl_->registrar()->AddExternalApp(
*app_id,
{install_url, install_options().install_source, launch_url});
externally_installed_app_prefs_.Insert(
install_url, *app_id, install_options().install_source);
const bool is_placeholder =
(url_loaded_result != WebAppUrlLoader::Result::kUrlLoaded);
externally_installed_app_prefs_.SetIsPlaceholder(install_url,
is_placeholder);
}
std::move(callback).Run({result_code, app_id});
}
private:
TestPendingAppManagerImpl* pending_app_manager_impl_;
ExternallyInstalledWebAppPrefs externally_installed_app_prefs_;
DISALLOW_COPY_AND_ASSIGN(TestPendingAppInstallTask);
};
class TestPendingAppRegistrationTask : public PendingAppRegistrationTaskBase {
public:
TestPendingAppRegistrationTask(
const GURL& launch_url,
TestPendingAppManagerImpl* pending_app_manager_impl)
: PendingAppRegistrationTaskBase(launch_url),
pending_app_manager_impl_(pending_app_manager_impl) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&TestPendingAppRegistrationTask::OnProgress,
weak_ptr_factory_.GetWeakPtr(), launch_url));
}
~TestPendingAppRegistrationTask() override = default;
private:
void OnProgress(GURL launch_url) {
if (pending_app_manager_impl_->MaybePreemptRegistration())
return;
pending_app_manager_impl_->OnRegistrationFinished(
launch_url, RegistrationResultCode::kSuccess);
}
TestPendingAppManagerImpl* const pending_app_manager_impl_;
base::WeakPtrFactory<TestPendingAppRegistrationTask> weak_ptr_factory_{
this};
DISALLOW_COPY_AND_ASSIGN(TestPendingAppRegistrationTask);
};
TestAppRegistrar* test_app_registrar_;
std::vector<ExternalInstallOptions> install_options_list_;
GURL last_registered_launch_url_;
size_t install_run_count_ = 0;
size_t registration_run_count_ = 0;
std::map<GURL, InstallResultCode> next_installation_task_results_;
std::map<GURL, GURL> next_installation_launch_urls_;
base::Optional<base::OnceClosure> preempt_registration_callback_;
};
} // namespace
class PendingAppManagerImplTest : public ChromeRenderViewHostTestHarness {
public:
PendingAppManagerImplTest() = default;
~PendingAppManagerImplTest() override = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
auto* provider = TestWebAppProvider::Get(profile());
auto test_app_registrar = std::make_unique<TestAppRegistrar>();
app_registrar_ = test_app_registrar.get();
provider->SetRegistrar(std::move(test_app_registrar));
auto test_pending_app_manager =
std::make_unique<TestPendingAppManagerImpl>(profile(), app_registrar_);
pending_app_manager_impl_ = test_pending_app_manager.get();
provider->SetPendingAppManager(std::move(test_pending_app_manager));
auto url_loader = std::make_unique<TestWebAppUrlLoader>();
url_loader_ = url_loader.get();
pending_app_manager_impl_->SetUrlLoaderForTesting(std::move(url_loader));
auto test_install_finalizer = std::make_unique<TestInstallFinalizer>();
install_finalizer_ = test_install_finalizer.get();
provider->SetInstallFinalizer(std::move(test_install_finalizer));
auto ui_manager = std::make_unique<TestWebAppUiManager>();
ui_manager_ = ui_manager.get();
provider->SetWebAppUiManager(std::move(ui_manager));
provider->Start();
}
protected:
std::pair<GURL, InstallResultCode> InstallAndWait(
PendingAppManager* pending_app_manager,
ExternalInstallOptions install_options) {
base::RunLoop run_loop;
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
pending_app_manager_impl()->Install(
std::move(install_options),
base::BindLambdaForTesting([&](const GURL& u, InstallResultCode c) {
url = u;
code = c;
run_loop.Quit();
}));
run_loop.Run();
return {url.value(), code.value()};
}
std::vector<std::pair<GURL, InstallResultCode>> InstallAppsAndWait(
PendingAppManager* pending_app_manager,
std::vector<ExternalInstallOptions> apps_to_install) {
std::vector<std::pair<GURL, InstallResultCode>> results;
base::RunLoop run_loop;
auto barrier_closure =
base::BarrierClosure(apps_to_install.size(), run_loop.QuitClosure());
pending_app_manager_impl()->InstallApps(
std::move(apps_to_install),
base::BindLambdaForTesting(
[&](const GURL& url, InstallResultCode code) {
results.emplace_back(url, code);
barrier_closure.Run();
}));
run_loop.Run();
return results;
}
std::vector<std::pair<GURL, bool>> UninstallAppsAndWait(
PendingAppManager* pending_app_manager,
ExternalInstallSource install_source,
std::vector<GURL> apps_to_uninstall) {
std::vector<std::pair<GURL, bool>> results;
base::RunLoop run_loop;
auto barrier_closure =
base::BarrierClosure(apps_to_uninstall.size(), run_loop.QuitClosure());
pending_app_manager->UninstallApps(
std::move(apps_to_uninstall), install_source,
base::BindLambdaForTesting(
[&](const GURL& url, bool successfully_uninstalled) {
results.emplace_back(url, successfully_uninstalled);
barrier_closure.Run();
}));
run_loop.Run();
return results;
}
// ExternalInstallOptions that was used to run the last installation task.
const ExternalInstallOptions& last_install_options() {
DCHECK(!pending_app_manager_impl_->install_options_list().empty());
return pending_app_manager_impl_->install_options_list().back();
}
// Number of times PendingAppInstallTask::Install was called. Reflects
// how many times we've tried to create a web app.
size_t install_run_count() {
return pending_app_manager_impl_->install_run_count();
}
// Number of times PendingAppManagerImpl::StartRegistration was called.
// Reflects how many times we've tried to cache service worker resources
// for a web app.
size_t registration_run_count() {
return pending_app_manager_impl_->registration_run_count();
}
size_t uninstall_call_count() {
return install_finalizer_->uninstall_external_web_app_urls().size();
}
const std::vector<GURL>& uninstalled_app_urls() {
return install_finalizer_->uninstall_external_web_app_urls();
}
const GURL& last_registered_launch_url() {
return pending_app_manager_impl_->last_registered_launch_url();
}
const GURL& last_uninstalled_app_url() {
return install_finalizer_->uninstall_external_web_app_urls().back();
}
TestPendingAppManagerImpl* pending_app_manager_impl() {
return pending_app_manager_impl_;
}
TestAppRegistrar* registrar() { return app_registrar_; }
TestWebAppUiManager* ui_manager() { return ui_manager_; }
TestWebAppUrlLoader* url_loader() { return url_loader_; }
TestInstallFinalizer* install_finalizer() { return install_finalizer_; }
private:
TestAppRegistrar* app_registrar_ = nullptr;
TestPendingAppManagerImpl* pending_app_manager_impl_ = nullptr;
TestInstallFinalizer* install_finalizer_ = nullptr;
TestWebAppUiManager* ui_manager_ = nullptr;
TestWebAppUrlLoader* url_loader_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(PendingAppManagerImplTest);
};
TEST_F(PendingAppManagerImplTest, Install_Succeeds) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(),
FooLaunchUrl());
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(FooLaunchUrl(), RegistrationResultCode::kSuccess);
EXPECT_EQ(1U, registration_run_count());
EXPECT_EQ(FooLaunchUrl(), last_registered_launch_url());
}
TEST_F(PendingAppManagerImplTest, Install_SerialCallsDifferentApps) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(),
FooLaunchUrl());
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
}
pending_app_manager_impl()->WaitForRegistrationAndCancel();
// FooLaunchUrl() registration will be attempted again after
// BarWebAppUrl() installs.
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(BarWebAppUrl(),
BarLaunchUrl());
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetBarInstallOptions());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(BarWebAppUrl(), url.value());
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
}
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(FooLaunchUrl(), RegistrationResultCode::kSuccess);
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(BarLaunchUrl(), RegistrationResultCode::kSuccess);
EXPECT_EQ(3U, registration_run_count());
EXPECT_EQ(BarLaunchUrl(), last_registered_launch_url());
}
TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsDifferentApps) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
// Two installations tasks should have run at this point,
// one from the last call to install (which gets higher priority),
// and another one for this call to install.
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
run_loop.Quit();
}));
pending_app_manager_impl()->Install(
GetBarInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
// The last call gets higher priority so only one
// installation task should have run at this point.
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
}));
run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, Install_PendingSuccessfulTask) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
url_loader()->SaveLoadUrlRequests();
base::RunLoop foo_run_loop;
base::RunLoop bar_run_loop;
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
foo_run_loop.Quit();
}));
// Make sure the installation has started.
base::RunLoop().RunUntilIdle();
pending_app_manager_impl()->Install(
GetBarInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
bar_run_loop.Quit();
}));
url_loader()->ProcessLoadUrlRequests();
foo_run_loop.Run();
// Make sure the second installation has started.
base::RunLoop().RunUntilIdle();
url_loader()->ProcessLoadUrlRequests();
bar_run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, Install_PendingFailingTask) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kWebAppDisabled);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
url_loader()->SaveLoadUrlRequests();
base::RunLoop foo_run_loop;
base::RunLoop bar_run_loop;
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kWebAppDisabled, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
foo_run_loop.Quit();
}));
// Make sure the installation has started.
base::RunLoop().RunUntilIdle();
pending_app_manager_impl()->Install(
GetBarInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
bar_run_loop.Quit();
}));
url_loader()->ProcessLoadUrlRequests();
foo_run_loop.Run();
// Make sure the second installation has started.
base::RunLoop().RunUntilIdle();
url_loader()->ProcessLoadUrlRequests();
bar_run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, Install_ReentrantCallback) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
auto final_callback =
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
run_loop.Quit();
});
auto reentrant_callback =
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
pending_app_manager_impl()->Install(GetBarInstallOptions(),
final_callback);
});
// Call Install() with a callback that tries to install another app.
pending_app_manager_impl()->Install(GetFooInstallOptions(),
reentrant_callback);
run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, Install_SerialCallsSameApp) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
}
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
EXPECT_EQ(FooWebAppUrl(), url);
// The app is already installed so we shouldn't try to install it again.
EXPECT_EQ(1u, install_run_count());
}
}
TEST_F(PendingAppManagerImplTest, Install_ConcurrentCallsSameApp) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
bool first_callback_ran = false;
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
// kSuccessAlreadyInstalled because the last call to Install gets higher
// priority.
EXPECT_EQ(InstallResultCode::kSuccessAlreadyInstalled, code);
EXPECT_EQ(FooWebAppUrl(), url);
// Only one installation task should run because the app was already
// installed.
EXPECT_EQ(1u, install_run_count());
EXPECT_TRUE(first_callback_ran);
run_loop.Quit();
}));
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
first_callback_ran = true;
}));
run_loop.Run();
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
}
TEST_F(PendingAppManagerImplTest, Install_AlwaysUpdate) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
auto get_force_reinstall_info = []() {
ExternalInstallOptions options(FooWebAppUrl(), DisplayMode::kStandalone,
ExternalInstallSource::kExternalPolicy);
options.force_reinstall = true;
return options;
};
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), get_force_reinstall_info());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(get_force_reinstall_info(), last_install_options());
}
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), get_force_reinstall_info());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
// The app should be installed again because of the |force_reinstall| flag.
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(get_force_reinstall_info(), last_install_options());
}
}
TEST_F(PendingAppManagerImplTest, Install_InstallationFails) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kWebAppDisabled);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(InstallResultCode::kWebAppDisabled, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
}
TEST_F(PendingAppManagerImplTest, Install_PlaceholderApp) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(install_options, last_install_options());
}
TEST_F(PendingAppManagerImplTest, InstallApps_Succeeds) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
InstallAppsResults results = InstallAppsAndWait(pending_app_manager_impl(),
std::move(apps_to_install));
EXPECT_EQ(results,
InstallAppsResults(
{{FooWebAppUrl(), InstallResultCode::kSuccessNewInstall}}));
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
}
TEST_F(PendingAppManagerImplTest, InstallApps_FailsInstallationFails) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kWebAppDisabled);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
InstallAppsResults results = InstallAppsAndWait(pending_app_manager_impl(),
std::move(apps_to_install));
EXPECT_EQ(results,
InstallAppsResults(
{{FooWebAppUrl(), InstallResultCode::kWebAppDisabled}}));
EXPECT_EQ(1u, install_run_count());
}
TEST_F(PendingAppManagerImplTest, InstallApps_PlaceholderApp) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(install_options);
InstallAppsResults results = InstallAppsAndWait(pending_app_manager_impl(),
std::move(apps_to_install));
EXPECT_EQ(results,
InstallAppsResults(
{{FooWebAppUrl(), InstallResultCode::kSuccessNewInstall}}));
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(install_options, last_install_options());
}
TEST_F(PendingAppManagerImplTest, InstallApps_Multiple) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
apps_to_install.push_back(GetBarInstallOptions());
InstallAppsResults results = InstallAppsAndWait(pending_app_manager_impl(),
std::move(apps_to_install));
EXPECT_EQ(results,
InstallAppsResults(
{{FooWebAppUrl(), InstallResultCode::kSuccessNewInstall},
{BarWebAppUrl(), InstallResultCode::kSuccessNewInstall}}));
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
}
TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstallApps) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
{
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
pending_app_manager_impl()->InstallApps(
std::move(apps_to_install),
base::BindLambdaForTesting(
[&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
}));
}
{
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetBarInstallOptions());
pending_app_manager_impl()->InstallApps(
std::move(apps_to_install),
base::BindLambdaForTesting(
[&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
run_loop.Quit();
}));
}
run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, Install_PendingMultipleInstallApps) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(FooWebAppUrl(),
FooLaunchUrl());
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(BarWebAppUrl(),
BarLaunchUrl());
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
QuxWebAppUrl(), InstallResultCode::kSuccessNewInstall);
pending_app_manager_impl()->SetNextInstallationLaunchURL(QuxWebAppUrl(),
QuxLaunchUrl());
url_loader()->SetNextLoadUrlResult(QuxWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
apps_to_install.push_back(GetBarInstallOptions());
// Queue through InstallApps.
int callback_calls = 0;
pending_app_manager_impl()->InstallApps(
std::move(apps_to_install),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
++callback_calls;
if (callback_calls == 1) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
} else if (callback_calls == 2) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(3u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
} else {
NOTREACHED();
}
}));
// Queue through Install.
pending_app_manager_impl()->Install(
GetQuxInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(QuxWebAppUrl(), url);
// The install request from Install should be processed first.
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetQuxInstallOptions(), last_install_options());
}));
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(QuxLaunchUrl(), RegistrationResultCode::kSuccess);
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(FooLaunchUrl(), RegistrationResultCode::kSuccess);
WebAppRegistrationWaiter(pending_app_manager_impl())
.AwaitNextRegistration(BarLaunchUrl(), RegistrationResultCode::kSuccess);
EXPECT_EQ(3U, registration_run_count());
EXPECT_EQ(BarLaunchUrl(), last_registered_launch_url());
}
TEST_F(PendingAppManagerImplTest, InstallApps_PendingInstall) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
BarWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(BarWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
pending_app_manager_impl()->SetNextInstallationTaskResult(
QuxWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(QuxWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
// Queue through Install.
pending_app_manager_impl()->Install(
GetQuxInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(QuxWebAppUrl(), url);
// The install request from Install should be processed first.
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(GetQuxInstallOptions(), last_install_options());
}));
// Queue through InstallApps.
std::vector<ExternalInstallOptions> apps_to_install;
apps_to_install.push_back(GetFooInstallOptions());
apps_to_install.push_back(GetBarInstallOptions());
int callback_calls = 0;
pending_app_manager_impl()->InstallApps(
std::move(apps_to_install),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
++callback_calls;
if (callback_calls == 1) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
// The install requests from InstallApps should be processed next.
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(GetFooInstallOptions(), last_install_options());
return;
}
if (callback_calls == 2) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(BarWebAppUrl(), url);
EXPECT_EQ(3u, install_run_count());
EXPECT_EQ(GetBarInstallOptions(), last_install_options());
run_loop.Quit();
return;
}
NOTREACHED();
}));
run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, AppUninstalled) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
}
// Simulate the app getting uninstalled.
registrar()->RemoveExternalAppByInstallUrl(FooWebAppUrl());
// Try to install the app again.
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
// The app was uninstalled so a new installation task should run.
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
}
}
TEST_F(PendingAppManagerImplTest, ExternalAppUninstalled) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), GetFooInstallOptions());
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
}
// Simulate external app for the app getting uninstalled by the user.
const std::string app_id = GenerateFakeAppId(FooWebAppUrl());
install_finalizer()->SimulateExternalAppUninstalledByUser(app_id);
if (registrar()->IsInstalled(app_id))
registrar()->RemoveExternalApp(app_id);
// The app was uninstalled by the user. Installing again should succeed
// or fail depending on whether we set override_previous_user_uninstall. We
// try with override_previous_user_uninstall false first, true second.
{
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) = InstallAndWait(
pending_app_manager_impl(),
GetFooInstallOptions(false /* override_previous_user_uninstall */));
// The app shouldn't be installed because the user previously uninstalled
// it, so there shouldn't be any new installation task runs.
EXPECT_EQ(1u, install_run_count());
EXPECT_EQ(InstallResultCode::kPreviouslyUninstalled, code.value());
}
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) = InstallAndWait(
pending_app_manager_impl(),
GetFooInstallOptions(true /* override_previous_user_uninstall */));
EXPECT_EQ(2u, install_run_count());
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
}
}
TEST_F(PendingAppManagerImplTest, UninstallApps_Succeeds) {
registrar()->AddExternalApp(
GenerateFakeAppId(FooWebAppUrl()),
{FooWebAppUrl(), ExternalInstallSource::kExternalPolicy});
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
true);
UninstallAppsResults results = UninstallAppsAndWait(
pending_app_manager_impl(), ExternalInstallSource::kExternalPolicy,
std::vector<GURL>{FooWebAppUrl()});
EXPECT_EQ(results, UninstallAppsResults({{FooWebAppUrl(), true}}));
EXPECT_EQ(1u, uninstall_call_count());
EXPECT_EQ(FooWebAppUrl(), last_uninstalled_app_url());
}
TEST_F(PendingAppManagerImplTest, UninstallApps_Fails) {
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
false);
UninstallAppsResults results = UninstallAppsAndWait(
pending_app_manager_impl(), ExternalInstallSource::kExternalPolicy,
std::vector<GURL>{FooWebAppUrl()});
EXPECT_EQ(results, UninstallAppsResults({{FooWebAppUrl(), false}}));
EXPECT_EQ(1u, uninstall_call_count());
EXPECT_EQ(FooWebAppUrl(), last_uninstalled_app_url());
}
TEST_F(PendingAppManagerImplTest, UninstallApps_Multiple) {
registrar()->AddExternalApp(
GenerateFakeAppId(FooWebAppUrl()),
{FooWebAppUrl(), ExternalInstallSource::kExternalPolicy});
registrar()->AddExternalApp(
GenerateFakeAppId(BarWebAppUrl()),
{FooWebAppUrl(), ExternalInstallSource::kExternalPolicy});
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
true);
install_finalizer()->SetNextUninstallExternalWebAppResult(BarWebAppUrl(),
true);
UninstallAppsResults results = UninstallAppsAndWait(
pending_app_manager_impl(), ExternalInstallSource::kExternalPolicy,
std::vector<GURL>{FooWebAppUrl(), BarWebAppUrl()});
EXPECT_EQ(results, UninstallAppsResults(
{{FooWebAppUrl(), true}, {BarWebAppUrl(), true}}));
EXPECT_EQ(2u, uninstall_call_count());
EXPECT_EQ(std::vector<GURL>({FooWebAppUrl(), BarWebAppUrl()}),
uninstalled_app_urls());
}
TEST_F(PendingAppManagerImplTest, UninstallApps_PendingInstall) {
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::RunLoop run_loop;
pending_app_manager_impl()->Install(
GetFooInstallOptions(),
base::BindLambdaForTesting([&](const GURL& url, InstallResultCode code) {
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code);
EXPECT_EQ(FooWebAppUrl(), url);
run_loop.Quit();
}));
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
false);
UninstallAppsResults uninstall_results = UninstallAppsAndWait(
pending_app_manager_impl(), ExternalInstallSource::kExternalPolicy,
std::vector<GURL>{FooWebAppUrl()});
EXPECT_EQ(uninstall_results, UninstallAppsResults({{FooWebAppUrl(), false}}));
EXPECT_EQ(1u, uninstall_call_count());
run_loop.Run();
}
TEST_F(PendingAppManagerImplTest, ReinstallPlaceholderApp_Success) {
// Install a placeholder app
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(1u, install_run_count());
}
// Reinstall placeholder
{
install_options.reinstall_placeholder = true;
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
true);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
EXPECT_EQ(2u, install_run_count());
}
}
TEST_F(PendingAppManagerImplTest,
ReinstallPlaceholderApp_ReinstallNotPossible) {
// Install a placeholder app
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(1u, install_run_count());
}
// Try to reinstall placeholder
{
install_options.reinstall_placeholder = true;
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
// Even though the placeholder app is already install, we make a call to
// InstallFinalizer. InstallFinalizer ensures we don't unnecessarily
// install the placeholder app again.
EXPECT_EQ(2u, install_run_count());
}
}
TEST_F(PendingAppManagerImplTest,
ReinstallPlaceholderAppWhenUnused_NoOpenedWindows) {
// Install a placeholder app
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(1u, install_run_count());
}
// Reinstall placeholder
{
install_options.reinstall_placeholder = true;
install_options.wait_for_windows_closed = true;
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(FooWebAppUrl()), 0);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
EXPECT_EQ(2u, install_run_count());
}
}
TEST_F(PendingAppManagerImplTest,
ReinstallPlaceholderAppWhenUnused_OneWindowOpened) {
// Install a placeholder app
auto install_options = GetFooInstallOptions();
install_options.install_placeholder = true;
{
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
url_loader()->SetNextLoadUrlResult(
FooWebAppUrl(), WebAppUrlLoader::Result::kRedirectedUrlLoaded);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
ASSERT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(1u, install_run_count());
}
// Reinstall placeholder
{
install_options.reinstall_placeholder = true;
install_options.wait_for_windows_closed = true;
pending_app_manager_impl()->SetNextInstallationTaskResult(
FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
ui_manager()->SetNumWindowsForApp(GenerateFakeAppId(FooWebAppUrl()), 1);
url_loader()->SetNextLoadUrlResult(FooWebAppUrl(),
WebAppUrlLoader::Result::kUrlLoaded);
install_finalizer()->SetNextUninstallExternalWebAppResult(FooWebAppUrl(),
true);
base::Optional<GURL> url;
base::Optional<InstallResultCode> code;
std::tie(url, code) =
InstallAndWait(pending_app_manager_impl(), install_options);
EXPECT_EQ(InstallResultCode::kSuccessNewInstall, code.value());
EXPECT_EQ(FooWebAppUrl(), url.value());
EXPECT_EQ(2u, install_run_count());
}
}
} // namespace web_app