chromium/chromeos/ash/components/dbus/concierge/fake_concierge_client.cc

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

#include "chromeos/ash/components/dbus/concierge/fake_concierge_client.h"

#include <utility>

#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "chromeos/ash/components/dbus/cicerone/fake_cicerone_client.h"

namespace ash {

namespace {

FakeConciergeClient* g_instance = nullptr;

}  // namespace

// static
FakeConciergeClient* FakeConciergeClient::Get() {
  return g_instance;
}

FakeConciergeClient::FakeConciergeClient(
    FakeCiceroneClient* fake_cicerone_client)
    : fake_cicerone_client_(fake_cicerone_client) {
  DCHECK(!g_instance);
  g_instance = this;

  InitializeProtoResponses();
}

FakeConciergeClient::~FakeConciergeClient() {
  DCHECK_EQ(this, g_instance);
  g_instance = nullptr;
}

void FakeConciergeClient::AddObserver(Observer* observer) {
  observer_list_.AddObserver(observer);
}

void FakeConciergeClient::RemoveObserver(Observer* observer) {
  observer_list_.RemoveObserver(observer);
}

void FakeConciergeClient::NotifyConciergeStopped() {
  for (auto& observer : observer_list_) {
    observer.ConciergeServiceStopped();
  }
}
void FakeConciergeClient::NotifyConciergeStarted() {
  for (auto& observer : observer_list_) {
    observer.ConciergeServiceStarted();
  }
}

void FakeConciergeClient::AddVmObserver(VmObserver* observer) {
  vm_observer_list_.AddObserver(observer);
}

void FakeConciergeClient::RemoveVmObserver(VmObserver* observer) {
  vm_observer_list_.RemoveObserver(observer);
}

void FakeConciergeClient::AddDiskImageObserver(DiskImageObserver* observer) {
  disk_image_observer_list_.AddObserver(observer);
}

void FakeConciergeClient::RemoveDiskImageObserver(DiskImageObserver* observer) {
  disk_image_observer_list_.RemoveObserver(observer);
}

bool FakeConciergeClient::IsVmStartedSignalConnected() {
  return is_vm_started_signal_connected_;
}

bool FakeConciergeClient::IsVmStoppedSignalConnected() {
  return is_vm_stopped_signal_connected_;
}

bool FakeConciergeClient::IsVmStoppingSignalConnected() {
  return is_vm_stopping_signal_connected_;
}

bool FakeConciergeClient::IsDiskImageProgressSignalConnected() {
  return is_disk_image_progress_signal_connected_;
}

void FakeConciergeClient::CreateDiskImage(
    const vm_tools::concierge::CreateDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::CreateDiskImageResponse>
        callback) {
  create_disk_image_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), create_disk_image_response_),
      send_create_disk_image_response_delay_);
}

void FakeConciergeClient::CreateDiskImageWithFd(
    base::ScopedFD fd,
    const vm_tools::concierge::CreateDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::CreateDiskImageResponse>
        callback) {
  create_disk_image_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), create_disk_image_response_));
}

void FakeConciergeClient::DestroyDiskImage(
    const vm_tools::concierge::DestroyDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::DestroyDiskImageResponse>
        callback) {
  destroy_disk_image_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), destroy_disk_image_response_));
}

void FakeConciergeClient::ImportDiskImage(
    base::ScopedFD fd,
    const vm_tools::concierge::ImportDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ImportDiskImageResponse>
        callback) {
  import_disk_image_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), import_disk_image_response_));
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&FakeConciergeClient::NotifyDiskImageProgress,
                                weak_ptr_factory_.GetWeakPtr()));
}

void FakeConciergeClient::CancelDiskImageOperation(
    const vm_tools::concierge::CancelDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::CancelDiskImageResponse>
        callback) {
  // Removes signals sent during disk image import.
  disk_image_status_signals_.clear();
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), cancel_disk_image_response_));
}

void FakeConciergeClient::NotifyDiskImageProgress() {
  // Trigger DiskImageStatus signals.
  for (auto const& signal : disk_image_status_signals_) {
    OnDiskImageProgress(signal);
  }
}

void FakeConciergeClient::OnDiskImageProgress(
    const vm_tools::concierge::DiskImageStatusResponse& signal) {
  for (auto& observer : disk_image_observer_list_) {
    observer.OnDiskImageProgress(signal);
  }
}

void FakeConciergeClient::DiskImageStatus(
    const vm_tools::concierge::DiskImageStatusRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::DiskImageStatusResponse>
        callback) {
  disk_image_status_call_count_++;

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), disk_image_status_response_));
}

void FakeConciergeClient::ListVmDisks(
    const vm_tools::concierge::ListVmDisksRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ListVmDisksResponse>
        callback) {
  list_vm_disks_call_count_++;

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), list_vm_disks_response_));
}

