chromium/chrome/browser/ash/printing/cups_printers_manager_unittest.cc

// Copyright 2017 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/printing/cups_printers_manager.h"

#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>

#include "ash/constants/ash_features.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chrome/browser/ash/printing/enterprise/enterprise_printers_provider.h"
#include "chrome/browser/ash/printing/printer_configurer.h"
#include "chrome/browser/ash/printing/printer_event_tracker.h"
#include "chrome/browser/ash/printing/printers_map.h"
#include "chrome/browser/ash/printing/server_printers_provider.h"
#include "chrome/browser/ash/printing/synced_printers_manager.h"
#include "chrome/browser/ash/printing/usb_printer_detector.h"
#include "chrome/browser/ash/printing/usb_printer_notification_controller.h"
#include "chrome/browser/printing/print_preview_sticky_settings.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
#include "chromeos/ash/components/dbus/dlcservice/fake_dlcservice_client.h"
#include "chromeos/ash/components/dbus/printscanmgr/printscanmgr_client.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "chromeos/ash/services/network_config/public/cpp/cros_network_config_test_helper.h"
#include "chromeos/printing/ppd_provider.h"
#include "components/prefs/pref_service.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "printing/printing_features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/dlcservice/dbus-constants.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"

namespace ash {
namespace {

using ::chromeos::kPrinterId;
using ::chromeos::PpdProvider;
using ::chromeos::Printer;
using ::chromeos::PrinterClass;
using ::chromeos::PrinterSearchData;

constexpr base::TimeDelta kMetricsDelayTimerInterval = base::Seconds(60);

// Fake backend for EnterprisePrintersProvider.  This allows us to poke
// arbitrary changes in the enterprise printer lists.
class FakeEnterprisePrintersProvider : public EnterprisePrintersProvider {
 public:
  FakeEnterprisePrintersProvider() = default;
  ~FakeEnterprisePrintersProvider() override = default;

  // Attach |observer| for notification of events.  |observer| is expected to
  // live on the same thread (UI) as this object.  OnPrinter* methods are
  // invoked inline so calling RegisterPrinter in response to OnPrinterAdded is
  // forbidden.
  void AddObserver(EnterprisePrintersProvider::Observer* observer) override {
    observers_.AddObserver(observer);
  }

  // Remove |observer| so that it no longer receives notifications.  After the
  // completion of this method, the |observer| can be safely destroyed.
  void RemoveObserver(EnterprisePrintersProvider::Observer* observer) override {
    observers_.RemoveObserver(observer);
  }

  // Fake manipulation functions.

  // Add the given printers to the list of enterprise printers and
  // notify observers.
  void AddEnterprisePrinters(const std::vector<Printer>& printers) {
    enterprise_printers_.insert(enterprise_printers_.end(), printers.begin(),
                                printers.end());
    for (Observer& observer : observers_) {
      observer.OnPrintersChanged(true, enterprise_printers_);
    }
  }

 private:
  base::ObserverList<EnterprisePrintersProvider::Observer>::Unchecked
      observers_;
  std::vector<Printer> enterprise_printers_;
};

// Fake backend for SyncedPrintersManager.  This allows us to poke arbitrary
// changes in the saved printer lists.
class FakeSyncedPrintersManager : public SyncedPrintersManager {
 public:
  FakeSyncedPrintersManager() = default;
  ~FakeSyncedPrintersManager() override = default;

  // Returns the printers that are saved in preferences.
  std::vector<Printer> GetSavedPrinters() const override {
    return saved_printers_;
  }

  // Attach |observer| for notification of events.  |observer| is expected to
  // live on the same thread (UI) as this object.  OnPrinter* methods are
  // invoked inline so calling RegisterPrinter in response to OnPrinterAdded is
  // forbidden.
  void AddObserver(SyncedPrintersManager::Observer* observer) override {
    observers_.AddObserver(observer);
  }

  // Remove |observer| so that it no longer receives notifications.  After the
  // completion of this method, the |observer| can be safely destroyed.
  void RemoveObserver(SyncedPrintersManager::Observer* observer) override {
    observers_.RemoveObserver(observer);
  }

  void UpdateSavedPrinter(const Printer& printer) override {
    if (!IsPrinterAlreadySaved(printer)) {
      SavePrinter(printer);
      return;
    }

    for (size_t i = 0; i < saved_printers_.size(); ++i) {
      if (saved_printers_[i].id() == printer.id()) {
        saved_printers_[i] = printer;
        break;
      }
    }

    NotifyOnSavedPrintersObservers();
  }

  bool RemoveSavedPrinter(const std::string& printer_id) override {
    for (auto it = saved_printers_.begin(); it != saved_printers_.end(); ++it) {
      if (it->id() == printer_id) {
        saved_printers_.erase(it);
        NotifyOnSavedPrintersObservers();
        return true;
      }
    }
    return false;
  }

  // Everything else in the interface we either don't use in
  // CupsPrintersManager, or just use in a simple pass-through manner that's not
  // worth additional layers of testing on top of the testing in
  // SyncedPrintersManager.
  PrintersSyncBridge* GetSyncBridge() override { return nullptr; }
  // Returns the printer with id |printer_id|, or nullptr if no such printer
  // exists.
  std::unique_ptr<Printer> GetPrinter(
      const std::string& printer_id) const override {
    return nullptr;
  }

  // Fake manipulation functions.

  // Add the given printers to the list of saved printers and
  // notify observers.
  void AddSavedPrinters(const std::vector<Printer>& printers) {
    saved_printers_.insert(saved_printers_.end(), printers.begin(),
                           printers.end());
    NotifyOnSavedPrintersObservers();
  }

  // Remove the printers with the given ids from the set of saved printers,
  // notify observers.
  void RemoveSavedPrinters(const std::unordered_set<std::string>& ids) {
    RemovePrinters(ids, &saved_printers_);
    NotifyOnSavedPrintersObservers();
  }

 private:
  void RemovePrinters(const std::unordered_set<std::string>& ids,
                      std::vector<Printer>* target) {
    std::erase_if(*target, [&ids](const Printer& printer) {
      return base::Contains(ids, printer.id());
    });
  }

  bool IsPrinterAlreadySaved(const Printer& printer) const {
    for (const Printer& saved_printer : saved_printers_) {
      if (printer.id() == saved_printer.id()) {
        return true;
      }
    }
    return false;
  }

  void SavePrinter(const Printer& printer) {
    DCHECK(!IsPrinterAlreadySaved(printer));

    saved_printers_.push_back(printer);

    NotifyOnSavedPrintersObservers();
  }

  void NotifyOnSavedPrintersObservers() const {
    for (Observer& observer : observers_) {
      observer.OnSavedPrintersChanged();
    }
  }

  base::ObserverList<SyncedPrintersManager::Observer>::Unchecked observers_;
  std::vector<Printer> saved_printers_;
};

class FakePrinterDetector : public PrinterDetector {
 public:
  FakePrinterDetector() {}
  ~FakePrinterDetector() override = default;

  void RegisterPrintersFoundCallback(OnPrintersFoundCallback cb) override {
    on_printers_found_callback_ = std::move(cb);
  }

  std::vector<DetectedPrinter> GetPrinters() override { return detections_; }

