chromium/chrome/browser/ash/crosapi/stateful_lacros_loader_unittest.cc

// Copyright 2023 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/ash/crosapi/stateful_lacros_loader.h"

#include <memory>
#include <string_view>

#include "base/auto_reset.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_path_override.h"
#include "base/test/test_future.h"
#include "base/version.h"
#include "chrome/browser/ash/crosapi/browser_loader.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
#include "chromeos/ash/components/standalone_browser/browser_support.h"
#include "components/component_updater/ash/fake_component_manager_ash.h"
#include "components/component_updater/component_updater_paths.h"
#include "components/component_updater/mock_component_updater_service.h"
#include "components/update_client/update_client.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace crosapi {
namespace {

using testing::Return;

constexpr char kLacrosComponentName[] = "lacros-dogfood-dev";
constexpr char kLacrosComponentId[] = "ldobopbhiamakmncndpkeelenhdmgfhk";

class StatefulLacrosLoaderTest : public testing::Test {
 public:
  StatefulLacrosLoaderTest() {
    // Create dependencies for object under test.
    component_manager_ =
        base::MakeRefCounted<component_updater::FakeComponentManagerAsh>();
    component_manager_->set_supported_components({kLacrosComponentName});
    component_manager_->ResetComponentState(
        kLacrosComponentName,
        component_updater::FakeComponentManagerAsh::ComponentInfo(
            component_updater::ComponentManagerAsh::Error::NONE,
            base::FilePath("/install/path"), base::FilePath("/mount/path"),
            version));
    browser_part_ = std::make_unique<BrowserProcessPlatformPartTestApi>(
        g_browser_process->platform_part());
    browser_part_->InitializeComponentManager(component_manager_);

    // Set up component path.
    base::FilePath root_dir;
    CHECK(base::PathService::Get(component_updater::DIR_COMPONENT_USER,
                                 &root_dir));
    base::FilePath component_root =
        root_dir.Append(component_updater::kComponentsRootPath)
            .Append(kLacrosComponentName);
    base::CreateDirectory(component_root.Append("sub-dir"));

    stateful_lacros_loader_ = std::make_unique<StatefulLacrosLoader>(
        component_manager_, &mock_component_update_service_,
        kLacrosComponentName);
    EXPECT_TRUE(BrowserLoader::WillLoadStatefulComponentBuilds());
  }

  ~StatefulLacrosLoaderTest() override {
    stateful_lacros_loader_.reset();

    browser_part_->ShutdownComponentManager();
  }

  const base::Version version = base::Version("1.0.0");

 protected:
  content::BrowserTaskEnvironment task_environment_;

  base::ScopedPathOverride scoped_component_user_dir_{
      component_updater::DIR_COMPONENT_USER};
  component_updater::MockComponentUpdateService mock_component_update_service_;
  scoped_refptr<component_updater::FakeComponentManagerAsh> component_manager_;
  std::unique_ptr<BrowserProcessPlatformPartTestApi> browser_part_;
  std::unique_ptr<StatefulLacrosLoader> stateful_lacros_loader_;
};

TEST_F(StatefulLacrosLoaderTest,
       LoadStatefulLacrosSelectedByCompatibilityCheck) {
  std::u16string lacros_component_name =
      base::UTF8ToUTF16(std::string_view(kLacrosComponentName));
  EXPECT_CALL(mock_component_update_service_, GetComponents())
      .WillOnce(Return(std::vector<component_updater::ComponentInfo>{
          {kLacrosComponentId, "", lacros_component_name, version, ""}}));

  EXPECT_EQ(StatefulLacrosLoader::State::kNotLoaded,
            stateful_lacros_loader_->GetState());

  // If stateful is selected by compatibility check, it first calls GetVersion
  // and complete loading, and then Load is called.
  base::test::TestFuture<const base::Version&> future;
  stateful_lacros_loader_->GetVersion(
      future.GetCallback<const base::Version&>());
  EXPECT_EQ(version, future.Get<0>());
  EXPECT_EQ(StatefulLacrosLoader::State::kLoaded,
            stateful_lacros_loader_->GetState());

  // Load is already completed in GetVersion, so this call is synchronous.
  base::Version result_version;
  stateful_lacros_loader_->Load(
      base::BindOnce([](base::Version* result_version, base::Version version,
                        const base::FilePath&) { *result_version = version; },
                     &result_version),
      /*forced=*/false);
  EXPECT_EQ(version, result_version);
}

TEST_F(StatefulLacrosLoaderTest, LoadStatefulLacrosSelectedByPolicy) {
  std::u16string lacros_component_name =
      base::UTF8ToUTF16(std::string_view(kLacrosComponentName));
  EXPECT_CALL(mock_component_update_service_, GetComponents())
      .WillOnce(Return(std::vector<component_updater::ComponentInfo>{
          {kLacrosComponentId, "", lacros_component_name, version, ""}}));

  EXPECT_EQ(StatefulLacrosLoader::State::kNotLoaded,
            stateful_lacros_loader_->GetState());

  // If stateful is forced by policy, it does not call GetVersion. Instead, it
  // calls Load directly and compute the version inside Load together.
  base::test::TestFuture<base::Version, const base::FilePath&> future;
  stateful_lacros_loader_->Load(
      future.GetCallback<base::Version, const base::FilePath&>(),
      /*forced=*/true);
  EXPECT_EQ(version, future.Get<0>());
}

}  // namespace
}  // namespace crosapi