chromium/chromeos/ash/components/disks/suspend_unmount_manager_unittest.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string>
#include <vector>

#include "base/ranges/algorithm.h"
#include "chromeos/ash/components/disks/disk_mount_manager.h"
#include "chromeos/ash/components/disks/mock_disk_mount_manager.h"
#include "chromeos/ash/components/disks/suspend_unmount_manager.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power_manager/suspend.pb.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash {
namespace disks {
namespace {

const char kDeviceId[] = "device_id";
const char kDeviceLabel[] = "device_label";
const char kVendor[] = "vendor";
const char kProduct[] = "product";
const char kFileSystemType[] = "exfat";

class FakeDiskMountManager : public MockDiskMountManager {
 public:
  void NotifyUnmountDeviceComplete(MountError error) {
    for (size_t i = 0; i < callbacks_.size(); i++) {
      std::move(callbacks_[i]).Run(error);
    }
    callbacks_.clear();
  }

  const std::vector<std::string>& unmounting_mount_paths() const {
    return unmounting_mount_paths_;
  }

 private:
  void UnmountPath(const std::string& mount_path,
                   UnmountPathCallback callback) override {
    unmounting_mount_paths_.push_back(mount_path);
    callbacks_.push_back(std::move(callback));
  }
  std::vector<std::string> unmounting_mount_paths_;
  std::vector<UnmountPathCallback> callbacks_;
};

class SuspendUnmountManagerTest : public testing::Test {
 public:
  SuspendUnmountManagerTest() {
    chromeos::PowerManagerClient::InitializeFake();
    suspend_unmount_manager_ =
        std::make_unique<SuspendUnmountManager>(&disk_mount_manager_);
  }

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

  ~SuspendUnmountManagerTest() override {
    suspend_unmount_manager_.reset();
    chromeos::PowerManagerClient::Shutdown();
  }

 protected:
  FakeDiskMountManager disk_mount_manager_;
  std::unique_ptr<SuspendUnmountManager> suspend_unmount_manager_;
};

TEST_F(SuspendUnmountManagerTest, Basic) {
  const std::string kDummyMountPathUsb = "/dummy/mount/usb";
  const std::string kDummyMountPathSd = "/dummy/mount/sd";
  const std::string kDummyMountPathUnknown = "/dummy/mount/unknown";
  disk_mount_manager_.CreateDiskEntryForMountDevice(
      {"/dummy/device/usb", kDummyMountPathUsb, MountType::kDevice}, kDeviceId,
      kDeviceLabel, kVendor, kProduct, DeviceType::kUSB, 1024 * 1024,
      false /* is_parent */, false /* has_media */, false /* on_boot_device */,
      true /* on_removable_device */, kFileSystemType);
  disk_mount_manager_.CreateDiskEntryForMountDevice(
      {"/dummy/device/sd", kDummyMountPathSd, MountType::kDevice}, kDeviceId,
      kDeviceLabel, kVendor, kProduct, DeviceType::kSD, 1024 * 1024,
      false /* is_parent */, false /* has_media */, false /* on_boot_device */,
      true /* on_removable_device */, kFileSystemType);
  disk_mount_manager_.CreateDiskEntryForMountDevice(
      {"/dummy/device/unknown", kDummyMountPathUnknown, MountType::kDevice},
      kDeviceId, kDeviceLabel, kVendor, kProduct, DeviceType::kUnknown,
      1024 * 1024, false /* is_parent */, false /* has_media */,
      false /* on_boot_device */, true /* on_removable_device */,
      kFileSystemType);
  disk_mount_manager_.SetupDefaultReplies();
  chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
      power_manager::SuspendImminent_Reason_OTHER);

  EXPECT_EQ(1, chromeos::FakePowerManagerClient::Get()
                   ->num_pending_suspend_readiness_callbacks());
  EXPECT_EQ(2u, disk_mount_manager_.unmounting_mount_paths().size());
  EXPECT_EQ(1, base::ranges::count(disk_mount_manager_.unmounting_mount_paths(),
                                   kDummyMountPathUsb));
  EXPECT_EQ(1, base::ranges::count(disk_mount_manager_.unmounting_mount_paths(),
                                   kDummyMountPathSd));
  EXPECT_EQ(0, base::ranges::count(disk_mount_manager_.unmounting_mount_paths(),
                                   kDummyMountPathUnknown));
  disk_mount_manager_.NotifyUnmountDeviceComplete(MountError::kSuccess);
  EXPECT_EQ(0, chromeos::FakePowerManagerClient::Get()
                   ->num_pending_suspend_readiness_callbacks());
}

TEST_F(SuspendUnmountManagerTest, CancelAndSuspendAgain) {
  const std::string kDummyMountPath = "/dummy/mount";
  disk_mount_manager_.CreateDiskEntryForMountDevice(
      {"/dummy/device", kDummyMountPath, MountType::kDevice}, kDeviceId,
      kDeviceLabel, kVendor, kProduct, DeviceType::kUSB, 1024 * 1024,
      false /* is_parent */, false /* has_media */, false /* on_boot_device */,
      true /* on_removable_device */, kFileSystemType);
  disk_mount_manager_.SetupDefaultReplies();
  chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
      power_manager::SuspendImminent_Reason_OTHER);
  EXPECT_EQ(1, chromeos::FakePowerManagerClient::Get()
                   ->num_pending_suspend_readiness_callbacks());
  ASSERT_EQ(1u, disk_mount_manager_.unmounting_mount_paths().size());
  EXPECT_EQ(kDummyMountPath,
            disk_mount_manager_.unmounting_mount_paths().front());

  // Suspend cancelled.
  chromeos::FakePowerManagerClient::Get()->SendSuspendDone();

  // Suspend again.
  chromeos::FakePowerManagerClient::Get()->SendSuspendImminent(
      power_manager::SuspendImminent_Reason_OTHER);
  ASSERT_EQ(2u, disk_mount_manager_.unmounting_mount_paths().size());
  EXPECT_EQ(kDummyMountPath,
            disk_mount_manager_.unmounting_mount_paths().front());
}

}  // namespace
}  // namespace disks
}  // namespace ash