  void AddDetections(
      const std::vector<PrinterDetector::DetectedPrinter>& new_detections) {
    detections_.insert(detections_.end(), new_detections.begin(),
                       new_detections.end());
    on_printers_found_callback_.Run(detections_);
  }

  // Remove printers that have ids in ids.
  void RemoveDetections(const std::unordered_set<std::string>& ids) {
    std::erase_if(detections_, [&ids](const DetectedPrinter& detection) {
      return base::Contains(ids, detection.printer.id());
    });
    on_printers_found_callback_.Run(detections_);
  }

  void RunPrintersFoundCallback() {
    on_printers_found_callback_.Run(detections_);
  }

 private:
  std::vector<DetectedPrinter> detections_;
  OnPrintersFoundCallback on_printers_found_callback_;
};

// Fake PpdProvider backend.  This fake generates PpdReferences based on
// the passed make_and_model strings using these rules:
//
// If make_and_model is empty, then we say NOT_FOUND
// Otherwise, generate a ppd reference with make_and_model[0] as
// the effective make and model in the PpdReference.
class FakePpdProvider : public PpdProvider {
 public:
  FakePpdProvider() {}

  void ResolvePpdReference(const PrinterSearchData& search_data,
                           ResolvePpdReferenceCallback cb) override {
    if (search_data.make_and_model.empty()) {
      base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
          FROM_HERE,
          base::BindOnce(std::move(cb), PpdProvider::NOT_FOUND,
                         Printer::PpdReference(), usb_manufacturer_));
    } else {
      Printer::PpdReference ret;
      ret.effective_make_and_model = search_data.make_and_model[0];
      base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
          FROM_HERE, base::BindOnce(std::move(cb), PpdProvider::SUCCESS, ret,
                                    "" /* usb_manufacturer */));
    }
  }

  void SetUsbManufacturer(const std::string& manufacturer) {
    usb_manufacturer_ = manufacturer;
  }

  void SetLicenseName(const std::string& license_name) {
    license_name_ = license_name;
  }

  void SetPpdContent(const std::string& ppd_content) {
    ppd_content_ = ppd_content;
  }

  void ResolvePpd(const Printer::PpdReference& reference,
                  ResolvePpdCallback cb) override {
    std::move(cb).Run(PpdProvider::CallbackResultCode::SUCCESS, ppd_content_);
  }

  void ResolvePpdLicense(std::string_view effective_make_and_model,
                         ResolvePpdLicenseCallback cb) override {
    std::move(cb).Run(PpdProvider::CallbackResultCode::SUCCESS, license_name_);
  }

  // These methods are not used by CupsPrintersManager.
  void ResolveManufacturers(ResolveManufacturersCallback cb) override {}
  void ResolvePrinters(const std::string& manufacturer,
                       ResolvePrintersCallback cb) override {}
  void ReverseLookup(const std::string& effective_make_and_model,
                     ReverseLookupCallback cb) override {}

 private:
  ~FakePpdProvider() override {}
  std::string usb_manufacturer_;
  std::string license_name_;
  std::string ppd_content_ = "ppd content";
};

class FakeLocalPrintersObserver
    : public CupsPrintersManager::LocalPrintersObserver {
 public:
  FakeLocalPrintersObserver() {}
  ~FakeLocalPrintersObserver() override = default;

  void OnLocalPrintersUpdated() override { ++num_observer_calls_; }

  size_t num_observer_calls() const { return num_observer_calls_; }

 private:
  size_t num_observer_calls_ = 0;
};

// Expect that the printers in printers have the given ids, without
// considering order.
void ExpectPrinterIdsAre(const std::vector<Printer>& printers,
                         const std::vector<std::string>& ids) {
  std::vector<std::string> found_ids;
  for (const Printer& printer : printers) {
    found_ids.push_back(printer.id());
  }
  std::sort(found_ids.begin(), found_ids.end());
  std::vector<std::string> sorted_ids(ids);
  std::sort(sorted_ids.begin(), sorted_ids.end());
  EXPECT_EQ(sorted_ids, found_ids);
}

class FakeUsbPrinterNotificationController
    : public UsbPrinterNotificationController {
 public:
  FakeUsbPrinterNotificationController() = default;
  ~FakeUsbPrinterNotificationController() override = default;

  void ShowEphemeralNotification(const Printer& printer) override {
    // Do nothing.
  }
  void ShowConfigurationNotification(const Printer& printer) override {
    configuration_notifications_.insert(printer.id());
  }
  void ShowSavedNotification(const Printer& printer) override {
    saved_notifications_.insert(printer.id());
  }
  void RemoveNotification(const std::string& printer_id) override {
    saved_notifications_.erase(printer_id);
    configuration_notifications_.erase(printer_id);
  }
  bool IsNotificationDisplayed(const std::string& printer_id) const override {
    return configuration_notifications_.contains(printer_id) ||
           saved_notifications_.contains(printer_id);
  }

  bool IsSavedNotification(const std::string& printer_id) const {
    return saved_notifications_.contains(printer_id);
  }

  bool IsConfigurationNotification(const std::string& printer_id) const {
    return configuration_notifications_.contains(printer_id);
  }

 private:
  base::flat_set<std::string> saved_notifications_;
  base::flat_set<std::string> configuration_notifications_;
};

class FakePrintServersManager : public PrintServersManager {
 public:
  FakePrintServersManager() = default;
  ~FakePrintServersManager() override = default;

  void AddObserver(Observer* observer) override { observer_ = observer; }
  void RemoveObserver(Observer* observer) override { observer_ = nullptr; }
  void ChoosePrintServer(
      const std::vector<std::string>& selected_print_server_ids) override {}
  PrintServersConfig GetPrintServersConfig() const override {
    return PrintServersConfig();
  }

  void ServerPrintersChanged(
      const std::vector<PrinterDetector::DetectedPrinter>& printers) {
    observer_->OnServerPrintersChanged(printers);
  }

 private:
  raw_ptr<Observer> observer_;
};

