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