Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(577)

Side by Side Diff: chromeos/printing/ppd_provider_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698