| // 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/strings/stringprintf.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" |
| #include "third_party/metrics_proto/printer_event.pb.h" |
| |
| namespace ash { |
| namespace { |
| |
| using ::chromeos::kPrinterId; |
| using ::chromeos::PpdProvider; |
| using ::chromeos::Printer; |
| using ::chromeos::PrinterClass; |
| using ::chromeos::PrinterSearchData; |
| using DetectedPrinter = PrinterDetector::DetectedPrinter; |
| using ::chromeos::CupsPrinterStatus; |
| using CupsPrinterStatusReason = |
| ::chromeos::CupsPrinterStatus::CupsPrinterStatusReason; |
| |
| 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() = default; |
| ~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() = default; |
| |
| 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 = default; |
| std::string usb_manufacturer_; |
| std::string license_name_; |
| std::string ppd_content_ = "ppd content"; |
| }; |
| |
| class FakeLocalPrintersObserver |
| : public CupsPrintersManager::LocalPrintersObserver { |
| public: |
| FakeLocalPrintersObserver() = default; |
| ~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); |
| |
| event_tracker_.set_logging(true); |
| } |
| |
| ~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; |
| } |
| |
| void ExpectPrinterStatusReason( |
| const std::string& printer_id, |
| CupsPrinterStatusReason::Reason expected_reason) { |
| manager_->FetchPrinterStatus( |
| printer_id, |
| base::BindLambdaForTesting([&](const CupsPrinterStatus& status) { |
| ASSERT_EQ(status.GetStatusReasons().size(), 1u); |
| EXPECT_EQ(status.GetStatusReasons().begin()->GetReason(), |
| expected_reason); |
| })); |
| } |
| |
| std::vector<metrics::PrinterEventProto> GetLoggedEvents() { |
| std::vector<metrics::PrinterEventProto> events; |
| event_tracker_.FlushPrinterEvents(&events); |
| return events; |
| } |
| |
| 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)); |
| } |
| |
| DetectedPrinter CreateDetectedUsbPrinter(const std::string& id, |
| const std::string& uri, |
| int vendor_id, |
| int product_id) { |
| DetectedPrinter ret; |
| ret.printer.set_id(id); |
| ret.printer.SetUri(uri); |
| ret.printer.set_usb_device_id(Printer::UsbDeviceId(vendor_id, product_id)); |
| // Add make and model to make it automatic. |
| ret.ppd_search_data.make_and_model.push_back("make and model"); |
| return ret; |
| } |
| |
| Printer CreateEnterpriseUsbPrinter(const std::string& id, |
| int vendor_id, |
| int product_id, |
| bool is_ippusb = false) { |
| Printer printer(id); |
| printer.set_usb_device_id(Printer::UsbDeviceId(vendor_id, product_id)); |
| if (is_ippusb) { |
| EXPECT_TRUE(printer.SetUri(base::StringPrintf( |
| "ippusb://%04x_%04x/ipp/print", vendor_id, product_id))); |
| } else { |
| EXPECT_TRUE(printer.SetUri( |
| base::StringPrintf("usb://%04x/%04x?serial", vendor_id, product_id))); |
| } |
| printer.set_source(Printer::SRC_POLICY); |
| return printer; |
| } |
| |
| Printer CreateEnterpriseIppUsbPrinter(const std::string& id, |
| int vendor_id, |
| int product_id) { |
| return CreateEnterpriseUsbPrinter(id, vendor_id, product_id, true); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, EnterprisePrinter_DetectUsbPrinter) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0x1234, 0x5678); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| |
| // Detected USB printer matching the enterprise one. |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Detected printer is suppressed, still only see the Enterprise one. |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| |
| // The Enterprise printer's URI should be updated. |
| std::optional<Printer> updated_enterprise = |
| manager_->GetPrinter("EnterpriseUsb"); |
| ASSERT_TRUE(updated_enterprise.has_value()); |
| EXPECT_EQ("usb://1234/5678?serial=ABC", |
| updated_enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, DetectUsbPrinter_EnterprisePrinter) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Detected USB printer. |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // The detected printer should be in Automatic. |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"DetectedUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| |
| // Enterprise printer matching detected one. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0x1234, 0x5678); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Detected printer gets suppressed now, see only Enterprise one. |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| |
| // The Enterprise printer's URI should be updated. |
| std::optional<Printer> updated_enterprise = |
| manager_->GetPrinter("EnterpriseUsb"); |
| ASSERT_TRUE(updated_enterprise.has_value()); |
| EXPECT_EQ("usb://1234/5678?serial=ABC", |
| updated_enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, EnterprisePrinter_DetectDifferentUsbPrinter) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer with a DIFFERENT VID/PID identifier. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0xAAAA, 0xBBBB); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Detected USB printer NOT matching the enterprise printer. |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // The detected printer should be in Automatic |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"DetectedUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| |
| // The Enterprise printer's URI should NOT be updated. |
| std::optional<Printer> updated_enterprise = |
| manager_->GetPrinter("EnterpriseUsb"); |
| ASSERT_TRUE(updated_enterprise.has_value()); |
| EXPECT_EQ("usb://aaaa/bbbb?serial", |
| updated_enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, EnterprisePrinter_DetectUsbPrinter_Ipp) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer with ippusb. |
| Printer enterprise_printer = |
| CreateEnterpriseIppUsbPrinter("EnterpriseIppUsb", 0x1234, 0x5678); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseIppUsb"}); |
| |
| // Detected USB printer matching. |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| detected_printer.printer.set_supports_ippusb(true); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Detected printer is suppressed, only the Enterprise one shows. |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseIppUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| |
| // Enterprise printer's URI should NOT be updated in the ippusb case. |
| std::optional<Printer> updated_enterprise = |
| manager_->GetPrinter("EnterpriseIppUsb"); |
| ASSERT_TRUE(updated_enterprise.has_value()); |
| EXPECT_EQ("ippusb://1234_5678/ipp/print", |
| updated_enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, DetectUsbPrinter_EnterprisePrinter_Race) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Detected USB printer |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "RacePrinter", "usb://8888/9999?serial=XYZ", 0x8888, 0x9999); |
| usb_detector_->AddDetections({detected_printer}); |
| // Note that we don't call `task_environment_.RunUntilIdle()` here yet. |
| |
| // Enterprise printer comes in after setup started, but before it finished. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseRace", 0x8888, 0x9999); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // The race should be detected and the detected printer should be uninstalled. |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseRace"}); |
| EXPECT_FALSE(manager_->IsPrinterInstalled(detected_printer.printer)); |
| |
| // Enterprise printer URI should be updated. |
| std::optional<Printer> updated_enterprise = |
| manager_->GetPrinter("EnterpriseRace"); |
| ASSERT_TRUE(updated_enterprise.has_value()); |
| EXPECT_EQ("usb://8888/9999?serial=XYZ", |
| updated_enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, |
| EnterprisePrinter_DetectUsbPrinter_FeatureDisabled) { |
| feature_list_.InitAndDisableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0x1234, 0x5678); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| |
| // Detected USB printer matching the enterprise VID/PID |
| DetectedPrinter detected_printer = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // With the flag off, the detected printer should appear in Automatic. |
| ExpectPrintersInClassAre(PrinterClass::kAutomatic, {"DetectedUsb"}); |
| ExpectPrintersInClassAre(PrinterClass::kDiscovered, {}); |
| ExpectPrintersInClassAre(PrinterClass::kEnterprise, {"EnterpriseUsb"}); |
| |
| // Enterprise printer's URI should NOT be updated. |
| std::optional<Printer> enterprise = manager_->GetPrinter("EnterpriseUsb"); |
| ASSERT_TRUE(enterprise.has_value()); |
| EXPECT_EQ("usb://1234/5678?serial", enterprise->uri().GetNormalized()); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Status_DetectedUsbPrinter) { |
| // Add a detected USB printer. |
| DetectedPrinter detected_usb = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1234/5678?serial=ABC", 0x1234, 0x5678); |
| usb_detector_->AddDetections({detected_usb}); |
| task_environment_.RunUntilIdle(); |
| |
| // It should be connected and have NoError status. |
| ExpectPrinterStatusReason("DetectedUsb", |
| CupsPrinterStatusReason::Reason::kNoError); |
| |
| // Remove the detection |
| usb_detector_->RemoveDetections({"DetectedUsb"}); |
| task_environment_.RunUntilIdle(); |
| |
| // Now it should be unreachable. |
| ExpectPrinterStatusReason( |
| "DetectedUsb", CupsPrinterStatusReason::Reason::kPrinterUnreachable); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Status_EnterpriseUsbPrinter) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0xAAAA, 0xBBBB); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Initially, the enterprise printer is not detected via USB. |
| ExpectPrinterStatusReason( |
| "EnterpriseUsb", CupsPrinterStatusReason::Reason::kPrinterUnreachable); |
| |
| // Detected USB printer matching the enterprise one. |
| DetectedPrinter detected_usb = CreateDetectedUsbPrinter( |
| "MatchedUsb", "usb://AAAA/BBBB?serial=XYZ", 0xAAAA, 0xBBBB); |
| usb_detector_->AddDetections({detected_usb}); |
| task_environment_.RunUntilIdle(); |
| |
| // Now the enterprise printer should be considered connected. |
| ExpectPrinterStatusReason("EnterpriseUsb", |
| CupsPrinterStatusReason::Reason::kNoError); |
| |
| // Remove the USB detection. |
| usb_detector_->RemoveDetections({"MatchedUsb"}); |
| task_environment_.RunUntilIdle(); |
| |
| // Should be unreachable again. |
| ExpectPrinterStatusReason( |
| "EnterpriseUsb", CupsPrinterStatusReason::Reason::kPrinterUnreachable); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Status_EnterpriseUsbPrinter_FeatureDisabled) { |
| feature_list_.InitAndDisableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EnterpriseUsb", 0xCCCC, 0xDDDD); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Detected USB printer matching the enterprise VID/PID. |
| DetectedPrinter detected_usb = CreateDetectedUsbPrinter( |
| "MatchedUsb", "usb://CCCC/DDDD?serial=123", 0xCCCC, 0xDDDD); |
| usb_detector_->AddDetections({detected_usb}); |
| task_environment_.RunUntilIdle(); |
| |
| // The enterprise printer is unreachable since the feature is disabled. |
| ExpectPrinterStatusReason( |
| "EnterpriseUsb", CupsPrinterStatusReason::Reason::kPrinterUnreachable); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Status_MixUsbPrinters) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Regular Detected USB that is also saved. |
| DetectedPrinter detected_usb = CreateDetectedUsbPrinter( |
| "DetectedUsb", "usb://1111/2222?serial=A", 0x1111, 0x2222); |
| usb_detector_->AddDetections({detected_usb}); |
| manager_->SavePrinter(detected_usb.printer); |
| |
| // Enterprise USB - Connected. |
| Printer enterprise_conn = |
| CreateEnterpriseUsbPrinter("EnterpriseConn", 0x3333, 0x4444); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_conn}); |
| DetectedPrinter detected_enterprise = CreateDetectedUsbPrinter( |
| "MatchedEnterprise", "usb://3333/4444?serial=B", 0x3333, 0x4444); |
| usb_detector_->AddDetections({detected_enterprise}); |
| |
| // Enterprise USB - Disconnected. |
| Printer enterprise_disconn = |
| CreateEnterpriseUsbPrinter("EnterpriseDisconn", 0x5555, 0x6666); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_disconn}); |
| |
| task_environment_.RunUntilIdle(); |
| |
| ExpectPrinterStatusReason("DetectedUsb", |
| CupsPrinterStatusReason::Reason::kNoError); |
| ExpectPrinterStatusReason("EnterpriseConn", |
| CupsPrinterStatusReason::Reason::kNoError); |
| ExpectPrinterStatusReason( |
| "EnterpriseDisconn", |
| CupsPrinterStatusReason::Reason::kPrinterUnreachable); |
| } |
| |
| DetectedPrinter CreateDetectedUsbPrinterWithPpdData(const std::string& id, |
| const std::string& uri, |
| int vendor_id, |
| int product_id) { |
| DetectedPrinter ret = |
| CreateDetectedUsbPrinter(id, uri, vendor_id, product_id); |
| |
| // Populate ppd_search data. |
| ret.ppd_search_data.usb_vendor_id = vendor_id; |
| ret.ppd_search_data.usb_product_id = product_id; |
| ret.ppd_search_data.usb_manufacturer = "ACME"; |
| ret.ppd_search_data.usb_model = "Anvil"; |
| |
| // Populate ppd_reference. |
| ret.printer.mutable_ppd_reference()->effective_make_and_model = |
| "Invisible paint"; |
| return ret; |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Metrics_RecordInstallRegularUsb) { |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "RegUsb", "usb://1111/2222?serial=A", 0x1111, 0x2222); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // This will trigger the call to MaybeRecordInstallation in |
| // OnPrinterSetupResult |
| base::RunLoop run_loop; |
| manager_->SetUpPrinter(detected_printer.printer, |
| /*is_automatic_installation=*/true, |
| CallQuitOnRunLoop(&run_loop)); |
| run_loop.Run(); |
| task_environment_.RunUntilIdle(); |
| |
| auto events = GetLoggedEvents(); |
| ASSERT_THAT(events.size(), 1); |
| const auto& event = events[0]; |
| EXPECT_EQ(event.event_type(), metrics::PrinterEventProto::SETUP_AUTOMATIC); |
| EXPECT_EQ(event.usb_vendor_id(), 0x1111); |
| EXPECT_EQ(event.usb_model_id(), 0x2222); |
| EXPECT_EQ(event.usb_printer_manufacturer(), "ACME"); |
| EXPECT_EQ(event.usb_printer_model(), "Anvil"); |
| EXPECT_EQ(event.ppd_identifier(), "Invisible paint"); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, Metrics_RecordInstallEnterpriseUsb) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EntUsb", 0x3333, 0x4444); |
| enterprise_printer.mutable_ppd_reference()->effective_make_and_model = |
| "Jet-Propelled Unicycle"; |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Matching detected USB printer. |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "MatchUsb", "usb://3333/4444?serial=B", 0x3333, 0x4444); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Setup the *enterprise* printer. MaybeRecordInstallation should find the |
| // matching detected printer for PPD info. |
| base::RunLoop run_loop; |
| manager_->SetUpPrinter(enterprise_printer, |
| /*is_automatic_installation=*/false, |
| CallQuitOnRunLoop(&run_loop)); |
| run_loop.Run(); |
| task_environment_.RunUntilIdle(); |
| |
| auto events = GetLoggedEvents(); |
| ASSERT_THAT(events.size(), 1); |
| const auto& event = events[0]; |
| EXPECT_EQ(event.event_type(), metrics::PrinterEventProto::SETUP_MANUAL); |
| // The usb_* information should come from the detected printer, while the |
| // ppd_* information should come from the enterprise printer itself. |
| EXPECT_EQ(event.usb_vendor_id(), 0x3333); |
| EXPECT_EQ(event.usb_model_id(), 0x4444); |
| EXPECT_EQ(event.usb_printer_manufacturer(), "ACME"); |
| EXPECT_EQ(event.usb_printer_model(), "Anvil"); |
| EXPECT_EQ(event.ppd_identifier(), "Jet-Propelled Unicycle"); |
| } |
| |
| // Test metrics when a regular USB printer setup is abandoned. |
| TEST_F(CupsPrintersManagerTest, Metrics_RecordAbandonRegularUsb) { |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "RegUsb", "usb://5555/6666?serial=C", 0x5555, 0x6666); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| manager_->RecordSetupAbandoned(detected_printer.printer); |
| task_environment_.RunUntilIdle(); |
| |
| auto events = GetLoggedEvents(); |
| ASSERT_THAT(events.size(), 1); |
| const auto& event = events[0]; |
| EXPECT_EQ(event.event_type(), metrics::PrinterEventProto::SETUP_ABANDONED); |
| EXPECT_EQ(event.usb_vendor_id(), 0x5555); |
| EXPECT_EQ(event.usb_model_id(), 0x6666); |
| EXPECT_EQ(event.usb_printer_manufacturer(), "ACME"); |
| EXPECT_EQ(event.usb_printer_model(), "Anvil"); |
| } |
| |
| // Test metrics when an enterprise USB printer setup is abandoned. |
| TEST_F(CupsPrintersManagerTest, Metrics_RecordAbandonEnterpriseUsb) { |
| feature_list_.InitAndEnableFeature(features::kManagedUsbPrinters); |
| |
| // Enterprise printer. |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EntUsb", 0x7777, 0x8888); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| // Matching detected USB printer. |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "MatchUsb", "usb://7777/8888?serial=D", 0x7777, 0x8888); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| manager_->RecordSetupAbandoned(enterprise_printer); |
| task_environment_.RunUntilIdle(); |
| |
| auto events = GetLoggedEvents(); |
| ASSERT_THAT(events.size(), 1); |
| const auto& event = events[0]; |
| EXPECT_EQ(event.event_type(), metrics::PrinterEventProto::SETUP_ABANDONED); |
| // The ppd information should come from the detected printer. |
| EXPECT_EQ(event.usb_vendor_id(), 0x7777); |
| EXPECT_EQ(event.usb_model_id(), 0x8888); |
| EXPECT_EQ(event.usb_printer_manufacturer(), "ACME"); |
| EXPECT_EQ(event.usb_printer_model(), "Anvil"); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, |
| Metrics_NoRecordInstallEnterpriseUsb_FeatureDisabled) { |
| feature_list_.InitAndDisableFeature(features::kManagedUsbPrinters); |
| |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EntUsb", 0x9999, 0xAAAA); |
| enterprise_printer.set_make_and_model("Enterprise Make"); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "MatchUsb", "usb://9999/AAAA?serial=E", 0x9999, 0xAAAA); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| base::RunLoop run_loop; |
| manager_->SetUpPrinter(enterprise_printer, |
| /*is_automatic_installation=*/true, |
| CallQuitOnRunLoop(&run_loop)); |
| run_loop.Run(); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(GetLoggedEvents().size(), 0u); |
| } |
| |
| TEST_F(CupsPrintersManagerTest, |
| Metrics_NoRecordAbandonEnterpriseUsb_FeatureDisabled) { |
| feature_list_.InitAndDisableFeature(features::kManagedUsbPrinters); |
| |
| Printer enterprise_printer = |
| CreateEnterpriseUsbPrinter("EntUsb", 0xBBBB, 0xCCCC); |
| enterprise_printer.set_make_and_model("Enterprise Make Abandon"); |
| enterprise_printers_provider_->AddEnterprisePrinters({enterprise_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| auto detected_printer = CreateDetectedUsbPrinterWithPpdData( |
| "MatchUsb", "usb://BBBB/CCCC?serial=F", 0xBBBB, 0xCCCC); |
| usb_detector_->AddDetections({detected_printer}); |
| task_environment_.RunUntilIdle(); |
| |
| manager_->RecordSetupAbandoned(enterprise_printer); |
| task_environment_.RunUntilIdle(); |
| |
| EXPECT_EQ(GetLoggedEvents().size(), 0u); |
| } |
| |
| } // namespace |
| } // namespace ash |