| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/printing/zeroconf_printer_detector.h" |
| |
| #include <algorithm> |
| #include <functional> |
| #include <map> |
| #include <memory> |
| #include <random> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/containers/flat_set.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/task_environment.h" |
| #include "chrome/browser/local_discovery/fake_service_discovery_device_lister.h" |
| #include "chrome/browser/local_discovery/service_discovery_device_lister.h" |
| #include "net/base/ip_address.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace ash { |
| namespace { |
| |
| using ::local_discovery::FakeServiceDiscoveryDeviceLister; |
| using ::local_discovery::ServiceDescription; |
| using ::local_discovery::ServiceDiscoveryDeviceLister; |
| |
| // Determine basic printer attributes deterministically but pseudorandomly based |
| // on the printer name. The exact values returned here are not really |
| // important, the important parts are that there's variety based on the name, |
| // and it's deterministic. |
| |
| // Should this printer provide usb_MFG and usb_MDL fields? |
| bool GetUsbFor(const std::string& name) { |
| return std::hash<std::string>()(name) & 1; |
| } |
| |
| // Get an IP address for this printer. The returned address may be IPv4 or IPv6 |
| net::IPAddress GetIPAddressFor(const std::string& name) { |
| std::mt19937 rng(std::hash<std::string>()(name)); |
| if (rng() & 1) { |
| // Give an IPv4 address. |
| return net::IPAddress(rng(), rng(), rng(), rng()); |
| } else { |
| // Give an IPv6 address. |
| return net::IPAddress(rng(), rng(), rng(), rng(), rng(), rng(), rng(), |
| rng(), rng(), rng(), rng(), rng(), rng(), rng(), |
| rng(), rng()); |
| } |
| } |
| |
| int GetPortFor(const std::string& name) { |
| return (std::hash<std::string>()(name) % 1000) + 1; |
| } |
| |
| // Enums for MakeExpectedPrinter(). |
| enum class ServiceType { |
| kIpp, // IPP |
| kIpps, // IPPS |
| kIppE, // IPP-Everywhere |
| kIppsE, // IPPS-Everywhere |
| kSocket, // Socket |
| kLpd, // LPD |
| }; |
| |
| // This corresponds to MakeServiceDescription() below. Given the same name (and |
| // the correct service type), this generates the DetectedPrinter record we |
| // expect from ZeroconfPrinterDetector when it gets that ServiceDescription. |
| // This needs to be kept in sync with MakeServiceDescription(). |
| PrinterDetector::DetectedPrinter MakeExpectedPrinter(const std::string& name, |
| ServiceType service_type) { |
| PrinterDetector::DetectedPrinter detected; |
| chromeos::Printer& printer = detected.printer; |
| int port = GetPortFor(name); |
| std::string scheme; |
| std::string rp = base::StrCat({name, "_rp"}); |
| switch (service_type) { |
| case ServiceType::kIpp: |
| scheme = "ipp"; |
| break; |
| case ServiceType::kIpps: |
| scheme = "ipps"; |
| break; |
| case ServiceType::kIppE: |
| scheme = "ipp"; |
| printer.mutable_ppd_reference()->autoconf = true; |
| break; |
| case ServiceType::kIppsE: |
| scheme = "ipps"; |
| printer.mutable_ppd_reference()->autoconf = true; |
| break; |
| case ServiceType::kSocket: |
| scheme = "socket"; |
| rp = ""; |
| break; |
| case ServiceType::kLpd: |
| scheme = "lpd"; |
| break; |
| } |
| printer.SetUri(base::StringPrintf("%s://%s.local:%d/%s", scheme.c_str(), |
| name.c_str(), port, rp.c_str())); |
| |
| printer.set_uuid(base::StrCat({name, "_UUID"})); |
| printer.set_display_name(name); |
| printer.set_description(base::StrCat({name, "_note"})); |
| printer.set_make_and_model(base::StrCat({name, "_ty"})); |
| detected.ppd_search_data.make_and_model.push_back(printer.make_and_model()); |
| detected.ppd_search_data.make_and_model.push_back( |
| base::StrCat({name, "_product"})); |
| if (GetUsbFor(name)) { |
| // We should get an effective make and model guess from the usb fields |
| // if they exist. |
| detected.ppd_search_data.make_and_model.push_back( |
| base::StrCat({name, "_usb_MFG ", name, "_usb_MDL"})); |
| } |
| |
| return detected; |
| } |
| |
| // Creates a deterministic ServiceDescription based on the service name and |
| // type. See the note on MakeExpectedPrinter() above. This must be kept in sync |
| // with MakeExpectedPrinter(). |
| ServiceDescription MakeServiceDescription(const std::string& name, |
| const std::string& service_type) { |
| ServiceDescription sd; |
| sd.service_name = base::StrCat({name, ".", service_type}); |
| sd.metadata.push_back(base::StrCat({"ty=", name, "_ty"})); |
| sd.metadata.push_back(base::StrCat({"product=(", name, "_product)"})); |
| if (GetUsbFor(name)) { |
| sd.metadata.push_back(base::StrCat({"usb_MFG=", name, "_usb_MFG"})); |
| sd.metadata.push_back(base::StrCat({"usb_MDL=", name, "_usb_MDL"})); |
| } |
| sd.metadata.push_back(base::StrCat({"rp=", name, "_rp"})); |
| sd.metadata.push_back(base::StrCat({"note=", name, "_note"})); |
| sd.metadata.push_back(base::StrCat({"UUID=", name, "_UUID"})); |
| sd.address.set_host(base::StrCat({name, ".local"})); |
| sd.ip_address = GetIPAddressFor(name); |
| sd.address.set_port(GetPortFor(name)); |
| return sd; |
| } |
| |
| class ZeroconfPrinterDetectorTest : public testing::Test { |
| public: |
| ZeroconfPrinterDetectorTest() { |
| auto* runner = task_environment_.GetMainThreadTaskRunner().get(); |
| auto ipp_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kIppServiceName); |
| ipp_lister_ = ipp_lister.get(); |
| auto ipps_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kIppsServiceName); |
| ipps_lister_ = ipps_lister.get(); |
| auto ippe_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kIppEverywhereServiceName); |
| ippe_lister_ = ippe_lister.get(); |
| auto ippse_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kIppsEverywhereServiceName); |
| ippse_lister_ = ippse_lister.get(); |
| auto socket_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kSocketServiceName); |
| socket_lister_ = socket_lister.get(); |
| auto lpd_lister = std::make_unique<FakeServiceDiscoveryDeviceLister>( |
| runner, ZeroconfPrinterDetector::kLpdServiceName); |
| lpd_lister_ = lpd_lister.get(); |
| |
| listers_[ZeroconfPrinterDetector::kIppServiceName] = std::move(ipp_lister); |
| listers_[ZeroconfPrinterDetector::kIppsServiceName] = |
| std::move(ipps_lister); |
| listers_[ZeroconfPrinterDetector::kIppEverywhereServiceName] = |
| std::move(ippe_lister); |
| listers_[ZeroconfPrinterDetector::kIppsEverywhereServiceName] = |
| std::move(ippse_lister); |
| listers_[ZeroconfPrinterDetector::kSocketServiceName] = |
| std::move(socket_lister); |
| listers_[ZeroconfPrinterDetector::kLpdServiceName] = std::move(lpd_lister); |
| } |
| ~ZeroconfPrinterDetectorTest() override = default; |
| |
| void CreateDetectorWithIppRejectList( |
| base::flat_set<std::string> ipp_reject_list) { |
| detector_ = ZeroconfPrinterDetector::CreateForTesting( |
| &listers_, std::move(ipp_reject_list)); |
| // The previously allocated listers_ are swapped into the detector_, and so |
| // the unique_ptr values of the listers_ map are no longer valid at this |
| // point. The ipp[se]_lister_ raw pointers are kept as seperate members to |
| // keep the lister fakes accessible after ownership is transferred into the |
| // detector. |
| listers_.clear(); |
| detector_->RegisterPrintersFoundCallback(base::BindRepeating( |
| &ZeroconfPrinterDetectorTest::OnPrintersFound, base::Unretained(this))); |
| ipp_lister_->SetDelegate(detector_.get()); |
| ipps_lister_->SetDelegate(detector_.get()); |
| ippe_lister_->SetDelegate(detector_.get()); |
| ippse_lister_->SetDelegate(detector_.get()); |
| socket_lister_->SetDelegate(detector_.get()); |
| lpd_lister_->SetDelegate(detector_.get()); |
| } |
| |
| void CreateDetector() { CreateDetectorWithIppRejectList({}); } |
| |
| // Expect that the most up-to-date results from the detector match those |
| // in printers. |
| void ExpectPrintersAre( |
| const std::vector<PrinterDetector::DetectedPrinter>& printers) { |
| // The last observer callback should tell us the same thing as the querying |
| // the detector manually. |
| ASSERT_FALSE(printers_found_callbacks_.empty()); |
| ExpectPrintersEq(printers, printers_found_callbacks_.back()); |
| ExpectPrintersEq(printers, detector_->GetPrinters()); |
| } |
| |
| // Expect that the detected printers list is empty. |
| void ExpectPrintersEmpty() { |
| // Assert that the most recent callbacks are empty. |
| ASSERT_FALSE(printers_found_callbacks_.empty()); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| ASSERT_TRUE(detector_->GetPrinters().empty()); |
| } |
| |
| // Expect that the given vectors have the same contents. The ordering |
| // may be different. |
| void ExpectPrintersEq( |
| const std::vector<PrinterDetector::DetectedPrinter>& expected, |
| const std::vector<PrinterDetector::DetectedPrinter>& actual) { |
| if (expected.size() != actual.size()) { |
| ADD_FAILURE() << "Printers size mismatch, found " << actual.size() |
| << " expected " << expected.size(); |
| return; |
| } |
| std::vector<PrinterDetector::DetectedPrinter> sorted_expected = expected; |
| std::vector<PrinterDetector::DetectedPrinter> sorted_actual = actual; |
| |
| std::sort(sorted_expected.begin(), sorted_expected.end(), |
| [](const PrinterDetector::DetectedPrinter& a, |
| const PrinterDetector::DetectedPrinter& b) -> bool { |
| return a.printer.uuid() < b.printer.uuid(); |
| }); |
| std::sort(sorted_actual.begin(), sorted_actual.end(), |
| [](const PrinterDetector::DetectedPrinter& a, |
| const PrinterDetector::DetectedPrinter& b) -> bool { |
| return a.printer.uuid() < b.printer.uuid(); |
| }); |
| for (size_t i = 0; i < sorted_expected.size(); ++i) { |
| ExpectPrinterEq(sorted_expected[i], sorted_actual[i]); |
| } |
| } |
| |
| void ExpectPrinterEq(const PrinterDetector::DetectedPrinter& expected, |
| const PrinterDetector::DetectedPrinter& actual) { |
| EXPECT_EQ(expected.printer.uri(), actual.printer.uri()); |
| // We don't have a good way to directly check for an expected id. |
| EXPECT_EQ(expected.printer.uuid(), actual.printer.uuid()); |
| EXPECT_EQ(expected.printer.display_name(), actual.printer.display_name()); |
| EXPECT_EQ(expected.printer.description(), actual.printer.description()); |
| EXPECT_EQ(expected.printer.IsIppEverywhere(), |
| actual.printer.IsIppEverywhere()); |
| EXPECT_EQ(expected.printer.make_and_model(), |
| actual.printer.make_and_model()); |
| EXPECT_EQ(expected.ppd_search_data.usb_vendor_id, |
| actual.ppd_search_data.usb_vendor_id); |
| EXPECT_EQ(expected.ppd_search_data.usb_product_id, |
| actual.ppd_search_data.usb_product_id); |
| EXPECT_EQ(expected.ppd_search_data.make_and_model, |
| actual.ppd_search_data.make_and_model); |
| } |
| |
| // PrinterDetector callback. |
| void OnPrintersFound( |
| const std::vector<PrinterDetector::DetectedPrinter>& printers) { |
| printers_found_callbacks_.push_back(printers); |
| } |
| |
| protected: |
| // Runs pending tasks regardless of delay. |
| void CompleteTasks() { task_environment_.FastForwardUntilNoTasksRemain(); } |
| |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| |
| // Device listers fakes. These are initialized when the test is constructed. |
| // These pointers don't involve ownership; ownership of the listers starts |
| // with this class in listers_ when the test starts, and is transferred to |
| // detector_ when the detector is created. Throughout, the listers remain |
| // available to the test via these pointers. |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> ipp_lister_; |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> ipps_lister_; |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> ippe_lister_; |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> ippse_lister_; |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> socket_lister_; |
| raw_ptr<FakeServiceDiscoveryDeviceLister, DanglingUntriaged> lpd_lister_; |
| |
| // Detector under test. |
| std::unique_ptr<ZeroconfPrinterDetector> detector_; |
| |
| // Saved copies of all the things given to OnPrintersFound. |
| std::vector<std::vector<PrinterDetector::DetectedPrinter>> |
| printers_found_callbacks_; |
| |
| private: |
| // Temporary storage for the device listers, between the time the test is |
| // constructed and the detector is created. Tests shouldn't access this |
| // directly, use the ipp*_lister_ variables instead. |
| std::map<std::string, std::unique_ptr<ServiceDiscoveryDeviceLister>> listers_; |
| }; |
| |
| // Very basic stuff, one printer of each protocol we support. |
| TEST_F(ZeroconfPrinterDetectorTest, SingleIppPrinter) { |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kIppServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer1", ServiceType::kIpp)}); |
| } |
| |
| TEST_F(ZeroconfPrinterDetectorTest, SingleIppsPrinter) { |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer2", ZeroconfPrinterDetector::kIppsServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer2", ServiceType::kIpps)}); |
| } |
| |
| TEST_F(ZeroconfPrinterDetectorTest, SingleIppEverywherePrinter) { |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer3", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer3", ServiceType::kIppE)}); |
| } |
| |
| TEST_F(ZeroconfPrinterDetectorTest, SingleIppsEverywherePrinter) { |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer4", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer4", ServiceType::kIppsE)}); |
| } |
| |
| TEST_F(ZeroconfPrinterDetectorTest, SingleSocketPrinter) { |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kSocketServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kSocket)}); |
| } |
| |
| TEST_F(ZeroconfPrinterDetectorTest, SingleLpdPrinter) { |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer6", ZeroconfPrinterDetector::kLpdServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer6", ServiceType::kLpd)}); |
| } |
| |
| // Test that an announce after the detector creation shows up as a printer. |
| TEST_F(ZeroconfPrinterDetectorTest, AnnounceAfterDetectorCreation) { |
| CreateDetector(); |
| CompleteTasks(); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer4", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer4", ServiceType::kIppsE)}); |
| } |
| |
| // Test that we use the same printer ID regardless of which service type it |
| // comes to us from. |
| TEST_F(ZeroconfPrinterDetectorTest, StableIds) { |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kIppServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ASSERT_FALSE(printers_found_callbacks_.empty()); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Grab the id when it's an IPPS printer We should continue to get the same id |
| // regardless of service type. |
| std::string id = printers_found_callbacks_.back()[0].printer.id(); |
| |
| // Remove it as an IPP printer, add it as an IPPS printer. |
| ipp_lister_->Remove("Printer1"); |
| CompleteTasks(); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kIppsServiceName)); |
| CompleteTasks(); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Id should be the same. |
| ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); |
| |
| // Remove it as an IPPS printer, add it as an IPP-Everywhere printer. |
| ipps_lister_->Remove("Printer1"); |
| CompleteTasks(); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| CompleteTasks(); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Id should be the same. |
| ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); |
| |
| // Remove it as an IPP-Everywhere printer, add it as an IPPS-Everywhere |
| // printer. |
| ippe_lister_->Remove("Printer1"); |
| CompleteTasks(); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| CompleteTasks(); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Id should be the same. |
| ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); |
| |
| // Remove it as an IPPS-Everywhere printer, add it as a socket printer. |
| ippse_lister_->Remove("Printer1"); |
| CompleteTasks(); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kSocketServiceName)); |
| CompleteTasks(); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Id should be the same. |
| ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); |
| |
| // Remove it as a socket printer, add it as an LPD printer. |
| socket_lister_->Remove("Printer1"); |
| CompleteTasks(); |
| ASSERT_TRUE(printers_found_callbacks_.back().empty()); |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer1", ZeroconfPrinterDetector::kLpdServiceName)); |
| CompleteTasks(); |
| ASSERT_EQ(1U, printers_found_callbacks_.back().size()); |
| // Id should be the same. |
| ASSERT_EQ(id, printers_found_callbacks_.back()[0].printer.id()); |
| } |
| |
| // Test a basic removal. |
| TEST_F(ZeroconfPrinterDetectorTest, Removal) { |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kIppServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer6", ZeroconfPrinterDetector::kIppServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer7", ZeroconfPrinterDetector::kIppServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer8", ZeroconfPrinterDetector::kIppServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer9", ZeroconfPrinterDetector::kIppServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer6", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer7", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer8", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer9", ServiceType::kIpp)}); |
| ipp_lister_->Remove("Printer7"); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer6", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer8", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer9", ServiceType::kIpp)}); |
| } |
| |
| // Test that, when the same printer appears in multiple services, we |
| // use the highest priority one. Priorities, from highest to lowest |
| // are IPPS-E, IPP-E, IPPS, IPP, Socket, LPD. |
| TEST_F(ZeroconfPrinterDetectorTest, ServiceTypePriorities) { |
| // Advertise on all services. |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kIppServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kIppsServiceName)); |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kSocketServiceName)); |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer5", ZeroconfPrinterDetector::kLpdServiceName)); |
| CreateDetector(); |
| CompleteTasks(); |
| // IPPS-E is highest priority. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIppsE)}); |
| ippse_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // IPP-E is highest remaining priority. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIppE)}); |
| |
| ippe_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // IPPS is highest remaining priority. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIpps)}); |
| |
| ipps_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // IPP is highest remaining priority. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kIpp)}); |
| |
| ipp_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // Socket is highest remaining entry. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kSocket)}); |
| |
| socket_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // LPD is only remaining entry. |
| ExpectPrintersAre({MakeExpectedPrinter("Printer5", ServiceType::kLpd)}); |
| |
| lpd_lister_->Remove("Printer5"); |
| CompleteTasks(); |
| // No entries left. |
| ExpectPrintersEmpty(); |
| } |
| |
| // Test a printer that is known not to work with IPP/IPPS and make sure a |
| // different protocol is chosen. |
| TEST_F(ZeroconfPrinterDetectorTest, RejectIpp) { |
| std::string bad_ipp_printer = "manufacturer awesome printer-name"; |
| base::flat_set<std::string> reject_list; |
| // We have to add the _ty suffix to match how MakeServiceDescription and |
| // MakeExpectedPrinter work. |
| reject_list.insert(bad_ipp_printer + "_ty"); |
| // Advertise on IPP and LPD services. |
| ipp_lister_->Announce(MakeServiceDescription( |
| bad_ipp_printer, ZeroconfPrinterDetector::kIppServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| bad_ipp_printer, ZeroconfPrinterDetector::kIppsServiceName)); |
| lpd_lister_->Announce(MakeServiceDescription( |
| bad_ipp_printer, ZeroconfPrinterDetector::kLpdServiceName)); |
| CreateDetectorWithIppRejectList(reject_list); |
| CompleteTasks(); |
| |
| // Should be rejected for IPPS-E and IPP-E, so it should only exist in LPD. |
| ExpectPrintersAre({MakeExpectedPrinter(bad_ipp_printer, ServiceType::kLpd)}); |
| |
| lpd_lister_->Remove(bad_ipp_printer); |
| CompleteTasks(); |
| // No entries left. |
| ExpectPrintersEmpty(); |
| } |
| |
| // Test that cache flushes appropriately remove entries. |
| TEST_F(ZeroconfPrinterDetectorTest, CacheFlushes) { |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer6", ZeroconfPrinterDetector::kIppServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer7", ZeroconfPrinterDetector::kIppServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer7", ZeroconfPrinterDetector::kIppsServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer8", ZeroconfPrinterDetector::kIppsServiceName)); |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer8", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer9", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer9", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer10", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer10", ZeroconfPrinterDetector::kSocketServiceName)); |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer11", ZeroconfPrinterDetector::kSocketServiceName)); |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer11", ZeroconfPrinterDetector::kLpdServiceName)); |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer12", ZeroconfPrinterDetector::kLpdServiceName)); |
| |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer6", ServiceType::kIpp), |
| MakeExpectedPrinter("Printer7", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer8", ServiceType::kIppE), |
| MakeExpectedPrinter("Printer9", ServiceType::kIppsE), |
| MakeExpectedPrinter("Printer10", ServiceType::kIppsE), |
| MakeExpectedPrinter("Printer11", ServiceType::kSocket), |
| MakeExpectedPrinter("Printer12", ServiceType::kLpd)}); |
| |
| ipps_lister_->Clear(); |
| |
| CompleteTasks(); |
| // With the IPPS lister cleared, all printers should be cleared. |
| ExpectPrintersEmpty(); |
| |
| // We should have restarted discovery after dealing with the cache flush. |
| EXPECT_TRUE(ipps_lister_->discovery_started()); |
| |
| // Just for kicks, announce something new at this point. |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer13", ZeroconfPrinterDetector::kIppsServiceName)); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer13", ServiceType::kIpps)}); |
| |
| // Clear out the IPPS lister, which will clear all printers too. |
| ipps_lister_->Clear(); |
| CompleteTasks(); |
| |
| // With the IPPS lister cleared, Printer13 should disappear. |
| ExpectPrintersEmpty(); |
| EXPECT_TRUE(ippe_lister_->discovery_started()); |
| } |
| |
| // Test some general traffic with a mix of everything we expect to handle. |
| TEST_F(ZeroconfPrinterDetectorTest, GeneralMixedTraffic) { |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer12", ZeroconfPrinterDetector::kIppServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer12", ZeroconfPrinterDetector::kIppsServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer13", ZeroconfPrinterDetector::kIppsServiceName)); |
| ippse_lister_->Announce(MakeServiceDescription( |
| "Printer14", ZeroconfPrinterDetector::kIppsEverywhereServiceName)); |
| ipps_lister_->Announce(MakeServiceDescription( |
| "Printer15", ZeroconfPrinterDetector::kIppsServiceName)); |
| socket_lister_->Announce(MakeServiceDescription( |
| "Printer16", ZeroconfPrinterDetector::kSocketServiceName)); |
| lpd_lister_->Announce(MakeServiceDescription( |
| "Printer17", ZeroconfPrinterDetector::kLpdServiceName)); |
| |
| CreateDetector(); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer12", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer13", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer14", ServiceType::kIppsE), |
| MakeExpectedPrinter("Printer15", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer16", ServiceType::kSocket), |
| MakeExpectedPrinter("Printer17", ServiceType::kLpd)}); |
| |
| ippe_lister_->Announce(MakeServiceDescription( |
| "Printer13", ZeroconfPrinterDetector::kIppEverywhereServiceName)); |
| ipp_lister_->Announce(MakeServiceDescription( |
| "Printer18", ZeroconfPrinterDetector::kIppServiceName)); |
| CompleteTasks(); |
| ExpectPrintersAre({MakeExpectedPrinter("Printer12", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer13", ServiceType::kIppE), |
| MakeExpectedPrinter("Printer14", ServiceType::kIppsE), |
| MakeExpectedPrinter("Printer15", ServiceType::kIpps), |
| MakeExpectedPrinter("Printer16", ServiceType::kSocket), |
| MakeExpectedPrinter("Printer17", ServiceType::kLpd), |
| MakeExpectedPrinter("Printer18", ServiceType::kIpp)}); |
| |
| ipp_lister_->Remove("NonexistantPrinter"); |
| ipps_lister_->Remove("Printer12"); |
| ipps_lister_->Clear(); |
| CompleteTasks(); |
| ExpectPrintersEmpty(); |
| } |
| |
| // Verify tasks are cleaned up properly when class is destroyed. |
| TEST_F(ZeroconfPrinterDetectorTest, DestroyedWithTasksPending) { |
| CreateDetector(); |
| // Cause a callback to be queued. |
| ipp_lister_->Announce(MakeServiceDescription( |
| "TestPrinter", ZeroconfPrinterDetector::kIppServiceName)); |
| // Run listers but don't run the delayed tasks. |
| task_environment_.RunUntilIdle(); |
| |
| // Delete the detector. |
| detector_.reset(); |
| |
| // Clear task queues where we would crash if we did something wrong. |
| task_environment_.FastForwardUntilNoTasksRemain(); |
| SUCCEED(); |
| } |
| |
| } // namespace |
| } // namespace ash |