chromium/chrome/browser/ash/crostini/crostini_browser_test_util.cc

// Copyright 2020 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/crostini/crostini_browser_test_util.h"

#include <utility>

#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ash/crostini/crostini_pref_names.h"
#include "chrome/browser/ash/crostini/fake_crostini_features.h"
#include "chrome/browser/ash/guest_os/public/guest_os_service.h"
#include "chrome/browser/ash/guest_os/public/guest_os_wayland_server.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
#include "components/component_updater/ash/fake_component_manager_ash.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/network_connection_change_simulator.h"
#include "third_party/cros_system_api/dbus/service_constants.h"

// ChromeBrowserMainExtraParts used to install a FakeComponentManagerAsh.
class CrostiniBrowserTestChromeBrowserMainExtraParts
    : public ChromeBrowserMainExtraParts {
 public:
  explicit CrostiniBrowserTestChromeBrowserMainExtraParts(bool register_termina)
      : register_termina_(register_termina) {}

  CrostiniBrowserTestChromeBrowserMainExtraParts(
      const CrostiniBrowserTestChromeBrowserMainExtraParts&) = delete;
  CrostiniBrowserTestChromeBrowserMainExtraParts& operator=(
      const CrostiniBrowserTestChromeBrowserMainExtraParts&) = delete;

  component_updater::FakeComponentManagerAsh* component_manager_ash() {
    return component_manager_ash_ptr_;
  }

  content::NetworkConnectionChangeSimulator* connection_change_simulator() {
    return &connection_change_simulator_;
  }

  // ChromeBrowserMainExtraParts:
  void PostEarlyInitialization() override {
    auto component_manager_ash =
        base::MakeRefCounted<component_updater::FakeComponentManagerAsh>();
    component_manager_ash->set_supported_components(
        {imageloader::kTerminaComponentName});

    if (register_termina_) {
      component_manager_ash->SetRegisteredComponents(
          {imageloader::kTerminaComponentName});
      component_manager_ash->ResetComponentState(
          imageloader::kTerminaComponentName,
          component_updater::FakeComponentManagerAsh::ComponentInfo(
              component_updater::ComponentManagerAsh::Error::NONE,
              base::FilePath("/dev/null"), base::FilePath("/dev/null")));
    }
    component_manager_ash_ptr_ = component_manager_ash.get();

    browser_process_platform_part_test_api_ =
        std::make_unique<BrowserProcessPlatformPartTestApi>(
            g_browser_process->platform_part());
    browser_process_platform_part_test_api_->InitializeComponentManager(
        std::move(component_manager_ash));
  }
  // Ideally we'd call SetConnectionType in PostCreateThreads, but currently we
  // have to wait for PreProfileInit to complete, since that creatse the
  // ash::Shell that AshService needs in order to start.
  void PostProfileInit(Profile* profile, bool is_initial_profile) override {
    // The setup below is intended to run for only the initial profile.
    if (!is_initial_profile) {
      return;
    }

    connection_change_simulator_.SetConnectionType(
        network::mojom::ConnectionType::CONNECTION_WIFI);
  }
  void PostMainMessageLoopRun() override {
    component_manager_ash_ptr_ = nullptr;
    browser_process_platform_part_test_api_->ShutdownComponentManager();
    browser_process_platform_part_test_api_.reset();
  }

 private:
  const bool register_termina_;

  std::unique_ptr<BrowserProcessPlatformPartTestApi>
      browser_process_platform_part_test_api_;
  raw_ptr<component_updater::FakeComponentManagerAsh>
      component_manager_ash_ptr_ = nullptr;

  content::NetworkConnectionChangeSimulator connection_change_simulator_;
};

CrostiniBrowserTestBase::CrostiniBrowserTestBase(bool register_termina)
    : register_termina_(register_termina) {
  scoped_feature_list_.InitAndEnableFeature(features::kCrostini);
  fake_crostini_features_.SetAll(true);

  dmgr_ = new ash::disks::MockDiskMountManager;
  ON_CALL(*dmgr_, MountPath)
      .WillByDefault(Invoke(this, &CrostiniBrowserTestBase::DiskMountImpl));
  // Test object will be deleted by DiskMountManager::Shutdown
  ash::disks::DiskMountManager::InitializeForTesting(dmgr_);
}
void CrostiniBrowserTestBase::DiskMountImpl(
    const std::string& source_path,
    const std::string& source_format,
    const std::string& mount_label,
    const std::vector<std::string>& mount_options,
    ash::MountType type,
    ash::MountAccessMode access_mode,
    ash::disks::DiskMountManager::MountPathCallback callback) {
  const ash::disks::DiskMountManager::MountPoint info{source_path,
                                                      "/path/to/mount", type};
  std::move(callback).Run(ash::MountError::kSuccess, info);
  dmgr_->NotifyMountEvent(ash::disks::DiskMountManager::MountEvent::MOUNTING,
                          ash::MountError::kSuccess, info);
}

void CrostiniBrowserTestBase::CreatedBrowserMainParts(
    content::BrowserMainParts* browser_main_parts) {
  ChromeBrowserMainParts* chrome_browser_main_parts =
      static_cast<ChromeBrowserMainParts*>(browser_main_parts);
  extra_parts_ =
      new CrostiniBrowserTestChromeBrowserMainExtraParts(register_termina_);
  chrome_browser_main_parts->AddParts(base::WrapUnique(extra_parts_.get()));
}

void CrostiniBrowserTestBase::SetUpOnMainThread() {
  browser()->profile()->GetPrefs()->SetBoolean(
      crostini::prefs::kCrostiniEnabled, true);
}

void CrostiniBrowserTestBase::SetConnectionType(
    network::mojom::ConnectionType connection_type) {
  extra_parts_->connection_change_simulator()->SetConnectionType(
      connection_type);
}

void CrostiniBrowserTestBase::UnregisterTermina() {
  extra_parts_->component_manager_ash()->ResetComponentState(
      imageloader::kTerminaComponentName,
      component_updater::FakeComponentManagerAsh::ComponentInfo(
          component_updater::ComponentManagerAsh::Error::INSTALL_FAILURE,
          base::FilePath(), base::FilePath()));
}