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

// Copyright 2019 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_util.h"

#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/test_future.h"
#include "chrome/browser/ash/crostini/crostini_manager.h"
#include "chrome/browser/ash/crostini/crostini_pref_names.h"
#include "chrome/browser/ash/crostini/crostini_test_helper.h"
#include "chrome/browser/ash/guest_os/guest_os_pref_names.h"
#include "chrome/test/base/browser_process_platform_part_test_api_chromeos.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/dbus/chunneld/chunneld_client.h"
#include "chromeos/ash/components/dbus/cicerone/cicerone_client.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/ash/components/dbus/concierge/fake_concierge_client.h"
#include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
#include "chromeos/ash/components/dbus/seneschal/seneschal_client.h"
#include "components/component_updater/ash/fake_component_manager_ash.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"

constexpr char kDesktopFileId[] = "dummy1";
constexpr int kDisplayId = 0;

namespace crostini {

class CrostiniUtilTest : public testing::Test {
 public:
  CrostiniUtilTest()
      : app_id_(crostini::CrostiniTestHelper::GenerateAppId(kDesktopFileId)),
        task_environment_(content::BrowserTaskEnvironment::REAL_IO_THREAD),
        local_state_(std::make_unique<ScopedTestingLocalState>(
            TestingBrowserProcess::GetGlobal())),
        browser_part_(g_browser_process->platform_part()) {
    ash::ChunneldClient::InitializeFake();
    ash::CiceroneClient::InitializeFake();
    ash::ConciergeClient::InitializeFake();
    ash::DebugDaemonClient::InitializeFake();
    ash::SeneschalClient::InitializeFake();

    fake_concierge_client_ = ash::FakeConciergeClient::Get();
  }

  ~CrostiniUtilTest() override {
    ash::SeneschalClient::Shutdown();
    ash::DebugDaemonClient::Shutdown();
    ash::ConciergeClient::Shutdown();
    ash::CiceroneClient::Shutdown();
    ash::ChunneldClient::Shutdown();
  }

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

  void SetUp() override {
    ash::DlcserviceClient::InitializeFake();

    component_manager_ =
        base::MakeRefCounted<component_updater::FakeComponentManagerAsh>();
    component_manager_->set_supported_components({"cros-termina"});
    component_manager_->ResetComponentState(
        "cros-termina",
        component_updater::FakeComponentManagerAsh::ComponentInfo(
            component_updater::ComponentManagerAsh::Error::NONE,
            base::FilePath("/install/path"), base::FilePath("/mount/path")));
    browser_part_.InitializeComponentManager(component_manager_);

    profile_ = std::make_unique<TestingProfile>();
    test_helper_ = std::make_unique<CrostiniTestHelper>(profile_.get());
    test_helper_->SetupDummyApps();
    g_browser_process->platform_part()
        ->InitializeSchedulerConfigurationManager();
  }

  void TearDown() override {
    g_browser_process->platform_part()->ShutdownSchedulerConfigurationManager();
    test_helper_.reset();
    profile_.reset();
    browser_part_.ShutdownComponentManager();
    component_manager_.reset();
    ash::DlcserviceClient::Shutdown();
  }

 protected:
  raw_ptr<ash::FakeConciergeClient, DanglingUntriaged> fake_concierge_client_;

  std::unique_ptr<TestingProfile> profile_;
  std::unique_ptr<CrostiniTestHelper> test_helper_;
  std::string app_id_;

 private:
  content::BrowserTaskEnvironment task_environment_;
  std::unique_ptr<ScopedTestingLocalState> local_state_;
  scoped_refptr<component_updater::FakeComponentManagerAsh> component_manager_;
  BrowserProcessPlatformPartTestApi browser_part_;
};

TEST_F(CrostiniUtilTest, LaunchCallbackRunsOnRestartError) {
  // Set Restart to fail.
  fake_concierge_client_->set_start_vm_response({});

  base::test::TestFuture<bool, const std::string&> result_future;
  // Launch should fail and invoke callback.
  LaunchCrostiniApp(profile_.get(), app_id_, kDisplayId, {},
                    result_future.GetCallback());
  EXPECT_FALSE(result_future.Get<0>());
  EXPECT_EQ(
      "crostini restart to launch app "
      "pfdnkhehloenlegacemoalhjljmpllpc failed: 5",
      result_future.Get<1>());
}

TEST_F(CrostiniUtilTest, ShouldStopVm) {
  CrostiniManager* manager = CrostiniManager::GetForProfile(profile_.get());
  guest_os::GuestId containera(kCrostiniDefaultVmType, "apple", "banana");
  guest_os::GuestId containerb(kCrostiniDefaultVmType, "potato", "strawberry");
  base::Value::List containers;
  containers.Append(containera.ToDictValue().Clone());
  containers.Append(containerb.ToDictValue().Clone());

  manager->AddRunningVmForTesting("apple");
  manager->AddRunningVmForTesting("potato");
  manager->AddRunningContainerForTesting(
      "apple", ContainerInfo("banana", "bo", "home", "1.2.3.4"));
  manager->AddRunningContainerForTesting(
      "potato", ContainerInfo("strawberry", "bo", "home", "1.2.3.4"));

  ASSERT_TRUE(manager->IsVmRunning("apple"));
  ASSERT_TRUE(manager->IsVmRunning("potato"));

  profile_->GetPrefs()->SetList(guest_os::prefs::kGuestOsContainers,
                                std::move(containers));

  EXPECT_TRUE(ShouldStopVm(profile_.get(), containera));
}

TEST_F(CrostiniUtilTest, ShouldNotStopVm) {
  CrostiniManager* manager = CrostiniManager::GetForProfile(profile_.get());
  guest_os::GuestId containera(kCrostiniDefaultVmType, "apple", "banana");
  guest_os::GuestId containerb(kCrostiniDefaultVmType, "apple", "strawberry");
  base::Value::List containers;
  containers.Append(containera.ToDictValue().Clone());
  containers.Append(containerb.ToDictValue().Clone());

  manager->AddRunningVmForTesting("apple");
  manager->AddRunningContainerForTesting(
      "apple", ContainerInfo("banana", "bo", "home", "1.2.3.4"));
  manager->AddRunningContainerForTesting(
      "apple", ContainerInfo("strawberry", "bo", "home", "1.2.3.4"));

  ASSERT_TRUE(manager->IsVmRunning("apple"));

  profile_->GetPrefs()->SetList(guest_os::prefs::kGuestOsContainers,
                                std::move(containers));

  EXPECT_FALSE(ShouldStopVm(profile_.get(), containera));
}

}  // namespace crostini