chromium/chrome/browser/web_applications/web_app_registrar_unittest.cc

// Copyright 2018 The Chromium Authors
// 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/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) {}

}  // namespace

ElementsAre;
Pair;

// TODO(dmurph): Make this test run from the default FakeWebAppProvider like all
// other unittests.
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) {}

// Link capturing preferences & overlapping scopes have custom behavior on CrOS.
#if !BUILDFLAG(IS_CHROMEOS)
TEST_F(WebAppRegistrarTest, AppsOverlapIfSharesScope) {}

TEST_F(WebAppRegistrarTest, AppsDoNotOverlapIfNestedScope) {}
#endif  // !BUILDFLAG(IS_CHROMEOS)

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 {
    // Set up user manager to so that Lacros mode can be enabled.
    // TODO(crbug.com/40275387): Consider setting up a fake user in all Ash web
    // app tests.
    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(),
                                    /*browser_restart=*/false,
                                    /*is_child=*/false);
    // Need to run the WebAppTest::SetUp() after the fake user manager set up
    // so that the scoped_user_manager can be destructed in the correct order.
    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) {
    // Non-system web apps are managed by Lacros, excluded in Ash
    // WebAppRegistrar.
    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);

  // System web apps are managed by Ash, excluded in Lacros
  // WebAppRegistrar.
  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  // BUILDFLAG(IS_CHROMEOS_LACROS)

}  // namespace web_app