class CupsPrintersManagerTest : public testing::Test,
                                public CupsPrintersManager::Observer {
 public:
  CupsPrintersManagerTest() : ppd_provider_(new FakePpdProvider) {
    // Zeroconf and usb detector ownerships are taken by the manager, so we
    // have to keep raw pointers to them.
    auto zeroconf_detector = std::make_unique<FakePrinterDetector>();
    zeroconf_detector_ = zeroconf_detector.get();
    auto usb_detector = std::make_unique<FakePrinterDetector>();
    usb_detector_ = usb_detector.get();
    auto usb_notif_controller =
        std::make_unique<FakeUsbPrinterNotificationController>();
    usb_notif_controller_ = usb_notif_controller.get();
    auto enterprise_printers_provider =
        std::make_unique<FakeEnterprisePrintersProvider>();
    enterprise_printers_provider_ = enterprise_printers_provider.get();
    auto print_servers_manager = std::make_unique<FakePrintServersManager>();
    print_servers_manager_ = print_servers_manager.get();

    // To make sure it is not called.
    dlc_service_client_.set_install_error(dlcservice::kErrorInternal);

    // Register the pref |UserPrintersAllowed|
    CupsPrintersManager::RegisterProfilePrefs(pref_service_.registry());

    manager_ = CupsPrintersManager::CreateForTesting(
        &synced_printers_manager_, std::move(usb_detector),
        std::move(zeroconf_detector), ppd_provider_, &dlc_service_client_,
        std::move(usb_notif_controller), std::move(print_servers_manager),
        std::move(enterprise_printers_provider), &event_tracker_,
        &pref_service_);
    manager_->AddObserver(this);
  }

  ~CupsPrintersManagerTest() override {
    // Fast forwarding so that delayed tasks like |SendScannerCountToUMA| will
    // run and not leak memory in unused callbacks.
    task_environment_.FastForwardUntilNoTasksRemain();
  }

  void SetUp() override {
    // TODO(b/257070388): Once the kAddPrinterViaPrintscanmgr feature is stable,
    // remove the DebugDaemonClient and its test variants.
    DebugDaemonClient::InitializeFake();
    PrintscanmgrClient::InitializeFake();
  }

  void TearDown() override {
    PrintscanmgrClient::Shutdown();
    DebugDaemonClient::Shutdown();
  }

  // CupsPrintersManager::Observer implementation
  void OnPrintersChanged(PrinterClass printer_class,
                         const std::vector<Printer>& printers) override {
    observed_printers_[printer_class] = printers;
  }

  // Check that, for the given printer class, the printers we have from the
  // observation callback and the printers we have when we query the manager
  // are both the same and have the passed ids.
  void ExpectPrintersInClassAre(PrinterClass printer_class,
                                const std::vector<std::string>& ids) {
    ExpectPrinterIdsAre(manager_->GetPrinters(printer_class), ids);
    ExpectPrinterIdsAre(observed_printers_[printer_class], ids);
  }

  void UpdatePolicyValue(const char* name, bool value) {
    auto value_ptr = std::make_unique<base::Value>(value);
    // TestingPrefSyncableService assumes ownership of |value_ptr|.
    pref_service_.SetManagedPref(name, std::move(value_ptr));
  }

  static PrintServer CreatePrintServer(std::string id,
                                       std::string server_url,
                                       std::string name) {
    GURL url(server_url);
    PrintServer print_server(id, url, name);
    return print_server;
  }

 protected:
  // Everything from PrintServersProvider must be called on Chrome_UIThread
  // Note: MainThreadType::IO is strictly about requesting a specific
  // MessagePumpType for the main thread. It has nothing to do with
  // BrowserThread::UI or BrowserThread::IO which are named threads in the
  // //content/browser code.
  // See
  // //docs/threading_and_tasks_testing.md#mainthreadtype-trait
  content::BrowserTaskEnvironment task_environment_{
      base::test::TaskEnvironment::MainThreadType::IO,
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};

  // Captured printer lists from observer callbacks.
  base::flat_map<PrinterClass, std::vector<Printer>> observed_printers_;

  // Backend fakes driving the CupsPrintersManager.
  FakeSyncedPrintersManager synced_printers_manager_;
  raw_ptr<FakeEnterprisePrintersProvider, DanglingUntriaged>
      enterprise_printers_provider_;  // Not owned.
  raw_ptr<FakePrinterDetector, DanglingUntriaged> usb_detector_;  // Not owned.
  raw_ptr<FakePrinterDetector, DanglingUntriaged>
      zeroconf_detector_;  // Not owned.
  raw_ptr<FakeUsbPrinterNotificationController,
          DanglingUntriaged>
      usb_notif_controller_;  // Not owned.
  raw_ptr<FakePrintServersManager, DanglingUntriaged>
      print_servers_manager_;  // Not owned.
  scoped_refptr<FakePpdProvider> ppd_provider_;
  FakeDlcserviceClient dlc_service_client_;

  // This is unused, it's just here for memory ownership.
  PrinterEventTracker event_tracker_;

  // PrefService used to register the |UserPrintersAllowed| pref and
  // change its value for testing.
  sync_preferences::TestingPrefServiceSyncable pref_service_;

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

  // Manages active networks.
  network_config::CrosNetworkConfigTestHelper cros_network_config_helper_;

  base::test::ScopedFeatureList feature_list_;
};

// Pseudo-constructor for inline creation of a DetectedPrinter that should (in
// this test) be handled as a Discovered printer (because it has no make and
// model information, and that's now the FakePpdProvider is set up to
// determine whether or not something has a Ppd available).
PrinterDetector::DetectedPrinter MakeDiscoveredPrinter(const std::string& id,
                                                       const std::string& uri) {
  PrinterDetector::DetectedPrinter ret;
  ret.printer.set_id(id);
  ret.printer.SetUri(uri);
  return ret;
}

// Calls MakeDiscoveredPrinter with empty uri.
PrinterDetector::DetectedPrinter MakeDiscoveredPrinter(const std::string& id) {
  return MakeDiscoveredPrinter(id, /*uri=*/"ipp://discovered.printer/" + id);
}

// Calls MakeDiscoveredPrinter with the USB protocol as the uri.
PrinterDetector::DetectedPrinter MakeUsbDiscoveredPrinter(
    const std::string& id) {
  return MakeDiscoveredPrinter(id, "usb://host/path");
}

// Pseudo-constructor for inline creation of a DetectedPrinter that should (in
// this test) be handled as an Automatic printer (because it has a make and
// model string).
PrinterDetector::DetectedPrinter MakeAutomaticPrinter(const std::string& id) {
  PrinterDetector::DetectedPrinter ret;
  ret.printer.set_id(id);
  ret.printer.SetUri("ipp://automatic.printer/" + id);
  ret.ppd_search_data.make_and_model.push_back("make and model string");
  return ret;
}

PrinterSetupCallback CallQuitOnRunLoop(base::RunLoop* run_loop,
                                       PrinterSetupResult* result = nullptr) {
  if (result == nullptr) {
    return base::IgnoreArgs<PrinterSetupResult>(run_loop->QuitClosure());
  }
  return base::BindLambdaForTesting([run_loop, result](PrinterSetupResult res) {
    *result = res;
    run_loop->Quit();
  });
}

// Test that Enterprise printers from SyncedPrinterManager are
// surfaced appropriately.
TEST_F(CupsPrintersManagerTest, GetEnterprisePrinters) {
  enterprise_printers_provider_->AddEnterprisePrinters(
      {Printer("Foo"), Printer("Bar")});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"Foo", "Bar"});
}

// Test that Saved printers from SyncedPrinterManager are
// surfaced appropriately.
TEST_F(CupsPrintersManagerTest, GetSavedPrinters) {
  synced_printers_manager_.AddSavedPrinters({Printer("Foo"), Printer("Bar")});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Foo", "Bar"});
}

// Test that USB printers from the usb detector are converted to 'Printer's
// and surfaced appropriately.  One printer should be "automatic" because it
// has a findable Ppd, the other should be "discovered".
TEST_F(CupsPrintersManagerTest, GetUsbPrinters) {
  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                MakeAutomaticPrinter("AutomaticPrinter")});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});
}

// Same as GetUsbPrinters, using debugd.
TEST_F(CupsPrintersManagerTest, GetUsbPrintersDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                MakeAutomaticPrinter("AutomaticPrinter")});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});
}

// Same as GetUsbPrinters, only for Zeroconf printers.
TEST_F(CupsPrintersManagerTest, GetZeroconfPrinters) {
  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                     MakeAutomaticPrinter("AutomaticPrinter")});
  synced_printers_manager_.AddSavedPrinters({Printer("Foo"), Printer("Bar")});

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});
}

