blob: fd506c72a393011d074a29f29fbd9e7750f2c718 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/printing/printer_event_tracker.h"
#include "base/macros.h"
#include "base/metrics/histogram_functions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/printing/printer_configurer.h"
#include "chromeos/printing/printer_configuration.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/printer_event.pb.h"
namespace chromeos {
namespace {
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";
constexpr char kEmptyNetworkAutomaticSetupSourceMetric[] =
"Printing.CUPS.EmptyNetworkAutomaticSetupEventSource";
constexpr char kEmptyUsbAutomaticSetupSourceMetric[] =
"Printing.CUPS.EmptyUsbAutomaticSetupEventSource";
class PrinterEventTrackerTest : public testing::Test {
public:
PrinterEventTrackerTest() = default;
~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;
}
private:
DISALLOW_COPY_AND_ASSIGN(PrinterEventTrackerTest);
};
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,
PrinterSetupSource::kSettings);
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,
PrinterSetupSource::kSettings);
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,
PrinterSetupSource::kSettings);
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,
PrinterSetupSource::kSettings);
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,
PrinterSetupSource::kSettings);
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,
PrinterSetupSource::kSettings);
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.printer.set_manufacturer(kUsbManufacturer);
usb_printer.printer.set_model(kUsbModel);
usb_printer.printer.mutable_ppd_reference()->effective_make_and_model =
kEffectiveMakeAndModel;
tracker_.RecordUsbPrinterInstalled(usb_printer,
PrinterEventTracker::SetupMode::kUser,
PrinterSetupSource::kSettings);
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.printer.set_manufacturer(kUsbManufacturer);
usb_printer.printer.set_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());
}
// Tests that when a network printer is automatically installed that does not
// have any populated make and model values, that the appropriate UMA histogram
// will be updated.
TEST_F(PrinterEventTrackerTest, LogEmptyIppAutomaticSetupEvents) {
tracker_.set_logging(true);
base::HistogramTester histograms;
// Create a printer which has no fields populated except for the ppd
// identifier.
Printer printer;
printer.mutable_ppd_reference()->effective_make_and_model = "test_ppd";
tracker_.RecordIppPrinterInstalled(printer, PrinterEventTracker::kAutomatic,
PrinterSetupSource::kSettings);
histograms.ExpectBucketCount(kEmptyNetworkAutomaticSetupSourceMetric,
PrinterSetupSource::kSettings, 1);
}
// Tests that when a USB printer is automatically installed that does not have
// any populated make and model values, that the appropriate UMA histogram will
// be updated.
TEST_F(PrinterEventTrackerTest, LogEmptyUsbAutomaticSetupEvents) {
tracker_.set_logging(true);
base::HistogramTester histograms;
// Create a detected printer which has no fields populated except for the ppd
// identifier.
PrinterDetector::DetectedPrinter usb_printer;
usb_printer.printer.mutable_ppd_reference()->effective_make_and_model =
kEffectiveMakeAndModel;
tracker_.RecordUsbPrinterInstalled(usb_printer,
PrinterEventTracker::kAutomatic,
PrinterSetupSource::kPrintPreview);
histograms.ExpectBucketCount(kEmptyUsbAutomaticSetupSourceMetric,
PrinterSetupSource::kPrintPreview, 1);
}
// Test that when a non-empty network printer is installed automatically, that
// we don't log any UMA metrics for empty setup events.
TEST_F(PrinterEventTrackerTest, SkipLoggingValidNetworkInstallations) {
tracker_.set_logging(true);
base::HistogramTester histograms;
// The histogram object isn't actually created until at least one enumeration
// has been logged. So we log an event for print preview, and then expect that
// after installing a valid printer that the histogram has not been changed.
base::UmaHistogramEnumeration(kEmptyNetworkAutomaticSetupSourceMetric,
PrinterSetupSource::kPrintPreview);
// Create a printer which has a value set for the make_and_model field.
Printer printer;
printer.set_make_and_model("make_and_model");
printer.mutable_ppd_reference()->effective_make_and_model = "test_ppd";
tracker_.RecordIppPrinterInstalled(printer, PrinterEventTracker::kAutomatic,
PrinterSetupSource::kArcPrintService);
// Since |printer| is not an "empty" setup event, we expect that the UMA
// histogram has not been updated.
histograms.ExpectBucketCount(kEmptyNetworkAutomaticSetupSourceMetric,
PrinterSetupSource::kPrintPreview, 1);
}
// Test that when a non-empty network printer is installed automatically, that
// we don't log any UMA metrics for empty setup events.
TEST_F(PrinterEventTrackerTest, SkipLoggingValidUsbInstallations) {
tracker_.set_logging(true);
base::HistogramTester histograms;
// The histogram object isn't actually created until at least one enumeration
// has been logged. So we log an event for print preview, and then expect that
// after installing a valid printer that the histogram has not been changed.
base::UmaHistogramEnumeration(kEmptyUsbAutomaticSetupSourceMetric,
PrinterSetupSource::kPrintPreview);
// Create a detected printer which has fields set for the
// usb_printer_manufacturer and usb_printer_model fields.
PrinterDetector::DetectedPrinter usb_printer;
usb_printer.ppd_search_data.usb_vendor_id = 1;
usb_printer.ppd_search_data.usb_product_id = 1;
usb_printer.printer.set_manufacturer("manufacturer");
usb_printer.printer.set_model("model");
usb_printer.printer.mutable_ppd_reference()->effective_make_and_model =
kEffectiveMakeAndModel;
tracker_.RecordUsbPrinterInstalled(usb_printer,
PrinterEventTracker::kAutomatic,
PrinterSetupSource::kPrintPreview);
// Since |usb_printer| is not an "empty" setup event, we expect that the UMA
// histogram has not been updated.
histograms.ExpectBucketCount(kEmptyUsbAutomaticSetupSourceMetric,
PrinterSetupSource::kPrintPreview, 1);
}
} // namespace
} // namespace chromeos