void FakeConciergeClient::StartVm(
    const vm_tools::concierge::StartVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::StartVmResponse>
        callback) {
  start_vm_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE, base::BindOnce(std::move(callback), start_vm_response_),
      send_start_vm_response_delay_);

  if (!start_vm_response_ ||
      start_vm_response_->status() != vm_tools::concierge::VM_STATUS_STARTING) {
    // Don't send the tremplin signal unless the VM was STARTING.
    return;
  }

  // Trigger CiceroneClient::Observer::NotifyTremplinStartedSignal.
  vm_tools::cicerone::TremplinStartedSignal tremplin_started_signal;
  tremplin_started_signal.set_vm_name(request.name());
  tremplin_started_signal.set_owner_id(request.owner_id());
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&FakeConciergeClient::NotifyTremplinStarted,
                     weak_ptr_factory_.GetWeakPtr(),
                     std::move(tremplin_started_signal)),
      send_tremplin_started_signal_delay_);

  // Trigger VmStartedSignal
  vm_tools::concierge::VmStartedSignal vm_started_signal;
  vm_started_signal.set_name(request.name());
  vm_started_signal.set_owner_id(request.owner_id());
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&FakeConciergeClient::NotifyVmStarted,
                                weak_ptr_factory_.GetWeakPtr(),
                                std::move(vm_started_signal)));
}

void FakeConciergeClient::StartVmWithFd(
    base::ScopedFD fd,
    const vm_tools::concierge::StartVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::StartVmResponse>
        callback) {
  StartVm(std::move(request), std::move(callback));
}

void FakeConciergeClient::NotifyTremplinStarted(
    const vm_tools::cicerone::TremplinStartedSignal& signal) {
  DCHECK(fake_cicerone_client_)
      << "|fake_cicerone_client_| is not set. Your test has to call "
      << "ConciergeClient::InitializeFake() with a non-null pointer to "
      << "CiceroniClient e.g. the one returned from FakeCiceroneClient::Get().";
  if (fake_cicerone_client_)
    fake_cicerone_client_->NotifyTremplinStarted(signal);
}

void FakeConciergeClient::StopVm(
    const vm_tools::concierge::StopVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::StopVmResponse>
        callback) {
  stop_vm_call_count_++;
  vm_tools::concierge::VmStoppedSignal signal;
  signal.set_name(request.name());
  signal.set_owner_id(request.owner_id());
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(&FakeConciergeClient::NotifyVmStopped,
                     weak_ptr_factory_.GetWeakPtr(), std::move(signal)));
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), stop_vm_response_));
}

void FakeConciergeClient::SuspendVm(
    const vm_tools::concierge::SuspendVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::SuspendVmResponse>
        callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), suspend_vm_response_));
}

void FakeConciergeClient::ResumeVm(
    const vm_tools::concierge::ResumeVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ResumeVmResponse>
        callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), resume_vm_response_));
}

void FakeConciergeClient::GetVmInfo(
    const vm_tools::concierge::GetVmInfoRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::GetVmInfoResponse>
        callback) {
  get_vm_info_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), get_vm_info_response_));
}

void FakeConciergeClient::GetVmEnterpriseReportingInfo(
    const vm_tools::concierge::GetVmEnterpriseReportingInfoRequest& request,
    chromeos::DBusMethodCallback<
        vm_tools::concierge::GetVmEnterpriseReportingInfoResponse> callback) {
  get_vm_enterprise_reporting_info_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback),
                                get_vm_enterprise_reporting_info_response_));
}

void FakeConciergeClient::ArcVmCompleteBoot(
    const vm_tools::concierge::ArcVmCompleteBootRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ArcVmCompleteBootResponse>
        callback) {
  arcvm_complete_boot_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), arcvm_complete_boot_response_));
}

void FakeConciergeClient::SetVmCpuRestriction(
    const vm_tools::concierge::SetVmCpuRestrictionRequest& request,
    chromeos::DBusMethodCallback<
        vm_tools::concierge::SetVmCpuRestrictionResponse> callback) {
  set_vm_cpu_restriction_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), set_vm_cpu_restriction_response_));
}

void FakeConciergeClient::WaitForServiceToBeAvailable(
    dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
  wait_for_service_to_be_available_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback),
                                wait_for_service_to_be_available_response_));
}

void FakeConciergeClient::AttachUsbDevice(
    base::ScopedFD fd,
    const vm_tools::concierge::AttachUsbDeviceRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::AttachUsbDeviceResponse>
        callback) {
  attach_usb_device_call_count_++;

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), attach_usb_device_response_));
}

void FakeConciergeClient::DetachUsbDevice(
    const vm_tools::concierge::DetachUsbDeviceRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::DetachUsbDeviceResponse>
        callback) {
  detach_usb_device_call_count_++;

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), detach_usb_device_response_));
}