// Test that USB printers that prefer IPP-USB end up in the automatic class
// instead of the discovered class.
TEST_F(CupsPrintersManagerTest, GetIppUsbPrinters) {
  PrinterDetector::DetectedPrinter printer;
  printer.printer.set_id("IppUsbPrinter");
  printer.printer.SetUri("usb://1234/5678");
  printer.printer.set_make_and_model("EPSON WF-110 Series");

  usb_detector_->AddDetections({printer});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"IppUsbPrinter"});
}

// Same as GetIppUsbPrinters, using debugd.
TEST_F(CupsPrintersManagerTest, GetIppUsbPrintersDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  PrinterDetector::DetectedPrinter printer;
  printer.printer.set_id("IppUsbPrinter");
  printer.printer.SetUri("usb://1234/5678");
  printer.printer.set_make_and_model("EPSON WF-110 Series");

  usb_detector_->AddDetections({printer});
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"IppUsbPrinter"});
}

// Test that printers that appear in either a Saved or Enterprise set do
// *not* appear in Discovered or Automatic, even if they are detected as such.
TEST_F(CupsPrintersManagerTest, SyncedPrintersTrumpDetections) {
  PrinterDetector::DetectedPrinter disc0 =
      MakeDiscoveredPrinter("DiscoveredPrinter0");
  PrinterDetector::DetectedPrinter disc1 =
      MakeDiscoveredPrinter("DiscoveredPrinter1");
  PrinterDetector::DetectedPrinter auto0 =
      MakeAutomaticPrinter("AutomaticPrinter0");
  PrinterDetector::DetectedPrinter auto1 =
      MakeAutomaticPrinter("AutomaticPrinter1");
  zeroconf_detector_->AddDetections({disc0, disc1, auto0, auto1});
  task_environment_.RunUntilIdle();
  // Before we muck with anything else, check that automatic and discovered
  // classes are what we intended to set up.
  ExpectPrintersInClassAre(PrinterClass::kDiscovered,
                           {"DiscoveredPrinter0", "DiscoveredPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic,
                           {"AutomaticPrinter0", "AutomaticPrinter1"});

  // Save both the Discovered and Automatic printers.  This should put them
  // into the Saved class and thus *remove* them from their previous
  // classes.
  base::RunLoop run_loop_1;
  manager_->SetUpPrinter(disc0.printer,
                         /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop_1));
  run_loop_1.Run();
  manager_->SavePrinter(disc0.printer);

  base::RunLoop run_loop_2;
  manager_->SetUpPrinter(auto0.printer,
                         /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop_2));
  run_loop_2.Run();
  manager_->SavePrinter(auto0.printer);

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kSaved,
                           {"DiscoveredPrinter0", "AutomaticPrinter0"});
}

// Same as SyncedPrintersTrumpDetections, using debugd.
TEST_F(CupsPrintersManagerTest, SyncedPrintersTrumpDetectionsDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  PrinterDetector::DetectedPrinter disc0 =
      MakeDiscoveredPrinter("DiscoveredPrinter0");
  PrinterDetector::DetectedPrinter disc1 =
      MakeDiscoveredPrinter("DiscoveredPrinter1");
  PrinterDetector::DetectedPrinter auto0 =
      MakeAutomaticPrinter("AutomaticPrinter0");
  PrinterDetector::DetectedPrinter auto1 =
      MakeAutomaticPrinter("AutomaticPrinter1");
  zeroconf_detector_->AddDetections({disc0, disc1, auto0, auto1});
  task_environment_.RunUntilIdle();
  // Before we muck with anything else, check that automatic and discovered
  // classes are what we intended to set up.
  ExpectPrintersInClassAre(PrinterClass::kDiscovered,
                           {"DiscoveredPrinter0", "DiscoveredPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic,
                           {"AutomaticPrinter0", "AutomaticPrinter1"});

  // Save both the Discovered and Automatic printers.  This should put them
  // into the Saved class and thus *remove* them from their previous
  // classes.
  base::RunLoop run_loop_1;
  manager_->SetUpPrinter(disc0.printer,
                         /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop_1));
  run_loop_1.Run();
  manager_->SavePrinter(disc0.printer);

  base::RunLoop run_loop_2;
  manager_->SetUpPrinter(auto0.printer,
                         /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop_2));
  run_loop_2.Run();
  manager_->SavePrinter(auto0.printer);

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter1"});
  ExpectPrintersInClassAre(PrinterClass::kSaved,
                           {"DiscoveredPrinter0", "AutomaticPrinter0"});
}
// Test updates of saved printers.  Updates of existing saved printers
// should propagate.  Updates of printers in other classes should result in
// those printers becoming saved.  Updates of unknown printers should
// result in a new saved printer.
TEST_F(CupsPrintersManagerTest, SavePrinter) {
  // Start with a printer in each class named after the class it's in, except
  // Enterprise which is not relevant to this test.
  Printer existing_saved("Saved");
  synced_printers_manager_.AddSavedPrinters({existing_saved});
  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
  zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
  task_environment_.RunUntilIdle();

  // Sanity check that we do, indeed, have one printer in each class.
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"Automatic"});
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"Discovered"});

  // Update the existing saved printer.  Check that the new display name
  // propagated.
  existing_saved.set_display_name("New Display Name");
  manager_->SavePrinter(existing_saved);
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  EXPECT_EQ(manager_->GetPrinters(PrinterClass::kSaved)[0].display_name(),
            "New Display Name");

  // Do the same thing for the Automatic and Discovered printers.
  // Create a configuration for the zeroconf printer, which should shift it
  // into the saved category.
  manager_->SavePrinter(Printer("Automatic"));
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {});
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Automatic", "Saved"});

  manager_->SavePrinter(Printer("Discovered"));
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {});
  ExpectPrintersInClassAre(PrinterClass::kSaved,
                           {"Automatic", "Saved", "Discovered"});

  // Save a printer we haven't seen before, which should just add it to
  // kSaved.
  manager_->SavePrinter(Printer("NewFangled"));
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kSaved,
                           {"Automatic", "Saved", "Discovered", "NewFangled"});

  // Remove the automatic printer, make sure it ends up back in the automatic
  // class after removal.
  manager_->RemoveSavedPrinter("Automatic");
  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kSaved,
                           {"Saved", "Discovered", "NewFangled"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"Automatic"});
}

// Test that GetPrinter() finds printers in any class, and returns null if
// a printer is not found.
TEST_F(CupsPrintersManagerTest, GetPrinter) {
  synced_printers_manager_.AddSavedPrinters({Printer("Saved")});
  enterprise_printers_provider_->AddEnterprisePrinters({Printer("Enterprise")});
  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
  zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
  task_environment_.RunUntilIdle();

  for (const std::string& id :
       {"Saved", "Enterprise", "Discovered", "Automatic"}) {
    std::optional<Printer> printer = manager_->GetPrinter(id);
    ASSERT_TRUE(printer);
    EXPECT_EQ(printer->id(), id);
  }

  std::optional<Printer> printer = manager_->GetPrinter("Nope");
  EXPECT_FALSE(printer);
}

