#include "chromeos/printing/ppd_provider.h"
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.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/strcat.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/simple_test_clock.h"
#include "base/test/task_environment.h"
#include "base/test/test_message_loop.h"
#include "base/version.h"
#include "chromeos/printing/fake_printer_config_cache.h"
#include "chromeos/printing/ppd_cache.h"
#include "chromeos/printing/ppd_metadata_manager.h"
#include "chromeos/printing/printer_config_cache.h"
#include "chromeos/printing/printer_configuration.h"
#include "chromeos/printing/remote_ppd_fetcher.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace chromeos {
namespace {
using PrinterDiscoveryType = PrinterSearchData::PrinterDiscoveryType;
using ::testing::_;
using ::testing::AllOf;
using ::testing::Eq;
using ::testing::Field;
using ::testing::StrEq;
using ::testing::UnorderedElementsAre;
using ::testing::WithArg;
const char kCupsFilterPpdContents[] = R"(
Other random contents that we don't care about.
*cupsFilter: "application/vnd.cups-raster 0 my_filter"
More random contents that we don't care about
*cupsFilter: "application/vnd.cups-awesome 0 a_different_filter"
*cupsFilter: "application/vnd.cups-awesomesauce 0 filter3"
Yet more randome contents that we don't care about.
More random contents that we don't care about.
)";
const char kCupsFilter2PpdContents[] = R"(
Other random contents that we don't care about.
*cupsFilter: "application/vnd.cups-raster 0 my_filter"
More random contents that we don't care about
*cupsFilter2: "foo bar 0 the_real_filter"
*cupsFilter2: "bar baz 381 another_real_filter"
Yet more randome contents that we don't care about.
More random contents that we don't care about.
)";
const char kDefaultManufacturersJson[] = R"({
"filesMap": {
"Manufacturer A": "manufacturer_a-en.json",
"Manufacturer B": "manufacturer_b-en.json"
}
})";
struct MockRemotePpdFetcher : RemotePpdFetcher {
MOCK_METHOD(void,
Fetch,
(const GURL& url, FetchCallback cb),
(const, override));
};
struct PpdProviderComposedMembers {
raw_ptr<FakePrinterConfigCache, DanglingUntriaged> config_cache = nullptr;
raw_ptr<FakePrinterConfigCache, DanglingUntriaged> manager_config_cache =
nullptr;
raw_ptr<PpdMetadataManager, DanglingUntriaged> metadata_manager = nullptr;
raw_ptr<MockRemotePpdFetcher, DanglingUntriaged> remote_ppd_fetcher = nullptr;
};
class PpdProviderTest : public ::testing::Test {
public:
enum class PpdCacheRunLocation {
kOnTestThread,
kInBackgroundThreads,
};
PpdProviderTest()
: task_environment_(base::test::TaskEnvironment::MainThreadType::IO,
base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
void SetUp() override {
ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir());
}
scoped_refptr<PpdProvider> CreateProvider(
PpdCacheRunLocation where_ppd_cache_runs) {
switch (where_ppd_cache_runs) {
case PpdCacheRunLocation::kOnTestThread:
ppd_cache_ = PpdCache::CreateForTesting(
ppd_cache_temp_dir_.GetPath(),
task_environment_.GetMainThreadTaskRunner());
break;
case PpdCacheRunLocation::kInBackgroundThreads:
default:
ppd_cache_ = PpdCache::Create(ppd_cache_temp_dir_.GetPath());
break;
}
auto manager_config_cache = std::make_unique<FakePrinterConfigCache>();
provider_backdoor_.manager_config_cache = manager_config_cache.get();
auto manager = PpdMetadataManager::Create(
PpdIndexChannel::kProduction, &clock_, std::move(manager_config_cache));
provider_backdoor_.metadata_manager = manager.get();
auto config_cache = std::make_unique<FakePrinterConfigCache>();
provider_backdoor_.config_cache = config_cache.get();
auto remote_ppd_fetcher = std::make_unique<MockRemotePpdFetcher>();
provider_backdoor_.remote_ppd_fetcher = remote_ppd_fetcher.get();
return PpdProvider::Create(base::Version("40.8.6753.09"), ppd_cache_,
std::move(manager), std::move(config_cache),
std::move(remote_ppd_fetcher));
}
void StartFakePpdServer() {
for (const auto& entry : server_contents()) {
provider_backdoor_.config_cache->SetFetchResponseForTesting(entry.first,
entry.second);
provider_backdoor_.manager_config_cache->SetFetchResponseForTesting(
entry.first, entry.second);
}
}
void StopFakePpdServer() {
for (const auto& entry : server_contents()) {
provider_backdoor_.config_cache->Drop(entry.first);
provider_backdoor_.manager_config_cache->Drop(entry.first);
}
task_environment_.RunUntilIdle();
}
void CaptureResolveManufacturers(PpdProvider::CallbackResultCode code,
const std::vector<std::string>& data) {
captured_resolve_manufacturers_.push_back({code, data});
}
void CaptureResolvePrinters(PpdProvider::CallbackResultCode code,
const PpdProvider::ResolvedPrintersList& data) {
captured_resolve_printers_.push_back({code, data});
}
void CaptureResolvePpd(PpdProvider::CallbackResultCode code,
const std::string& ppd_contents) {
CapturedResolvePpdResults results;
results.code = code;
results.ppd_contents = ppd_contents;
captured_resolve_ppd_.push_back(results);
}
void CaptureResolvePpdReference(PpdProvider::CallbackResultCode code,
const Printer::PpdReference& ref,
const std::string& usb_manufacturer) {
captured_resolve_ppd_references_.push_back({code, ref, usb_manufacturer});
}
void CaptureResolvePpdLicense(PpdProvider::CallbackResultCode code,
const std::string& license) {
captured_resolve_ppd_license_.push_back({code, license});
}
void CaptureReverseLookup(PpdProvider::CallbackResultCode code,
const std::string& manufacturer,
const std::string& model) {
captured_reverse_lookup_.push_back({code, manufacturer, model});
}
void DiscardResolvePpd(PpdProvider::CallbackResultCode code,
const std::string& contents) {}
void MockRemotePpdFetchResult(const std::string& url, std::string content) {
auto invoke_callback_with_content =
[content](RemotePpdFetcher::FetchCallback cb) {
std::move(cb).Run(RemotePpdFetcher::FetchResultCode::kSuccess,
std::move(content));
};
EXPECT_CALL(*provider_backdoor_.remote_ppd_fetcher, Fetch(GURL(url), _))
.WillOnce(WithArg<1>(invoke_callback_with_content));
}
void MockRemotePpdFetchResult(const std::string& url,
RemotePpdFetcher::FetchResultCode code) {
auto invoke_callback_with_content =
[code](RemotePpdFetcher::FetchCallback cb) {
std::move(cb).Run(code, std::string());
};
EXPECT_CALL(*provider_backdoor_.remote_ppd_fetcher, Fetch(GURL(url), _))
.WillOnce(WithArg<1>(invoke_callback_with_content));
}
bool SuccessfullyResolveManufacturers(PpdProvider* provider) {
base::RunLoop run_loop;
PpdProvider::CallbackResultCode code;
provider->ResolveManufacturers(base::BindLambdaForTesting(
[&run_loop, &code](
PpdProvider::CallbackResultCode result_code,
const std::vector<std::string>& unused_manufacturers) {
code = result_code;
run_loop.QuitClosure().Run();
}));
run_loop.Run();
return code == PpdProvider::CallbackResultCode::SUCCESS;
}
protected:
std::vector<std::pair<std::string, std::string>> server_contents() const {
return {{"metadata_v3/manufacturers-en.json", kDefaultManufacturersJson},
{"metadata_v3/manufacturer_a-en.json",
R"({
"printers": [ {
"name": "printer_a",
"emm": "printer_a_ref"
}, {
"name": "printer_b",
"emm": "printer_b_ref"
} ]
})"},
{"metadata_v3/manufacturer_b-en.json",
R"({
"printers": [ {
"name": "printer_c",
"emm": "printer_c_ref"
} ]
})"},
{"metadata_v3/index-01.json",
R"({
"ppdIndex": {
"printer_a_ref": {
"ppdMetadata": [ {
"name": "printer_a.ppd",
"license": "fake_license"
} ]
}
}
})"},
{"metadata_v3/index-02.json",
R"({
"ppdIndex": {
"printer_b_ref": {
"ppdMetadata": [ {
"name": "printer_b.ppd"
} ]
}
}
})"},
{"metadata_v3/index-03.json",
R"({
"ppdIndex": {
"printer_c_ref": {
"ppdMetadata": [ {
"name": "printer_c.ppd"
} ]
}
}
})"},
{"metadata_v3/index-04.json",
R"({
"ppdIndex": {
"printer_d_ref": {
"ppdMetadata": [ {
"name": "printer_d.ppd"
} ]
}
}
})"},
{"metadata_v3/index-05.json",
R"({
"ppdIndex": {
"printer_e_ref": {
"ppdMetadata": [ {
"name": "printer_e.ppd"
} ]
}
}
})"},
{"metadata_v3/index-08.json",
R"({
"ppdIndex": {
"Some canonical reference": {
"ppdMetadata": [ {
"name": "unused.ppd"
} ]
}
}
})"},
{"metadata_v3/index-10.json",
R"({
"ppdIndex": {
"Some other canonical reference": {
"ppdMetadata": [ {
"name": "unused.ppd"
} ]
},
"printer_a_ref_2": {
"ppdMetadata": [ {
"name": "printer_a.ppd",
"license": "fake_license"
} ]
}
}
})"},
{"metadata_v3/index-15.json",
R"({
"ppdIndex": {
"zebra zpl label printer": {
"ppdMetadata": [ {
"name": "unused.ppd"
} ]
}
}
})"},
{"metadata_v3/usb-031f.json",
R"({
"usbIndex": {
"1592": {
"effectiveMakeAndModel": "Some canonical reference"
},
"6535": {
"effectiveMakeAndModel": "Some other canonical reference"
}
}
})"},
{"metadata_v3/usb-03f0.json", ""},
{"metadata_v3/usb-1234.json", ""},
{"metadata_v3/usb_vendor_ids.json", R"({
"entries": [ {
"vendorId": 799,
"vendorName": "Seven Ninety Nine LLC"
}, {
"vendorId": 1008,
"vendorName": "HP"
} ]
})"},
{"metadata_v3/reverse_index-en-01.json",
R"({
"reverseIndex": {
"printer_a_ref": {
"manufacturer": "manufacturer_a_en",
"model": "printer_a"
}
}
})"},
{"metadata_v3/reverse_index-en-10.json",
R"({
"reverseIndex": {
"printer_a_ref_2": {
"manufacturer": "manufacturer_a_en",
"model": "printer_a"
}
}
})"},
{"metadata_v3/reverse_index-en-19.json",
R"({
"reverseIndex": {
"unused effective make and model": {
"manufacturer": "unused manufacturer",
"model": "unused model"
}
}
})"},
{"ppds_for_metadata_v3/printer_a.ppd", kCupsFilterPpdContents},
{"ppds_for_metadata_v3/printer_b.ppd", kCupsFilter2PpdContents},
{"ppds_for_metadata_v3/printer_c.ppd", "c"},
{"ppds_for_metadata_v3/printer_d.ppd", "d"},
{"ppds_for_metadata_v3/printer_e.ppd", "e"},
{"user_supplied_ppd_directory/user_supplied.ppd", "u"}};
}
base::test::TaskEnvironment task_environment_;
std::vector<
std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>>
captured_resolve_manufacturers_;
std::vector<std::pair<PpdProvider::CallbackResultCode,
PpdProvider::ResolvedPrintersList>>
captured_resolve_printers_;
struct CapturedResolvePpdResults {
PpdProvider::CallbackResultCode code;
std::string ppd_contents;
};
std::vector<CapturedResolvePpdResults> captured_resolve_ppd_;
struct CapturedResolvePpdReferenceResults {
PpdProvider::CallbackResultCode code;
Printer::PpdReference ref;
std::string usb_manufacturer;
};
std::vector<CapturedResolvePpdReferenceResults>
captured_resolve_ppd_references_;
struct CapturedReverseLookup {
PpdProvider::CallbackResultCode code;
std::string manufacturer;
std::string model;
};
std::vector<CapturedReverseLookup> captured_reverse_lookup_;
struct CapturedResolvePpdLicense {
PpdProvider::CallbackResultCode code;
std::string license;
};
std::vector<CapturedResolvePpdLicense> captured_resolve_ppd_license_;
base::ScopedTempDir ppd_cache_temp_dir_;
base::ScopedTempDir interceptor_temp_dir_;
scoped_refptr<PpdCache> ppd_cache_;
PpdProviderComposedMembers provider_backdoor_;
base::SimpleTestClock clock_;
};
TEST_F(PpdProviderTest, ManufacturersFetch) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
provider->ResolveManufacturers(base::BindOnce(
&PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
provider->ResolveManufacturers(base::BindOnce(
&PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
task_environment_.FastForwardUntilNoTasksRemain();
ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
std::vector<std::string> expected_result(
{"Manufacturer A", "Manufacturer B"});
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[0].first);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[1].first);
EXPECT_TRUE(captured_resolve_manufacturers_[0].second == expected_result);
EXPECT_TRUE(captured_resolve_manufacturers_[1].second == expected_result);
}
TEST_F(PpdProviderTest, ManufacturersFetchNoServer) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
provider->ResolveManufacturers(base::BindOnce(
&PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
provider->ResolveManufacturers(base::BindOnce(
&PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
task_environment_.FastForwardUntilNoTasksRemain();
ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
EXPECT_EQ(PpdProvider::SERVER_ERROR,
captured_resolve_manufacturers_[0].first);
EXPECT_EQ(PpdProvider::SERVER_ERROR,
captured_resolve_manufacturers_[1].first);
EXPECT_TRUE(captured_resolve_manufacturers_[0].second.empty());
EXPECT_TRUE(captured_resolve_manufacturers_[1].second.empty());
}
TEST_F(PpdProviderTest, RepeatedMakeModel) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
PrinterSearchData unrecognized_printer;
unrecognized_printer.discovery_type = PrinterDiscoveryType::kManual;
unrecognized_printer.make_and_model = {"Printer Printer"};
PrinterSearchData recognized_printer;
recognized_printer.discovery_type = PrinterDiscoveryType::kManual;
recognized_printer.make_and_model = {"printer_a_ref"};
PrinterSearchData mixed;
mixed.discovery_type = PrinterDiscoveryType::kManual;
mixed.make_and_model = {"printer_a_ref", "Printer Printer"};
provider->ResolvePpdReference(
unrecognized_printer,
base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
provider->ResolvePpdReference(
mixed, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
provider->ResolvePpdReference(
recognized_printer,
base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(static_cast<size_t>(3), captured_resolve_ppd_references_.size());
EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[1].code);
EXPECT_EQ("printer_a_ref",
captured_resolve_ppd_references_[1].ref.effective_make_and_model);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[2].code);
EXPECT_EQ("printer_a_ref",
captured_resolve_ppd_references_[2].ref.effective_make_and_model);
}
TEST_F(PpdProviderTest, UsbResolution) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
PrinterSearchData search_data;
search_data.discovery_type = PrinterDiscoveryType::kUsb;
search_data.usb_vendor_id = 0x031f;
search_data.usb_product_id = 1592;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
search_data.usb_vendor_id = 0x031f;
search_data.usb_product_id = 6535;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
search_data.usb_vendor_id = 0x031f;
search_data.usb_product_id = 8162;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
search_data.usb_vendor_id = 0x1234;
search_data.usb_product_id = 1782;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(captured_resolve_ppd_references_.size(), static_cast<size_t>(4));
EXPECT_THAT(
captured_resolve_ppd_references_,
UnorderedElementsAre(
AllOf(Field(&CapturedResolvePpdReferenceResults::code,
Eq(PpdProvider::SUCCESS)),
Field(&CapturedResolvePpdReferenceResults::ref,
Field(&Printer::PpdReference::effective_make_and_model,
StrEq("Some canonical reference")))),
AllOf(Field(&CapturedResolvePpdReferenceResults::code,
Eq(PpdProvider::SUCCESS)),
Field(&CapturedResolvePpdReferenceResults::ref,
Field(&Printer::PpdReference::effective_make_and_model,
StrEq("Some other canonical reference")))),
AllOf(Field(&CapturedResolvePpdReferenceResults::code,
Eq(PpdProvider::NOT_FOUND)),
Field(&CapturedResolvePpdReferenceResults::usb_manufacturer,
StrEq("Seven Ninety Nine LLC"))),
Field(&CapturedResolvePpdReferenceResults::code,
Eq(PpdProvider::NOT_FOUND))));
}
TEST_F(PpdProviderTest, ResolvePrinters) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
kDefaultManufacturersJson));
ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
provider->ResolvePrinters(
"Manufacturer A", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
base::Unretained(this)));
provider->ResolvePrinters(
"Manufacturer B", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(2UL, captured_resolve_printers_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first);
EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size());
const auto& capture0 = captured_resolve_printers_[0].second;
ASSERT_EQ(2UL, capture0.size());
EXPECT_EQ("printer_a", capture0[0].name);
EXPECT_EQ("printer_a_ref", capture0[0].ppd_ref.effective_make_and_model);
EXPECT_EQ("printer_b", capture0[1].name);
EXPECT_EQ("printer_b_ref", capture0[1].ppd_ref.effective_make_and_model);
const auto& capture1 = captured_resolve_printers_[1].second;
ASSERT_EQ(1UL, capture1.size());
EXPECT_EQ("printer_c", capture1[0].name);
EXPECT_EQ("printer_c_ref", capture1[0].ppd_ref.effective_make_and_model);
}
TEST_F(PpdProviderTest, ResolvePrintersBadReference) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
kDefaultManufacturersJson));
ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
provider->ResolvePrinters(
"bogus_doesnt_exist",
base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_printers_.size());
EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first);
}
TEST_F(PpdProviderTest, ResolvePrintersNoServer) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
kDefaultManufacturersJson));
ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
provider->ResolvePrinters(
"Manufacturer A", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
base::Unretained(this)));
provider->ResolvePrinters(
"Manufacturer B", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(2UL, captured_resolve_printers_.size());
EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first);
EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[1].first);
}
TEST_F(PpdProviderTest, ResolveServerKeyPpd) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
Printer::PpdReference ref;
ref.effective_make_and_model = "printer_b_ref";
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
ref.effective_make_and_model = "printer_c_ref";
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(2UL, captured_resolve_ppd_.size());
EXPECT_THAT(
captured_resolve_ppd_,
UnorderedElementsAre(
AllOf(Field(&CapturedResolvePpdResults::code,
PpdProvider::CallbackResultCode::SUCCESS),
Field(&CapturedResolvePpdResults::ppd_contents,
StrEq(kCupsFilter2PpdContents))),
AllOf(Field(&CapturedResolvePpdResults::code,
PpdProvider::CallbackResultCode::SUCCESS),
Field(&CapturedResolvePpdResults::ppd_contents, StrEq("c")))));
}
TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromFile) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
std::string user_ppd_contents = "Woohoo";
ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
Printer::PpdReference ref;
ref.user_supplied_ppd_url =
base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
}
TEST_F(PpdProviderTest, ResolvedPpdsGetCached) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
std::string user_ppd_contents = "Woohoo";
Printer::PpdReference ref;
{
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
ref.user_supplied_ppd_url =
base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
provider->ResolvePpd(ref,
base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
}
captured_resolve_ppd_.clear();
provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
}
TEST_F(PpdProviderTest, CaseInsensitiveMakeAndModel) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
std::string ref = "pRiNteR_A_reF";
Printer::PpdReference ppd_ref;
ppd_ref.effective_make_and_model = ref;
provider->ResolvePpd(ppd_ref,
base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
provider->ReverseLookup(ref,
base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
base::Unretained(this)));
PrinterSearchData printer_info;
printer_info.make_and_model = {ref};
provider->ResolvePpdReference(
printer_info, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(kCupsFilterPpdContents, captured_resolve_ppd_[0].ppd_contents);
ASSERT_EQ(1UL, captured_reverse_lookup_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_reverse_lookup_[0].code);
EXPECT_EQ("manufacturer_a_en", captured_reverse_lookup_[0].manufacturer);
EXPECT_EQ("printer_a", captured_reverse_lookup_[0].model);
ASSERT_EQ(1UL, captured_resolve_ppd_references_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[0].code);
EXPECT_EQ("printer_a_ref",
captured_resolve_ppd_references_[0].ref.effective_make_and_model);
}
TEST_F(PpdProviderTest, ResolvePpdFromSecondaryMakeAndModel) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
std::string ref = "pRiNteR_A_reF_2";
Printer::PpdReference ppd_ref;
ppd_ref.effective_make_and_model = ref;
provider->ResolvePpd(ppd_ref,
base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(kCupsFilterPpdContents, captured_resolve_ppd_[0].ppd_contents);
}
TEST_F(PpdProviderTest, ResolvePpdLicense) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
const char kEmm1[] = "printer_a_ref";
provider->ResolvePpdLicense(
kEmm1, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
base::Unretained(this)));
const char kEmm2[] = "printer_b_ref";
provider->ResolvePpdLicense(
kEmm2, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(2UL, captured_resolve_ppd_license_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[0].code);
EXPECT_EQ("fake_license", captured_resolve_ppd_license_[0].license);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[1].code);
EXPECT_EQ("", captured_resolve_ppd_license_[1].license);
}
TEST_F(PpdProviderTest, ResolvePpdLicenseFromSecondaryMakeAndModel) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
const char kEmm1[] = "printer_A_ref_2";
provider->ResolvePpdLicense(
kEmm1, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_license_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[0].code);
EXPECT_EQ("fake_license", captured_resolve_ppd_license_[0].license);
}
TEST_F(PpdProviderTest, ReverseLookup) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
std::string ref = "printer_a_ref";
provider->ReverseLookup(ref,
base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
base::Unretained(this)));
task_environment_.RunUntilIdle();
std::string ref_fail = "printer_does_not_exist";
provider->ReverseLookup(ref_fail,
base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(2U, captured_reverse_lookup_.size());
CapturedReverseLookup success_capture = captured_reverse_lookup_[0];
EXPECT_EQ(PpdProvider::SUCCESS, success_capture.code);
EXPECT_EQ("manufacturer_a_en", success_capture.manufacturer);
EXPECT_EQ("printer_a", success_capture.model);
CapturedReverseLookup failed_capture = captured_reverse_lookup_[1];
EXPECT_EQ(PpdProvider::NOT_FOUND, failed_capture.code);
}
TEST_F(PpdProviderTest, ReverseLookupFromSecondaryMakeAndModel) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
std::string ref = "printer_A_ref_2";
provider->ReverseLookup(ref,
base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1U, captured_reverse_lookup_.size());
CapturedReverseLookup success_capture = captured_reverse_lookup_[0];
EXPECT_EQ(PpdProvider::SUCCESS, success_capture.code);
EXPECT_EQ("manufacturer_a_en", success_capture.manufacturer);
EXPECT_EQ("printer_a", success_capture.model);
}
TEST_F(PpdProviderTest, PreferToResolvePpdFromPpdCacheOverServingRoot) {
std::string cached_ppd_contents =
"These cached contents are different from what's being served";
auto provider = CreateProvider(PpdCacheRunLocation::kOnTestThread);
Printer::PpdReference ref;
ref.effective_make_and_model = "printer_a_ref";
std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
const std::string ppd_basename = "printer_a.ppd";
ppd_cache_->StoreForTesting(PpdProvider::PpdBasenameToCacheKey(ppd_basename),
cached_ppd_contents, base::TimeDelta());
ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
ppd_basename, base::TimeDelta());
task_environment_.RunUntilIdle();
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
}
TEST_F(PpdProviderTest, UserPpdAlwaysRefreshedIfAvailable) {
base::ScopedTempDir temp_dir;
std::string cached_ppd_contents = "Cached Ppd Contents";
std::string disk_ppd_contents = "Updated Ppd Contents";
auto provider = CreateProvider(PpdCacheRunLocation::kOnTestThread);
StartFakePpdServer();
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
Printer::PpdReference ref;
ref.user_supplied_ppd_url =
base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
cached_ppd_contents, base::TimeDelta());
task_environment_.RunUntilIdle();
ASSERT_TRUE(base::WriteFile(filename, disk_ppd_contents));
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(disk_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
PpdCache::FindResult captured_find_result;
ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
base::BindOnce(
[](PpdCache::FindResult* captured_find_result,
const PpdCache::FindResult& find_result) {
*captured_find_result = find_result;
},
&captured_find_result));
task_environment_.RunUntilIdle();
EXPECT_EQ(captured_find_result.success, true);
EXPECT_EQ(captured_find_result.contents, disk_ppd_contents);
}
TEST_F(PpdProviderTest, ResolveUsbManufacturer) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
PrinterSearchData search_data;
search_data.discovery_type = PrinterDiscoveryType::kUsb;
search_data.usb_vendor_id = 0x03f0;
search_data.usb_product_id = 9999;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
search_data.usb_vendor_id = 0x1234;
search_data.usb_product_id = 1782;
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(static_cast<size_t>(2), captured_resolve_ppd_references_.size());
EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
EXPECT_EQ("HP", captured_resolve_ppd_references_[0].usb_manufacturer);
EXPECT_FALSE(captured_resolve_ppd_references_[1].code ==
PpdProvider::SUCCESS);
EXPECT_TRUE(captured_resolve_ppd_references_[1].usb_manufacturer.empty());
}
TEST_F(PpdProviderTest, GenericZebraPpdResolution) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
StartFakePpdServer();
PrinterSearchData search_data;
search_data.discovery_type = PrinterDiscoveryType::kManual;
search_data.printer_id.set_make("Zebra");
search_data.printer_id.set_model("ZTC label printer 2000 ZPL");
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
search_data.printer_id.set_make("Zebra Technologies");
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
search_data.printer_id.set_model("ZTC label printer 4000");
provider->ResolvePpdReference(
search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(3UL, captured_resolve_ppd_references_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[0].code);
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[1].code);
EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[2].code);
}
TEST_F(PpdProviderTest, RemotePpdFetchedFromUrlIfAvailable) {
auto provider = CreateProvider(PpdCacheRunLocation::kOnTestThread);
Printer::PpdReference ref;
ref.user_supplied_ppd_url = "https://ppd-url";
ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
"cached-content", base::TimeDelta());
MockRemotePpdFetchResult("https://ppd-url", "ppd-content");
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(captured_resolve_ppd_[0].ppd_contents, "ppd-content");
}
TEST_F(PpdProviderTest, RemotePpdResolveUsesCacheIfFetchFails) {
auto provider = CreateProvider(PpdCacheRunLocation::kOnTestThread);
Printer::PpdReference ref;
ref.user_supplied_ppd_url = "https://ppd-url";
ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
"cached-content", base::TimeDelta());
MockRemotePpdFetchResult("https://ppd-url",
RemotePpdFetcher::FetchResultCode::kNetworkError);
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
EXPECT_EQ(captured_resolve_ppd_[0].ppd_contents, "cached-content");
}
TEST_F(PpdProviderTest, RemotePpdResolveFailureResultsInServerError) {
auto provider = CreateProvider(PpdCacheRunLocation::kInBackgroundThreads);
Printer::PpdReference ref;
ref.user_supplied_ppd_url = "https://ppd-url";
MockRemotePpdFetchResult("https://ppd-url",
RemotePpdFetcher::FetchResultCode::kNetworkError);
provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
base::Unretained(this)));
task_environment_.RunUntilIdle();
ASSERT_EQ(1UL, captured_resolve_ppd_.size());
EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_ppd_[0].code);
EXPECT_TRUE(captured_resolve_ppd_[0].ppd_contents.empty());
}
TEST_F(PpdProviderTest, ResultCodeNames) {
EXPECT_EQ(PpdProvider::CallbackResultCodeName(PpdProvider::SUCCESS),
"SUCCESS");
EXPECT_EQ(PpdProvider::CallbackResultCodeName(PpdProvider::NOT_FOUND),
"NOT_FOUND");
EXPECT_EQ(PpdProvider::CallbackResultCodeName(PpdProvider::SERVER_ERROR),
"SERVER_ERROR");
EXPECT_EQ(PpdProvider::CallbackResultCodeName(PpdProvider::INTERNAL_ERROR),
"INTERNAL_ERROR");
EXPECT_EQ(PpdProvider::CallbackResultCodeName(PpdProvider::PPD_TOO_LARGE),
"PPD_TOO_LARGE");
}
}
}