Chromium Code Reviews| Index: chromeos/printing/ppd_provider_unittest.cc |
| diff --git a/chromeos/printing/ppd_provider_unittest.cc b/chromeos/printing/ppd_provider_unittest.cc |
| index c21089fcb208f6ab45d22da615ffc7007e954bd8..06036ea4dcf42098ff7a9ebfc9be3aff1c664e9c 100644 |
| --- a/chromeos/printing/ppd_provider_unittest.cc |
| +++ b/chromeos/printing/ppd_provider_unittest.cc |
| @@ -2,7 +2,10 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| +#include <map> |
| + |
| #include "base/bind.h" |
| +#include "base/bind_helpers.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/logging.h" |
| @@ -10,6 +13,8 @@ |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/stringprintf.h" |
| +#include "base/test/test_message_loop.h" |
| +#include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "chromeos/chromeos_paths.h" |
| #include "chromeos/printing/ppd_cache.h" |
| @@ -20,245 +25,428 @@ |
| namespace chromeos { |
| namespace printing { |
| -namespace { |
| -const char kTestQuirksServer[] = "bogusserver.bogus.com"; |
| -const char kTestAPIKey[] = "BOGUSAPIKEY"; |
| -const char kLocalPpdUrl[] = "/some/path"; |
| -const char kTestManufacturer[] = "Bogus Printer Corp"; |
| -const char kTestModel[] = "MegaPrint 9000"; |
| -// The compressedPPD contents here comes from running the command |
| -// echo -n "This is the quirks ppd" | base64 |
| -const char kQuirksResponse[] = |
| - "{\n" |
| - " \"compressedPpd\": \"VGhpcyBpcyB0aGUgcXVpcmtzIHBwZA==\",\n" |
| - " \"lastUpdatedTime\": \"1\"\n" |
| - "}\n"; |
| -const char kQuirksPpd[] = "This is the quirks ppd"; |
| - |
| -// A well-formatted response for a list of ppds from quirks server. This |
| -// corresponds to the AvailablePrintersMap returned by QuirksPrinters() below. |
| -const char kQuirksListResponse[] = |
| - "{\n" |
| - " \"manufacturers\": [\n" |
| - " {\n" |
| - " \"manufacturer\": \"manu_a\",\n" |
| - " \"models\": [\n" |
| - " \"model_1\",\n" |
| - " \"model_2\"\n" |
| - " ]\n" |
| - " },\n" |
| - " {\n" |
| - " \"manufacturer\": \"manu_b\",\n" |
| - " \"models\": [\n" |
| - " \"model_3\",\n" |
| - " \"model_1\"\n" |
| - " ]\n" |
| - " }\n" |
| - " ]\n" |
| - "}\n"; |
| - |
| -// Return an AvailablePrintersMap that matches what's in kQuirksListResponse. |
| -PpdProvider::AvailablePrintersMap QuirksPrinters() { |
| - return {{"manu_a", {"model_1", "model_2"}}, |
| - {"manu_b", {"model_3", "model_1"}}}; |
| +// Have to define ManufacturerReference equivalence to be able to compare |
| +// ManufacturerMaps with ==. This can't be in the anonymous namespace |
| +// as the definition has to be in the same namespace as the referenced |
| +// class. |
| +bool operator==(const PpdProvider::ManufacturerReference& a, |
| + const PpdProvider::ManufacturerReference& b) { |
| + return a.key == b.key; |
| } |
| +namespace { |
| + |
| +// Name of the fake server we're resolving ppds from. |
| +const char kPpdServer[] = "bogus.google.com"; |
| + |
| class PpdProviderTest : public ::testing::Test { |
| public: |
| PpdProviderTest() |
| : loop_(base::MessageLoop::TYPE_IO), |
| - request_context_getter_( |
| - new net::TestURLRequestContextGetter(loop_.task_runner().get())) {} |
| + request_context_getter_(new net::TestURLRequestContextGetter( |
| + base::MessageLoop::current()->task_runner())) {} |
| void SetUp() override { |
| ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir()); |
| + } |
| + |
| + void TearDown() override { StopFakePpdServer(); } |
| + |
| + // Create and return a provider for a test that uses the given |locale|. |
| + scoped_refptr<PpdProvider> CreateProvider(const std::string& locale) { |
| auto provider_options = PpdProvider::Options(); |
| - provider_options.quirks_server = kTestQuirksServer; |
| - ppd_provider_ = PpdProvider::Create( |
| - kTestAPIKey, request_context_getter_.get(), loop_.task_runner().get(), |
| - PpdCache::Create(ppd_cache_temp_dir_.GetPath()), provider_options); |
| + provider_options.ppd_server_root = std::string("https://") + kPpdServer; |
| + |
| + return PpdProvider::Create( |
| + locale, request_context_getter_.get(), |
| + PpdCache::Create(ppd_cache_temp_dir_.GetPath(), |
| + base::MessageLoop::current()->task_runner()), |
| + provider_options); |
| + } |
| + |
| + // Create an interceptor that serves a small fileset of ppd server files. |
| + void StartFakePpdServer() { |
| + ASSERT_TRUE(interceptor_temp_dir_.CreateUniqueTempDir()); |
| + interceptor_ = base::MakeUnique<net::TestURLRequestInterceptor>( |
| + "https", kPpdServer, base::ThreadTaskRunnerHandle::Get(), |
| + base::ThreadTaskRunnerHandle::Get()); |
| + // Use brace initialization to express the desired server contents as "url", |
| + // "contents" pairs. |
| + std::vector<std::pair<std::string, std::string>> server_contents = { |
| + {"metadata/locales.json", |
| + R"(["en", |
| + "es-mx", |
| + "en-gb"])"}, |
| + {"metadata/index.json", |
| + R"([ |
| + ["printer_a_ref", "printer_a.ppd"], |
| + ["printer_b_ref", "printer_b.ppd"], |
| + ["printer_c_ref", "printer_c.ppd"] |
| + ])"}, |
| + {"metadata/manufacturers-en.json", |
| + R"([ |
| + ["manufacturer_a_en", "manufacturer_a.json"], |
| + ["manufacturer_b_en", "manufacturer_b.json"] |
| + ])"}, |
| + {"metadata/manufacturers-en-gb.json", |
| + R"([ |
| + ["manufacturer_a_en-gb", "manufacturer_a.json"], |
| + ["manufacturer_b_en-gb", "manufacturer_b.json"] |
| + ])"}, |
| + {"metadata/manufacturers-es-mx.json", |
| + R"([ |
| + ["manufacturer_a_es-mx", "manufacturer_a.json"], |
| + ["manufacturer_b_es-mx", "manufacturer_b.json"] |
| + ])"}, |
| + {"metadata/manufacturer_a.json", |
| + R"([ |
| + ["printer_a", "printer_a_ref"], |
| + ["printer_b", "printer_b_ref"] |
| + ])"}, |
| + {"metadata/manufacturer_b.json", |
| + R"([ |
| + ["printer_c", "printer_c_ref"] |
| + ])"}, |
| + {"ppds/printer_a.ppd", "a"}, |
| + {"ppds/printer_b.ppd", "b"}, |
| + {"ppds/printer_c.ppd", "c"}, |
| + {"user_supplied_ppd_directory/user_supplied.ppd", "u"}}; |
| + int next_file_num = 0; |
| + for (const auto& entry : server_contents) { |
| + base::FilePath filename = interceptor_temp_dir_.GetPath().Append( |
| + base::StringPrintf("%d.json", next_file_num++)); |
| + ASSERT_EQ( |
| + base::WriteFile(filename, entry.second.data(), entry.second.size()), |
| + static_cast<int>(entry.second.size())) |
| + << "Failed to write temp server file"; |
| + interceptor_->SetResponse( |
| + GURL(base::StringPrintf("https://%s/%s", kPpdServer, |
| + entry.first.c_str())), |
| + filename); |
| + } |
| + } |
| + |
| + // Interceptor posts a *task* during destruction that actually unregisters |
| + // things. So we have to run the message loop post-interceptor-destruction to |
| + // actually unregister the URLs, otherwise they won't *actually* be |
| + // unregistered until the next time we invoke the message loop. Which may be |
| + // in the middle of the next test. |
| + // |
| + // Note this is harmless to call if we haven't started a fake ppd server. |
| + void StopFakePpdServer() { |
| + interceptor_.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + } |
| + |
| + // Capture the result of a ResolveManufacturers() call. |
| + void CaptureResolveManufacturers(PpdProvider::CallbackResultCode code, |
| + const PpdProvider::ManufacturerMap& data) { |
| + captured_resolve_manufacturers_.push_back({code, data}); |
| + } |
| + |
| + // Capture the result of a ResolvePrinters() call. |
| + void CaptureResolvePrinters(PpdProvider::CallbackResultCode code, |
| + const PpdProvider::PrinterMap& data) { |
| + captured_resolve_printers_.push_back({code, data}); |
| + } |
| + |
| + // Capture the result of a ResolvePpd() call. |
| + void CaptureResolvePpd(PpdProvider::CallbackResultCode code, |
| + const std::string& contents) { |
| + captured_resolve_ppd_.push_back({code, contents}); |
| } |
| + // Discard the result of a ResolvePpd() call. |
| + void DiscardResolvePpd(PpdProvider::CallbackResultCode code, |
| + const std::string& contents) {} |
| + |
| protected: |
| + // Run a ResolveManufacturers run from the given locale, expect to get |
| + // results in expected_used_locale. |
| + void RunLocalizationTest(const std::string& browser_locale, |
| + const std::string& expected_used_locale) { |
| + captured_resolve_manufacturers_.clear(); |
| + auto provider = CreateProvider(browser_locale); |
| + provider->ResolveManufacturers(base::Bind( |
| + &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| + base::RunLoop().RunUntilIdle(); |
| + provider = nullptr; |
| + // Should have an exact match for en-gb. |
|
skau
2017/01/05 20:38:46
this comment is incorrect
Carlson
2017/01/26 21:59:36
Done.
|
| + ASSERT_EQ(captured_resolve_manufacturers_.size(), 1UL); |
| + EXPECT_EQ(captured_resolve_manufacturers_[0].first, PpdProvider::SUCCESS); |
| + |
| + // It's sufficient to check for one of the en-gb keys to make sure we got |
| + // the right map. |
| + EXPECT_FALSE(captured_resolve_manufacturers_[0].second.find( |
| + "manufacturer_a_" + expected_used_locale) == |
| + captured_resolve_manufacturers_[0].second.end()); |
| + } |
| + |
| + // Drain tasks both on the loop we use for network/disk activity and the |
| + // top-level loop that we're using in the test itself. Unfortunately, even |
| + // thought the TestURLRequestContextGetter tells the url fetcher to run on the |
| + // current message loop, some deep backend processes can get put into other |
| + // loops, which means we can't just trust RunLoop::RunUntilIdle() to drain |
| + // outstanding work. |
| + void Drain(const PpdProvider& provider) { |
| + do { |
| + base::RunLoop().RunUntilIdle(); |
| + } while (!provider.Idle()); |
| + } |
| + |
| + // Message loop that runs on the current thread. |
| + base::TestMessageLoop loop_; |
| + |
| + std::vector< |
| + std::pair<PpdProvider::CallbackResultCode, PpdProvider::ManufacturerMap>> |
| + captured_resolve_manufacturers_; |
| + |
| + std::vector< |
| + std::pair<PpdProvider::CallbackResultCode, PpdProvider::PrinterMap>> |
| + captured_resolve_printers_; |
| + |
| + std::vector<std::pair<PpdProvider::CallbackResultCode, std::string>> |
| + captured_resolve_ppd_; |
| + |
| + std::unique_ptr<net::TestURLRequestInterceptor> interceptor_; |
| + |
| base::ScopedTempDir ppd_cache_temp_dir_; |
| + base::ScopedTempDir interceptor_temp_dir_; |
| // Provider to be used in the test. |
| - std::unique_ptr<PpdProvider> ppd_provider_; |
| + scoped_refptr<PpdProvider> ppd_provider_; |
| // Misc extra stuff needed for the test environment to function. |
| - base::MessageLoop loop_; |
| + // base::TestMessageLoop loop_; |
| scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| }; |
| -// Struct that just captures the callback result for a PpdProvider lookup and |
| -// saves it for inspection by the test. |
| -struct CapturedResolveResult { |
| - bool initialized = false; |
| - PpdProvider::CallbackResultCode result; |
| - base::FilePath file; |
| -}; |
| - |
| -// Callback for saving a resolve callback. |
| -void CaptureResolveResultCallback(CapturedResolveResult* capture, |
| - PpdProvider::CallbackResultCode result, |
| - base::FilePath file) { |
| - capture->initialized = true; |
| - capture->result = result; |
| - capture->file = file; |
| +// Test that we get back manufacturer maps as expected. |
| +TEST_F(PpdProviderTest, ManufacturersFetch) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + // Issue two requests at the same time, both should be resolved properly. |
| + provider->ResolveManufacturers(base::Bind( |
| + &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| + provider->ResolveManufacturers(base::Bind( |
| + &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| + Drain(*provider); |
| + ASSERT_EQ(2UL, captured_resolve_manufacturers_.size()); |
| + PpdProvider::ManufacturerMap expected_map( |
| + {{"manufacturer_a_en", {"manufacturer_a.json"}}, |
| + {"manufacturer_b_en", {"manufacturer_b.json"}}}); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[0].first); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[1].first); |
| + EXPECT_TRUE(captured_resolve_manufacturers_[0].second == expected_map); |
| + EXPECT_TRUE(captured_resolve_manufacturers_[1].second == expected_map); |
| } |
| -// For a resolve result that should end up successful, check that it is |
| -// successful and the contents are expected_contents. |
| -void CheckResolveSuccessful(const CapturedResolveResult& captured, |
| - const std::string& expected_contents) { |
| - ASSERT_TRUE(captured.initialized); |
| - EXPECT_EQ(PpdProvider::SUCCESS, captured.result); |
| - |
| - std::string contents; |
| - ASSERT_TRUE(base::ReadFileToString(captured.file, &contents)); |
| - EXPECT_EQ(expected_contents, contents); |
| +// Test that we get a reasonable error when we have no server to contact. Tis |
| +// is almost exactly the same as the above test, we just don't bring up the fake |
| +// server first. |
| +TEST_F(PpdProviderTest, ManufacturersFetchNoServer) { |
| + auto provider = CreateProvider("en"); |
| + // Issue two requests at the same time, both should be resolved properly. |
| + provider->ResolveManufacturers(base::Bind( |
| + &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| + provider->ResolveManufacturers(base::Bind( |
| + &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| + Drain(*provider); |
| + ASSERT_EQ(2UL, captured_resolve_manufacturers_.size()); |
| + EXPECT_EQ(PpdProvider::SERVER_ERROR, |
| + captured_resolve_manufacturers_[0].first); |
| + EXPECT_EQ(PpdProvider::SERVER_ERROR, |
| + captured_resolve_manufacturers_[1].first); |
| + EXPECT_TRUE(captured_resolve_manufacturers_[0].second.empty()); |
| + EXPECT_TRUE(captured_resolve_manufacturers_[1].second.empty()); |
| } |
| -// Resolve a PPD via the quirks server. |
| -TEST_F(PpdProviderTest, QuirksServerResolve) { |
| - base::ScopedTempDir temp_dir; |
| - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| - |
| - Printer::PpdReference ppd_reference; |
| - ppd_reference.effective_manufacturer = kTestManufacturer; |
| - ppd_reference.effective_model = kTestModel; |
| - |
| - { |
| - net::TestURLRequestInterceptor interceptor( |
| - "https", kTestQuirksServer, base::ThreadTaskRunnerHandle::Get(), |
| - base::ThreadTaskRunnerHandle::Get()); |
| - |
| - GURL expected_url(base::StringPrintf( |
| - "https://%s/v2/printer/manufacturers/%s/models/%s?key=%s", |
| - kTestQuirksServer, kTestManufacturer, kTestModel, kTestAPIKey)); |
| +// Test that we get things in the requested locale, and that fallbacks are sane. |
| +TEST_F(PpdProviderTest, LocalizationAndFallbacks) { |
| + StartFakePpdServer(); |
| + RunLocalizationTest("en-gb", "en-gb"); |
| + RunLocalizationTest("en-blah", "en"); |
| + RunLocalizationTest("en-gb-foo", "en-gb"); |
| + RunLocalizationTest("es", "es-mx"); |
| + RunLocalizationTest("bogus", "en"); |
| +} |
| - base::FilePath contents_path = temp_dir.GetPath().Append("response"); |
| - std::string contents = kQuirksResponse; |
| - int bytes_written = |
| - base::WriteFile(contents_path, contents.data(), contents.size()); |
| - ASSERT_EQ(bytes_written, static_cast<int>(contents.size())); |
| +// Test basic ResolvePrinters() functionality. |
| +TEST_F(PpdProviderTest, ResolvePrinters) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + |
| + PpdProvider::ManufacturerReference ref; |
| + ref.key = "manufacturer_a.json"; |
| + provider->ResolvePrinters(ref, |
| + base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| + base::Unretained(this))); |
| + ref.key = "manufacturer_b.json"; |
| + provider->ResolvePrinters(ref, |
| + base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| + base::Unretained(this))); |
| + Drain(*provider); |
| + ASSERT_EQ(2UL, captured_resolve_printers_.size()); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first); |
| + EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size()); |
| + EXPECT_EQ("printer_a_ref", |
| + captured_resolve_printers_[0].second["printer_a"].effective_model); |
| + EXPECT_EQ("printer_b_ref", |
| + captured_resolve_printers_[0].second["printer_b"].effective_model); |
| + EXPECT_EQ(1UL, captured_resolve_printers_[1].second.size()); |
| + EXPECT_EQ("printer_c_ref", |
| + captured_resolve_printers_[1].second["printer_c"].effective_model); |
| +} |
| - interceptor.SetResponse(expected_url, contents_path); |
| +// Test that if we give a bad reference to ResolvePrinters(), we get an |
| +// INTERNAL_ERROR. |
| +TEST_F(PpdProviderTest, ResolvePrintersBadReference) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + |
| + PpdProvider::ManufacturerReference ref; |
| + ref.key = "bogus_doesnt_exist.json"; |
| + provider->ResolvePrinters(ref, |
| + base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| + base::Unretained(this))); |
| + Drain(*provider); |
| + ASSERT_EQ(1UL, captured_resolve_printers_.size()); |
| + EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first); |
| +} |
| - CapturedResolveResult captured; |
| - ppd_provider_->Resolve(ppd_reference, |
| - base::Bind(CaptureResolveResultCallback, &captured)); |
| - base::RunLoop().RunUntilIdle(); |
| - CheckResolveSuccessful(captured, kQuirksPpd); |
| - } |
| +// Test that if the server is unavailable, we get SERVER_ERRORs back out. |
| +TEST_F(PpdProviderTest, ResolvePrintersNoServer) { |
| + auto provider = CreateProvider("en"); |
| + |
| + PpdProvider::ManufacturerReference ref; |
| + ref.key = "manufacturer_a.json"; |
| + provider->ResolvePrinters(ref, |
| + base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| + base::Unretained(this))); |
| + ref.key = "manufacturer_b.json"; |
| + provider->ResolvePrinters(ref, |
| + base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| + base::Unretained(this))); |
| + Drain(*provider); |
| + ASSERT_EQ(2UL, captured_resolve_printers_.size()); |
| + EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first); |
| + EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[1].first); |
| +} |
| - // Now that the interceptor is out of scope, re-run the query. We should |
| - // hit in the cache, and thus *not* re-run the query. |
| - CapturedResolveResult captured; |
| - ppd_provider_->Resolve(ppd_reference, |
| - base::Bind(CaptureResolveResultCallback, &captured)); |
| - base::RunLoop().RunUntilIdle(); |
| - CheckResolveSuccessful(captured, kQuirksPpd); |
| +// Test a successful ppd resolution from an effective_model reference. |
| +TEST_F(PpdProviderTest, ResolveEffectiveModelPpd) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + Printer::PpdReference ref; |
| + ref.effective_model = "printer_b_ref"; |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| + base::Unretained(this))); |
| + ref.effective_model = "printer_c_ref"; |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| + base::Unretained(this))); |
| + Drain(*provider); |
| + |
| + ASSERT_EQ(2UL, captured_resolve_ppd_.size()); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| + EXPECT_EQ("b", captured_resolve_ppd_[0].second); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].first); |
| + EXPECT_EQ("c", captured_resolve_ppd_[1].second); |
| } |
| -// Test storage and retrieval of PPDs that are added manually. Even though we |
| -// supply a manufacturer and model, we should *not* hit the network for this |
| -// resolution since we should find the stored version already cached. |
| -TEST_F(PpdProviderTest, LocalResolve) { |
| - Printer::PpdReference ppd_reference; |
| - ppd_reference.user_supplied_ppd_url = kLocalPpdUrl; |
| - ppd_reference.effective_manufacturer = kTestManufacturer; |
| - ppd_reference.effective_model = kTestModel; |
| - |
| - // Initially, should not resolve. |
| - { |
| - CapturedResolveResult captured; |
| - ppd_provider_->Resolve(ppd_reference, |
| - base::Bind(CaptureResolveResultCallback, &captured)); |
| - base::RunLoop().RunUntilIdle(); |
| - EXPECT_TRUE(captured.initialized); |
| - EXPECT_EQ(PpdProvider::NOT_FOUND, captured.result); |
| - } |
| +// Test a successful ppd resolution from a user_supplied_url field. |
| +TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpd) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + |
| + Printer::PpdReference ref; |
| + ref.user_supplied_ppd_url = base::StringPrintf( |
| + "https://%s/user_supplied_ppd_directory/user_supplied.ppd", kPpdServer); |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| + base::Unretained(this))); |
| + Drain(*provider); |
| + |
| + ASSERT_EQ(1UL, captured_resolve_ppd_.size()); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| + EXPECT_EQ("u", captured_resolve_ppd_[0].second); |
| +} |
| - // Store a local ppd. |
| - const std::string kLocalPpdContents("My local ppd contents"); |
| - { |
| - base::ScopedTempDir temp_dir; |
| - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| - |
| - base::FilePath local_ppd_path = temp_dir.GetPath().Append("local_ppd"); |
| - ASSERT_EQ(base::WriteFile(local_ppd_path, kLocalPpdContents.data(), |
| - kLocalPpdContents.size()), |
| - static_cast<int>(kLocalPpdContents.size())); |
| - ASSERT_TRUE(ppd_provider_->CachePpd(ppd_reference, local_ppd_path)); |
| +// Test that we cache effective model resolutions when we fetch them and that we |
| +// can resolve from the cache without the server available. |
| +TEST_F(PpdProviderTest, ResolvedPpdsGetCached) { |
| + StartFakePpdServer(); |
| + auto provider = CreateProvider("en"); |
| + |
| + // We'll use 3 references here, 2 effective model, 1 user supplied url. |
| + std::vector<Printer::PpdReference> refs(3); |
| + refs[0].effective_model = "printer_a_ref"; |
| + refs[1].user_supplied_ppd_url = base::StringPrintf( |
| + "https://%s/user_supplied_ppd_directory/user_supplied.ppd", kPpdServer); |
| + refs[2].effective_model = "printer_b_ref"; |
| + |
| + // Resolve three ppds from the server, discarding the results. This should |
| + // get the ppds into the cache. |
| + for (const Printer::PpdReference& ref : refs) { |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::DiscardResolvePpd, |
| + base::Unretained(this))); |
| } |
| - // temp_dir should now be deleted, which helps make sure we actually latched a |
| - // copy, not a reference. |
| + Drain(*provider); |
| - // Retry the resove, should get the PPD back now. |
| - { |
| - CapturedResolveResult captured; |
| + // Now take down the server and resolve again. All should succeed. Also |
| + // recreate the provider for good measure. |
| + StopFakePpdServer(); |
| + provider = CreateProvider("en"); |
| - ppd_provider_->Resolve(ppd_reference, |
| - base::Bind(CaptureResolveResultCallback, &captured)); |
| - base::RunLoop().RunUntilIdle(); |
| - CheckResolveSuccessful(captured, kLocalPpdContents); |
| + // Re-resolve, this time capturing the results. |
| + for (const Printer::PpdReference& ref : refs) { |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| + base::Unretained(this))); |
| } |
| + Drain(*provider); |
| + |
| + ASSERT_EQ(3UL, captured_resolve_ppd_.size()); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| + EXPECT_EQ("a", captured_resolve_ppd_[0].second); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].first); |
| + EXPECT_EQ("u", captured_resolve_ppd_[1].second); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[2].first); |
| + EXPECT_EQ("b", captured_resolve_ppd_[2].second); |
| } |
| -// Run a query for the list of available printers. |
| -TEST_F(PpdProviderTest, QueryAvailable) { |
| - base::ScopedTempDir temp_dir; |
| - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| - PpdProvider::CallbackResultCode result_code; |
| - PpdProvider::AvailablePrintersMap available_printers; |
| - |
| - // Define a callback that sets the above variables with the callback results. |
| - // This would be cleaner with capture groups, but Bind disallows them in |
| - // lambdas. |
| - PpdProvider::QueryAvailableCallback query_callback = base::Bind( |
| - [](PpdProvider::CallbackResultCode* code_out, |
| - PpdProvider::AvailablePrintersMap* query_result_out, |
| - PpdProvider::CallbackResultCode code, |
| - const PpdProvider::AvailablePrintersMap& query_result) { |
| - *code_out = code; |
| - *query_result_out = query_result; |
| - }, |
| - &result_code, &available_printers); |
| - |
| - { |
| - net::TestURLRequestInterceptor interceptor( |
| - "https", kTestQuirksServer, base::ThreadTaskRunnerHandle::Get(), |
| - base::ThreadTaskRunnerHandle::Get()); |
| - |
| - GURL expected_url(base::StringPrintf("https://%s/v2/printer/list?key=%s", |
| - kTestQuirksServer, kTestAPIKey)); |
| - |
| - base::FilePath contents_path = temp_dir.GetPath().Append("response"); |
| - std::string contents = kQuirksListResponse; |
| - int bytes_written = base::WriteFile(contents_path, kQuirksListResponse, |
| - strlen(kQuirksListResponse)); |
| - ASSERT_EQ(static_cast<int>(strlen(kQuirksListResponse)), bytes_written); |
| - |
| - interceptor.SetResponse(expected_url, contents_path); |
| - |
| - CapturedResolveResult captured; |
| - ppd_provider_->QueryAvailable(query_callback); |
| - base::RunLoop().RunUntilIdle(); |
| - EXPECT_EQ(PpdProvider::SUCCESS, result_code); |
| - EXPECT_EQ(QuirksPrinters(), available_printers); |
| +// Test that CachePpd() works as advertised. Note we *don't* bring up a fake |
| +// server in this test -- we shouldn't need to hit the network at all. |
| +TEST_F(PpdProviderTest, CachePpd) { |
| + auto provider = CreateProvider("en"); |
| + |
| + // Set both fields to the same thing to test that we distinguish don't |
| + // trivially collide fields in the cache. The key has to be a valid url |
| + // because the provider will vomit below if we try to resolve a user-supplied |
| + // url that isn't valid. |
| + const char kKey[] = "http://www.google.com/foo.ppd"; |
| + std::vector<Printer::PpdReference> refs(2); |
| + refs[0].effective_model = kKey; |
| + refs[1].user_supplied_ppd_url = kKey; |
| + provider->CachePpd(refs[0], "a"); |
| + provider->CachePpd(refs[1], "b"); |
| + |
| + // Ensure the cache ops complete, recreate the provider for good measure. |
| + Drain(*provider); |
| + |
| + provider = CreateProvider("en"); |
| + |
| + // Resolve the (cached) ppds and check the results. |
| + for (const Printer::PpdReference& ref : refs) { |
| + provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| + base::Unretained(this))); |
| } |
| + Drain(*provider); |
| - // Now that the interceptor is out of scope, re-run the query. We should |
| - // hit in the cache, and thus *not* re-run the query. Reset the capture |
| - // variables first. |
| - result_code = PpdProvider::SERVER_ERROR; |
| - available_printers.clear(); |
| - ppd_provider_->QueryAvailable(query_callback); |
| - base::RunLoop().RunUntilIdle(); |
| - EXPECT_EQ(PpdProvider::SUCCESS, result_code); |
| - EXPECT_EQ(QuirksPrinters(), available_printers); |
| + ASSERT_EQ(2UL, captured_resolve_ppd_.size()); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| + EXPECT_EQ("a", captured_resolve_ppd_[0].second); |
| + EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].first); |
| + EXPECT_EQ("b", captured_resolve_ppd_[1].second); |
| } |
| } // namespace |