// Test that if |UserPrintersAllowed| pref is set to false, then
// GetPrinters() will only return printers from
// |PrinterClass::kEnterprise|.
TEST_F(CupsPrintersManagerTest, GetPrintersUserNativePrintersDisabled) {
  synced_printers_manager_.AddSavedPrinters({Printer("Saved")});
  enterprise_printers_provider_->AddEnterprisePrinters({Printer("Enterprise")});
  task_environment_.RunUntilIdle();

  // Disable the use of non-enterprise printers.
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  // Verify that non-enterprise printers are not returned by GetPrinters()
  std::vector<Printer> saved_printers =
      manager_->GetPrinters(PrinterClass::kSaved);
  ExpectPrinterIdsAre(saved_printers, {});

  // Verify that enterprise printers are returned by GetPrinters()
  std::vector<Printer> enterprise_printers =
      manager_->GetPrinters(PrinterClass::kEnterprise);
  ExpectPrinterIdsAre(enterprise_printers, {"Enterprise"});
}

// Test that if |UserPrintersAllowed| pref is set to false, then
// SavePrinter() will simply do nothing.
TEST_F(CupsPrintersManagerTest, SavePrinterUserNativePrintersDisabled) {
  // Start by installing a saved printer to be used to test than any
  // changes made to the printer will not be propagated.
  Printer existing_saved("Saved");
  synced_printers_manager_.AddSavedPrinters({existing_saved});
  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
  zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
  task_environment_.RunUntilIdle();

  // Sanity check that we do, indeed, have one printer in each class.
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"Automatic"});
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"Discovered"});

  // Disable the use of non-enterprise printers.
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  // Update the existing saved printer. Verify that the changes did not
  // progogate.
  existing_saved.set_display_name("New Display Name");
  manager_->SavePrinter(existing_saved);
  task_environment_.RunUntilIdle();

  // Reenable user printers in order to do checking.
  UpdatePolicyValue(prefs::kUserPrintersAllowed, true);
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  EXPECT_EQ(manager_->GetPrinters(PrinterClass::kSaved)[0].display_name(), "");
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  // Attempt to update the Automatic and Discovered printers. In both cases
  // check that the printers do not move into the saved category.
  manager_->SavePrinter(Printer("Automatic"));
  task_environment_.RunUntilIdle();
  UpdatePolicyValue(prefs::kUserPrintersAllowed, true);
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"Automatic"});
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  manager_->SavePrinter(Printer("Discovered"));
  task_environment_.RunUntilIdle();
  UpdatePolicyValue(prefs::kUserPrintersAllowed, true);
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"Discovered"});
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  // Attempt to update a printer that we haven't seen before, check that
  // nothing changed.
  manager_->SavePrinter(Printer("NewFangled"));
  task_environment_.RunUntilIdle();
  UpdatePolicyValue(prefs::kUserPrintersAllowed, true);
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
}

// Test that if |UserPrintersAllowed| pref is set to false GetPrinter only
// returns a printer when the given printer id corresponds to an enterprise
// printer. Otherwise, it returns nothing.
TEST_F(CupsPrintersManagerTest, GetPrinterUserNativePrintersDisabled) {
  synced_printers_manager_.AddSavedPrinters({Printer("Saved")});
  enterprise_printers_provider_->AddEnterprisePrinters({Printer("Enterprise")});
  task_environment_.RunUntilIdle();

  // Sanity check that the printers were added.
  ExpectPrintersInClassAre(PrinterClass::kSaved, {"Saved"});
  ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"Enterprise"});

  // Disable the use of non-enterprise printers.
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  std::optional<Printer> saved_printer = manager_->GetPrinter("Saved");
  EXPECT_FALSE(saved_printer);

  std::optional<Printer> enterprise_printer =
      manager_->GetPrinter("Enterprise");
  ASSERT_TRUE(enterprise_printer);
  EXPECT_EQ(enterprise_printer->id(), "Enterprise");
}

TEST_F(CupsPrintersManagerTest, SetUsbManufacturer) {
  const std::string& expected_manufacturer = "HP";
  ppd_provider_->SetUsbManufacturer(expected_manufacturer);
  usb_detector_->AddDetections({MakeUsbDiscoveredPrinter("DiscoveredPrinter")});
  task_environment_.RunUntilIdle();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});

  EXPECT_EQ(
      expected_manufacturer,
      manager_->GetPrinter("DiscoveredPrinter")->usb_printer_manufacturer());
}

TEST_F(CupsPrintersManagerTest, EmptyUsbManufacturer) {
  usb_detector_->AddDetections({MakeUsbDiscoveredPrinter("DiscoveredPrinter")});
  task_environment_.RunUntilIdle();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});

  EXPECT_TRUE(manager_->GetPrinter("DiscoveredPrinter")
                  ->usb_printer_manufacturer()
                  .empty());
}

TEST_F(CupsPrintersManagerTest, PrinterNotInstalled) {
  Printer printer(kPrinterId);
  EXPECT_FALSE(manager_->IsPrinterInstalled(printer));
}

TEST_F(CupsPrintersManagerTest, PrinterIsInstalled) {
  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));
}

// Same as PrinterIsInstalled, using debugd.
TEST_F(CupsPrintersManagerTest, PrinterIsInstalledDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));
}

// Test that we detect that the configuration is stale when any of the
// relevant fields change.
TEST_F(CupsPrintersManagerTest, UpdatedPrinterConfiguration) {
  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  Printer updated(printer);
  updated.SetUri("ipp://different.value");
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->autoconf = true;
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->user_supplied_ppd_url = "different value";
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->effective_make_and_model = "different value";
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->autoconf = true;
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  // Sanity check, configuration for the original printers should still be
  // current.
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));
}

// Same as UpdatedPrinterConfiguration, using debugd.
TEST_F(CupsPrintersManagerTest, UpdatedPrinterConfigurationDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  Printer updated(printer);
  updated.SetUri("ipp://different.value");
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->autoconf = true;
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->user_supplied_ppd_url = "different value";
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->effective_make_and_model = "different value";
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  updated = printer;
  updated.mutable_ppd_reference()->autoconf = true;
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  // Sanity check, configuration for the original printers should still be
  // current.
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));
}

// Test that we can save non-discovered printers.
TEST_F(CupsPrintersManagerTest, SavePrinterSucceedsOnManualPrinter) {
  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  manager_->SavePrinter(printer);

  auto saved_printers = manager_->GetPrinters(PrinterClass::kSaved);
  ASSERT_EQ(1u, saved_printers.size());
  EXPECT_EQ(printer.uri(), saved_printers[0].uri());
}

// Test that installing a printer does not put it in the saved class.
TEST_F(CupsPrintersManagerTest, PrinterInstalledDoesNotSavePrinter) {
  Printer printer(kPrinterId);
  EXPECT_TRUE(printer.SetUri("ipp://abcde/ipp/print"));
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  auto saved_printers = manager_->GetPrinters(PrinterClass::kSaved);
  EXPECT_EQ(0u, saved_printers.size());
}

// Same as PrinterInstalledDoesNotSavePrinter, using debugd.
TEST_F(CupsPrintersManagerTest, PrinterInstalledDoesNotSavePrinterDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  EXPECT_TRUE(printer.SetUri("ipp://abcde/ipp/print"));
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  auto saved_printers = manager_->GetPrinters(PrinterClass::kSaved);
  EXPECT_EQ(0u, saved_printers.size());
}

