chromium/chrome/services/cups_proxy/printer_installer_unittest.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 <cups/cups.h>

#include <map>
#include <string>
#include <utility>

#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/test/task_environment.h"
#include "chrome/services/cups_proxy/fake_cups_proxy_service_delegate.h"
#include "chrome/services/cups_proxy/printer_installer.h"
#include "printing/backend/cups_ipp_helper.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cups_proxy {
namespace {

using Printer = chromeos::Printer;

// Generated via base::Uuid::GenerateRandomV4().AsLowercaseString().
const char kGenericGUID[] = "fd4c5f2e-7549-43d5-b931-9bf4e4f1bf51";

// Faked delegate gives control over PrinterInstaller's printing stack
// dependencies.
class FakeServiceDelegate : public FakeCupsProxyServiceDelegate {
 public:
  FakeServiceDelegate() = default;
  ~FakeServiceDelegate() override = default;

  void AddPrinter(const Printer& printer) {
    installed_printers_.insert({printer.id(), false});
  }

  void FailSetupPrinter() { fail_printer_setup_ = true; }

  // Service delegate overrides.
  bool IsPrinterInstalled(const Printer& printer) override {
    if (!base::Contains(installed_printers_, printer.id())) {
      return false;
    }

    return installed_printers_.at(printer.id());
  }

  std::optional<Printer> GetPrinter(const std::string& id) override {
    if (!base::Contains(installed_printers_, id)) {
      return std::nullopt;
    }

    return Printer(id);
  }

  void SetupPrinter(const Printer& printer,
                    SetupPrinterCallback callback) override {
    if (fail_printer_setup_) {
      return std::move(callback).Run(false);
    }

    // PrinterInstaller is expected to have checked if |printer| is already
    // installed before trying setup.
    if (IsPrinterInstalled(printer)) {
      return std::move(callback).Run(false);
    }

    // Install printer.
    installed_printers_[printer.id()] = true;
    return std::move(callback).Run(true);
  }

 private:
  std::map<std::string, bool> installed_printers_;

  // Conditions whether calls to SetupPrinter succeed.
  bool fail_printer_setup_ = false;
};

class PrinterInstallerTest : public testing::Test {
 public:
  PrinterInstallerTest() : weak_factory_(this) {
    delegate_ = std::make_unique<FakeServiceDelegate>();
    printer_installer_ = std::make_unique<PrinterInstaller>(delegate_.get());
  }

  ~PrinterInstallerTest() override = default;

  InstallPrinterResult RunInstallPrinter(std::string printer_id) {
    InstallPrinterResult ret;

    base::RunLoop run_loop;
    printer_installer_->InstallPrinter(
        printer_id, base::BindOnce(&PrinterInstallerTest::OnRunInstallPrinter,
                                   weak_factory_.GetWeakPtr(),
                                   run_loop.QuitClosure(), &ret));

    run_loop.Run();
    return ret;
  }

 protected:
  base::test::TaskEnvironment task_environment_;

  void OnRunInstallPrinter(base::OnceClosure finish_cb,
                           InstallPrinterResult* ret,
                           InstallPrinterResult result) {
    *ret = result;
    std::move(finish_cb).Run();
  }

  // Backend fake driving the PrinterInstaller.
  std::unique_ptr<FakeServiceDelegate> delegate_;

  // The class being tested. This must be declared after the fakes, as its
  // initialization must come after that of the fakes.
  std::unique_ptr<PrinterInstaller> printer_installer_;

  base::WeakPtrFactory<PrinterInstallerTest> weak_factory_;
};

// Standard install known printer workflow.
TEST_F(PrinterInstallerTest, SimpleSanityTest) {
  Printer to_install(kGenericGUID);
  delegate_->AddPrinter(to_install);

  auto ret = RunInstallPrinter(kGenericGUID);
  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);
  EXPECT_TRUE(delegate_->IsPrinterInstalled(to_install));
}

// Should fail to install an unknown(previously unseen) printer.
TEST_F(PrinterInstallerTest, UnknownPrinter) {
  Printer to_install(kGenericGUID);

  auto ret = RunInstallPrinter(kGenericGUID);
  EXPECT_EQ(ret, InstallPrinterResult::kUnknownPrinterFound);
  EXPECT_FALSE(delegate_->IsPrinterInstalled(to_install));
}

// Ensure we never setup a printer that's already installed.
TEST_F(PrinterInstallerTest, InstallPrinterTwice) {
  Printer to_install(kGenericGUID);
  delegate_->AddPrinter(to_install);

  auto ret = RunInstallPrinter(kGenericGUID);
  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);

  // |printer_installer_| should notice printer is already installed and bail
  // out. If it attempts setup, FakeServiceDelegate will fail the request.
  ret = RunInstallPrinter(kGenericGUID);
  EXPECT_EQ(ret, InstallPrinterResult::kSuccess);
}

// Checks for correct response to failed SetupPrinter call.
TEST_F(PrinterInstallerTest, SetupPrinterFailure) {
  Printer to_install(kGenericGUID);
  delegate_->AddPrinter(to_install);
  delegate_->FailSetupPrinter();

  auto ret = RunInstallPrinter(kGenericGUID);
  EXPECT_EQ(ret, InstallPrinterResult::kPrinterInstallationFailure);
  EXPECT_FALSE(delegate_->IsPrinterInstalled(to_install));
}

}  // namespace
}  // namespace cups_proxy