| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <map> |
| 6 #include <utility> |
| 7 |
| 5 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/bind_helpers.h" |
| 6 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 7 #include "base/files/scoped_temp_dir.h" | 11 #include "base/files/scoped_temp_dir.h" |
| 8 #include "base/logging.h" | 12 #include "base/logging.h" |
| 9 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 10 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
| 11 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
| 12 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" |
| 17 #include "base/test/test_message_loop.h" |
| 18 #include "base/threading/sequenced_task_runner_handle.h" |
| 13 #include "base/threading/thread_task_runner_handle.h" | 19 #include "base/threading/thread_task_runner_handle.h" |
| 14 #include "chromeos/chromeos_paths.h" | 20 #include "chromeos/chromeos_paths.h" |
| 15 #include "chromeos/printing/ppd_cache.h" | 21 #include "chromeos/printing/ppd_cache.h" |
| 16 #include "chromeos/printing/ppd_provider.h" | 22 #include "chromeos/printing/ppd_provider.h" |
| 17 #include "net/url_request/test_url_request_interceptor.h" | 23 #include "net/url_request/test_url_request_interceptor.h" |
| 18 #include "net/url_request/url_request_test_util.h" | 24 #include "net/url_request/url_request_test_util.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 25 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 26 |
| 21 namespace chromeos { | 27 namespace chromeos { |
| 22 namespace printing { | 28 namespace printing { |
| 29 |
| 23 namespace { | 30 namespace { |
| 24 | 31 |
| 25 const char kTestQuirksServer[] = "bogusserver.bogus.com"; | 32 // Name of the fake server we're resolving ppds from. |
| 26 const char kTestAPIKey[] = "BOGUSAPIKEY"; | 33 const char kPpdServer[] = "bogus.google.com"; |
| 27 const char kLocalPpdUrl[] = "/some/path"; | |
| 28 const char kTestManufacturer[] = "Bogus Printer Corp"; | |
| 29 const char kTestModel[] = "MegaPrint 9000"; | |
| 30 // The compressedPPD contents here comes from running the command | |
| 31 // echo -n "This is the quirks ppd" | base64 | |
| 32 const char kQuirksResponse[] = | |
| 33 "{\n" | |
| 34 " \"compressedPpd\": \"VGhpcyBpcyB0aGUgcXVpcmtzIHBwZA==\",\n" | |
| 35 " \"lastUpdatedTime\": \"1\"\n" | |
| 36 "}\n"; | |
| 37 const char kQuirksPpd[] = "This is the quirks ppd"; | |
| 38 | |
| 39 // A well-formatted response for a list of ppds from quirks server. This | |
| 40 // corresponds to the AvailablePrintersMap returned by QuirksPrinters() below. | |
| 41 const char kQuirksListResponse[] = | |
| 42 "{\n" | |
| 43 " \"manufacturers\": [\n" | |
| 44 " {\n" | |
| 45 " \"manufacturer\": \"manu_a\",\n" | |
| 46 " \"models\": [\n" | |
| 47 " \"model_1\",\n" | |
| 48 " \"model_2\"\n" | |
| 49 " ]\n" | |
| 50 " },\n" | |
| 51 " {\n" | |
| 52 " \"manufacturer\": \"manu_b\",\n" | |
| 53 " \"models\": [\n" | |
| 54 " \"model_3\",\n" | |
| 55 " \"model_1\"\n" | |
| 56 " ]\n" | |
| 57 " }\n" | |
| 58 " ]\n" | |
| 59 "}\n"; | |
| 60 | |
| 61 // Return an AvailablePrintersMap that matches what's in kQuirksListResponse. | |
| 62 PpdProvider::AvailablePrintersMap QuirksPrinters() { | |
| 63 return {{"manu_a", {"model_1", "model_2"}}, | |
| 64 {"manu_b", {"model_3", "model_1"}}}; | |
| 65 } | |
| 66 | 34 |
| 67 class PpdProviderTest : public ::testing::Test { | 35 class PpdProviderTest : public ::testing::Test { |
| 68 public: | 36 public: |
| 69 PpdProviderTest() | 37 PpdProviderTest() |
| 70 : loop_(base::MessageLoop::TYPE_IO), | 38 : loop_(base::MessageLoop::TYPE_IO), |
| 71 request_context_getter_( | 39 request_context_getter_(new net::TestURLRequestContextGetter( |
| 72 new net::TestURLRequestContextGetter(loop_.task_runner().get())) {} | 40 base::MessageLoop::current()->task_runner())) {} |
| 73 | 41 |
| 74 void SetUp() override { | 42 void SetUp() override { |
| 75 ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir()); | 43 ASSERT_TRUE(ppd_cache_temp_dir_.CreateUniqueTempDir()); |
| 44 } |
| 45 |
| 46 void TearDown() override { StopFakePpdServer(); } |
| 47 |
| 48 // Create and return a provider for a test that uses the given |locale|. |
| 49 scoped_refptr<PpdProvider> CreateProvider(const std::string& locale) { |
| 76 auto provider_options = PpdProvider::Options(); | 50 auto provider_options = PpdProvider::Options(); |
| 77 provider_options.quirks_server = kTestQuirksServer; | 51 provider_options.ppd_server_root = std::string("https://") + kPpdServer; |
| 78 ppd_provider_ = PpdProvider::Create( | 52 |
| 79 kTestAPIKey, request_context_getter_.get(), loop_.task_runner().get(), | 53 return PpdProvider::Create( |
| 80 PpdCache::Create(ppd_cache_temp_dir_.GetPath()), provider_options); | 54 locale, request_context_getter_.get(), |
| 81 } | 55 PpdCache::Create(ppd_cache_temp_dir_.GetPath(), |
| 56 base::MessageLoop::current()->task_runner()), |
| 57 provider_options); |
| 58 } |
| 59 |
| 60 // Create an interceptor that serves a small fileset of ppd server files. |
| 61 void StartFakePpdServer() { |
| 62 ASSERT_TRUE(interceptor_temp_dir_.CreateUniqueTempDir()); |
| 63 interceptor_ = base::MakeUnique<net::TestURLRequestInterceptor>( |
| 64 "https", kPpdServer, base::ThreadTaskRunnerHandle::Get(), |
| 65 base::ThreadTaskRunnerHandle::Get()); |
| 66 // Use brace initialization to express the desired server contents as "url", |
| 67 // "contents" pairs. |
| 68 std::vector<std::pair<std::string, std::string>> server_contents = { |
| 69 {"metadata/locales.json", |
| 70 R"(["en", |
| 71 "es-mx", |
| 72 "en-gb"])"}, |
| 73 {"metadata/index.json", |
| 74 R"([ |
| 75 ["printer_a_ref", "printer_a.ppd"], |
| 76 ["printer_b_ref", "printer_b.ppd"], |
| 77 ["printer_c_ref", "printer_c.ppd"] |
| 78 ])"}, |
| 79 {"metadata/manufacturers-en.json", |
| 80 R"([ |
| 81 ["manufacturer_a_en", "manufacturer_a.json"], |
| 82 ["manufacturer_b_en", "manufacturer_b.json"] |
| 83 ])"}, |
| 84 {"metadata/manufacturers-en-gb.json", |
| 85 R"([ |
| 86 ["manufacturer_a_en-gb", "manufacturer_a.json"], |
| 87 ["manufacturer_b_en-gb", "manufacturer_b.json"] |
| 88 ])"}, |
| 89 {"metadata/manufacturers-es-mx.json", |
| 90 R"([ |
| 91 ["manufacturer_a_es-mx", "manufacturer_a.json"], |
| 92 ["manufacturer_b_es-mx", "manufacturer_b.json"] |
| 93 ])"}, |
| 94 {"metadata/manufacturer_a.json", |
| 95 R"([ |
| 96 ["printer_a", "printer_a_ref"], |
| 97 ["printer_b", "printer_b_ref"] |
| 98 ])"}, |
| 99 {"metadata/manufacturer_b.json", |
| 100 R"([ |
| 101 ["printer_c", "printer_c_ref"] |
| 102 ])"}, |
| 103 {"ppds/printer_a.ppd", "a"}, |
| 104 {"ppds/printer_b.ppd", "b"}, |
| 105 {"ppds/printer_c.ppd", "c"}, |
| 106 {"user_supplied_ppd_directory/user_supplied.ppd", "u"}}; |
| 107 int next_file_num = 0; |
| 108 for (const auto& entry : server_contents) { |
| 109 base::FilePath filename = interceptor_temp_dir_.GetPath().Append( |
| 110 base::StringPrintf("%d.json", next_file_num++)); |
| 111 ASSERT_EQ( |
| 112 base::WriteFile(filename, entry.second.data(), entry.second.size()), |
| 113 static_cast<int>(entry.second.size())) |
| 114 << "Failed to write temp server file"; |
| 115 interceptor_->SetResponse( |
| 116 GURL(base::StringPrintf("https://%s/%s", kPpdServer, |
| 117 entry.first.c_str())), |
| 118 filename); |
| 119 } |
| 120 } |
| 121 |
| 122 // Interceptor posts a *task* during destruction that actually unregisters |
| 123 // things. So we have to run the message loop post-interceptor-destruction to |
| 124 // actually unregister the URLs, otherwise they won't *actually* be |
| 125 // unregistered until the next time we invoke the message loop. Which may be |
| 126 // in the middle of the next test. |
| 127 // |
| 128 // Note this is harmless to call if we haven't started a fake ppd server. |
| 129 void StopFakePpdServer() { |
| 130 interceptor_.reset(); |
| 131 base::RunLoop().RunUntilIdle(); |
| 132 } |
| 133 |
| 134 // Capture the result of a ResolveManufacturers() call. |
| 135 void CaptureResolveManufacturers(PpdProvider::CallbackResultCode code, |
| 136 const std::vector<std::string>& data) { |
| 137 captured_resolve_manufacturers_.push_back({code, data}); |
| 138 } |
| 139 |
| 140 // Capture the result of a ResolvePrinters() call. |
| 141 void CaptureResolvePrinters(PpdProvider::CallbackResultCode code, |
| 142 const std::vector<std::string>& data) { |
| 143 captured_resolve_printers_.push_back({code, data}); |
| 144 } |
| 145 |
| 146 // Capture the result of a ResolvePpd() call. |
| 147 void CaptureResolvePpd(PpdProvider::CallbackResultCode code, |
| 148 const std::string& contents) { |
| 149 captured_resolve_ppd_.push_back({code, contents}); |
| 150 } |
| 151 |
| 152 // Discard the result of a ResolvePpd() call. |
| 153 void DiscardResolvePpd(PpdProvider::CallbackResultCode code, |
| 154 const std::string& contents) {} |
| 82 | 155 |
| 83 protected: | 156 protected: |
| 157 // Run a ResolveManufacturers run from the given locale, expect to get |
| 158 // results in expected_used_locale. |
| 159 void RunLocalizationTest(const std::string& browser_locale, |
| 160 const std::string& expected_used_locale) { |
| 161 captured_resolve_manufacturers_.clear(); |
| 162 auto provider = CreateProvider(browser_locale); |
| 163 provider->ResolveManufacturers(base::Bind( |
| 164 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| 165 base::RunLoop().RunUntilIdle(); |
| 166 provider = nullptr; |
| 167 ASSERT_EQ(captured_resolve_manufacturers_.size(), 1UL); |
| 168 EXPECT_EQ(captured_resolve_manufacturers_[0].first, PpdProvider::SUCCESS); |
| 169 |
| 170 const auto& result_vec = captured_resolve_manufacturers_[0].second; |
| 171 |
| 172 // It's sufficient to check for one of the expected locale keys to make sure |
| 173 // we got the right map. |
| 174 EXPECT_FALSE(std::find(result_vec.begin(), result_vec.end(), |
| 175 "manufacturer_a_" + expected_used_locale) == |
| 176 result_vec.end()); |
| 177 } |
| 178 |
| 179 // Drain tasks both on the loop we use for network/disk activity and the |
| 180 // top-level loop that we're using in the test itself. Unfortunately, even |
| 181 // thought the TestURLRequestContextGetter tells the url fetcher to run on the |
| 182 // current message loop, some deep backend processes can get put into other |
| 183 // loops, which means we can't just trust RunLoop::RunUntilIdle() to drain |
| 184 // outstanding work. |
| 185 void Drain(const PpdProvider& provider) { |
| 186 do { |
| 187 base::RunLoop().RunUntilIdle(); |
| 188 } while (!provider.Idle()); |
| 189 } |
| 190 |
| 191 // Message loop that runs on the current thread. |
| 192 base::TestMessageLoop loop_; |
| 193 |
| 194 std::vector< |
| 195 std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>> |
| 196 captured_resolve_manufacturers_; |
| 197 |
| 198 std::vector< |
| 199 std::pair<PpdProvider::CallbackResultCode, std::vector<std::string>>> |
| 200 captured_resolve_printers_; |
| 201 |
| 202 std::vector<std::pair<PpdProvider::CallbackResultCode, std::string>> |
| 203 captured_resolve_ppd_; |
| 204 |
| 205 std::unique_ptr<net::TestURLRequestInterceptor> interceptor_; |
| 206 |
| 84 base::ScopedTempDir ppd_cache_temp_dir_; | 207 base::ScopedTempDir ppd_cache_temp_dir_; |
| 208 base::ScopedTempDir interceptor_temp_dir_; |
| 85 | 209 |
| 86 // Provider to be used in the test. | 210 // Provider to be used in the test. |
| 87 std::unique_ptr<PpdProvider> ppd_provider_; | 211 scoped_refptr<PpdProvider> ppd_provider_; |
| 88 | 212 |
| 89 // Misc extra stuff needed for the test environment to function. | 213 // Misc extra stuff needed for the test environment to function. |
| 90 base::MessageLoop loop_; | 214 // base::TestMessageLoop loop_; |
| 91 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 215 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; |
| 92 }; | 216 }; |
| 93 | 217 |
| 94 // Struct that just captures the callback result for a PpdProvider lookup and | 218 // Test that we get back manufacturer maps as expected. |
| 95 // saves it for inspection by the test. | 219 TEST_F(PpdProviderTest, ManufacturersFetch) { |
| 96 struct CapturedResolveResult { | 220 StartFakePpdServer(); |
| 97 bool initialized = false; | 221 auto provider = CreateProvider("en"); |
| 98 PpdProvider::CallbackResultCode result; | 222 // Issue two requests at the same time, both should be resolved properly. |
| 99 base::FilePath file; | 223 provider->ResolveManufacturers(base::Bind( |
| 100 }; | 224 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| 101 | 225 provider->ResolveManufacturers(base::Bind( |
| 102 // Callback for saving a resolve callback. | 226 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| 103 void CaptureResolveResultCallback(CapturedResolveResult* capture, | 227 Drain(*provider); |
| 104 PpdProvider::CallbackResultCode result, | 228 ASSERT_EQ(2UL, captured_resolve_manufacturers_.size()); |
| 105 base::FilePath file) { | 229 std::vector<std::string> expected_result( |
| 106 capture->initialized = true; | 230 {"manufacturer_a_en", "manufacturer_b_en"}); |
| 107 capture->result = result; | 231 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[0].first); |
| 108 capture->file = file; | 232 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_manufacturers_[1].first); |
| 109 } | 233 EXPECT_TRUE(captured_resolve_manufacturers_[0].second == expected_result); |
| 110 | 234 EXPECT_TRUE(captured_resolve_manufacturers_[1].second == expected_result); |
| 111 // For a resolve result that should end up successful, check that it is | 235 } |
| 112 // successful and the contents are expected_contents. | 236 |
| 113 void CheckResolveSuccessful(const CapturedResolveResult& captured, | 237 // Test that we get a reasonable error when we have no server to contact. Tis |
| 114 const std::string& expected_contents) { | 238 // is almost exactly the same as the above test, we just don't bring up the fake |
| 115 ASSERT_TRUE(captured.initialized); | 239 // server first. |
| 116 EXPECT_EQ(PpdProvider::SUCCESS, captured.result); | 240 TEST_F(PpdProviderTest, ManufacturersFetchNoServer) { |
| 117 | 241 auto provider = CreateProvider("en"); |
| 118 std::string contents; | 242 // Issue two requests at the same time, both should be resolved properly. |
| 119 ASSERT_TRUE(base::ReadFileToString(captured.file, &contents)); | 243 provider->ResolveManufacturers(base::Bind( |
| 120 EXPECT_EQ(expected_contents, contents); | 244 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| 121 } | 245 provider->ResolveManufacturers(base::Bind( |
| 122 | 246 &PpdProviderTest::CaptureResolveManufacturers, base::Unretained(this))); |
| 123 // Resolve a PPD via the quirks server. | 247 Drain(*provider); |
| 124 TEST_F(PpdProviderTest, QuirksServerResolve) { | 248 ASSERT_EQ(2UL, captured_resolve_manufacturers_.size()); |
| 125 base::ScopedTempDir temp_dir; | 249 EXPECT_EQ(PpdProvider::SERVER_ERROR, |
| 126 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 250 captured_resolve_manufacturers_[0].first); |
| 127 | 251 EXPECT_EQ(PpdProvider::SERVER_ERROR, |
| 128 Printer::PpdReference ppd_reference; | 252 captured_resolve_manufacturers_[1].first); |
| 129 ppd_reference.effective_manufacturer = kTestManufacturer; | 253 EXPECT_TRUE(captured_resolve_manufacturers_[0].second.empty()); |
| 130 ppd_reference.effective_model = kTestModel; | 254 EXPECT_TRUE(captured_resolve_manufacturers_[1].second.empty()); |
| 131 | 255 } |
| 132 { | 256 |
| 133 net::TestURLRequestInterceptor interceptor( | 257 // Test that we get things in the requested locale, and that fallbacks are sane. |
| 134 "https", kTestQuirksServer, base::ThreadTaskRunnerHandle::Get(), | 258 TEST_F(PpdProviderTest, LocalizationAndFallbacks) { |
| 135 base::ThreadTaskRunnerHandle::Get()); | 259 StartFakePpdServer(); |
| 136 | 260 RunLocalizationTest("en-gb", "en-gb"); |
| 137 GURL expected_url(base::StringPrintf( | 261 RunLocalizationTest("en-blah", "en"); |
| 138 "https://%s/v2/printer/manufacturers/%s/models/%s?key=%s", | 262 RunLocalizationTest("en-gb-foo", "en-gb"); |
| 139 kTestQuirksServer, kTestManufacturer, kTestModel, kTestAPIKey)); | 263 RunLocalizationTest("es", "es-mx"); |
| 140 | 264 RunLocalizationTest("bogus", "en"); |
| 141 base::FilePath contents_path = temp_dir.GetPath().Append("response"); | 265 } |
| 142 std::string contents = kQuirksResponse; | 266 |
| 143 int bytes_written = | 267 // For convenience a null ResolveManufacturers callback target. |
| 144 base::WriteFile(contents_path, contents.data(), contents.size()); | 268 void ResolveManufacturersNop(PpdProvider::CallbackResultCode code, |
| 145 ASSERT_EQ(bytes_written, static_cast<int>(contents.size())); | 269 const std::vector<std::string>& v) {} |
| 146 | 270 |
| 147 interceptor.SetResponse(expected_url, contents_path); | 271 // Test basic ResolvePrinters() functionality. At the same time, make |
| 148 | 272 // sure we can get the PpdReference for each of the resolved printers. |
| 149 CapturedResolveResult captured; | 273 TEST_F(PpdProviderTest, ResolvePrinters) { |
| 150 ppd_provider_->Resolve(ppd_reference, | 274 StartFakePpdServer(); |
| 151 base::Bind(CaptureResolveResultCallback, &captured)); | 275 auto provider = CreateProvider("en"); |
| 152 base::RunLoop().RunUntilIdle(); | 276 |
| 153 CheckResolveSuccessful(captured, kQuirksPpd); | 277 // Grab the manufacturer list, but don't bother to save it, we know what |
| 154 } | 278 // should be in it and we check that elsewhere. We just need to run the |
| 155 | 279 // resolve to populate the internal PpdProvider structures. |
| 156 // Now that the interceptor is out of scope, re-run the query. We should | 280 provider->ResolveManufacturers(base::Bind(&ResolveManufacturersNop)); |
| 157 // hit in the cache, and thus *not* re-run the query. | 281 Drain(*provider); |
| 158 CapturedResolveResult captured; | 282 |
| 159 ppd_provider_->Resolve(ppd_reference, | 283 provider->ResolvePrinters("manufacturer_a_en", |
| 160 base::Bind(CaptureResolveResultCallback, &captured)); | 284 base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| 161 base::RunLoop().RunUntilIdle(); | 285 base::Unretained(this))); |
| 162 CheckResolveSuccessful(captured, kQuirksPpd); | 286 provider->ResolvePrinters("manufacturer_b_en", |
| 163 } | 287 base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| 164 | 288 base::Unretained(this))); |
| 165 // Test storage and retrieval of PPDs that are added manually. Even though we | 289 Drain(*provider); |
| 166 // supply a manufacturer and model, we should *not* hit the network for this | 290 ASSERT_EQ(2UL, captured_resolve_printers_.size()); |
| 167 // resolution since we should find the stored version already cached. | 291 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[0].first); |
| 168 TEST_F(PpdProviderTest, LocalResolve) { | 292 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_printers_[1].first); |
| 169 Printer::PpdReference ppd_reference; | 293 EXPECT_EQ(2UL, captured_resolve_printers_[0].second.size()); |
| 170 ppd_reference.user_supplied_ppd_url = kLocalPpdUrl; | 294 EXPECT_EQ(std::vector<std::string>({"printer_a", "printer_b"}), |
| 171 ppd_reference.effective_manufacturer = kTestManufacturer; | 295 captured_resolve_printers_[0].second); |
| 172 ppd_reference.effective_model = kTestModel; | 296 EXPECT_EQ(std::vector<std::string>({"printer_c"}), |
| 173 | 297 captured_resolve_printers_[1].second); |
| 174 // Initially, should not resolve. | 298 |
| 175 { | 299 // We have manufacturers and models, we should be able to get a ppd out of |
| 176 CapturedResolveResult captured; | 300 // this. |
| 177 ppd_provider_->Resolve(ppd_reference, | 301 Printer::PpdReference ref; |
| 178 base::Bind(CaptureResolveResultCallback, &captured)); | 302 ASSERT_TRUE( |
| 179 base::RunLoop().RunUntilIdle(); | 303 provider->GetPpdReference("manufacturer_a_en", "printer_b", &ref)); |
| 180 EXPECT_TRUE(captured.initialized); | 304 } |
| 181 EXPECT_EQ(PpdProvider::NOT_FOUND, captured.result); | 305 |
| 182 } | 306 // Test that if we give a bad reference to ResolvePrinters(), we get an |
| 183 | 307 // INTERNAL_ERROR. |
| 184 // Store a local ppd. | 308 TEST_F(PpdProviderTest, ResolvePrintersBadReference) { |
| 185 const std::string kLocalPpdContents("My local ppd contents"); | 309 StartFakePpdServer(); |
| 186 { | 310 auto provider = CreateProvider("en"); |
| 187 base::ScopedTempDir temp_dir; | 311 provider->ResolveManufacturers(base::Bind(&ResolveManufacturersNop)); |
| 188 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 312 Drain(*provider); |
| 189 | 313 |
| 190 base::FilePath local_ppd_path = temp_dir.GetPath().Append("local_ppd"); | 314 provider->ResolvePrinters("bogus_doesnt_exist", |
| 191 ASSERT_EQ(base::WriteFile(local_ppd_path, kLocalPpdContents.data(), | 315 base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| 192 kLocalPpdContents.size()), | 316 base::Unretained(this))); |
| 193 static_cast<int>(kLocalPpdContents.size())); | 317 Drain(*provider); |
| 194 ASSERT_TRUE(ppd_provider_->CachePpd(ppd_reference, local_ppd_path)); | 318 ASSERT_EQ(1UL, captured_resolve_printers_.size()); |
| 195 } | 319 EXPECT_EQ(PpdProvider::INTERNAL_ERROR, captured_resolve_printers_[0].first); |
| 196 // temp_dir should now be deleted, which helps make sure we actually latched a | 320 } |
| 197 // copy, not a reference. | 321 |
| 198 | 322 // Test that if the server is unavailable, we get SERVER_ERRORs back out. |
| 199 // Retry the resove, should get the PPD back now. | 323 TEST_F(PpdProviderTest, ResolvePrintersNoServer) { |
| 200 { | 324 StartFakePpdServer(); |
| 201 CapturedResolveResult captured; | 325 auto provider = CreateProvider("en"); |
| 202 | 326 provider->ResolveManufacturers(base::Bind(&ResolveManufacturersNop)); |
| 203 ppd_provider_->Resolve(ppd_reference, | 327 Drain(*provider); |
| 204 base::Bind(CaptureResolveResultCallback, &captured)); | 328 |
| 205 base::RunLoop().RunUntilIdle(); | 329 StopFakePpdServer(); |
| 206 CheckResolveSuccessful(captured, kLocalPpdContents); | 330 |
| 207 } | 331 provider->ResolvePrinters("manufacturer_a_en", |
| 208 } | 332 base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| 209 | 333 base::Unretained(this))); |
| 210 // Run a query for the list of available printers. | 334 provider->ResolvePrinters("manufacturer_b_en", |
| 211 TEST_F(PpdProviderTest, QueryAvailable) { | 335 base::Bind(&PpdProviderTest::CaptureResolvePrinters, |
| 212 base::ScopedTempDir temp_dir; | 336 base::Unretained(this))); |
| 213 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 337 Drain(*provider); |
| 214 PpdProvider::CallbackResultCode result_code; | 338 ASSERT_EQ(2UL, captured_resolve_printers_.size()); |
| 215 PpdProvider::AvailablePrintersMap available_printers; | 339 EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[0].first); |
| 216 | 340 EXPECT_EQ(PpdProvider::SERVER_ERROR, captured_resolve_printers_[1].first); |
| 217 // Define a callback that sets the above variables with the callback results. | 341 } |
| 218 // This would be cleaner with capture groups, but Bind disallows them in | 342 |
| 219 // lambdas. | 343 // Test a successful ppd resolution from an effective_make_and_model reference. |
| 220 PpdProvider::QueryAvailableCallback query_callback = base::Bind( | 344 TEST_F(PpdProviderTest, ResolveServerKeyPpd) { |
| 221 [](PpdProvider::CallbackResultCode* code_out, | 345 StartFakePpdServer(); |
| 222 PpdProvider::AvailablePrintersMap* query_result_out, | 346 auto provider = CreateProvider("en"); |
| 223 PpdProvider::CallbackResultCode code, | 347 Printer::PpdReference ref; |
| 224 const PpdProvider::AvailablePrintersMap& query_result) { | 348 ref.effective_make_and_model = "printer_b_ref"; |
| 225 *code_out = code; | 349 provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| 226 *query_result_out = query_result; | 350 base::Unretained(this))); |
| 227 }, | 351 ref.effective_make_and_model = "printer_c_ref"; |
| 228 &result_code, &available_printers); | 352 provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| 229 | 353 base::Unretained(this))); |
| 230 { | 354 Drain(*provider); |
| 231 net::TestURLRequestInterceptor interceptor( | 355 |
| 232 "https", kTestQuirksServer, base::ThreadTaskRunnerHandle::Get(), | 356 ASSERT_EQ(2UL, captured_resolve_ppd_.size()); |
| 233 base::ThreadTaskRunnerHandle::Get()); | 357 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| 234 | 358 EXPECT_EQ("b", captured_resolve_ppd_[0].second); |
| 235 GURL expected_url(base::StringPrintf("https://%s/v2/printer/list?key=%s", | 359 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].first); |
| 236 kTestQuirksServer, kTestAPIKey)); | 360 EXPECT_EQ("c", captured_resolve_ppd_[1].second); |
| 237 | 361 } |
| 238 base::FilePath contents_path = temp_dir.GetPath().Append("response"); | 362 |
| 239 std::string contents = kQuirksListResponse; | 363 // Test a successful ppd resolution from a user_supplied_url field. |
| 240 int bytes_written = base::WriteFile(contents_path, kQuirksListResponse, | 364 TEST_F(PpdProviderTest, ResolveUserSuppliedUrlPpd) { |
| 241 strlen(kQuirksListResponse)); | 365 StartFakePpdServer(); |
| 242 ASSERT_EQ(static_cast<int>(strlen(kQuirksListResponse)), bytes_written); | 366 auto provider = CreateProvider("en"); |
| 243 | 367 |
| 244 interceptor.SetResponse(expected_url, contents_path); | 368 Printer::PpdReference ref; |
| 245 | 369 ref.user_supplied_ppd_url = base::StringPrintf( |
| 246 CapturedResolveResult captured; | 370 "https://%s/user_supplied_ppd_directory/user_supplied.ppd", kPpdServer); |
| 247 ppd_provider_->QueryAvailable(query_callback); | 371 provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| 248 base::RunLoop().RunUntilIdle(); | 372 base::Unretained(this))); |
| 249 EXPECT_EQ(PpdProvider::SUCCESS, result_code); | 373 Drain(*provider); |
| 250 EXPECT_EQ(QuirksPrinters(), available_printers); | 374 |
| 251 } | 375 ASSERT_EQ(1UL, captured_resolve_ppd_.size()); |
| 252 | 376 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| 253 // Now that the interceptor is out of scope, re-run the query. We should | 377 EXPECT_EQ("u", captured_resolve_ppd_[0].second); |
| 254 // hit in the cache, and thus *not* re-run the query. Reset the capture | 378 } |
| 255 // variables first. | 379 |
| 256 result_code = PpdProvider::SERVER_ERROR; | 380 // Test that we cache ppd resolutions when we fetch them and that we can resolve |
| 257 available_printers.clear(); | 381 // from the cache without the server available. |
| 258 ppd_provider_->QueryAvailable(query_callback); | 382 TEST_F(PpdProviderTest, ResolvedPpdsGetCached) { |
| 259 base::RunLoop().RunUntilIdle(); | 383 StartFakePpdServer(); |
| 260 EXPECT_EQ(PpdProvider::SUCCESS, result_code); | 384 auto provider = CreateProvider("en"); |
| 261 EXPECT_EQ(QuirksPrinters(), available_printers); | 385 |
| 386 // We'll use 3 references here, 2 server-key based, 1 user supplied url. |
| 387 std::vector<Printer::PpdReference> refs(3); |
| 388 refs[0].effective_make_and_model = "printer_a_ref"; |
| 389 refs[1].user_supplied_ppd_url = base::StringPrintf( |
| 390 "https://%s/user_supplied_ppd_directory/user_supplied.ppd", kPpdServer); |
| 391 refs[2].effective_make_and_model = "printer_b_ref"; |
| 392 |
| 393 // Resolve three ppds from the server, discarding the results. This should |
| 394 // get the ppds into the cache. |
| 395 for (const Printer::PpdReference& ref : refs) { |
| 396 provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::DiscardResolvePpd, |
| 397 base::Unretained(this))); |
| 398 } |
| 399 Drain(*provider); |
| 400 |
| 401 // Now take down the server and resolve again. All should succeed. Also |
| 402 // recreate the provider for good measure. |
| 403 StopFakePpdServer(); |
| 404 provider = CreateProvider("en"); |
| 405 |
| 406 // Re-resolve, this time capturing the results. |
| 407 for (const Printer::PpdReference& ref : refs) { |
| 408 provider->ResolvePpd(ref, base::Bind(&PpdProviderTest::CaptureResolvePpd, |
| 409 base::Unretained(this))); |
| 410 } |
| 411 Drain(*provider); |
| 412 |
| 413 ASSERT_EQ(3UL, captured_resolve_ppd_.size()); |
| 414 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[0].first); |
| 415 EXPECT_EQ("a", captured_resolve_ppd_[0].second); |
| 416 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[1].first); |
| 417 EXPECT_EQ("u", captured_resolve_ppd_[1].second); |
| 418 EXPECT_EQ(PpdProvider::SUCCESS, captured_resolve_ppd_[2].first); |
| 419 EXPECT_EQ("b", captured_resolve_ppd_[2].second); |
| 262 } | 420 } |
| 263 | 421 |
| 264 } // namespace | 422 } // namespace |
| 265 } // namespace printing | 423 } // namespace printing |
| 266 } // namespace chromeos | 424 } // namespace chromeos |
| OLD | NEW |