// Test that calling SavePrinter() when printer configuration change updates
// the saved printer but does not install the updated printer.
TEST_F(CupsPrintersManagerTest, SavePrinterUpdatesPreviouslyInstalledPrinter) {
  Printer printer(kPrinterId);
  printer.SetUri("http://ble");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  manager_->SavePrinter(printer);
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));

  Printer updated(printer);
  updated.SetUri("ipps://different/value");
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  manager_->SavePrinter(updated);
  auto saved_printers = manager_->GetPrinters(PrinterClass::kSaved);
  ASSERT_EQ(1u, saved_printers.size());
  EXPECT_EQ(updated.uri(), saved_printers[0].uri());

  // Even though the updated printer was saved, it still needs to be marked as
  // installed again.
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));
}

// same as SavePrinterUpdatesPreviouslyInstalledPrinter, using debugd.
TEST_F(CupsPrintersManagerTest,
       SavePrinterUpdatesPreviouslyInstalledPrinterDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  printer.SetUri("http://ble");
  base::RunLoop run_loop;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop));
  run_loop.Run();

  manager_->SavePrinter(printer);
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));

  Printer updated(printer);
  updated.SetUri("ipps://different/value");
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));

  manager_->SavePrinter(updated);
  auto saved_printers = manager_->GetPrinters(PrinterClass::kSaved);
  ASSERT_EQ(1u, saved_printers.size());
  EXPECT_EQ(updated.uri(), saved_printers[0].uri());

  // Even though the updated printer was saved, it still needs to be marked as
  // installed again.
  EXPECT_FALSE(manager_->IsPrinterInstalled(updated));
}

// Automatic USB Printer is configured automatically.
TEST_F(CupsPrintersManagerTest, AutomaticUsbPrinterIsInstalledAutomatically) {
  auto automatic_printer = MakeAutomaticPrinter(kPrinterId);
  automatic_printer.printer.SetUri("usb://host/path");

  usb_detector_->AddDetections({automatic_printer});

  task_environment_.RunUntilIdle();

  std::optional<chromeos::Printer> printer =
      manager_->GetPrinter(automatic_printer.printer.id());
  ASSERT_TRUE(printer);
  EXPECT_TRUE(manager_->IsPrinterInstalled(*printer));
}

// Same as AutomaticUsbPrinterIsInstalledAutomatically, using debugd.
TEST_F(CupsPrintersManagerTest,
       AutomaticUsbPrinterIsInstalledAutomaticallyDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  auto automatic_printer = MakeAutomaticPrinter(kPrinterId);
  automatic_printer.printer.SetUri("usb://host/path");

  usb_detector_->AddDetections({automatic_printer});

  task_environment_.RunUntilIdle();

  std::optional<chromeos::Printer> printer =
      manager_->GetPrinter(automatic_printer.printer.id());
  ASSERT_TRUE(printer);
  EXPECT_TRUE(manager_->IsPrinterInstalled(*printer));
}

// Can handle four different USB printers at the same time.
TEST_F(CupsPrintersManagerTest, CanHandleManyUsbPrinters) {
  // Printer without PPD file and not supporting IPPUSB.
  auto p1 = MakeUsbDiscoveredPrinter("id1");
  // Printer with PPD file but not supporting IPPUSB.
  auto p2 = MakeUsbDiscoveredPrinter("id2");
  p2.ppd_search_data.make_and_model.push_back("make-and-model");
  // Printer without PPD file but supporting IPPUSB.
  auto p3 = MakeUsbDiscoveredPrinter("id3");
  p3.printer.set_supports_ippusb(true);
  // Printer with PPD file and supporting IPPUSB.
  auto p4 = MakeUsbDiscoveredPrinter("id4");
  p4.ppd_search_data.make_and_model.push_back("make-and-model");
  p4.printer.set_supports_ippusb(true);

  usb_detector_->AddDetections({p1, p2, p3, p4});

  task_environment_.RunUntilIdle();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"id1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"id2", "id3", "id4"});
  EXPECT_FALSE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id1")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id2")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id3")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id4")));
}

// Same as CanHandleManyUsbPrinters, using debugd.
TEST_F(CupsPrintersManagerTest, CanHandleManyUsbPrintersDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  // Printer without PPD file and not supporting IPPUSB.
  auto p1 = MakeUsbDiscoveredPrinter("id1");
  // Printer with PPD file but not supporting IPPUSB.
  auto p2 = MakeUsbDiscoveredPrinter("id2");
  p2.ppd_search_data.make_and_model.push_back("make-and-model");
  // Printer without PPD file but supporting IPPUSB.
  auto p3 = MakeUsbDiscoveredPrinter("id3");
  p3.printer.set_supports_ippusb(true);
  // Printer with PPD file and supporting IPPUSB.
  auto p4 = MakeUsbDiscoveredPrinter("id4");
  p4.ppd_search_data.make_and_model.push_back("make-and-model");
  p4.printer.set_supports_ippusb(true);

  usb_detector_->AddDetections({p1, p2, p3, p4});

  task_environment_.RunUntilIdle();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"id1"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"id2", "id3", "id4"});
  EXPECT_FALSE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id1")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id2")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id3")));
  EXPECT_TRUE(manager_->IsPrinterInstalled(*manager_->GetPrinter("id4")));
}

// Automatic Printer is *not* configured if |UserPrintersAllowed|
// pref is set to false.
TEST_F(CupsPrintersManagerTest, AutomaticPrinterNotInstalledAutomatically) {
  // Disable the use of non-enterprise printers.
  UpdatePolicyValue(prefs::kUserPrintersAllowed, false);

  auto automatic_printer = MakeAutomaticPrinter(kPrinterId);
  automatic_printer.printer.SetUri("usb://host/path");

  zeroconf_detector_->AddDetections({automatic_printer});

  task_environment_.RunUntilIdle();

  EXPECT_FALSE(manager_->IsPrinterInstalled(automatic_printer.printer));
}

// Nearby printers that are not automatic & USB are not automatically
// installed.
TEST_F(CupsPrintersManagerTest, OtherNearbyPrintersNotInstalledAutomatically) {
  auto discovered_printer = MakeDiscoveredPrinter("Discovered");
  discovered_printer.printer.SetUri("usb://host/path");
  auto automatic_printer = MakeAutomaticPrinter("Automatic");

  usb_detector_->AddDetections({discovered_printer});
  zeroconf_detector_->AddDetections({automatic_printer});

  task_environment_.RunUntilIdle();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"Discovered"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"Automatic"});
  EXPECT_FALSE(manager_->IsPrinterInstalled(discovered_printer.printer));
  EXPECT_FALSE(manager_->IsPrinterInstalled(automatic_printer.printer));
}

TEST_F(CupsPrintersManagerTest, DetectedUsbPrinterConfigurationNotification) {
  auto discovered_printer = MakeDiscoveredPrinter("Discovered");
  discovered_printer.printer.SetUri("usb://host/path");

  usb_detector_->AddDetections({discovered_printer});
  task_environment_.RunUntilIdle();

  EXPECT_TRUE(usb_notif_controller_->IsConfigurationNotification("Discovered"));

  usb_detector_->RemoveDetections({"Discovered"});

  EXPECT_FALSE(
      usb_notif_controller_->IsConfigurationNotification("Discovered"));
}

