chromium/chrome/services/cups_proxy/public/cpp/cups_util_unittest.cc

// Copyright 2019 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/services/cups_proxy/public/cpp/cups_util.h"

#include <cups/ipp.h>

#include <algorithm>
#include <string>
#include <string_view>
#include <vector>

#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "chromeos/printing/printer_configuration.h"
#include "printing/backend/cups_jobs.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cups_proxy {
namespace {

using chromeos::Printer;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::Pointwise;

// Matcher used to compare two Printers by display_name.
MATCHER(DisplayNameEq, "") {
  return std::get<0>(arg).display_name() == std::get<1>(arg).display_name();
}

const char kEndpointPrefix[] = "/printers/";

// Generated via base::GenerateGUID.
const char kDefaultPrinterId[] = "fd4c5f2e-7549-43d5-b931-9bf4e4f1bf51";

ipp_t* GetPrinterAttributesRequest(
    std::string printer_uri = kDefaultPrinterId) {
  ipp_t* ret = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
  if (!ret) {
    return nullptr;
  }

  printer_uri = printing::PrinterUriFromName(printer_uri);
  ippAddString(ret, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr,
               printer_uri.c_str());
  return ret;
}

// Generates |num_printers| printers with unique display_names starting with
// |prefix|.
std::vector<Printer> GenPrinters(int num_printers, std::string_view prefix) {
  std::vector<Printer> ret;
  for (int i = 0; i < num_printers; i++) {
    Printer printer;
    printer.set_display_name(base::StrCat({prefix, base::NumberToString(i)}));
    ret.push_back(printer);
  }
  return ret;
}

std::vector<Printer> GetSavedPrinters(int num_printers) {
  return GenPrinters(num_printers, "SavedPrinter");
}

std::vector<Printer> GetEnterprisePrinters(int num_printers) {
  return GenPrinters(num_printers, "EnterprisePrinter");
}

TEST(GetPrinterIdTest, SimpleSanityTest) {
  auto printer_id = GetPrinterId(GetPrinterAttributesRequest());
  EXPECT_TRUE(printer_id);
  EXPECT_EQ(*printer_id, kDefaultPrinterId);
}

// PrinterId's must be non-empty.
TEST(GetPrinterIdTest, EmptyPrinterId) {
  EXPECT_FALSE(GetPrinterId(GetPrinterAttributesRequest("")));
}

TEST(GetPrinterIdTest, MissingPrinterUri) {
  ipp_t* ipp = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
  EXPECT_FALSE(GetPrinterId(ipp));
}

// Embedded 'printer-uri' attribute must contain a '/'.
TEST(GetPrinterIdTest, MissingPathDelimiter) {
  ipp_t* ret = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
  if (!ret) {
    return;
  }

  // Omitting using printing::PrinterUriFromId to correctly embed the uri.
  ippAddString(ret, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", nullptr,
               kDefaultPrinterId);
  EXPECT_FALSE(GetPrinterId(ret));
}

TEST(ParseEndpointForPrinterIdTest, SimpleSanityTest) {
  std::optional<std::string> printer_id = ParseEndpointForPrinterId(
      std::string(kEndpointPrefix) + kDefaultPrinterId);

  EXPECT_TRUE(printer_id.has_value());
  EXPECT_THAT(*printer_id, Not(IsEmpty()));
}

// PrinterId's must be non-empty.
TEST(ParseEndpointForPrinterIdTest, EmptyPrinterId) {
  EXPECT_FALSE(ParseEndpointForPrinterId(kEndpointPrefix));
}

// Endpoints must contain a '/'.
TEST(ParseEndpointForPrinterIdTest, MissingPathDelimiter) {
  EXPECT_FALSE(ParseEndpointForPrinterId(kDefaultPrinterId));
}

// If there are enough saved printers, we should just serve those.
TEST(FilterPrintersForPluginVmTest, EnoughSavedPrinters) {
  auto saved = GetSavedPrinters(kPluginVmPrinterLimit);
  auto enterprise = GetEnterprisePrinters(10);
  auto ret = FilterPrintersForPluginVm(saved, enterprise, {});
  EXPECT_THAT(ret, Pointwise(DisplayNameEq(), saved));
}

// If there are less than kPluginVmPrinterLimit printers, serve all of them.
TEST(FilterPrintersForPluginVmTest, VeryFewSavedPrinters) {
  auto saved = GetSavedPrinters(4);
  auto enterprise = GetEnterprisePrinters(1);
  std::vector<std::string> recent = {saved[2].id(), saved[1].id(),
                                     saved[3].id()};
  std::vector<Printer> expected = {saved[2], saved[1], saved[3], saved[0],
                                   enterprise[0]};
  auto ret = FilterPrintersForPluginVm(saved, enterprise, recent);
  EXPECT_THAT(ret, Pointwise(DisplayNameEq(), expected));
}

// Make sure stale recent printers (printers not found in either the saved or
// enterprise list) are ignored.
TEST(FilterPrintersForPluginVmTest, StaleSavedPrinters) {
  auto stale = GetSavedPrinters(3);
  auto enterprise = GetEnterprisePrinters(2);
  std::vector<std::string> recent = {stale[0].id(), stale[1].id(),
                                     enterprise[1].id(), stale[2].id()};
  std::vector<Printer> expected = {enterprise[1], enterprise[0]};
  auto ret = FilterPrintersForPluginVm({}, enterprise, recent);
  EXPECT_THAT(ret, Pointwise(DisplayNameEq(), expected));
}

// Serve printers in the following order: recent printers followed by saved
// printers followed by enterprise printers, up to the limit.
TEST(FilterPrintersForPluginVmTest, EnterprisePrinters) {
  auto saved = GetSavedPrinters(10);
  auto enterprise = GetEnterprisePrinters(50);
  std::vector<std::string> recent = {enterprise[1].id(), saved[1].id()};

  std::vector<Printer> expected = {enterprise[1], saved[1], saved[0]};
  expected.insert(expected.end(), saved.begin() + 2, saved.end());
  expected.push_back(enterprise[0]);
  expected.insert(expected.end(), enterprise.begin() + 2, enterprise.end());
  if (expected.size() > kPluginVmPrinterLimit)
    expected.resize(kPluginVmPrinterLimit);

  auto ret = FilterPrintersForPluginVm(saved, enterprise, recent);
  EXPECT_THAT(ret, Pointwise(DisplayNameEq(), expected));

  // Test self-check.
  EXPECT_EQ(ret.front().display_name(), "EnterprisePrinter1");
  EXPECT_EQ(ret[1].display_name(), "SavedPrinter1");
  EXPECT_EQ(ret[2].display_name(), "SavedPrinter0");
  EXPECT_EQ(ret[3].display_name(), "SavedPrinter2");
  EXPECT_EQ(ret.back().display_name(), "EnterprisePrinter29");

  size_t last_saved_printer_idx = 10;
  EXPECT_EQ(ret[last_saved_printer_idx].display_name(), "SavedPrinter9");
  EXPECT_EQ(ret[last_saved_printer_idx + 1].display_name(),
            "EnterprisePrinter0");
  EXPECT_EQ(ret[last_saved_printer_idx + 2].display_name(),
            "EnterprisePrinter2");
}

}  // namespace
}  // namespace cups_proxy