#include "chrome/browser/web_applications/web_app_registrar.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/apps/link_capturing/link_capturing_feature_test_support.h"
#include "chrome/browser/web_applications/commands/run_on_os_login_command.h"
#include "chrome/browser/web_applications/commands/web_app_uninstall_command.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_storage_location.h"
#include "chrome/browser/web_applications/isolated_web_apps/isolated_web_app_url_info.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/proto/web_app_install_state.pb.h"
#include "chrome/browser/web_applications/proto/web_app_proto_package.pb.h"
#include "chrome/browser/web_applications/test/fake_web_app_database_factory.h"
#include "chrome/browser/web_applications/test/fake_web_app_provider.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/test/web_app_test.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_id_constants.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_registry_update.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/url_constants.h"
#include "components/sync/test/mock_data_type_local_change_processor.h"
#include "components/webapps/browser/uninstall_result_code.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/storage_partition_config.h"
#include "content/public/common/content_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "url/gurl.h"
#include "url/url_constants.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/ash_features.h"
#include "chrome/browser/ash/crosapi/browser_util.h"
#include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/web_applications/test/with_crosapi_param.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user_names.h"
using web_app::test::CrosapiParam;
using web_app::test::WithCrosapiParam;
#endif
namespace web_app {
namespace {
Registry CreateRegistryForTesting(const std::string& base_url, int num_apps) { … }
int CountApps(const WebAppRegistrar::AppSet& app_set) { … }
}
ElementsAre;
Pair;
class WebAppRegistrarTest : public WebAppTest { … };
class WebAppRegistrarTest_TabStrip : public WebAppRegistrarTest { … };
TEST_F(WebAppRegistrarTest, EmptyRegistrar) { … }
TEST_F(WebAppRegistrarTest, InitWithApps) { … }
TEST_F(WebAppRegistrarTest, InitRegistrarAndDoForEachApp) { … }
TEST_F(WebAppRegistrarTest, DoForEachAndUnregisterAllApps) { … }
TEST_F(WebAppRegistrarTest, AppsInstalledByUserMetric) { … }
TEST_F(WebAppRegistrarTest, AppsNonUserInstalledMetric) { … }
TEST_F(WebAppRegistrarTest, AppsNotLocallyInstalledMetric) { … }
TEST_F(WebAppRegistrarTest, GetApps) { … }
TEST_F(WebAppRegistrarTest, GetAppDataFields) { … }
TEST_F(WebAppRegistrarTest, CanFindAppsInScope) { … }
TEST_F(WebAppRegistrarTest, CanFindAppWithUrlInScope) { … }
TEST_F(WebAppRegistrarTest, CanFindShortcutWithUrlInScope) { … }
TEST_F(WebAppRegistrarTest, FindPwaOverShortcut) { … }
TEST_F(WebAppRegistrarTest, BeginAndCommitUpdate) { … }
TEST_F(WebAppRegistrarTest, CommitEmptyUpdate) { … }
TEST_F(WebAppRegistrarTest, ScopedRegistryUpdate) { … }
TEST_F(WebAppRegistrarTest, CopyOnWrite) { … }
TEST_F(WebAppRegistrarTest, CountUserInstalledApps) { … }
TEST_F(WebAppRegistrarTest, CountUserInstalledAppsDiy) { … }
TEST_F(WebAppRegistrarTest, GetAllIsolatedWebAppStoragePartitionConfigs) { … }
TEST_F(
WebAppRegistrarTest,
GetAllIsolatedWebAppStoragePartitionConfigsEmptyWhenNotLocallyInstalled) { … }
TEST_F(WebAppRegistrarTest, SaveAndGetInMemoryControlledFramePartitionConfig) { … }
TEST_F(WebAppRegistrarTest,
AppsFromSyncAndPendingInstallationExcludedFromGetAppIds) { … }
TEST_F(WebAppRegistrarTest, NotLocallyInstalledAppGetsDisplayModeBrowser) { … }
TEST_F(WebAppRegistrarTest,
NotLocallyInstalledAppGetsDisplayModeBrowserEvenForIsolatedWebApps) { … }
TEST_F(WebAppRegistrarTest,
IsolatedWebAppsGetDisplayModeStandaloneRegardlessOfUserSettings) { … }
TEST_F(WebAppRegistrarTest, NotLocallyInstalledAppGetsDisplayModeOverride) { … }
TEST_F(WebAppRegistrarTest,
CheckDisplayOverrideFromGetEffectiveDisplayModeFromManifest) { … }
TEST_F(WebAppRegistrarTest, WindowControlsOverlay) { … }
TEST_F(WebAppRegistrarTest, IsRegisteredLaunchProtocol) { … }
TEST_F(WebAppRegistrarTest, TestIsDefaultManagementInstalled) { … }
TEST_F(WebAppRegistrarTest, DefaultNotActivelyInstalled) { … }
#if !BUILDFLAG(IS_CHROMEOS)
TEST_F(WebAppRegistrarTest, AppsOverlapIfSharesScope) { … }
TEST_F(WebAppRegistrarTest, AppsDoNotOverlapIfNestedScope) { … }
#endif
class WebAppRegistrarTest_ScopeExtensions : public WebAppRegistrarTest { … };
TEST_F(WebAppRegistrarTest_ScopeExtensions, IsUrlInAppExtendedScope) { … }
TEST_F(WebAppRegistrarTest_TabStrip, TabbedAppNewTabUrl) { … }
TEST_F(WebAppRegistrarTest_TabStrip, TabbedAppAutoNewTabUrl) { … }
TEST_F(WebAppRegistrarTest, VerifyPlaceholderFinderBehavior) { … }
TEST_F(WebAppRegistrarTest, InnerAndOuterScopeIntentPicker) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
class WebAppRegistrarAshTest : public WebAppTest, public WithCrosapiParam {
public:
void SetUp() override {
auto user_manager = std::make_unique<ash::FakeChromeUserManager>();
auto* fake_user_manager = user_manager.get();
scoped_user_manager_ = std::make_unique<user_manager::ScopedUserManager>(
std::move(user_manager));
auto* user = fake_user_manager->AddUser(user_manager::StubAccountId());
fake_user_manager->UserLoggedIn(user_manager::StubAccountId(),
user->username_hash(),
false,
false);
WebAppTest::SetUp();
VerifyLacrosStatus();
}
WebAppRegistrarAshTest() = default;
~WebAppRegistrarAshTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager_;
};
TEST_P(WebAppRegistrarAshTest, SourceSupported) {
const GURL example_url("https://example.com/my-app/start");
const GURL swa_url("chrome://swa/start");
const GURL uninstalling_url("https://example.com/uninstalling/start");
webapps::AppId example_id;
webapps::AppId swa_id;
webapps::AppId uninstalling_id;
WebAppRegistrarMutable registrar(profile());
{
Registry registry;
auto example_app = test::CreateWebApp(example_url);
example_id = example_app->app_id();
registry.emplace(example_id, std::move(example_app));
auto swa_app = test::CreateWebApp(swa_url, WebAppManagement::Type::kSystem);
swa_id = swa_app->app_id();
registry.emplace(swa_id, std::move(swa_app));
auto uninstalling_app =
test::CreateWebApp(uninstalling_url, WebAppManagement::Type::kSystem);
uninstalling_app->SetIsUninstalling(true);
uninstalling_id = uninstalling_app->app_id();
registry.emplace(uninstalling_id, std::move(uninstalling_app));
registrar.InitRegistry(std::move(registry));
}
if (GetParam() == CrosapiParam::kEnabled) {
EXPECT_EQ(registrar.CountUserInstalledApps(), 0);
EXPECT_EQ(CountApps(registrar.GetApps()), 1);
EXPECT_FALSE(registrar.FindAppWithUrlInScope(example_url).has_value());
EXPECT_TRUE(registrar.GetAppScope(example_id).is_empty());
EXPECT_FALSE(registrar.GetAppUserDisplayMode(example_id).has_value());
} else {
EXPECT_EQ(registrar.CountUserInstalledApps(), 1);
EXPECT_EQ(CountApps(registrar.GetApps()), 2);
EXPECT_EQ(registrar.FindAppWithUrlInScope(example_url), example_id);
EXPECT_EQ(registrar.GetAppScope(example_id),
GURL("https://example.com/my-app/"));
EXPECT_TRUE(registrar.GetAppUserDisplayMode(example_id).has_value());
}
EXPECT_EQ(registrar.FindAppWithUrlInScope(swa_url), swa_id);
EXPECT_EQ(registrar.GetAppScope(swa_id), GURL("chrome://swa/"));
EXPECT_TRUE(registrar.GetAppUserDisplayMode(swa_id).has_value());
EXPECT_FALSE(registrar.FindAppWithUrlInScope(uninstalling_url).has_value());
EXPECT_EQ(registrar.GetAppScope(uninstalling_id),
GURL("https://example.com/uninstalling/"));
EXPECT_TRUE(registrar.GetAppUserDisplayMode(uninstalling_id).has_value());
EXPECT_FALSE(base::Contains(registrar.GetAppIds(), uninstalling_id));
}
INSTANTIATE_TEST_SUITE_P(All,
WebAppRegistrarAshTest,
::testing::Values(CrosapiParam::kEnabled,
CrosapiParam::kDisabled),
WithCrosapiParam::ParamToString);
#endif
#if BUILDFLAG(IS_CHROMEOS_LACROS)
using WebAppRegistrarLacrosTest = WebAppTest;
TEST_F(WebAppRegistrarLacrosTest, SwaSourceNotSupported) {
const GURL example_url("https://example.com/my-app/start");
const GURL swa_url("chrome://swa/start");
const GURL uninstalling_url("https://example.com/uninstalling/start");
webapps::AppId example_id;
webapps::AppId swa_id;
webapps::AppId uninstalling_id;
WebAppRegistrarMutable registrar(profile());
{
Registry registry;
auto example_app = test::CreateWebApp(example_url);
example_id = example_app->app_id();
registry.emplace(example_id, std::move(example_app));
auto swa_app = test::CreateWebApp(swa_url, WebAppManagement::Type::kSystem);
swa_id = swa_app->app_id();
registry.emplace(swa_id, std::move(swa_app));
auto uninstalling_app = test::CreateWebApp(uninstalling_url);
uninstalling_app->SetIsUninstalling(true);
uninstalling_id = uninstalling_app->app_id();
registry.emplace(uninstalling_id, std::move(uninstalling_app));
registrar.InitRegistry(std::move(registry));
}
EXPECT_EQ(registrar.FindAppWithUrlInScope(example_url), example_id);
EXPECT_EQ(registrar.GetAppScope(example_id),
GURL("https://example.com/my-app/"));
EXPECT_TRUE(registrar.GetAppUserDisplayMode(example_id).has_value());
EXPECT_EQ(registrar.CountUserInstalledApps(), 1);
EXPECT_EQ(CountApps(registrar.GetApps()), 1);
EXPECT_FALSE(registrar.FindAppWithUrlInScope(swa_url).has_value());
EXPECT_TRUE(registrar.GetAppScope(swa_id).is_empty());
EXPECT_FALSE(registrar.GetAppUserDisplayMode(swa_id).has_value());
EXPECT_FALSE(registrar.FindAppWithUrlInScope(uninstalling_url).has_value());
EXPECT_EQ(registrar.GetAppScope(uninstalling_id),
GURL("https://example.com/uninstalling/"));
EXPECT_TRUE(registrar.GetAppUserDisplayMode(uninstalling_id).has_value());
EXPECT_FALSE(base::Contains(registrar.GetAppIds(), uninstalling_id));
}
#endif
}