TEST_F(CupsPrintersManagerTest,
       DetectedZeroconfDiscoveredPrinterNoNotification) {
  auto discovered_printer = MakeDiscoveredPrinter("Discovered");
  discovered_printer.printer.SetUri("ipp://host");

  zeroconf_detector_->AddDetections({discovered_printer});
  task_environment_.RunUntilIdle();

  EXPECT_FALSE(
      usb_notif_controller_->IsConfigurationNotification("Discovered"));
}

// Test that RecordNearbyNetworkPrinterCounts logs the total number of
// detected network printers.
TEST_F(CupsPrintersManagerTest, RecordTotalNetworkPrinterCounts) {
  base::HistogramTester histogram_tester;
  manager_->SavePrinter(Printer("DiscoveredNetworkPrinter0"));
  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredUSBPrinter"),
                                MakeAutomaticPrinter("AutomaticUSBPrinter")});
  task_environment_.FastForwardBy(kMetricsDelayTimerInterval);
  histogram_tester.ExpectBucketCount("Printing.CUPS.TotalNetworkPrintersCount2",
                                     0, 1);
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount(
      "Printing.CUPS.TotalNetworkPrintersCount2.SettingsOpened", 0, 1);
  zeroconf_detector_->AddDetections(
      {MakeDiscoveredPrinter("DiscoveredNetworkPrinter0"),
       MakeDiscoveredPrinter("DiscoveredNetworkPrinter1"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter0"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter1")});
  task_environment_.FastForwardBy(kMetricsDelayTimerInterval);
  histogram_tester.ExpectBucketCount("Printing.CUPS.TotalNetworkPrintersCount2",
                                     4, 1);
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount(
      "Printing.CUPS.TotalNetworkPrintersCount2.SettingsOpened", 4, 1);
}

// Same as RecordTotalNetworkPrinterCounts, using debgud.
TEST_F(CupsPrintersManagerTest, RecordTotalNetworkPrinterCountsDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  base::HistogramTester histogram_tester;
  manager_->SavePrinter(Printer("DiscoveredNetworkPrinter0"));
  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredUSBPrinter"),
                                MakeAutomaticPrinter("AutomaticUSBPrinter")});
  task_environment_.FastForwardBy(kMetricsDelayTimerInterval);
  histogram_tester.ExpectBucketCount("Printing.CUPS.TotalNetworkPrintersCount2",
                                     0, 1);
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount(
      "Printing.CUPS.TotalNetworkPrintersCount2.SettingsOpened", 0, 1);
  zeroconf_detector_->AddDetections(
      {MakeDiscoveredPrinter("DiscoveredNetworkPrinter0"),
       MakeDiscoveredPrinter("DiscoveredNetworkPrinter1"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter0"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter1")});
  task_environment_.FastForwardBy(kMetricsDelayTimerInterval);
  histogram_tester.ExpectBucketCount("Printing.CUPS.TotalNetworkPrintersCount2",
                                     4, 1);
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount(
      "Printing.CUPS.TotalNetworkPrintersCount2.SettingsOpened", 4, 1);
}

// Test that RecordNearbyNetworkPrinterCounts logs the number of
// all nearby (not already saved) detected network printers.
TEST_F(CupsPrintersManagerTest, RecordNearbyNetworkPrinterCounts) {
  base::HistogramTester histogram_tester;
  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredUSBPrinter"),
                                MakeAutomaticPrinter("AutomaticUSBPrinter")});
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     0, 1);
  manager_->SavePrinter(Printer("DiscoveredNetworkPrinter0"));
  zeroconf_detector_->AddDetections(
      {MakeDiscoveredPrinter("DiscoveredNetworkPrinter0"),
       MakeDiscoveredPrinter("DiscoveredNetworkPrinter1"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter0"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter1")});
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     3, 1);

  // Save one more network printer.
  manager_->SavePrinter(Printer("AutomaticNetworkPrinter1"));
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     2, 1);
}

// Same as RecordNearbyNetworkPrinterCounts, using debugd.
TEST_F(CupsPrintersManagerTest, RecordNearbyNetworkPrinterCountsDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  base::HistogramTester histogram_tester;
  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredUSBPrinter"),
                                MakeAutomaticPrinter("AutomaticUSBPrinter")});
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     0, 1);
  manager_->SavePrinter(Printer("DiscoveredNetworkPrinter0"));
  zeroconf_detector_->AddDetections(
      {MakeDiscoveredPrinter("DiscoveredNetworkPrinter0"),
       MakeDiscoveredPrinter("DiscoveredNetworkPrinter1"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter0"),
       MakeAutomaticPrinter("AutomaticNetworkPrinter1")});
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     3, 1);

  // Save one more network printer.
  manager_->SavePrinter(Printer("AutomaticNetworkPrinter1"));
  manager_->RecordNearbyNetworkPrinterCounts();
  task_environment_.RunUntilIdle();
  histogram_tester.ExpectBucketCount("Printing.CUPS.NearbyNetworkPrintersCount",
                                     2, 1);
}

TEST_F(CupsPrintersManagerTest, OnServerPrintersChanged) {
  auto server_printer = MakeAutomaticPrinter("ServerPrinter");
  server_printer.printer.mutable_ppd_reference()->autoconf = true;

  print_servers_manager_->ServerPrintersChanged({server_printer});

  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"ServerPrinter"});
}

// Tests that when the active network is switched to a different network the
// list of nearby printers is cleared.
TEST_F(CupsPrintersManagerTest, ActiveNetworkSwitched) {
  cros_network_config_helper_.network_state_helper().ConfigureService(
      R"({"GUID": "Wifi1", "Type": "wifi", "State": "online"})");

  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                     MakeAutomaticPrinter("AutomaticPrinter")});

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});

  cros_network_config_helper_.network_state_helper().ClearServices();
  cros_network_config_helper_.network_state_helper().ConfigureService(
      R"({"GUID": "Wifi2", "Type": "wifi", "State": "online"})");

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {});
}

// Tests that when the active network is disconnected the list of nearby
// printers is cleared.
TEST_F(CupsPrintersManagerTest, ActiveNetworkDisconnected) {
  cros_network_config_helper_.network_state_helper().ConfigureService(
      R"({"GUID": "Wifi1", "Type": "wifi", "State": "online"})");

  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                     MakeAutomaticPrinter("AutomaticPrinter")});

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});

  cros_network_config_helper_.network_state_helper().ClearServices();

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {});
}

// Tests that when the a new wifi network is detected, but the active network
// remains the same, the list of nearby printers stays the same.
TEST_F(CupsPrintersManagerTest, NewNetworkDetected) {
  cros_network_config_helper_.network_state_helper().ConfigureService(
      R"({"GUID": "Wifi1", "Type": "wifi", "State": "online"})");
  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                     MakeAutomaticPrinter("AutomaticPrinter")});

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});

  cros_network_config_helper_.network_state_helper().ConfigureService(
      R"({"GUID": "Wifi2", "Type": "wifi", "State": "online"})");

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});
}

