1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chromeos/printing/ppd_provider_v3.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/callback_helpers.h"
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_temp_dir.h"
18 #include "base/run_loop.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/strings/strcat.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/test/bind.h"
23 #include "base/test/simple_test_clock.h"
24 #include "base/test/task_environment.h"
25 #include "base/test/test_message_loop.h"
26 #include "base/threading/sequenced_task_runner_handle.h"
27 #include "base/threading/thread_task_runner_handle.h"
28 #include "base/version.h"
29 #include "chromeos/constants/chromeos_paths.h"
30 #include "chromeos/printing/fake_printer_config_cache.h"
31 #include "chromeos/printing/ppd_cache.h"
32 #include "chromeos/printing/ppd_metadata_manager.h"
33 #include "chromeos/printing/printer_config_cache.h"
34 #include "chromeos/printing/printer_configuration.h"
35 #include "testing/gmock/include/gmock/gmock-matchers.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 namespace chromeos {
39
40 namespace {
41
42 using PrinterDiscoveryType = PrinterSearchData::PrinterDiscoveryType;
43 using ::testing::AllOf;
44 using ::testing::Eq;
45 using ::testing::Field;
46 using ::testing::StrEq;
47 using ::testing::UnorderedElementsAre;
48
49 // A pseudo-ppd that should get cupsFilter lines extracted from it.
50 const char kCupsFilterPpdContents[] = R"(
51 Other random contents that we don't care about.
52 *cupsFilter: "application/vnd.cups-raster 0 my_filter"
53 More random contents that we don't care about
54 *cupsFilter: "application/vnd.cups-awesome 0 a_different_filter"
55 *cupsFilter: "application/vnd.cups-awesomesauce 0 filter3"
56 Yet more randome contents that we don't care about.
57 More random contents that we don't care about.
58 )";
59
60 // A pseudo-ppd that should get cupsFilter2 lines extracted from it.
61 // We also have cupsFilter lines in here, but since cupsFilter2 lines
62 // exist, the cupsFilter lines should be ignored.
63 const char kCupsFilter2PpdContents[] = R"(
64 Other random contents that we don't care about.
65 *cupsFilter: "application/vnd.cups-raster 0 my_filter"
66 More random contents that we don't care about
67 *cupsFilter2: "foo bar 0 the_real_filter"
68 *cupsFilter2: "bar baz 381 another_real_filter"
69 Yet more randome contents that we don't care about.
70 More random contents that we don't care about.
71 )";
72
73 // Known number of public method calls that the PpdProvider will defer
74 // before posting failures directly.
75 // * This value is left unspecified in the header.
76 // * This value must be kept in sync with the exact value in the
77 // implementation of PpdProvider.
78 constexpr int kMethodDeferralLimitForTesting = 20;
79
80 // Default manufacturers metadata used for these tests.
81 const char kDefaultManufacturersJson[] = R"({
82 "filesMap": {
83 "Manufacturer A": "manufacturer_a-en.json",
84 "Manufacturer B": "manufacturer_b-en.json"
85 }
86 })";
87
88 // Unowned raw pointers to helper classes composed into the
89 // PpdProvider at construct time. Used throughout to activate testing
90 // codepaths.
91 struct PpdProviderComposedMembers {
92 FakePrinterConfigCache* config_cache = nullptr;
93 FakePrinterConfigCache* manager_config_cache = nullptr;
94 PpdMetadataManager* metadata_manager = nullptr;
95 };
96
97 class PpdProviderTest : public ::testing::Test {
98 public:
99 // * Determines where the PpdCache class runs.
100 // * If set to kOnTestThread, the PpdCache class will use the
101 // task environment of the test fixture.
102 // * If set to kInBackgroundThreads, the PpdCache class will
103 // spawn its own background threads.
104 // * Prefer only to run cache on the test thread if you need to
105 // manipulate its sequencing independently of PpdProvider;
106 // otherwise, allowing it spawn its own background threads
107 // should be safe and good for exercising its codepaths.
108 enum class PpdCacheRunLocation {
109 kOnTestThread,
110 kInBackgroundThreads,
111 };
112
113 // * Determines whether the browser locale given to PpdProvider
114 // should be propagated to the composed PpdMetadataManager as its
115 // metadata locale as well.
116 // * Useful to the caller depending on whether or not one is
117 // interested in the codepaths that fetch and parse the locales
118 // metadata.
119 enum class PropagateLocaleToMetadataManager {
120 kDoNotPropagate,
121 kDoPropagate,
122 };
123
124 // Options passed to CreateProvider().
125 struct CreateProviderOptions {
126 std::string browser_locale;
127 PpdCacheRunLocation where_ppd_cache_runs;
128 PropagateLocaleToMetadataManager propagate_locale;
129 };
130
PpdProviderTest()131 PpdProviderTest()
132 : task_environment_(base::test::TaskEnvironment::MainThreadType::IO,
133 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
134
SetUp()135 void SetUp() override {
136 ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir());
137 }
138
139 // Creates and return a provider for a test that uses the given |options|.
CreateProvider(const CreateProviderOptions & options)140 scoped_refptr<PpdProvider> CreateProvider(
141 const CreateProviderOptions& options) {
142 switch (options.where_ppd_cache_runs) {
143 case PpdCacheRunLocation::kOnTestThread:
144 ppd_cache_ = PpdCache::CreateForTesting(
145 ppd_cache_temp_dir_.GetPath(),
146 task_environment_.GetMainThreadTaskRunner());
147 break;
148 case PpdCacheRunLocation::kInBackgroundThreads:
149 default:
150 ppd_cache_ = PpdCache::Create(ppd_cache_temp_dir_.GetPath());
151 break;
152 }
153
154 auto manager_config_cache = std::make_unique<FakePrinterConfigCache>();
155 provider_backdoor_.manager_config_cache = manager_config_cache.get();
156
157 auto manager = PpdMetadataManager::Create(options.browser_locale, &clock_,
158 std::move(manager_config_cache));
159 provider_backdoor_.metadata_manager = manager.get();
160
161 switch (options.propagate_locale) {
162 case PropagateLocaleToMetadataManager::kDoNotPropagate:
163 // Nothing to do; the no-propagate case allows the
164 // PpdMetadataManager to acquire the metadata locale (or fail to
165 // do so) by natural means.
166 break;
167 case PropagateLocaleToMetadataManager::kDoPropagate:
168 default:
169 provider_backdoor_.metadata_manager->SetLocaleForTesting(
170 options.browser_locale);
171 break;
172 }
173
174 auto config_cache = std::make_unique<FakePrinterConfigCache>();
175 provider_backdoor_.config_cache = config_cache.get();
176
177 return CreateV3Provider(base::Version("40.8.6753.09"), ppd_cache_,
178 std::move(manager), std::move(config_cache));
179 }
180
181 // Fills the fake Chrome OS Printing serving root with content.
182 // Must be called after CreateProvider().
StartFakePpdServer()183 void StartFakePpdServer() {
184 for (const auto& entry : server_contents()) {
185 provider_backdoor_.config_cache->SetFetchResponseForTesting(entry.first,
186 entry.second);
187 provider_backdoor_.manager_config_cache->SetFetchResponseForTesting(
188 entry.first, entry.second);
189 }
190 }
191
192 // Interceptor posts a *task* during destruction that actually unregisters
193 // things. So we have to run the message loop post-interceptor-destruction to
194 // actually unregister the URLs, otherwise they won't *actually* be
195 // unregistered until the next time we invoke the message loop. Which may be
196 // in the middle of the next test.
197 //
198 // Note this is harmless to call if we haven't started a fake ppd server.
StopFakePpdServer()199 void StopFakePpdServer() {
200 for (const auto& entry : server_contents()) {
201 provider_backdoor_.config_cache->Drop(entry.first);
202 provider_backdoor_.manager_config_cache->Drop(entry.first);
203 }
204 task_environment_.RunUntilIdle();
205 }
206
207 // Capture the result of a ResolveManufacturers() call.
CaptureResolveManufacturers(PpdProvider::CallbackResultCode code,const std::vector<std::string> & data)208 void CaptureResolveManufacturers(PpdProvider::CallbackResultCode code,
209 const std::vector<std::string>& data) {
210 captured_resolve_manufacturers_.push_back({code, data});
211 }
212
213 // Capture the result of a ResolvePrinters() call.
CaptureResolvePrinters(PpdProvider::CallbackResultCode code,const PpdProvider::ResolvedPrintersList & data)214 void CaptureResolvePrinters(PpdProvider::CallbackResultCode code,
215 const PpdProvider::ResolvedPrintersList& data) {
216 captured_resolve_printers_.push_back({code, data});
217 }
218
219 // Capture the result of a ResolvePpd() call.
CaptureResolvePpd(PpdProvider::CallbackResultCode code,const std::string & ppd_contents)220 void CaptureResolvePpd(PpdProvider::CallbackResultCode code,
221 const std::string& ppd_contents) {
222 CapturedResolvePpdResults results;
223 results.code = code;
224 results.ppd_contents = ppd_contents;
225 captured_resolve_ppd_.push_back(results);
226 }
227
228 // Capture the result of a ResolveUsbIds() call.
CaptureResolvePpdReference(PpdProvider::CallbackResultCode code,const Printer::PpdReference & ref,const std::string & usb_manufacturer)229 void CaptureResolvePpdReference(PpdProvider::CallbackResultCode code,
230 const Printer::PpdReference& ref,
231 const std::string& usb_manufacturer) {
232 captured_resolve_ppd_references_.push_back({code, ref, usb_manufacturer});
233 }
234
235 // Capture the result of a ResolvePpdLicense() call.
CaptureResolvePpdLicense(PpdProvider::CallbackResultCode code,const std::string & license)236 void CaptureResolvePpdLicense(PpdProvider::CallbackResultCode code,
237 const std::string& license) {
238 captured_resolve_ppd_license_.push_back({code, license});
239 }
240
CaptureReverseLookup(PpdProvider::CallbackResultCode code,const std::string & manufacturer,const std::string & model)241 void CaptureReverseLookup(PpdProvider::CallbackResultCode code,
242 const std::string& manufacturer,
243 const std::string& model) {
244 captured_reverse_lookup_.push_back({code, manufacturer, model});
245 }
246
247 // Discard the result of a ResolvePpd() call.
DiscardResolvePpd(PpdProvider::CallbackResultCode code,const std::string & contents)248 void DiscardResolvePpd(PpdProvider::CallbackResultCode code,
249 const std::string& contents) {}
250
251 // Calls the ResolveManufacturer() method of the |provider| and
252 // waits for its completion. Ignores the returned string values and
253 // returns whether the result code was
254 // PpdProvider::CallbackResultCode::SUCCESS.
SuccessfullyResolveManufacturers(PpdProvider * provider)255 bool SuccessfullyResolveManufacturers(PpdProvider* provider) {
256 base::RunLoop run_loop;
257 PpdProvider::CallbackResultCode code;
258 provider->ResolveManufacturers(base::BindLambdaForTesting(
259 [&run_loop, &code](
260 PpdProvider::CallbackResultCode result_code,
261 const std::vector<std::string>& unused_manufacturers) {
262 code = result_code;
263 run_loop.QuitClosure().Run();
264 }));
265 run_loop.Run();
266 return code == PpdProvider::CallbackResultCode::SUCCESS;
267 }
268
269 protected:
270 // List of relevant endpoint for this FakeServer
server_contents() const271 std::vector<std::pair<std::string, std::string>> server_contents() const {
272 // Use brace initialization to express the desired server contents as "url",
273 // "contents" pairs.
274 return {{"metadata_v3/locales.json",
275 R"({
276 "locales": [ "de", "en", "es" ]
277 })"},
278 {"metadata_v3/manufacturers-en.json", kDefaultManufacturersJson},
279 {"metadata_v3/manufacturer_a-en.json",
280 R"({
281 "printers": [ {
282 "name": "printer_a",
283 "emm": "printer_a_ref"
284 }, {
285 "name": "printer_b",
286 "emm": "printer_b_ref"
287 } ]
288 })"},
289 {"metadata_v3/manufacturer_b-en.json",
290 R"({
291 "printers": [ {
292 "name": "printer_c",
293 "emm": "printer_c_ref"
294 } ]
295 })"},
296 {"metadata_v3/index-01.json",
297 R"({
298 "ppdIndex": {
299 "printer_a_ref": {
300 "ppdMetadata": [ {
301 "name": "printer_a.ppd",
302 "license": "fake_license"
303 } ]
304 }
305 }
306 })"},
307 {"metadata_v3/index-02.json",
308 R"({
309 "ppdIndex": {
310 "printer_b_ref": {
311 "ppdMetadata": [ {
312 "name": "printer_b.ppd"
313 } ]
314 }
315 }
316 })"},
317 {"metadata_v3/index-03.json",
318 R"({
319 "ppdIndex": {
320 "printer_c_ref": {
321 "ppdMetadata": [ {
322 "name": "printer_c.ppd"
323 } ]
324 }
325 }
326 })"},
327 {"metadata_v3/index-04.json",
328 R"({
329 "ppdIndex": {
330 "printer_d_ref": {
331 "ppdMetadata": [ {
332 "name": "printer_d.ppd"
333 } ]
334 }
335 }
336 })"},
337 {"metadata_v3/index-05.json",
338 R"({
339 "ppdIndex": {
340 "printer_e_ref": {
341 "ppdMetadata": [ {
342 "name": "printer_e.ppd"
343 } ]
344 }
345 }
346 })"},
347 {"metadata_v3/index-08.json",
348 R"({
349 "ppdIndex": {
350 "Some canonical reference": {
351 "ppdMetadata": [ {
352 "name": "unused.ppd"
353 } ]
354 }
355 }
356 })"},
357 {"metadata_v3/index-10.json",
358 R"({
359 "ppdIndex": {
360 "Some other canonical reference": {
361 "ppdMetadata": [ {
362 "name": "unused.ppd"
363 } ]
364 }
365 }
366 })"},
367 {"metadata_v3/usb-031f.json",
368 R"({
369 "usbIndex": {
370 "1592": {
371 "effectiveMakeAndModel": "Some canonical reference"
372 },
373 "6535": {
374 "effectiveMakeAndModel": "Some other canonical reference"
375 }
376 }
377 })"},
378 {"metadata_v3/usb-03f0.json", ""},
379 {"metadata_v3/usb-1234.json", ""},
380 {"metadata_v3/usb_vendor_ids.json", R"({
381 "entries": [ {
382 "vendorId": 799,
383 "vendorName": "Seven Ninety Nine LLC"
384 }, {
385 "vendorId": 1008,
386 "vendorName": "HP"
387 } ]
388 })"},
389 {"metadata_v3/reverse_index-en-01.json",
390 R"({
391 "reverseIndex": {
392 "printer_a_ref": {
393 "manufacturer": "manufacturer_a_en",
394 "model": "printer_a"
395 }
396 }
397 })"},
398 {"metadata_v3/reverse_index-en-19.json",
399 R"({
400 "reverseIndex": {
401 "unused effective make and model": {
402 "manufacturer": "unused manufacturer",
403 "model": "unused model"
404 }
405 }
406 })"},
407 {"ppds_for_metadata_v3/printer_a.ppd", kCupsFilterPpdContents},
408 {"ppds_for_metadata_v3/printer_b.ppd", kCupsFilter2PpdContents},
409 {"ppds_for_metadata_v3/printer_c.ppd", "c"},
410 {"ppds_for_metadata_v3/printer_d.ppd", "d"},
411 {"ppds_for_metadata_v3/printer_e.ppd", "e"},
412 {"user_supplied_ppd_directory/user_supplied.ppd", "u"}};
413 }
414
415 // Environment for task schedulers.
416 base::test::TaskEnvironment task_environment_;
417
418 std::vector<
419 std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>>
420 captured_resolve_manufacturers_;
421
422 std::vector<std::pair<PpdProvider::CallbackResultCode,
423 PpdProvider::ResolvedPrintersList>>
424 captured_resolve_printers_;
425
426 struct CapturedResolvePpdResults {
427 PpdProvider::CallbackResultCode code;
428 std::string ppd_contents;
429 };
430 std::vector<CapturedResolvePpdResults> captured_resolve_ppd_;
431
432 struct CapturedResolvePpdReferenceResults {
433 PpdProvider::CallbackResultCode code;
434 Printer::PpdReference ref;
435 std::string usb_manufacturer;
436 };
437
438 std::vector<CapturedResolvePpdReferenceResults>
439 captured_resolve_ppd_references_;
440
441 struct CapturedReverseLookup {
442 PpdProvider::CallbackResultCode code;
443 std::string manufacturer;
444 std::string model;
445 };
446 std::vector<CapturedReverseLookup> captured_reverse_lookup_;
447
448 struct CapturedResolvePpdLicense {
449 PpdProvider::CallbackResultCode code;
450 std::string license;
451 };
452 std::vector<CapturedResolvePpdLicense> captured_resolve_ppd_license_;
453
454 base::ScopedTempDir ppd_cache_temp_dir_;
455 base::ScopedTempDir interceptor_temp_dir_;
456
457 // Reference to the underlying ppd_cache_ so we can muck with it to test
458 // cache-dependent behavior of ppd_provider_.
459 scoped_refptr<PpdCache> ppd_cache_;
460
461 PpdProviderComposedMembers provider_backdoor_;
462
463 // Misc extra stuff needed for the test environment to function.
464 base::SimpleTestClock clock_;
465 };
466
467 // Tests that PpdProvider enqueues a bounded number of calls to
468 // ResolveManufacturers() and fails the oldest call when the queue is
469 // deemed full (implementation-specified detail).
TEST_F(PpdProviderTest,FailsOldestQueuedResolveManufacturers)470 TEST_F(PpdProviderTest, FailsOldestQueuedResolveManufacturers) {
471 auto provider =
472 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
473 PropagateLocaleToMetadataManager::kDoNotPropagate});
474
475 // Prevents the provider from ever getting a metadata locale.
476 // We want it to stall out, forcing it to perpetually defer method
477 // calls to ResolveManufacturers().
478 provider_backdoor_.manager_config_cache->DiscardFetchRequestFor(
479 "metadata_v3/locales.json");
480
481 for (int i = kMethodDeferralLimitForTesting; i >= 0; i--) {
482 provider->ResolveManufacturers(base::BindOnce(
483 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
484 }
485
486 // The for loop above should have overflowed the deferral queue by
487 // a factor of one: the oldest call to ResolveManufacturers() should
488 // have been forced out and asked to fail, and we expect it to be
489 // sitting on the sequence right now.
490 ASSERT_EQ(1UL, task_environment_.GetPendingMainThreadTaskCount());
491 task_environment_.FastForwardUntilNoTasksRemain();
492
493 ASSERT_EQ(1UL, captured_resolve_manufacturers_.size());
494 EXPECT_EQ(PpdProvider::CallbackResultCode::SERVER_ERROR,
495 captured_resolve_manufacturers_[0].first);
496 }
497
498 // Tests that PpdProvider enqueues a bounded number of calls to
499 // ReverseLookup() and fails the oldest call when the queue is deemed
500 // full (implementation-specified detail).
TEST_F(PpdProviderTest,FailsOldestQueuedReverseLookup)501 TEST_F(PpdProviderTest, FailsOldestQueuedReverseLookup) {
502 auto provider =
503 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
504 PropagateLocaleToMetadataManager::kDoNotPropagate});
505
506 // Prevents the provider from ever getting a metadata locale.
507 // We want it to stall out, forcing it to perpetually defer method
508 // calls to ReverseLookup().
509 provider_backdoor_.manager_config_cache->DiscardFetchRequestFor(
510 "metadata_v3/locales.json");
511
512 for (int i = kMethodDeferralLimitForTesting; i >= 0; i--) {
513 provider->ReverseLookup(
514 "some effective-make-and-model string",
515 base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
516 base::Unretained(this)));
517 }
518
519 // The for loop above should have overflowed the deferral queue by
520 // a factor of one: the oldest call to ReverseLookup() should have
521 // been forced out and asked to fail, and we expect it to be sitting
522 // on the sequence right now.
523 ASSERT_EQ(1UL, task_environment_.GetPendingMainThreadTaskCount());
524 task_environment_.FastForwardUntilNoTasksRemain();
525
526 ASSERT_EQ(1UL, captured_reverse_lookup_.size());
527 EXPECT_EQ(PpdProvider::CallbackResultCode::SERVER_ERROR,
528 captured_reverse_lookup_[0].code);
529 }
530
531 // Test that we get back manufacturer maps as expected.
TEST_F(PpdProviderTest,ManufacturersFetch)532 TEST_F(PpdProviderTest, ManufacturersFetch) {
533 auto provider =
534 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
535 PropagateLocaleToMetadataManager::kDoNotPropagate});
536 StartFakePpdServer();
537
538 // Issue two requests at the same time, both should be resolved properly.
539 provider->ResolveManufacturers(base::BindOnce(
540 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
541 provider->ResolveManufacturers(base::BindOnce(
542 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
543 task_environment_.FastForwardUntilNoTasksRemain();
544 ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
545 std::vector<std::string> expected_result(
546 {"Manufacturer A", "Manufacturer B"});
547 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[0].first);
548 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[1].first);
549 EXPECT_TRUE(captured_resolve_manufacturers_[0].second == expected_result);
550 EXPECT_TRUE(captured_resolve_manufacturers_[1].second == expected_result);
551 }
552
553 // Test that we get a reasonable error when we have no server to contact. Tis
554 // is almost exactly the same as the above test, we just don't bring up the fake
555 // server first.
TEST_F(PpdProviderTest,ManufacturersFetchNoServer)556 TEST_F(PpdProviderTest, ManufacturersFetchNoServer) {
557 auto provider =
558 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
559 PropagateLocaleToMetadataManager::kDoNotPropagate});
560
561 // Issue two requests at the same time, both should resolve properly
562 // (though they will fail).
563 provider->ResolveManufacturers(base::BindOnce(
564 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
565 provider->ResolveManufacturers(base::BindOnce(
566 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this)));
567 task_environment_.FastForwardUntilNoTasksRemain();
568
569 ASSERT_EQ(2UL, captured_resolve_manufacturers_.size());
570 EXPECT_EQ(PpdProvider::SERVER_ERROR,
571 captured_resolve_manufacturers_[0].first);
572 EXPECT_EQ(PpdProvider::SERVER_ERROR,
573 captured_resolve_manufacturers_[1].first);
574 EXPECT_TRUE(captured_resolve_manufacturers_[0].second.empty());
575 EXPECT_TRUE(captured_resolve_manufacturers_[1].second.empty());
576 }
577
578 // Tests that mutiples requests for make-and-model resolution can be fulfilled
579 // simultaneously.
TEST_F(PpdProviderTest,RepeatedMakeModel)580 TEST_F(PpdProviderTest, RepeatedMakeModel) {
581 auto provider =
582 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
583 PropagateLocaleToMetadataManager::kDoPropagate});
584 StartFakePpdServer();
585
586 PrinterSearchData unrecognized_printer;
587 unrecognized_printer.discovery_type = PrinterDiscoveryType::kManual;
588 unrecognized_printer.make_and_model = {"Printer Printer"};
589
590 PrinterSearchData recognized_printer;
591 recognized_printer.discovery_type = PrinterDiscoveryType::kManual;
592 recognized_printer.make_and_model = {"printer_a_ref"};
593
594 PrinterSearchData mixed;
595 mixed.discovery_type = PrinterDiscoveryType::kManual;
596 mixed.make_and_model = {"printer_a_ref", "Printer Printer"};
597
598 // Resolve the same thing repeatedly.
599 provider->ResolvePpdReference(
600 unrecognized_printer,
601 base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
602 base::Unretained(this)));
603 provider->ResolvePpdReference(
604 mixed, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
605 base::Unretained(this)));
606 provider->ResolvePpdReference(
607 recognized_printer,
608 base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
609 base::Unretained(this)));
610 task_environment_.RunUntilIdle();
611
612 ASSERT_EQ(static_cast<size_t>(3), captured_resolve_ppd_references_.size());
613 EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
614 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[1].code);
615 EXPECT_EQ("printer_a_ref",
616 captured_resolve_ppd_references_[1].ref.effective_make_and_model);
617 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[2].code);
618 EXPECT_EQ("printer_a_ref",
619 captured_resolve_ppd_references_[2].ref.effective_make_and_model);
620 }
621
622 // Test successful and unsuccessful usb resolutions.
TEST_F(PpdProviderTest,UsbResolution)623 TEST_F(PpdProviderTest, UsbResolution) {
624 auto provider =
625 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
626 PropagateLocaleToMetadataManager::kDoPropagate});
627 StartFakePpdServer();
628
629 PrinterSearchData search_data;
630 search_data.discovery_type = PrinterDiscoveryType::kUsb;
631
632 // Should get back "Some canonical reference"
633 search_data.usb_vendor_id = 0x031f;
634 search_data.usb_product_id = 1592;
635 provider->ResolvePpdReference(
636 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
637 base::Unretained(this)));
638 // Should get back "Some other canonical reference"
639 search_data.usb_vendor_id = 0x031f;
640 search_data.usb_product_id = 6535;
641 provider->ResolvePpdReference(
642 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
643 base::Unretained(this)));
644
645 // Vendor id that exists, nonexistent device id, should get a NOT_FOUND.
646 // In our fake serving root, the manufacturer with vendor ID 0x031f
647 // (== 799) is named "Seven Ninety Nine LLC."
648 search_data.usb_vendor_id = 0x031f;
649 search_data.usb_product_id = 8162;
650 provider->ResolvePpdReference(
651 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
652 base::Unretained(this)));
653
654 // Nonexistent vendor id, should get a NOT_FOUND in the real world, but
655 // the URL interceptor we're using considers all nonexistent files to
656 // be effectively CONNECTION REFUSED, so we just check for non-success
657 // on this one.
658 search_data.usb_vendor_id = 0x1234;
659 search_data.usb_product_id = 1782;
660 provider->ResolvePpdReference(
661 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
662 base::Unretained(this)));
663 task_environment_.RunUntilIdle();
664
665 ASSERT_EQ(captured_resolve_ppd_references_.size(), static_cast<size_t>(4));
666
667 // ResolvePpdReference() takes place in several asynchronous steps, so
668 // order is not guaranteed.
669 EXPECT_THAT(
670 captured_resolve_ppd_references_,
671 UnorderedElementsAre(
672 AllOf(Field(&CapturedResolvePpdReferenceResults::code,
673 Eq(PpdProvider::SUCCESS)),
674 Field(&CapturedResolvePpdReferenceResults::ref,
675 Field(&Printer::PpdReference::effective_make_and_model,
676 StrEq("Some canonical reference")))),
677 AllOf(Field(&CapturedResolvePpdReferenceResults::code,
678 Eq(PpdProvider::SUCCESS)),
679 Field(&CapturedResolvePpdReferenceResults::ref,
680 Field(&Printer::PpdReference::effective_make_and_model,
681 StrEq("Some other canonical reference")))),
682 AllOf(Field(&CapturedResolvePpdReferenceResults::code,
683 Eq(PpdProvider::NOT_FOUND)),
684 Field(&CapturedResolvePpdReferenceResults::usb_manufacturer,
685 StrEq("Seven Ninety Nine LLC"))),
686 Field(&CapturedResolvePpdReferenceResults::code,
687 Eq(PpdProvider::NOT_FOUND))));
688 }
689
690 // Test basic ResolvePrinters() functionality. At the same time, make
691 // sure we can get the PpdReference for each of the resolved printers.
TEST_F(PpdProviderTest,ResolvePrinters)692 TEST_F(PpdProviderTest, ResolvePrinters) {
693 auto provider =
694 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
695 PropagateLocaleToMetadataManager::kDoPropagate});
696 StartFakePpdServer();
697
698 // Required setup calls to advance past PpdProvider's method deferral.
699 ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
700 kDefaultManufacturersJson));
701 ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
702
703 provider->ResolvePrinters(
704 "Manufacturer A", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
705 base::Unretained(this)));
706 provider->ResolvePrinters(
707 "Manufacturer B", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
708 base::Unretained(this)));
709
710 task_environment_.RunUntilIdle();
711 ASSERT_EQ(2UL, captured_resolve_printers_.size());
712 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first);
713 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first);
714 EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size());
715
716 // First capture should get back printer_a, and printer_b, with ppd
717 // reference effective make and models of printer_a_ref and printer_b_ref.
718 const auto& capture0 = captured_resolve_printers_[0].second;
719 ASSERT_EQ(2UL, capture0.size());
720 EXPECT_EQ("printer_a", capture0[0].name);
721 EXPECT_EQ("printer_a_ref", capture0[0].ppd_ref.effective_make_and_model);
722
723 EXPECT_EQ("printer_b", capture0[1].name);
724 EXPECT_EQ("printer_b_ref", capture0[1].ppd_ref.effective_make_and_model);
725
726 // Second capture should get back printer_c with effective make and model of
727 // printer_c_ref
728 const auto& capture1 = captured_resolve_printers_[1].second;
729 ASSERT_EQ(1UL, capture1.size());
730 EXPECT_EQ("printer_c", capture1[0].name);
731 EXPECT_EQ("printer_c_ref", capture1[0].ppd_ref.effective_make_and_model);
732 }
733
734 // Test that if we give a bad reference to ResolvePrinters(), we get a
735 // SERVER_ERROR. There's currently no feedback that indicates
736 // specifically to the caller that they asked for the printers of
737 // a manufacturer we didn't previously advertise.
TEST_F(PpdProviderTest,ResolvePrintersBadReference)738 TEST_F(PpdProviderTest, ResolvePrintersBadReference) {
739 auto provider =
740 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
741 PropagateLocaleToMetadataManager::kDoPropagate});
742 StartFakePpdServer();
743
744 // Required setup calls to advance past PpdProvider's method deferral.
745 ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
746 kDefaultManufacturersJson));
747 ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
748
749 provider->ResolvePrinters(
750 "bogus_doesnt_exist",
751 base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
752 base::Unretained(this)));
753 task_environment_.RunUntilIdle();
754 ASSERT_EQ(1UL, captured_resolve_printers_.size());
755 EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first);
756 }
757
758 // Test that if the server is unavailable, we get SERVER_ERRORs back out.
TEST_F(PpdProviderTest,ResolvePrintersNoServer)759 TEST_F(PpdProviderTest, ResolvePrintersNoServer) {
760 auto provider =
761 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
762 PropagateLocaleToMetadataManager::kDoPropagate});
763
764 // Required setup calls to advance past PpdProvider's method deferral.
765 ASSERT_TRUE(provider_backdoor_.metadata_manager->SetManufacturersForTesting(
766 kDefaultManufacturersJson));
767 ASSERT_TRUE(SuccessfullyResolveManufacturers(provider.get()));
768
769 provider->ResolvePrinters(
770 "Manufacturer A", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
771 base::Unretained(this)));
772 provider->ResolvePrinters(
773 "Manufacturer B", base::BindOnce(&PpdProviderTest::CaptureResolvePrinters,
774 base::Unretained(this)));
775 task_environment_.RunUntilIdle();
776 ASSERT_EQ(2UL, captured_resolve_printers_.size());
777 EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first);
778 EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[1].first);
779 }
780
781 // Test a successful ppd resolution from an effective_make_and_model reference.
TEST_F(PpdProviderTest,ResolveServerKeyPpd)782 TEST_F(PpdProviderTest, ResolveServerKeyPpd) {
783 auto provider =
784 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
785 PropagateLocaleToMetadataManager::kDoPropagate});
786 StartFakePpdServer();
787 Printer::PpdReference ref;
788 ref.effective_make_and_model = "printer_b_ref";
789 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
790 base::Unretained(this)));
791 ref.effective_make_and_model = "printer_c_ref";
792 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
793 base::Unretained(this)));
794 task_environment_.RunUntilIdle();
795
796 ASSERT_EQ(2UL, captured_resolve_ppd_.size());
797
798 // ResolvePpd() works in several asynchronous steps, so order of
799 // return is not guaranteed.
800 EXPECT_THAT(
801 captured_resolve_ppd_,
802 UnorderedElementsAre(
803 AllOf(Field(&CapturedResolvePpdResults::code,
804 PpdProvider::CallbackResultCode::SUCCESS),
805 Field(&CapturedResolvePpdResults::ppd_contents,
806 StrEq(kCupsFilter2PpdContents))),
807 AllOf(Field(&CapturedResolvePpdResults::code,
808 PpdProvider::CallbackResultCode::SUCCESS),
809 Field(&CapturedResolvePpdResults::ppd_contents, StrEq("c")))));
810 }
811
812 // Test that we *don't* resolve a ppd URL over non-file schemes. It's not clear
813 // whether we'll want to do this in the long term, but for now this is
814 // disallowed because we're not sure we completely understand the security
815 // implications.
TEST_F(PpdProviderTest,ResolveUserSuppliedUrlPpdFromNetworkFails)816 TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromNetworkFails) {
817 auto provider =
818 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
819 PropagateLocaleToMetadataManager::kDoPropagate});
820 StartFakePpdServer();
821
822 Printer::PpdReference ref;
823 // PpdProvider::ResolvePpd() shall fail if a user-supplied PPD URL
824 // does not begin with the "file://" scheme.
825 ref.user_supplied_ppd_url = "nonfilescheme://unused";
826 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
827 base::Unretained(this)));
828 task_environment_.RunUntilIdle();
829
830 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
831 EXPECT_EQ(PpdProvider::INTERNAL_ERROR, captured_resolve_ppd_[0].code);
832 EXPECT_TRUE(captured_resolve_ppd_[0].ppd_contents.empty());
833 }
834
835 // Test a successful ppd resolution from a user_supplied_url field when
836 // reading from a file. Note we shouldn't need the server to be up
837 // to do this successfully, as we should be able to do this offline.
TEST_F(PpdProviderTest,ResolveUserSuppliedUrlPpdFromFile)838 TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpdFromFile) {
839 auto provider =
840 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
841 PropagateLocaleToMetadataManager::kDoPropagate});
842 base::ScopedTempDir temp_dir;
843 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
844 base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
845
846 std::string user_ppd_contents = "Woohoo";
847
848 ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
849
850 Printer::PpdReference ref;
851 ref.user_supplied_ppd_url =
852 base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
853 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
854 base::Unretained(this)));
855 task_environment_.RunUntilIdle();
856
857 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
858 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
859 EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
860 }
861
862 // Test that we cache ppd resolutions when we fetch them and that we can resolve
863 // from the cache without the server available.
TEST_F(PpdProviderTest,ResolvedPpdsGetCached)864 TEST_F(PpdProviderTest, ResolvedPpdsGetCached) {
865 auto provider =
866 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
867 PropagateLocaleToMetadataManager::kDoPropagate});
868 std::string user_ppd_contents = "Woohoo";
869 Printer::PpdReference ref;
870 {
871 base::ScopedTempDir temp_dir;
872 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
873 base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
874
875 ASSERT_TRUE(base::WriteFile(filename, user_ppd_contents));
876
877 ref.user_supplied_ppd_url =
878 base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
879 provider->ResolvePpd(ref,
880 base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
881 base::Unretained(this)));
882 task_environment_.RunUntilIdle();
883
884 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
885 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
886 EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
887 }
888 // ScopedTempDir goes out of scope, so the source file should now be
889 // deleted. But if we resolve again, we should hit the cache and
890 // still be successful.
891
892 captured_resolve_ppd_.clear();
893
894 // Recreate the provider to make sure we don't have any memory caches which
895 // would mask problems with disk persistence.
896 provider = CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
897 PropagateLocaleToMetadataManager::kDoPropagate});
898
899 // Re-resolve.
900 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
901 base::Unretained(this)));
902 task_environment_.RunUntilIdle();
903
904 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
905 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
906 EXPECT_EQ(user_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
907 }
908
909 // Test that all entrypoints will correctly work with case-insensitve
910 // effective-make-and-model strings.
TEST_F(PpdProviderTest,CaseInsensitiveMakeAndModel)911 TEST_F(PpdProviderTest, CaseInsensitiveMakeAndModel) {
912 auto provider =
913 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
914 PropagateLocaleToMetadataManager::kDoPropagate});
915 StartFakePpdServer();
916 std::string ref = "pRiNteR_A_reF";
917
918 Printer::PpdReference ppd_ref;
919 ppd_ref.effective_make_and_model = ref;
920 provider->ResolvePpd(ppd_ref,
921 base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
922 base::Unretained(this)));
923 provider->ReverseLookup(ref,
924 base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
925 base::Unretained(this)));
926 PrinterSearchData printer_info;
927 printer_info.make_and_model = {ref};
928 provider->ResolvePpdReference(
929 printer_info, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
930 base::Unretained(this)));
931 task_environment_.RunUntilIdle();
932
933 // Check PpdProvider::ResolvePpd
934 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
935 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
936 EXPECT_EQ(kCupsFilterPpdContents, captured_resolve_ppd_[0].ppd_contents);
937
938 // Check PpdProvider::ReverseLookup
939 ASSERT_EQ(1UL, captured_reverse_lookup_.size());
940 EXPECT_EQ(PpdProvider::SUCCESS, captured_reverse_lookup_[0].code);
941 EXPECT_EQ("manufacturer_a_en", captured_reverse_lookup_[0].manufacturer);
942 EXPECT_EQ("printer_a", captured_reverse_lookup_[0].model);
943
944 // Check PpdProvider::ResolvePpdReference
945 ASSERT_EQ(1UL, captured_resolve_ppd_references_.size());
946 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_references_[0].code);
947 EXPECT_EQ("printer_a_ref",
948 captured_resolve_ppd_references_[0].ref.effective_make_and_model);
949 }
950
951 // Tests that ResolvePpdLicense is able to correctly source the index and
952 // determine the name of the PPD license associated with the given effecive make
953 // and model (if any).
TEST_F(PpdProviderTest,ResolvePpdLicense)954 TEST_F(PpdProviderTest, ResolvePpdLicense) {
955 auto provider =
956 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
957 PropagateLocaleToMetadataManager::kDoNotPropagate});
958 StartFakePpdServer();
959
960 // For this effective_make_and_model, we expect that there is associated
961 // license.
962 const char kEmm1[] = "printer_a_ref";
963 provider->ResolvePpdLicense(
964 kEmm1, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
965 base::Unretained(this)));
966
967 // We do not expect there to be any license associated with this
968 // effective_make_and_model, so the response should be empty.
969 const char kEmm2[] = "printer_b_ref";
970 provider->ResolvePpdLicense(
971 kEmm2, base::BindOnce(&PpdProviderTest::CaptureResolvePpdLicense,
972 base::Unretained(this)));
973
974 task_environment_.RunUntilIdle();
975
976 ASSERT_EQ(2UL, captured_resolve_ppd_license_.size());
977 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[0].code);
978 EXPECT_EQ("fake_license", captured_resolve_ppd_license_[0].license);
979 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_license_[1].code);
980 EXPECT_EQ("", captured_resolve_ppd_license_[1].license);
981 }
982
983 // Verifies that we can extract the Manufacturer and Model selection for a
984 // given effective make and model.
TEST_F(PpdProviderTest,ReverseLookup)985 TEST_F(PpdProviderTest, ReverseLookup) {
986 auto provider =
987 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
988 PropagateLocaleToMetadataManager::kDoPropagate});
989 StartFakePpdServer();
990 std::string ref = "printer_a_ref";
991 provider->ReverseLookup(ref,
992 base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
993 base::Unretained(this)));
994 // TODO(skau): PpdProvider has a race condition that prevents running these
995 // requests in parallel.
996 task_environment_.RunUntilIdle();
997
998 std::string ref_fail = "printer_does_not_exist";
999 provider->ReverseLookup(ref_fail,
1000 base::BindOnce(&PpdProviderTest::CaptureReverseLookup,
1001 base::Unretained(this)));
1002 task_environment_.RunUntilIdle();
1003
1004 ASSERT_EQ(2U, captured_reverse_lookup_.size());
1005 CapturedReverseLookup success_capture = captured_reverse_lookup_[0];
1006 EXPECT_EQ(PpdProvider::SUCCESS, success_capture.code);
1007 EXPECT_EQ("manufacturer_a_en", success_capture.manufacturer);
1008 EXPECT_EQ("printer_a", success_capture.model);
1009
1010 CapturedReverseLookup failed_capture = captured_reverse_lookup_[1];
1011 EXPECT_EQ(PpdProvider::NOT_FOUND, failed_capture.code);
1012 }
1013
1014 // Verifies that we never attempt to re-download a PPD that we
1015 // previously retrieved from the serving root. The Chrome OS Printing
1016 // Team plans to keep PPDs immutable inside the serving root, so
1017 // PpdProvider should always prefer to retrieve a PPD from the PpdCache
1018 // when it's possible to do so.
TEST_F(PpdProviderTest,PreferToResolvePpdFromPpdCacheOverServingRoot)1019 TEST_F(PpdProviderTest, PreferToResolvePpdFromPpdCacheOverServingRoot) {
1020 // Explicitly *not* starting a fake server.
1021 std::string cached_ppd_contents =
1022 "These cached contents are different from what's being served";
1023 auto provider =
1024 CreateProvider({"en", PpdCacheRunLocation::kOnTestThread,
1025 PropagateLocaleToMetadataManager::kDoPropagate});
1026 Printer::PpdReference ref;
1027 ref.effective_make_and_model = "printer_a_ref";
1028 std::string cache_key = PpdProvider::PpdReferenceToCacheKey(ref);
1029
1030 // Cache exists, and is just created, so should be fresh.
1031 //
1032 // PPD basename is taken from value specified in forward index shard
1033 // defined in server_contents().
1034 const std::string ppd_basename = "printer_a.ppd";
1035 ppd_cache_->StoreForTesting(PpdBasenameToCacheKey(ppd_basename),
1036 cached_ppd_contents, base::TimeDelta());
1037 ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
1038 ppd_basename, base::TimeDelta());
1039 task_environment_.RunUntilIdle();
1040 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
1041 base::Unretained(this)));
1042 task_environment_.RunUntilIdle();
1043 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
1044
1045 // Should get the cached (not served) results back, and not have hit the
1046 // network.
1047 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
1048 EXPECT_EQ(cached_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
1049 }
1050
1051 // For user-provided ppds, we should always use the latest version on
1052 // disk if it still exists there.
TEST_F(PpdProviderTest,UserPpdAlwaysRefreshedIfAvailable)1053 TEST_F(PpdProviderTest, UserPpdAlwaysRefreshedIfAvailable) {
1054 base::ScopedTempDir temp_dir;
1055 std::string cached_ppd_contents = "Cached Ppd Contents";
1056 std::string disk_ppd_contents = "Updated Ppd Contents";
1057 auto provider =
1058 CreateProvider({"en", PpdCacheRunLocation::kOnTestThread,
1059 PropagateLocaleToMetadataManager::kDoPropagate});
1060 StartFakePpdServer();
1061 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1062 base::FilePath filename = temp_dir.GetPath().Append("my_spiffy.ppd");
1063
1064 Printer::PpdReference ref;
1065 ref.user_supplied_ppd_url =
1066 base::StringPrintf("file://%s", filename.MaybeAsASCII().c_str());
1067
1068 // Put cached_ppd_contents into the cache.
1069 ppd_cache_->StoreForTesting(PpdProvider::PpdReferenceToCacheKey(ref),
1070 cached_ppd_contents, base::TimeDelta());
1071 task_environment_.RunUntilIdle();
1072
1073 // Write different contents to disk, so that the cached contents are
1074 // now stale.
1075 ASSERT_TRUE(base::WriteFile(filename, disk_ppd_contents));
1076
1077 provider->ResolvePpd(ref, base::BindOnce(&PpdProviderTest::CaptureResolvePpd,
1078 base::Unretained(this)));
1079 task_environment_.RunUntilIdle();
1080 ASSERT_EQ(1UL, captured_resolve_ppd_.size());
1081 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].code);
1082 EXPECT_EQ(disk_ppd_contents, captured_resolve_ppd_[0].ppd_contents);
1083
1084 // Check that the cache was also updated with the new contents.
1085 PpdCache::FindResult captured_find_result;
1086 ppd_cache_->Find(PpdProvider::PpdReferenceToCacheKey(ref),
1087 base::BindOnce(
1088 [](PpdCache::FindResult* captured_find_result,
1089 const PpdCache::FindResult& find_result) {
1090 *captured_find_result = find_result;
1091 },
1092 &captured_find_result));
1093 task_environment_.RunUntilIdle();
1094 EXPECT_EQ(captured_find_result.success, true);
1095 EXPECT_EQ(captured_find_result.contents, disk_ppd_contents);
1096 }
1097
1098 // Test resolving usb manufacturer when failed to resolve PpdReference.
TEST_F(PpdProviderTest,ResolveUsbManufacturer)1099 TEST_F(PpdProviderTest, ResolveUsbManufacturer) {
1100 auto provider =
1101 CreateProvider({"en", PpdCacheRunLocation::kInBackgroundThreads,
1102 PropagateLocaleToMetadataManager::kDoPropagate});
1103 StartFakePpdServer();
1104
1105 PrinterSearchData search_data;
1106 search_data.discovery_type = PrinterDiscoveryType::kUsb;
1107
1108 // Vendor id that exists, nonexistent device id, should get a NOT_FOUND.
1109 // Although this is an unsupported printer model, we can still expect to get
1110 // the manufacturer name.
1111 search_data.usb_vendor_id = 0x03f0;
1112 search_data.usb_product_id = 9999;
1113 provider->ResolvePpdReference(
1114 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
1115 base::Unretained(this)));
1116
1117 // Nonexistent vendor id, should get a NOT_FOUND in the real world, but
1118 // the URL interceptor we're using considers all nonexistent files to
1119 // be effectively CONNECTION REFUSED, so we just check for non-success
1120 // on this one. We should also not be able to get a manufacturer name from a
1121 // nonexistent vendor id.
1122 search_data.usb_vendor_id = 0x1234;
1123 search_data.usb_product_id = 1782;
1124 provider->ResolvePpdReference(
1125 search_data, base::BindOnce(&PpdProviderTest::CaptureResolvePpdReference,
1126 base::Unretained(this)));
1127 task_environment_.RunUntilIdle();
1128
1129 ASSERT_EQ(static_cast<size_t>(2), captured_resolve_ppd_references_.size());
1130 // Was able to find the printer manufactuer but unable to find the printer
1131 // model should result in a NOT_FOUND.
1132 EXPECT_EQ(PpdProvider::NOT_FOUND, captured_resolve_ppd_references_[0].code);
1133 // Failed to grab the PPD for a USB printer, but should still be able to grab
1134 // its manufacturer name.
1135 EXPECT_EQ("HP", captured_resolve_ppd_references_[0].usb_manufacturer);
1136
1137 // Unable to find the PPD file should result in a failure.
1138 EXPECT_FALSE(captured_resolve_ppd_references_[1].code ==
1139 PpdProvider::SUCCESS);
1140 // Unknown vendor id should result in an empty manufacturer string.
1141 EXPECT_TRUE(captured_resolve_ppd_references_[1].usb_manufacturer.empty());
1142 }
1143
1144 } // namespace
1145 } // namespace chromeos
1146