void FakeConciergeClient::StartArcVm(
    const vm_tools::concierge::StartArcVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::StartVmResponse>
        callback) {
  start_arc_vm_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), start_vm_response_));
}

void FakeConciergeClient::ResizeDiskImage(
    const vm_tools::concierge::ResizeDiskImageRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ResizeDiskImageResponse>
        callback) {
  resize_disk_image_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), resize_disk_image_response_));
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(&FakeConciergeClient::NotifyDiskImageProgress,
                                weak_ptr_factory_.GetWeakPtr()));
}

void FakeConciergeClient::ReclaimVmMemory(
    const vm_tools::concierge::ReclaimVmMemoryRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ReclaimVmMemoryResponse>
        callback) {
  reclaim_vm_memory_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), reclaim_vm_memory_response_));
}

void FakeConciergeClient::ListVms(
    const vm_tools::concierge::ListVmsRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::ListVmsResponse>
        callback) {
  list_vms_call_count_++;
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), list_vms_response_));
}

void FakeConciergeClient::GetVmLaunchAllowed(
    const vm_tools::concierge::GetVmLaunchAllowedRequest& request,
    chromeos::DBusMethodCallback<
        vm_tools::concierge::GetVmLaunchAllowedResponse> callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), get_vm_launch_allowed_response_));
}

void FakeConciergeClient::SwapVm(
    const vm_tools::concierge::SwapVmRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::SwapVmResponse>
        callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), swap_vm_response_));
}

void FakeConciergeClient::InstallPflash(
    base::ScopedFD fd,
    const vm_tools::concierge::InstallPflashRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::InstallPflashResponse>
        callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE, base::BindOnce(std::move(callback), install_pflash_response_));
}

void FakeConciergeClient::AggressiveBalloon(
    const vm_tools::concierge::AggressiveBalloonRequest& request,
    chromeos::DBusMethodCallback<vm_tools::concierge::AggressiveBalloonResponse>
        callback) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(std::move(callback), aggressive_balloon_response_));
}

void FakeConciergeClient::NotifyVmStarted(
    const vm_tools::concierge::VmStartedSignal& signal) {
  // Now GetVmInfo can return success.
  get_vm_info_response_->set_success(true);
  for (auto& observer : vm_observer_list_)
    observer.OnVmStarted(signal);
}

void FakeConciergeClient::NotifyVmStopped(
    const vm_tools::concierge::VmStoppedSignal& signal) {
  // Now GetVmInfo can no longer succeed.
  get_vm_info_response_->set_success(false);
  for (auto& observer : vm_observer_list_)
    observer.OnVmStopped(signal);
}

void FakeConciergeClient::NotifyVmStopping(
    const vm_tools::concierge::VmStoppingSignal& signal) {
  for (auto& observer : vm_observer_list_) {
    observer.OnVmStopping(signal);
  }
}

bool FakeConciergeClient::HasVmObservers() const {
  return !vm_observer_list_.empty();
}

void FakeConciergeClient::InitializeProtoResponses() {
  create_disk_image_response_.emplace();
  create_disk_image_response_->set_status(
      vm_tools::concierge::DISK_STATUS_CREATED);
  create_disk_image_response_->set_disk_path("foo");

  destroy_disk_image_response_.emplace();
  destroy_disk_image_response_->set_status(
      vm_tools::concierge::DISK_STATUS_DESTROYED);

  import_disk_image_response_.emplace();
  cancel_disk_image_response_.emplace();
  disk_image_status_response_.emplace();

  list_vm_disks_response_.emplace();
  list_vm_disks_response_->set_success(true);

  start_vm_response_.emplace();
  start_vm_response_->set_status(vm_tools::concierge::VM_STATUS_STARTING);
  start_vm_response_->set_mount_result(
      vm_tools::concierge::StartVmResponse::SUCCESS);

  stop_vm_response_.emplace();
  stop_vm_response_->set_success(true);

  suspend_vm_response_.emplace();
  suspend_vm_response_->set_success(true);

  resume_vm_response_.emplace();
  resume_vm_response_->set_success(true);

  get_vm_info_response_.emplace();
  get_vm_info_response_->set_success(false);
  get_vm_info_response_->mutable_vm_info()->set_seneschal_server_handle(1);

  get_vm_enterprise_reporting_info_response_.emplace();

  arcvm_complete_boot_response_.emplace();
  arcvm_complete_boot_response_->set_result(
      vm_tools::concierge::ArcVmCompleteBootResult::SUCCESS);

  set_vm_cpu_restriction_response_.emplace();

  attach_usb_device_response_.emplace();
  attach_usb_device_response_->set_success(true);
  attach_usb_device_response_->set_guest_port(0);

  detach_usb_device_response_.emplace();
  detach_usb_device_response_->set_success(true);

  install_pflash_response_.emplace();
  install_pflash_response_->set_success(true);
}

}  // namespace ash