// Tests that when the signal strength of the active network changes, the list
// of nearby printers stays the same.
TEST_F(CupsPrintersManagerTest, ActiveNetworkStrengthChanged) {
  const std::string service_path =
      cros_network_config_helper_.network_state_helper().ConfigureService(
          R"({"GUID": "Wifi1", "Type": "wifi", "State": "online"})");
  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
                                     MakeAutomaticPrinter("AutomaticPrinter")});

  task_environment_.RunUntilIdle();
  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});

  cros_network_config_helper_.network_state_helper().SetServiceProperty(
      service_path, shill::kSignalStrengthProperty, base::Value(50));

  ExpectPrintersInClassAre(PrinterClass::kDiscovered, {"DiscoveredPrinter"});
  ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"AutomaticPrinter"});
}

// Tests that local printers observers are triggered when added.
TEST_F(CupsPrintersManagerTest, AddLocalPrintersObserver) {
  // Add the same observer twice to verify it's only added once and triggered
  // once.
  FakeLocalPrintersObserver observer1;
  manager_->AddLocalPrintersObserver(&observer1);
  manager_->AddLocalPrintersObserver(&observer1);
  EXPECT_EQ(1u, observer1.num_observer_calls());

  // Add another observer and verify it's the only one that's triggered this
  // time.
  FakeLocalPrintersObserver observer2;
  manager_->AddLocalPrintersObserver(&observer2);
  EXPECT_EQ(1u, observer2.num_observer_calls());
  EXPECT_EQ(1u, observer1.num_observer_calls());
}

// Tests that when a new local printer is detected the observer is triggered.
TEST_F(CupsPrintersManagerTest, LocalPrintersDetected) {
  // The observer should fire when first registered.
  FakeLocalPrintersObserver observer1;
  manager_->AddLocalPrintersObserver(&observer1);
  EXPECT_EQ(1u, observer1.num_observer_calls());

  // The observer should fire for a new zeroconf printer detection.
  const auto detected_printer = MakeDiscoveredPrinter("DiscoveredPrinter");
  zeroconf_detector_->AddDetections({detected_printer});
  task_environment_.RunUntilIdle();
  EXPECT_EQ(2u, observer1.num_observer_calls());

  // The observer shouldn't fire when the same printer is sent for detection so
  // the call count should remain the same.
  zeroconf_detector_->RunPrintersFoundCallback();
  task_environment_.RunUntilIdle();
  EXPECT_EQ(2u, observer1.num_observer_calls());

  // The observer should fire again for a new USB printer detection.
  const auto usb_detected_printer = MakeUsbDiscoveredPrinter("UsbPrinter");
  usb_detector_->AddDetections({usb_detected_printer});
  task_environment_.RunUntilIdle();
  EXPECT_EQ(3u, observer1.num_observer_calls());
}

// Tests that the polling printer status requests trigger the local printers
// observer up until the max time allocated for polling statuses.
TEST_F(CupsPrintersManagerTest, PrinterStatusPolling) {
  // Add `RecentPrinter` to the Print Preview sticky settings so it'll get
  // polled for status. `OldPrinter` will not get queried.
  ::printing::PrintPreviewStickySettings* sticky_settings =
      ::printing::PrintPreviewStickySettings::GetInstance();
  sticky_settings->StoreAppState(R"({
    "recentDestinations": [
      {
        "id": "RecentPrinter"
      }
    ]
  })");

  // Add a saved printer to be queried for status.
  Printer saved_printer("SavedPrinter");
  saved_printer.SetUri("ipp://discovered.printer/");
  synced_printers_manager_.AddSavedPrinters({saved_printer});
  zeroconf_detector_->AddDetections({MakeDiscoveredPrinter("RecentPrinter"),
                                     MakeDiscoveredPrinter("OldPrinter")});
  task_environment_.RunUntilIdle();

  // Add the observer to capture the triggers from printer status queries.
  FakeLocalPrintersObserver observer;
  manager_->AddLocalPrintersObserver(&observer);
  task_environment_.FastForwardUntilNoTasksRemain();

  // 1 call when the observer is added + 2 calls for initial printer status
  // queries to the Saved and Recent printer
  EXPECT_EQ(3u, observer.num_observer_calls());
}

TEST_F(CupsPrintersManagerTest, PrinterWithHplipPluginLicenseDlcFails) {
  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  printer.mutable_ppd_reference()->effective_make_and_model = "Make and model";
  ppd_provider_->SetLicenseName("hplip-plugin");

  base::RunLoop run_loop;
  PrinterSetupResult result;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop, &result));
  run_loop.Run();

  EXPECT_EQ(result, PrinterSetupResult::kComponentUnavailable);
  EXPECT_FALSE(manager_->IsPrinterInstalled(printer));
}

TEST_F(CupsPrintersManagerTest, PrinterWithHplipPluginLicenseDlcSucceeds) {
  feature_list_.InitAndEnableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  printer.mutable_ppd_reference()->effective_make_and_model = "Make and model";
  ppd_provider_->SetLicenseName("hplip-plugin");
  ppd_provider_->SetPpdContent("*hpPrinterLanguage: lang\nsomething else\n");
  dlc_service_client_.set_install_error(dlcservice::kErrorNone);
  dlc_service_client_.set_install_root_path("/root/path");

  base::RunLoop run_loop;
  PrinterSetupResult result;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop, &result));
  run_loop.Run();

  EXPECT_EQ(result, PrinterSetupResult::kSuccess);
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));

  // Check if the PPD content was updated.
  base::RunLoop run_loop_2;
  std::string ppd_content;
  printscanmgr::CupsRetrievePpdRequest request;
  request.set_name(kPrinterId);
  PrintscanmgrClient::Get()->CupsRetrievePrinterPpd(
      request,
      base::BindLambdaForTesting(
          [&run_loop_2, &ppd_content](
              std::optional<printscanmgr::CupsRetrievePpdResponse> response) {
            if (response) {
              ppd_content = response->ppd();
            }
            run_loop_2.Quit();
          }),
      base::BindLambdaForTesting([&run_loop_2]() { run_loop_2.Quit(); }));
  run_loop_2.Run();

  EXPECT_EQ(ppd_content,
            "*hpPrinterLanguage: lang\n*chromeOSHplipPluginPath: "
            "\"/root/path\"\nsomething else\n");
}

// Same as PrinterWithHplipPluginLicenseDlcSucceeds, using debugd.
TEST_F(CupsPrintersManagerTest,
       PrinterWithHplipPluginLicenseDlcSucceedsDebugd) {
  feature_list_.InitAndDisableFeature(
      printing::features::kAddPrinterViaPrintscanmgr);

  Printer printer(kPrinterId);
  printer.SetUri("ipp://manual.uri");
  printer.mutable_ppd_reference()->effective_make_and_model = "Make and model";
  ppd_provider_->SetLicenseName("hplip-plugin");
  dlc_service_client_.set_install_error(dlcservice::kErrorNone);
  dlc_service_client_.set_install_root_path("/root/path");

  base::RunLoop run_loop;
  PrinterSetupResult result;
  manager_->SetUpPrinter(printer, /*is_automatic_installation=*/true,
                         CallQuitOnRunLoop(&run_loop, &result));
  run_loop.Run();

  EXPECT_EQ(result, PrinterSetupResult::kSuccess);
  EXPECT_TRUE(manager_->IsPrinterInstalled(printer));
}

}  // namespace
}  // namespace ash