chromium/chrome/browser/apps/app_service/app_install/web_app_installer_lacros_browsertest.cc

// Copyright 2024 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/apps/app_service/app_install/web_app_installer.h"

#include "base/functional/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/test_future.h"
#include "chrome/browser/apps/app_service/app_registry_cache_waiter.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/ash/crosapi/ash_requires_lacros_browsertestbase.h"
#include "chrome/browser/ash/crosapi/browser_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/test/base/chromeos/ash_browser_test_starter.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/services/app_service/public/cpp/app_registry_cache.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/app_update.h"
#include "components/webapps/browser/install_result_code.h"
#include "content/public/test/browser_test.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace apps {

class WebAppInstallerLacrosBrowserTest
    : public crosapi::AshRequiresLacrosBrowserTestBase {
 public:
  void SetUp() override {
    if (!HasLacrosArgument()) {
      GTEST_SKIP() << "Skipping test class because Lacros is not enabled";
    }
    AshRequiresLacrosBrowserTestBase::SetUp();
  }

  void SetUpOnMainThread() override {
    AshRequiresLacrosBrowserTestBase::SetUpOnMainThread();

    https_server_.RegisterRequestHandler(
        base::BindRepeating(&WebAppInstallerLacrosBrowserTest::HandleRequest,
                            base::Unretained(this)));
    https_server_.AddDefaultHandlers(GetChromeTestDataDir());

    ASSERT_TRUE(https_server_.Start());
  }

  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
      const net::test_server::HttpRequest& request) {
    if (request.relative_url != "/manifest.json" || manifest_.empty()) {
      return nullptr;
    }

    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
    response->set_code(net::HTTP_OK);
    response->set_content_type("application/json");
    response->set_content(manifest_);
    return response;
  }

  std::string AddIconToManifest(const std::string& manifest_template) {
    GURL icon_url = https_server()->GetURL("/web_apps/blue-192.png");
    constexpr char kIconsBlock[] = R"([{
        "src": "$1",
        "sizes": "192x192",
        "type": "image/png"
      }])";
    std::string icon_value = base::ReplaceStringPlaceholders(
        kIconsBlock, {icon_url.spec()}, nullptr);
    return base::ReplaceStringPlaceholders(manifest_template, {icon_value},
                                           nullptr);
  }

  void SetManifestResponse(std::string manifest) { manifest_ = manifest; }

  net::EmbeddedTestServer* https_server() { return &https_server_; }

  AppRegistryCache& app_registry_cache() {
    auto* proxy = AppServiceProxyFactory::GetForProfile(GetAshProfile());
    return proxy->AppRegistryCache();
  }

 private:
  net::EmbeddedTestServer https_server_;
  std::string manifest_;
};

IN_PROC_BROWSER_TEST_F(WebAppInstallerLacrosBrowserTest, InstallApp) {
  // Assert Lacros is running.
  ASSERT_TRUE(crosapi::BrowserManager::Get()->IsRunning());

  AppInstallData app_install_data(
      PackageId::FromString("web:https://www.example.com/index.html").value());
  app_install_data.name = "Example app";
  WebAppInstallData& web_app_data =
      app_install_data.app_type_data.emplace<WebAppInstallData>();
  web_app_data.original_manifest_url =
      GURL("https://www.example.com/manifest.json");
  web_app_data.proxied_manifest_url = https_server()->GetURL("/manifest.json");
  web_app_data.document_url = GURL("https://www.example.com");

  constexpr char kManifestTemplate[] = R"({
    "name": "Example App",
    "start_url": "/index.html",
    "scope": "/",
    "icons": $1
  })";

  SetManifestResponse(AddIconToManifest(kManifestTemplate));

  base::HistogramTester histograms;
  base::test::TestFuture<bool> result;

  // Install the app.
  WebAppInstaller installer(GetAshProfile());
  installer.InstallApp(AppInstallSurface::kAppPreloadServiceOem,
                       std::move(app_install_data), result.GetCallback());
  ASSERT_TRUE(result.Get());

  // Check the app is installed in app_registry_cache.
  auto app_id = web_app::GenerateAppId(
      std::nullopt, GURL("https://www.example.com/index.html"));

  // Wait for update to be registered with the app registry cache.
  AppReadinessWaiter(GetAshProfile(), app_id).Await();
  bool found =
      app_registry_cache().ForOneApp(app_id, [](const AppUpdate& update) {
        EXPECT_EQ(update.Name(), "Example App");
        EXPECT_EQ(update.InstallReason(), InstallReason::kOem);
      });
  ASSERT_TRUE(found);

  histograms.ExpectBucketCount(
      "Apps.AppInstallService.WebAppInstaller.InstallResult",
      WebAppInstallResult::kSuccess, 1);
  histograms.ExpectBucketCount(
      "Apps.AppInstallService.WebAppInstaller.InstallResult."
      "AppPreloadServiceOem",
      WebAppInstallResult::kSuccess, 1);
  histograms.ExpectBucketCount(
      "Apps.AppInstallService.WebAppInstaller.CommandResultCode",
      webapps::InstallResultCode::kSuccessNewInstall, 1);
  histograms.ExpectBucketCount(
      "Apps.AppInstallService.WebAppInstaller.CommandResultCode."
      "AppPreloadServiceOem",
      webapps::InstallResultCode::kSuccessNewInstall, 1);
}

}  // namespace apps