|  | // 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/printer_event_tracker.h" | 
|  |  | 
|  | #include "base/time/time.h" | 
|  | #include "chromeos/printing/printer_configuration.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/metrics_proto/printer_event.pb.h" | 
|  |  | 
|  | namespace ash { | 
|  | namespace { | 
|  |  | 
|  | using ::chromeos::Printer; | 
|  |  | 
|  | constexpr int kVendorId = 0x3241; | 
|  | constexpr int kProductId = 0x1337; | 
|  | constexpr char kUsbManufacturer[] = "Usb MakesPrinters"; | 
|  | constexpr char kUsbModel[] = "Printer ModelName"; | 
|  |  | 
|  | constexpr char kMakeAndModel[] = "Chromium RazLazer X4321er"; | 
|  | constexpr char kEffectiveMakeAndModel[] = "Generic PostScript"; | 
|  |  | 
|  | class PrinterEventTrackerTest : public testing::Test { | 
|  | public: | 
|  | PrinterEventTrackerTest() = default; | 
|  |  | 
|  | PrinterEventTrackerTest(const PrinterEventTrackerTest&) = delete; | 
|  | PrinterEventTrackerTest& operator=(const PrinterEventTrackerTest&) = delete; | 
|  |  | 
|  | ~PrinterEventTrackerTest() override = default; | 
|  |  | 
|  | protected: | 
|  | PrinterEventTracker tracker_; | 
|  |  | 
|  | // Returns a copy of the first element recorded by the tracker.  Calls Flush | 
|  | // on the |tracker_|. | 
|  | std::vector<metrics::PrinterEventProto> GetEvents() { | 
|  | std::vector<metrics::PrinterEventProto> events; | 
|  | tracker_.FlushPrinterEvents(&events); | 
|  | return events; | 
|  | } | 
|  | }; | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, RecordsWhenEnabled) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled(test_printer, PrinterEventTracker::kUser); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | EXPECT_EQ(1U, events.size()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, DefaultLoggingOff) { | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled(test_printer, | 
|  | PrinterEventTracker::kAutomatic); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | EXPECT_TRUE(events.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, DoesNotRecordWhileDisabled) { | 
|  | tracker_.set_logging(false); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled(test_printer, | 
|  | PrinterEventTracker::kAutomatic); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | EXPECT_TRUE(events.empty()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, InstalledIppPrinter) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled(test_printer, PrinterEventTracker::kUser); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  | metrics::PrinterEventProto recorded_event = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_MANUAL, | 
|  | recorded_event.event_type()); | 
|  | EXPECT_EQ(kMakeAndModel, recorded_event.ipp_make_and_model()); | 
|  | EXPECT_EQ(kEffectiveMakeAndModel, recorded_event.ppd_identifier()); | 
|  |  | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_manufacturer()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_model()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_vendor_id()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_model_id()); | 
|  | EXPECT_FALSE(recorded_event.user_ppd()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, InstalledPrinterAuto) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->autoconf = true; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled( | 
|  | test_printer, PrinterEventTracker::SetupMode::kAutomatic); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto recorded_event = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_AUTOMATIC, | 
|  | recorded_event.event_type()); | 
|  | EXPECT_EQ(kMakeAndModel, recorded_event.ipp_make_and_model()); | 
|  | // For autoconf printers, ppd identifier is blank but a successful setup is | 
|  | // recorded. | 
|  | EXPECT_FALSE(recorded_event.has_ppd_identifier()); | 
|  |  | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_manufacturer()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_model()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_vendor_id()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_model_id()); | 
|  | EXPECT_FALSE(recorded_event.user_ppd()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, InstalledPrinterUserPpd) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.mutable_ppd_reference()->user_supplied_ppd_url = | 
|  | "file:///i_dont_record_this_field/blah/blah/blah/some_ppd.ppd"; | 
|  |  | 
|  | tracker_.RecordIppPrinterInstalled(test_printer, | 
|  | PrinterEventTracker::SetupMode::kUser); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto recorded_event = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_MANUAL, | 
|  | recorded_event.event_type()); | 
|  |  | 
|  | // For user PPDs we just record that it was a user PPD, the value is not | 
|  | // recorded. | 
|  | EXPECT_TRUE(recorded_event.user_ppd()); | 
|  | EXPECT_FALSE(recorded_event.has_ppd_identifier()); | 
|  |  | 
|  | // This is empty if it was not detected. | 
|  | EXPECT_FALSE(recorded_event.has_ipp_make_and_model()); | 
|  |  | 
|  | // Network printers do not have usb information. | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_manufacturer()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_model()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_vendor_id()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_model_id()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, InstalledUsbPrinter) { | 
|  | tracker_.set_logging(true); | 
|  | PrinterDetector::DetectedPrinter usb_printer; | 
|  | usb_printer.ppd_search_data.usb_vendor_id = kVendorId; | 
|  | usb_printer.ppd_search_data.usb_product_id = kProductId; | 
|  | usb_printer.ppd_search_data.usb_manufacturer = kUsbManufacturer; | 
|  | usb_printer.ppd_search_data.usb_model = kUsbModel; | 
|  | usb_printer.printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordUsbPrinterInstalled(usb_printer, | 
|  | PrinterEventTracker::SetupMode::kUser); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto record = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_MANUAL, record.event_type()); | 
|  | EXPECT_EQ(kVendorId, record.usb_vendor_id()); | 
|  | EXPECT_EQ(kProductId, record.usb_model_id()); | 
|  | EXPECT_EQ(kUsbManufacturer, record.usb_printer_manufacturer()); | 
|  | EXPECT_EQ(kUsbModel, record.usb_printer_model()); | 
|  |  | 
|  | EXPECT_EQ(kEffectiveMakeAndModel, record.ppd_identifier()); | 
|  | EXPECT_FALSE(record.user_ppd()); | 
|  |  | 
|  | // USB doesn't detect this field. | 
|  | EXPECT_FALSE(record.has_ipp_make_and_model()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, AbandonedNetworkPrinter) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  |  | 
|  | tracker_.RecordSetupAbandoned(test_printer); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto recorded_event = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_ABANDONED, | 
|  | recorded_event.event_type()); | 
|  | EXPECT_EQ(kMakeAndModel, recorded_event.ipp_make_and_model()); | 
|  |  | 
|  | // Abandoned setups should not record a chosen PPD or user PPD. | 
|  | EXPECT_FALSE(recorded_event.has_user_ppd()); | 
|  | EXPECT_FALSE(recorded_event.has_ppd_identifier()); | 
|  |  | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_manufacturer()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_model()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_vendor_id()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_model_id()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, AbandonedUsbPrinter) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | PrinterDetector::DetectedPrinter usb_printer; | 
|  | usb_printer.ppd_search_data.usb_vendor_id = kVendorId; | 
|  | usb_printer.ppd_search_data.usb_product_id = kProductId; | 
|  | usb_printer.ppd_search_data.usb_manufacturer = kUsbManufacturer; | 
|  | usb_printer.ppd_search_data.usb_model = kUsbModel; | 
|  |  | 
|  | tracker_.RecordUsbSetupAbandoned(usb_printer); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto record = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::SETUP_ABANDONED, record.event_type()); | 
|  | EXPECT_EQ(kVendorId, record.usb_vendor_id()); | 
|  | EXPECT_EQ(kProductId, record.usb_model_id()); | 
|  | EXPECT_EQ(kUsbManufacturer, record.usb_printer_manufacturer()); | 
|  | EXPECT_EQ(kUsbModel, record.usb_printer_model()); | 
|  |  | 
|  | EXPECT_FALSE(record.has_user_ppd()); | 
|  | EXPECT_FALSE(record.has_ppd_identifier()); | 
|  | } | 
|  |  | 
|  | TEST_F(PrinterEventTrackerTest, RemovedPrinter) { | 
|  | tracker_.set_logging(true); | 
|  |  | 
|  | Printer test_printer; | 
|  | test_printer.set_make_and_model(kMakeAndModel); | 
|  | test_printer.mutable_ppd_reference()->effective_make_and_model = | 
|  | kEffectiveMakeAndModel; | 
|  |  | 
|  | tracker_.RecordPrinterRemoved(test_printer); | 
|  |  | 
|  | auto events = GetEvents(); | 
|  | ASSERT_FALSE(events.empty()); | 
|  |  | 
|  | metrics::PrinterEventProto recorded_event = events.front(); | 
|  | EXPECT_EQ(metrics::PrinterEventProto::PRINTER_DELETED, | 
|  | recorded_event.event_type()); | 
|  | // All printers record make and model information here. | 
|  | EXPECT_EQ(kMakeAndModel, recorded_event.ipp_make_and_model()); | 
|  |  | 
|  | // PPD info. | 
|  | EXPECT_EQ(kEffectiveMakeAndModel, recorded_event.ppd_identifier()); | 
|  | EXPECT_FALSE(recorded_event.user_ppd()); | 
|  |  | 
|  | // USB Info is not retained for removed printers. | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_manufacturer()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_printer_model()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_vendor_id()); | 
|  | EXPECT_FALSE(recorded_event.has_usb_model_id()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace ash |