1 // Copyright 2017 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 "chrome/browser/ui/webui/print_preview/print_preview_handler.h"
6
7 #include <map>
8 #include <utility>
9 #include <vector>
10
11 #include "base/base64.h"
12 #include "base/containers/flat_set.h"
13 #include "base/i18n/number_formatting.h"
14 #include "base/json/json_reader.h"
15 #include "base/json/json_writer.h"
16 #include "base/memory/ref_counted_memory.h"
17 #include "base/optional.h"
18 #include "base/run_loop.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string16.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/test/icu_test_util.h"
23 #include "base/test/metrics/histogram_tester.h"
24 #include "base/values.h"
25 #include "chrome/browser/printing/print_test_utils.h"
26 #include "chrome/browser/printing/print_view_manager.h"
27 #include "chrome/browser/ui/webui/print_preview/fake_print_render_frame.h"
28 #include "chrome/browser/ui/webui/print_preview/policy_settings.h"
29 #include "chrome/browser/ui/webui/print_preview/print_preview_metrics.h"
30 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
31 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/test/base/testing_browser_process.h"
34 #include "chrome/test/base/testing_profile.h"
35 #include "components/prefs/pref_service.h"
36 #include "components/sync_preferences/testing_pref_service_syncable.h"
37 #include "content/public/browser/render_frame_host.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_ui_controller.h"
40 #include "content/public/test/browser_task_environment.h"
41 #include "content/public/test/test_renderer_host.h"
42 #include "content/public/test/test_web_ui.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44
45 namespace printing {
46
47 namespace {
48
49 const char kDummyInitiatorName[] = "TestInitiator";
50 const char kEmptyPrinterName[] = "EmptyPrinter";
51 const char kTestData[] = "abc";
52
53 // Array of all PrinterTypes.
54 constexpr PrinterType kAllTypes[] = {PrinterType::kPrivet,
55 PrinterType::kExtension, PrinterType::kPdf,
56 PrinterType::kLocal, PrinterType::kCloud};
57
58 // Array of all PrinterTypes that have working PrinterHandlers.
59 constexpr PrinterType kAllSupportedTypes[] = {
60 PrinterType::kPrivet, PrinterType::kExtension, PrinterType::kPdf,
61 PrinterType::kLocal};
62
63 // All three printer types that implement PrinterHandler::StartGetPrinters().
64 constexpr PrinterType kFetchableTypes[] = {
65 PrinterType::kPrivet, PrinterType::kExtension, PrinterType::kLocal};
66
67 struct PrinterInfo {
68 std::string id;
69 bool is_default;
70 base::Value basic_info = base::Value(base::Value::Type::DICTIONARY);
71 base::Value capabilities = base::Value(base::Value::Type::DICTIONARY);
72 };
73
GetSimplePrinterInfo(const std::string & name,bool is_default)74 PrinterInfo GetSimplePrinterInfo(const std::string& name, bool is_default) {
75 PrinterInfo simple_printer;
76 simple_printer.id = name;
77 simple_printer.is_default = is_default;
78 simple_printer.basic_info.SetKey("printer_name",
79 base::Value(simple_printer.id));
80 simple_printer.basic_info.SetKey("printer_description",
81 base::Value("Printer for test"));
82 simple_printer.basic_info.SetKey("printer_status", base::Value(1));
83 base::Value cdd(base::Value::Type::DICTIONARY);
84 base::Value capabilities(base::Value::Type::DICTIONARY);
85 simple_printer.capabilities.SetKey("printer",
86 simple_printer.basic_info.Clone());
87 simple_printer.capabilities.SetKey("capabilities", cdd.Clone());
88 return simple_printer;
89 }
90
GetEmptyPrinterInfo()91 PrinterInfo GetEmptyPrinterInfo() {
92 PrinterInfo empty_printer;
93 empty_printer.id = kEmptyPrinterName;
94 empty_printer.is_default = false;
95 empty_printer.basic_info.SetKey("printer_name",
96 base::Value(empty_printer.id));
97 empty_printer.basic_info.SetKey("printer_description",
98 base::Value("Printer with no capabilities"));
99 empty_printer.basic_info.SetKey("printer_status", base::Value(0));
100 empty_printer.capabilities.SetKey("printer",
101 empty_printer.basic_info.Clone());
102 return empty_printer;
103 }
104
GetPrintPreviewTicket()105 base::Value GetPrintPreviewTicket() {
106 base::Value print_ticket = GetPrintTicket(PrinterType::kLocal);
107
108 // Make some modifications to match a preview print ticket.
109 print_ticket.SetKey(kSettingPageRange, base::Value());
110 print_ticket.SetBoolKey(kIsFirstRequest, true);
111 print_ticket.SetIntKey(kPreviewRequestID, 0);
112 print_ticket.SetBoolKey(kSettingPreviewModifiable, false);
113 print_ticket.SetBoolKey(kSettingPreviewIsPdf, true);
114 print_ticket.RemoveKey(kSettingPageWidth);
115 print_ticket.RemoveKey(kSettingPageHeight);
116 print_ticket.RemoveKey(kSettingShowSystemDialog);
117
118 return print_ticket;
119 }
120
ConstructPreviewArgs(base::StringPiece callback_id,const base::Value & print_ticket)121 std::unique_ptr<base::ListValue> ConstructPreviewArgs(
122 base::StringPiece callback_id,
123 const base::Value& print_ticket) {
124 base::Value args(base::Value::Type::LIST);
125 args.Append(callback_id);
126 std::string json;
127 base::JSONWriter::Write(print_ticket, &json);
128 args.Append(json);
129 return base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
130 }
131
GetUserActionForPrinterType(PrinterType type)132 UserActionBuckets GetUserActionForPrinterType(PrinterType type) {
133 switch (type) {
134 case PrinterType::kPrivet:
135 return UserActionBuckets::kPrintWithPrivet;
136 case PrinterType::kExtension:
137 return UserActionBuckets::kPrintWithExtension;
138 case PrinterType::kPdf:
139 return UserActionBuckets::kPrintToPdf;
140 case PrinterType::kLocal:
141 return UserActionBuckets::kPrintToPrinter;
142 case PrinterType::kCloud:
143 return UserActionBuckets::kPrintWithCloudPrint;
144 }
145 }
146
147 // Checks whether |histograms| was updated correctly by a job with a printer
148 // type |type| with arguments generated by GetPrintTicket().
CheckHistograms(const base::HistogramTester & histograms,PrinterType type)149 void CheckHistograms(const base::HistogramTester& histograms,
150 PrinterType type) {
151 static constexpr PrintSettingsBuckets kPopulatedPrintSettingsBuckets[] = {
152 PrintSettingsBuckets::kPortrait, PrintSettingsBuckets::kColor,
153 PrintSettingsBuckets::kCollate, PrintSettingsBuckets::kDuplex,
154 PrintSettingsBuckets::kTotal, PrintSettingsBuckets::kDefaultMedia,
155 };
156
157 for (auto bucket : kPopulatedPrintSettingsBuckets)
158 histograms.ExpectBucketCount("PrintPreview.PrintSettings", bucket, 1);
159
160 // All other PrintPreview.PrintSettings buckets should be empty.
161 histograms.ExpectTotalCount("PrintPreview.PrintSettings",
162 base::size(kPopulatedPrintSettingsBuckets));
163
164 const UserActionBuckets user_action = GetUserActionForPrinterType(type);
165 histograms.ExpectBucketCount("PrintPreview.UserAction", user_action, 1);
166 // Only one PrintPreview.UserAction bucket should have been populated.
167 histograms.ExpectTotalCount("PrintPreview.UserAction", 1);
168
169 histograms.ExpectTotalCount("PrintPreview.PrintDocumentSize.HTML", 1);
170 histograms.ExpectTotalCount("PrintPreview.PrintDocumentSize.PDF", 0);
171 histograms.ExpectBucketCount("PrintPreview.PrintDocumentType",
172 PrintDocumentTypeBuckets::kHtmlDocument, 1);
173 histograms.ExpectBucketCount("PrintPreview.PrintDocumentType",
174 PrintDocumentTypeBuckets::kPdfDocument, 0);
175 }
176
177 class TestPrinterHandler : public PrinterHandler {
178 public:
TestPrinterHandler(const std::vector<PrinterInfo> & printers)179 explicit TestPrinterHandler(const std::vector<PrinterInfo>& printers) {
180 SetPrinters(printers);
181 }
182
~TestPrinterHandler()183 ~TestPrinterHandler() override {}
184
Reset()185 void Reset() override {}
186
GetDefaultPrinter(DefaultPrinterCallback cb)187 void GetDefaultPrinter(DefaultPrinterCallback cb) override {
188 std::move(cb).Run(default_printer_);
189 }
190
StartGetPrinters(AddedPrintersCallback added_printers_callback,GetPrintersDoneCallback done_callback)191 void StartGetPrinters(AddedPrintersCallback added_printers_callback,
192 GetPrintersDoneCallback done_callback) override {
193 if (!printers_.empty())
194 added_printers_callback.Run(printers_);
195 std::move(done_callback).Run();
196 }
197
StartGetCapability(const std::string & destination_id,GetCapabilityCallback callback)198 void StartGetCapability(const std::string& destination_id,
199 GetCapabilityCallback callback) override {
200 std::move(callback).Run(printer_capabilities_[destination_id]->Clone());
201 }
202
StartGrantPrinterAccess(const std::string & printer_id,GetPrinterInfoCallback callback)203 void StartGrantPrinterAccess(const std::string& printer_id,
204 GetPrinterInfoCallback callback) override {}
205
StartPrint(const base::string16 & job_title,base::Value settings,scoped_refptr<base::RefCountedMemory> print_data,PrintCallback callback)206 void StartPrint(const base::string16& job_title,
207 base::Value settings,
208 scoped_refptr<base::RefCountedMemory> print_data,
209 PrintCallback callback) override {
210 std::move(callback).Run(base::Value());
211 }
212
SetPrinters(const std::vector<PrinterInfo> & printers)213 void SetPrinters(const std::vector<PrinterInfo>& printers) {
214 base::Value::ListStorage printer_list;
215 for (const auto& printer : printers) {
216 if (printer.is_default)
217 default_printer_ = printer.id;
218 printer_list.push_back(printer.basic_info.Clone());
219 printer_capabilities_[printer.id] = base::DictionaryValue::From(
220 std::make_unique<base::Value>(printer.capabilities.Clone()));
221 }
222 printers_ = base::ListValue(printer_list);
223 }
224
225 private:
226 std::string default_printer_;
227 base::ListValue printers_;
228 std::map<std::string, std::unique_ptr<base::DictionaryValue>>
229 printer_capabilities_;
230
231 DISALLOW_COPY_AND_ASSIGN(TestPrinterHandler);
232 };
233
234 class FakePrintPreviewUI : public PrintPreviewUI {
235 public:
FakePrintPreviewUI(content::WebUI * web_ui,std::unique_ptr<PrintPreviewHandler> handler)236 FakePrintPreviewUI(content::WebUI* web_ui,
237 std::unique_ptr<PrintPreviewHandler> handler)
238 : PrintPreviewUI(web_ui, std::move(handler)) {}
239
~FakePrintPreviewUI()240 ~FakePrintPreviewUI() override {}
241
GetPrintPreviewDataForIndex(int index,scoped_refptr<base::RefCountedMemory> * data) const242 void GetPrintPreviewDataForIndex(
243 int index,
244 scoped_refptr<base::RefCountedMemory>* data) const override {
245 *data = base::MakeRefCounted<base::RefCountedStaticMemory>(
246 reinterpret_cast<const unsigned char*>(kTestData),
247 sizeof(kTestData) - 1);
248 }
249
OnPrintPreviewRequest(int request_id)250 void OnPrintPreviewRequest(int request_id) override {}
OnCancelPendingPreviewRequest()251 void OnCancelPendingPreviewRequest() override {}
OnHidePreviewDialog()252 void OnHidePreviewDialog() override {}
OnClosePrintPreviewDialog()253 void OnClosePrintPreviewDialog() override {}
254
255 private:
256 DISALLOW_COPY_AND_ASSIGN(FakePrintPreviewUI);
257 };
258
259 class TestPrintPreviewPrintRenderFrame : public FakePrintRenderFrame {
260 public:
TestPrintPreviewPrintRenderFrame(blink::AssociatedInterfaceProvider * provider)261 explicit TestPrintPreviewPrintRenderFrame(
262 blink::AssociatedInterfaceProvider* provider)
263 : FakePrintRenderFrame(provider) {}
264
265 ~TestPrintPreviewPrintRenderFrame() final = default;
266
GetSettings()267 const base::Value& GetSettings() { return settings_; }
268
SetCompletionClosure(base::OnceClosure closure)269 void SetCompletionClosure(base::OnceClosure closure) {
270 closure_ = std::move(closure);
271 }
272
273 private:
274 // FakePrintRenderFrame:
PrintPreview(base::Value settings)275 void PrintPreview(base::Value settings) final {
276 settings_ = std::move(settings);
277 std::move(closure_).Run();
278 }
279
280 base::OnceClosure closure_;
281 base::Value settings_;
282 };
283
284 class TestPrintPreviewHandler : public PrintPreviewHandler {
285 public:
TestPrintPreviewHandler(std::unique_ptr<PrinterHandler> printer_handler,content::WebContents * initiator)286 TestPrintPreviewHandler(std::unique_ptr<PrinterHandler> printer_handler,
287 content::WebContents* initiator)
288 : bad_messages_(0),
289 test_printer_handler_(std::move(printer_handler)),
290 initiator_(initiator) {}
291
GetPrinterHandler(PrinterType printer_type)292 PrinterHandler* GetPrinterHandler(PrinterType printer_type) override {
293 called_for_type_.insert(printer_type);
294 return test_printer_handler_.get();
295 }
296
IsCloudPrintEnabled()297 bool IsCloudPrintEnabled() override { return true; }
298
RegisterForGaiaCookieChanges()299 void RegisterForGaiaCookieChanges() override {}
UnregisterForGaiaCookieChanges()300 void UnregisterForGaiaCookieChanges() override {}
301
BadMessageReceived()302 void BadMessageReceived() override { bad_messages_++; }
303
GetInitiator() const304 content::WebContents* GetInitiator() const override { return initiator_; }
305
CalledOnlyForType(PrinterType printer_type)306 bool CalledOnlyForType(PrinterType printer_type) {
307 return (called_for_type_.size() == 1 &&
308 *called_for_type_.begin() == printer_type);
309 }
310
NotCalled()311 bool NotCalled() { return called_for_type_.empty(); }
312
reset_calls()313 void reset_calls() { called_for_type_.clear(); }
314
bad_messages()315 int bad_messages() { return bad_messages_; }
316
317 private:
318 int bad_messages_;
319 base::flat_set<PrinterType> called_for_type_;
320 std::unique_ptr<PrinterHandler> test_printer_handler_;
321 content::WebContents* const initiator_;
322
323 DISALLOW_COPY_AND_ASSIGN(TestPrintPreviewHandler);
324 };
325
326 } // namespace
327
328 class PrintPreviewHandlerTest : public testing::Test {
329 public:
330 PrintPreviewHandlerTest() = default;
331 ~PrintPreviewHandlerTest() override = default;
332
SetUp()333 void SetUp() override {
334 TestingProfile::Builder builder;
335 profile_ = builder.Build();
336 initiator_web_contents_ = content::WebContents::Create(
337 content::WebContents::CreateParams(profile_.get()));
338 content::WebContents* initiator = initiator_web_contents_.get();
339 preview_web_contents_ = content::WebContents::Create(
340 content::WebContents::CreateParams(profile_.get()));
341 PrintViewManager::CreateForWebContents(initiator);
342 PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(
343 initiator->GetMainFrame(), false);
344 web_ui_ = std::make_unique<content::TestWebUI>();
345 web_ui_->set_web_contents(preview_web_contents_.get());
346
347 printers_.push_back(GetSimplePrinterInfo(kDummyPrinterName, true));
348 auto printer_handler = CreatePrinterHandler(printers_);
349 printer_handler_ = printer_handler.get();
350
351 auto preview_handler = std::make_unique<TestPrintPreviewHandler>(
352 std::move(printer_handler), initiator);
353 preview_handler->set_web_ui(web_ui());
354 handler_ = preview_handler.get();
355
356 auto preview_ui = std::make_unique<FakePrintPreviewUI>(
357 web_ui(), std::move(preview_handler));
358 preview_ui->SetInitiatorTitle(base::ASCIIToUTF16(kDummyInitiatorName));
359 web_ui()->SetController(std::move(preview_ui));
360 }
361
TearDown()362 void TearDown() override {
363 PrintViewManager::FromWebContents(initiator_web_contents_.get())
364 ->PrintPreviewDone();
365 }
366
CreatePrinterHandler(const std::vector<PrinterInfo> & printers)367 virtual std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
368 const std::vector<PrinterInfo>& printers) {
369 return std::make_unique<TestPrinterHandler>(printers);
370 }
371
Initialize()372 void Initialize() { InitializeWithLocale("en"); }
373
InitializeWithLocale(const std::string & locale)374 void InitializeWithLocale(const std::string& locale) {
375 // Sending this message will enable javascript, so it must always be called
376 // before any other messages are sent.
377 base::Value args(base::Value::Type::LIST);
378 args.Append("test-callback-id-0");
379 std::unique_ptr<base::ListValue> list_args =
380 base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
381
382 auto* browser_process = TestingBrowserProcess::GetGlobal();
383 std::string original_locale = browser_process->GetApplicationLocale();
384 {
385 // Set locale since the delimiters checked in VerifyInitialSettings()
386 // depend on it. This has to be done in several ways to make various
387 // locale code sync up correctly.
388 browser_process->SetApplicationLocale(locale);
389 base::test::ScopedRestoreICUDefaultLocale scoped_locale(locale);
390 base::ResetFormattersForTesting();
391 handler()->HandleGetInitialSettings(list_args.get());
392 }
393 // Reset again now that |scoped_locale| has been destroyed.
394 browser_process->SetApplicationLocale(original_locale);
395 base::ResetFormattersForTesting();
396
397 // In response to get initial settings, the initial settings are sent back.
398 ASSERT_EQ(1u, web_ui()->call_data().size());
399 }
400
AssertWebUIEventFired(const content::TestWebUI::CallData & data,const std::string & event_id)401 void AssertWebUIEventFired(const content::TestWebUI::CallData& data,
402 const std::string& event_id) {
403 EXPECT_EQ("cr.webUIListenerCallback", data.function_name());
404 std::string event_fired;
405 ASSERT_TRUE(data.arg1()->GetAsString(&event_fired));
406 EXPECT_EQ(event_id, event_fired);
407 }
408
CheckWebUIResponse(const content::TestWebUI::CallData & data,const std::string & callback_id_in,bool expect_success)409 void CheckWebUIResponse(const content::TestWebUI::CallData& data,
410 const std::string& callback_id_in,
411 bool expect_success) {
412 EXPECT_EQ("cr.webUIResponse", data.function_name());
413 std::string callback_id;
414 ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
415 EXPECT_EQ(callback_id_in, callback_id);
416 bool success = false;
417 ASSERT_TRUE(data.arg2()->GetAsBoolean(&success));
418 EXPECT_EQ(expect_success, success);
419 }
420
ValidateInitialSettings(const content::TestWebUI::CallData & data,const std::string & default_printer_name,const std::string & initiator_title)421 void ValidateInitialSettings(const content::TestWebUI::CallData& data,
422 const std::string& default_printer_name,
423 const std::string& initiator_title) {
424 ValidateInitialSettingsForLocale(data, default_printer_name,
425 initiator_title, "en", ",", ".");
426 }
427
428 // Validates the initial settings structure in the response matches the
429 // print_preview.NativeInitialSettings type in
430 // chrome/browser/resources/print_preview/native_layer.js. Checks that:
431 // - |default_printer_name| is the printer name returned
432 // - |initiator_title| is the initiator title returned
433 // Also validates that delimiters are correct for |locale| (set in
434 // InitializeWithLocale()) with the associated |thousands_delimiter| and
435 // |decimal_delimiter|.
436 // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsForLocale(const content::TestWebUI::CallData & data,const std::string & default_printer_name,const std::string & initiator_title,const std::string & locale,const std::string & thousands_delimiter,const std::string & decimal_delimiter)437 void ValidateInitialSettingsForLocale(
438 const content::TestWebUI::CallData& data,
439 const std::string& default_printer_name,
440 const std::string& initiator_title,
441 const std::string& locale,
442 const std::string& thousands_delimiter,
443 const std::string& decimal_delimiter) {
444 CheckWebUIResponse(data, "test-callback-id-0", true);
445 const base::Value* settings = data.arg3();
446 ASSERT_TRUE(settings->FindKeyOfType("isInKioskAutoPrintMode",
447 base::Value::Type::BOOLEAN));
448 ASSERT_TRUE(settings->FindKeyOfType("isInAppKioskMode",
449 base::Value::Type::BOOLEAN));
450
451 const std::string* actual_locale = settings->FindStringKey("uiLocale");
452 ASSERT_TRUE(actual_locale);
453 EXPECT_EQ(locale, *actual_locale);
454 const std::string* actual_thousands_delimiter =
455 settings->FindStringKey("thousandsDelimiter");
456 ASSERT_TRUE(actual_thousands_delimiter);
457 EXPECT_EQ(thousands_delimiter, *actual_thousands_delimiter);
458 const std::string* actual_decimal_delimiter =
459 settings->FindStringKey("decimalDelimiter");
460 ASSERT_TRUE(actual_decimal_delimiter);
461 EXPECT_EQ(decimal_delimiter, *actual_decimal_delimiter);
462
463 ASSERT_TRUE(
464 settings->FindKeyOfType("unitType", base::Value::Type::INTEGER));
465 ASSERT_TRUE(settings->FindKeyOfType("previewModifiable",
466 base::Value::Type::BOOLEAN));
467 const base::Value* title =
468 settings->FindKeyOfType("documentTitle", base::Value::Type::STRING);
469 ASSERT_TRUE(title);
470 EXPECT_EQ(initiator_title, title->GetString());
471 ASSERT_TRUE(settings->FindKeyOfType("documentHasSelection",
472 base::Value::Type::BOOLEAN));
473 ASSERT_TRUE(settings->FindKeyOfType("shouldPrintSelectionOnly",
474 base::Value::Type::BOOLEAN));
475 const base::Value* printer =
476 settings->FindKeyOfType("printerName", base::Value::Type::STRING);
477 ASSERT_TRUE(printer);
478 EXPECT_EQ(default_printer_name, printer->GetString());
479
480 ASSERT_TRUE(settings->FindKeyOfType("pdfPrinterDisabled",
481 base::Value::Type::BOOLEAN));
482 ASSERT_TRUE(settings->FindKeyOfType("destinationsManaged",
483 base::Value::Type::BOOLEAN));
484 ASSERT_TRUE(
485 settings->FindKeyOfType("cloudPrintURL", base::Value::Type::STRING));
486 ASSERT_TRUE(
487 settings->FindKeyOfType("userAccounts", base::Value::Type::LIST));
488 ASSERT_TRUE(
489 settings->FindKeyOfType("syncAvailable", base::Value::Type::BOOLEAN));
490 }
491
492 // Returns |policy_name| entry from initial settings policies.
GetInitialSettingsPolicy(const base::Value & settings,const std::string & policy_name)493 const base::Value* GetInitialSettingsPolicy(const base::Value& settings,
494 const std::string& policy_name) {
495 const base::Value* policies =
496 settings.FindKeyOfType("policies", base::Value::Type::DICTIONARY);
497 if (!policies)
498 return nullptr;
499 return policies->FindKeyOfType(policy_name, base::Value::Type::DICTIONARY);
500 }
501
502 // Validates the initial settings value policies structure in the response
503 // matches the print_preview.Policies type in
504 // chrome/browser/resources/print_preview/native_layer.js.
505 // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsValuePolicy(const content::TestWebUI::CallData & data,const std::string & policy_name,base::Optional<base::Value> expected_policy_value)506 void ValidateInitialSettingsValuePolicy(
507 const content::TestWebUI::CallData& data,
508 const std::string& policy_name,
509 base::Optional<base::Value> expected_policy_value) {
510 CheckWebUIResponse(data, "test-callback-id-0", true);
511 const base::Value* settings = data.arg3();
512
513 const base::Value* policy =
514 GetInitialSettingsPolicy(*settings, policy_name);
515 const base::Value* policy_value =
516 policy ? policy->FindKey("value") : nullptr;
517
518 ASSERT_EQ(expected_policy_value.has_value(), !!policy_value);
519 if (expected_policy_value.has_value())
520 EXPECT_EQ(expected_policy_value.value(), *policy_value);
521 }
522
523 // Validates the initial settings allowed/default mode policies structure in
524 // the response matches the print_preview.Policies type in
525 // chrome/browser/resources/print_preview/native_layer.js.
526 // Assumes "test-callback-id-0" was used as the callback id.
ValidateInitialSettingsAllowedDefaultModePolicy(const content::TestWebUI::CallData & data,const std::string & policy_name,base::Optional<base::Value> expected_allowed_mode,base::Optional<base::Value> expected_default_mode)527 void ValidateInitialSettingsAllowedDefaultModePolicy(
528 const content::TestWebUI::CallData& data,
529 const std::string& policy_name,
530 base::Optional<base::Value> expected_allowed_mode,
531 base::Optional<base::Value> expected_default_mode) {
532 CheckWebUIResponse(data, "test-callback-id-0", true);
533 const base::Value* settings = data.arg3();
534
535 const base::Value* policy =
536 GetInitialSettingsPolicy(*settings, policy_name);
537 const base::Value* allowed_mode =
538 policy ? policy->FindKey("allowedMode") : nullptr;
539 const base::Value* default_mode =
540 policy ? policy->FindKey("defaultMode") : nullptr;
541
542 ASSERT_EQ(expected_allowed_mode.has_value(), !!allowed_mode);
543 if (expected_allowed_mode.has_value())
544 EXPECT_EQ(expected_allowed_mode.value(), *allowed_mode);
545
546 ASSERT_EQ(expected_default_mode.has_value(), !!default_mode);
547 if (expected_default_mode.has_value())
548 EXPECT_EQ(expected_default_mode.value(), *default_mode);
549 }
550
551 // Simulates a 'getPrinters' Web UI message by constructing the arguments and
552 // making the call to the handler.
SendGetPrinters(PrinterType type,const std::string & callback_id_in)553 void SendGetPrinters(PrinterType type, const std::string& callback_id_in) {
554 base::Value args(base::Value::Type::LIST);
555 args.Append(callback_id_in);
556 args.Append(static_cast<int>(type));
557 handler()->HandleGetPrinters(&base::Value::AsListValue(args));
558 }
559
560 // Validates that the printers-added Web UI event has been fired for
561 // |expected-type| with 1 printer. This should be the second most recent call,
562 // as the resolution of the getPrinters() promise will be the most recent.
ValidatePrinterTypeAdded(PrinterType expected_type)563 void ValidatePrinterTypeAdded(PrinterType expected_type) {
564 const size_t call_data_size = web_ui()->call_data().size();
565 ASSERT_GE(call_data_size, 2u);
566 const content::TestWebUI::CallData& add_data =
567 *web_ui()->call_data()[call_data_size - 2];
568 AssertWebUIEventFired(add_data, "printers-added");
569 const auto type = static_cast<PrinterType>(add_data.arg2()->GetInt());
570 EXPECT_EQ(expected_type, type);
571 ASSERT_TRUE(add_data.arg3());
572 base::Value::ConstListView printer_list = add_data.arg3()->GetList();
573 ASSERT_EQ(printer_list.size(), 1u);
574 EXPECT_TRUE(printer_list[0].FindKeyOfType("printer_name",
575 base::Value::Type::STRING));
576 }
577
578 // Simulates a 'getPrinterCapabilities' Web UI message by constructing the
579 // arguments and making the call to the handler.
SendGetPrinterCapabilities(PrinterType type,const std::string & callback_id_in,const std::string & printer_name)580 void SendGetPrinterCapabilities(PrinterType type,
581 const std::string& callback_id_in,
582 const std::string& printer_name) {
583 base::Value args(base::Value::Type::LIST);
584 args.Append(callback_id_in);
585 args.Append(printer_name);
586 args.Append(static_cast<int>(type));
587 handler()->HandleGetPrinterCapabilities(&base::Value::AsListValue(args));
588 }
589
590 // Validates that a printer capabilities promise was resolved/rejected.
ValidatePrinterCapabilities(const std::string & callback_id_in,bool expect_resolved)591 void ValidatePrinterCapabilities(const std::string& callback_id_in,
592 bool expect_resolved) {
593 const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
594 CheckWebUIResponse(data, callback_id_in, expect_resolved);
595 if (expect_resolved) {
596 const base::Value* settings = data.arg3();
597 ASSERT_TRUE(settings);
598 EXPECT_TRUE(settings->FindKeyOfType(kSettingCapabilities,
599 base::Value::Type::DICTIONARY));
600 }
601 }
602
603 blink::AssociatedInterfaceProvider*
GetInitiatorAssociatedInterfaceProvider()604 GetInitiatorAssociatedInterfaceProvider() {
605 return initiator_web_contents_->GetMainFrame()
606 ->GetRemoteAssociatedInterfaces();
607 }
608
profile()609 const Profile* profile() { return profile_.get(); }
prefs()610 sync_preferences::TestingPrefServiceSyncable* prefs() {
611 return profile_->GetTestingPrefService();
612 }
web_ui()613 content::TestWebUI* web_ui() { return web_ui_.get(); }
handler()614 TestPrintPreviewHandler* handler() { return handler_; }
printer_handler()615 TestPrinterHandler* printer_handler() { return printer_handler_; }
printers()616 std::vector<PrinterInfo>& printers() { return printers_; }
617
618 private:
619 content::BrowserTaskEnvironment task_environment_;
620 std::unique_ptr<TestingProfile> profile_;
621 std::unique_ptr<content::TestWebUI> web_ui_;
622 content::RenderViewHostTestEnabler rvh_test_enabler_;
623 std::unique_ptr<content::WebContents> preview_web_contents_;
624 std::unique_ptr<content::WebContents> initiator_web_contents_;
625 std::vector<PrinterInfo> printers_;
626 TestPrinterHandler* printer_handler_;
627 TestPrintPreviewHandler* handler_;
628
629 DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandlerTest);
630 };
631
TEST_F(PrintPreviewHandlerTest,InitialSettingsSimple)632 TEST_F(PrintPreviewHandlerTest, InitialSettingsSimple) {
633 Initialize();
634
635 // Verify initial settings were sent.
636 ValidateInitialSettings(*web_ui()->call_data().back(), kDummyPrinterName,
637 kDummyInitiatorName);
638 }
639
TEST_F(PrintPreviewHandlerTest,InitialSettingsHiLocale)640 TEST_F(PrintPreviewHandlerTest, InitialSettingsHiLocale) {
641 InitializeWithLocale("hi");
642
643 // Verify initial settings were sent for Hindi.
644 ValidateInitialSettingsForLocale(*web_ui()->call_data().back(),
645 kDummyPrinterName, kDummyInitiatorName, "hi",
646 ",", ".");
647 }
648
TEST_F(PrintPreviewHandlerTest,InitialSettingsRuLocale)649 TEST_F(PrintPreviewHandlerTest, InitialSettingsRuLocale) {
650 InitializeWithLocale("ru");
651
652 // Verify initial settings were sent for Russian.
653 ValidateInitialSettingsForLocale(*web_ui()->call_data().back(),
654 kDummyPrinterName, kDummyInitiatorName, "ru",
655 "\xC2\xA0", ",");
656 }
657
TEST_F(PrintPreviewHandlerTest,InitialSettingsNoPolicies)658 TEST_F(PrintPreviewHandlerTest, InitialSettingsNoPolicies) {
659 Initialize();
660 ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
661 "headerFooter", base::nullopt,
662 base::nullopt);
663 ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
664 "cssBackground",
665 base::nullopt, base::nullopt);
666 ValidateInitialSettingsAllowedDefaultModePolicy(
667 *web_ui()->call_data().back(), "mediaSize", base::nullopt, base::nullopt);
668 ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
669 base::nullopt);
670 }
671
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictHeaderFooterEnabled)672 TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterEnabled) {
673 // Set a pref with allowed value.
674 prefs()->SetManagedPref(prefs::kPrintHeaderFooter,
675 std::make_unique<base::Value>(true));
676 Initialize();
677 ValidateInitialSettingsAllowedDefaultModePolicy(
678 *web_ui()->call_data().back(), "headerFooter", base::Value(true),
679 base::nullopt);
680 }
681
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictHeaderFooterDisabled)682 TEST_F(PrintPreviewHandlerTest, InitialSettingsRestrictHeaderFooterDisabled) {
683 // Set a pref with allowed value.
684 prefs()->SetManagedPref(prefs::kPrintHeaderFooter,
685 std::make_unique<base::Value>(false));
686 Initialize();
687 ValidateInitialSettingsAllowedDefaultModePolicy(
688 *web_ui()->call_data().back(), "headerFooter", base::Value(false),
689 base::nullopt);
690 }
691
TEST_F(PrintPreviewHandlerTest,InitialSettingsEnableHeaderFooter)692 TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableHeaderFooter) {
693 // Set a pref that should take priority over StickySettings.
694 prefs()->SetBoolean(prefs::kPrintHeaderFooter, true);
695 Initialize();
696 ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
697 "headerFooter", base::nullopt,
698 base::Value(true));
699 }
700
TEST_F(PrintPreviewHandlerTest,InitialSettingsDisableHeaderFooter)701 TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableHeaderFooter) {
702 // Set a pref that should take priority over StickySettings.
703 prefs()->SetBoolean(prefs::kPrintHeaderFooter, false);
704 Initialize();
705 ValidateInitialSettingsAllowedDefaultModePolicy(*web_ui()->call_data().back(),
706 "headerFooter", base::nullopt,
707 base::Value(false));
708 }
709
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictBackgroundGraphicsEnabled)710 TEST_F(PrintPreviewHandlerTest,
711 InitialSettingsRestrictBackgroundGraphicsEnabled) {
712 // Set a pref with allowed value.
713 prefs()->SetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes, 1);
714 Initialize();
715 ValidateInitialSettingsAllowedDefaultModePolicy(
716 *web_ui()->call_data().back(), "cssBackground", base::Value(1),
717 base::nullopt);
718 }
719
TEST_F(PrintPreviewHandlerTest,InitialSettingsRestrictBackgroundGraphicsDisabled)720 TEST_F(PrintPreviewHandlerTest,
721 InitialSettingsRestrictBackgroundGraphicsDisabled) {
722 // Set a pref with allowed value.
723 prefs()->SetInteger(prefs::kPrintingAllowedBackgroundGraphicsModes, 2);
724 Initialize();
725 ValidateInitialSettingsAllowedDefaultModePolicy(
726 *web_ui()->call_data().back(), "cssBackground", base::Value(2),
727 base::nullopt);
728 }
729
TEST_F(PrintPreviewHandlerTest,InitialSettingsEnableBackgroundGraphics)730 TEST_F(PrintPreviewHandlerTest, InitialSettingsEnableBackgroundGraphics) {
731 // Set a pref that should take priority over StickySettings.
732 prefs()->SetInteger(prefs::kPrintingBackgroundGraphicsDefault, 1);
733 Initialize();
734 ValidateInitialSettingsAllowedDefaultModePolicy(
735 *web_ui()->call_data().back(), "cssBackground", base::nullopt,
736 base::Value(1));
737 }
738
TEST_F(PrintPreviewHandlerTest,InitialSettingsDisableBackgroundGraphics)739 TEST_F(PrintPreviewHandlerTest, InitialSettingsDisableBackgroundGraphics) {
740 // Set a pref that should take priority over StickySettings.
741 prefs()->SetInteger(prefs::kPrintingBackgroundGraphicsDefault, 2);
742 Initialize();
743 ValidateInitialSettingsAllowedDefaultModePolicy(
744 *web_ui()->call_data().back(), "cssBackground", base::nullopt,
745 base::Value(2));
746 }
747
TEST_F(PrintPreviewHandlerTest,InitialSettingsDefaultPaperSizeName)748 TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeName) {
749 const char kPrintingPaperSizeDefaultName[] = R"(
750 {
751 "name": "iso_a5_148x210mm"
752 })";
753 const char kExpectedInitialSettingsPolicy[] = R"(
754 {
755 "width": 148000,
756 "height": 210000
757 })";
758
759 base::Optional<base::Value> default_paper_size =
760 base::JSONReader::Read(kPrintingPaperSizeDefaultName);
761 ASSERT_TRUE(default_paper_size.has_value());
762 // Set a pref that should take priority over StickySettings.
763 prefs()->Set(prefs::kPrintingPaperSizeDefault, default_paper_size.value());
764 Initialize();
765
766 base::Optional<base::Value> expected_initial_settings_policy =
767 base::JSONReader::Read(kExpectedInitialSettingsPolicy);
768 ASSERT_TRUE(expected_initial_settings_policy.has_value());
769
770 ValidateInitialSettingsAllowedDefaultModePolicy(
771 *web_ui()->call_data().back(), "mediaSize", base::nullopt,
772 std::move(expected_initial_settings_policy));
773 }
774
TEST_F(PrintPreviewHandlerTest,InitialSettingsDefaultPaperSizeCustomSize)775 TEST_F(PrintPreviewHandlerTest, InitialSettingsDefaultPaperSizeCustomSize) {
776 const char kPrintingPaperSizeDefaultCustomSize[] = R"(
777 {
778 "name": "custom",
779 "custom_size": {
780 "width": 148000,
781 "height": 210000
782 }
783 })";
784 const char kExpectedInitialSettingsPolicy[] = R"(
785 {
786 "width": 148000,
787 "height": 210000
788 })";
789
790 base::Optional<base::Value> default_paper_size =
791 base::JSONReader::Read(kPrintingPaperSizeDefaultCustomSize);
792 ASSERT_TRUE(default_paper_size.has_value());
793 // Set a pref that should take priority over StickySettings.
794 prefs()->Set(prefs::kPrintingPaperSizeDefault, default_paper_size.value());
795 Initialize();
796
797 base::Optional<base::Value> expected_initial_settings_policy =
798 base::JSONReader::Read(kExpectedInitialSettingsPolicy);
799 ASSERT_TRUE(expected_initial_settings_policy.has_value());
800
801 ValidateInitialSettingsAllowedDefaultModePolicy(
802 *web_ui()->call_data().back(), "mediaSize", base::nullopt,
803 std::move(expected_initial_settings_policy));
804 }
805
806 #if defined(OS_CHROMEOS)
TEST_F(PrintPreviewHandlerTest,InitialSettingsMaxSheetsAllowedPolicy)807 TEST_F(PrintPreviewHandlerTest, InitialSettingsMaxSheetsAllowedPolicy) {
808 prefs()->SetInteger(prefs::kPrintingMaxSheetsAllowed, 2);
809 Initialize();
810 ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
811 base::Value(2));
812 }
813 #endif // defined(OS_CHROMEOS)
814
TEST_F(PrintPreviewHandlerTest,GetPrinters)815 TEST_F(PrintPreviewHandlerTest, GetPrinters) {
816 Initialize();
817
818 // Check all three printer types that implement
819 for (size_t i = 0; i < base::size(kFetchableTypes); i++) {
820 PrinterType type = kFetchableTypes[i];
821 std::string callback_id_in =
822 "test-callback-id-" + base::NumberToString(i + 1);
823 handler()->reset_calls();
824 SendGetPrinters(type, callback_id_in);
825
826 EXPECT_TRUE(handler()->CalledOnlyForType(type));
827
828 // Start with 1 call from initial settings, then add 2 more for each loop
829 // iteration (one for printers-added, and one for the response).
830 ASSERT_EQ(1u + 2 * (i + 1), web_ui()->call_data().size());
831
832 ValidatePrinterTypeAdded(type);
833
834 // Verify getPrinters promise was resolved successfully.
835 const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
836 CheckWebUIResponse(data, callback_id_in, true);
837 }
838 }
839
840 // Validates the 'printing.printer_type_deny_list' pref by placing the extension
841 // and privet printer types on a deny list. A 'getPrinters' Web UI message is
842 // then called for all three fetchable printer types; only local printers should
843 // be successfully fetched.
TEST_F(PrintPreviewHandlerTest,GetNoDenyListPrinters)844 TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinters) {
845 base::Value::ListStorage deny_list;
846 deny_list.push_back(base::Value("extension"));
847 deny_list.push_back(base::Value("privet"));
848 prefs()->Set(prefs::kPrinterTypeDenyList, base::Value(std::move(deny_list)));
849 Initialize();
850
851 size_t expected_callbacks = 1;
852 for (size_t i = 0; i < base::size(kFetchableTypes); i++) {
853 PrinterType type = kFetchableTypes[i];
854 std::string callback_id_in =
855 "test-callback-id-" + base::NumberToString(i + 1);
856 handler()->reset_calls();
857 SendGetPrinters(type, callback_id_in);
858
859 // Start with 1 call from initial settings, then add 2 more for each printer
860 // type that isn't on the deny list (one for printers-added, and one for the
861 // response), and only 1 more for each type on the deny list (just for
862 // response).
863 const bool is_allowed_type = type == PrinterType::kLocal;
864 EXPECT_EQ(is_allowed_type, handler()->CalledOnlyForType(type));
865 expected_callbacks += is_allowed_type ? 2 : 1;
866 ASSERT_EQ(expected_callbacks, web_ui()->call_data().size());
867
868 if (is_allowed_type) {
869 ValidatePrinterTypeAdded(type);
870 }
871
872 // Verify getPrinters promise was resolved successfully.
873 const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
874 CheckWebUIResponse(data, callback_id_in, true);
875 }
876 }
877
TEST_F(PrintPreviewHandlerTest,GetPrinterCapabilities)878 TEST_F(PrintPreviewHandlerTest, GetPrinterCapabilities) {
879 // Add an empty printer to the handler.
880 printers().push_back(GetEmptyPrinterInfo());
881 printer_handler()->SetPrinters(printers());
882
883 // Initial settings first to enable javascript.
884 Initialize();
885
886 // Check all four printer types that implement
887 // PrinterHandler::StartGetCapability().
888 for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
889 PrinterType type = kAllSupportedTypes[i];
890 std::string callback_id_in =
891 "test-callback-id-" + base::NumberToString(i + 1);
892 handler()->reset_calls();
893 SendGetPrinterCapabilities(type, callback_id_in, kDummyPrinterName);
894 EXPECT_TRUE(handler()->CalledOnlyForType(type));
895
896 // Start with 1 call from initial settings, then add 1 more for each loop
897 // iteration.
898 ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
899
900 ValidatePrinterCapabilities(callback_id_in, /*expect_resolved=*/true);
901 }
902
903 // Run through the loop again, this time with a printer that has no
904 // capabilities.
905 for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
906 PrinterType type = kAllSupportedTypes[i];
907 std::string callback_id_in =
908 "test-callback-id-" +
909 base::NumberToString(i + base::size(kAllSupportedTypes) + 1);
910 handler()->reset_calls();
911 SendGetPrinterCapabilities(type, callback_id_in, kEmptyPrinterName);
912 EXPECT_TRUE(handler()->CalledOnlyForType(type));
913
914 // Start with 1 call from initial settings plus
915 // base::size(kAllSupportedTypes) from first loop, then add 1 more for each
916 // loop iteration.
917 ASSERT_EQ(1u + base::size(kAllSupportedTypes) + (i + 1),
918 web_ui()->call_data().size());
919
920 ValidatePrinterCapabilities(callback_id_in, /*expect_resolved=*/false);
921 }
922 }
923
924 // Validates the 'printing.printer_type_deny_list' pref by placing the local and
925 // PDF printer types on the deny list. A 'getPrinterCapabilities' Web UI message
926 // is then called for all supported printer types; only privet and extension
927 // printer capabilties should be successfully fetched.
TEST_F(PrintPreviewHandlerTest,GetNoDenyListPrinterCapabilities)928 TEST_F(PrintPreviewHandlerTest, GetNoDenyListPrinterCapabilities) {
929 base::Value::ListStorage deny_list;
930 deny_list.push_back(base::Value("local"));
931 deny_list.push_back(base::Value("pdf"));
932 prefs()->Set(prefs::kPrinterTypeDenyList, base::Value(std::move(deny_list)));
933 Initialize();
934
935 // Check all four printer types that implement
936 // PrinterHandler::StartGetCapability().
937 for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
938 PrinterType type = kAllSupportedTypes[i];
939 std::string callback_id_in =
940 "test-callback-id-" + base::NumberToString(i + 1);
941 handler()->reset_calls();
942 SendGetPrinterCapabilities(type, callback_id_in, kDummyPrinterName);
943
944 const bool is_allowed_type =
945 type == PrinterType::kPrivet || type == PrinterType::kExtension;
946 EXPECT_EQ(is_allowed_type, handler()->CalledOnlyForType(type));
947
948 // Start with 1 call from initial settings, then add 1 more for each loop
949 // iteration.
950 ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
951
952 ValidatePrinterCapabilities(callback_id_in, is_allowed_type);
953 }
954 }
955
TEST_F(PrintPreviewHandlerTest,Print)956 TEST_F(PrintPreviewHandlerTest, Print) {
957 Initialize();
958
959 // All printer types can print.
960 for (size_t i = 0; i < base::size(kAllTypes); i++) {
961 base::HistogramTester histograms;
962 handler()->reset_calls();
963
964 // Send print preview request.
965 base::Value preview_ticket = GetPrintPreviewTicket();
966 preview_ticket.SetIntKey(kPreviewRequestID, i);
967 std::string preview_callback_id =
968 "test-callback-id-" + base::NumberToString(2 * i + 1);
969 std::unique_ptr<base::ListValue> preview_list_args =
970 ConstructPreviewArgs(preview_callback_id, preview_ticket);
971 handler()->HandleGetPreview(preview_list_args.get());
972
973 // Send printing request.
974 PrinterType type = kAllTypes[i];
975 base::Value print_args(base::Value::Type::LIST);
976 std::string print_callback_id =
977 "test-callback-id-" + base::NumberToString(2 * (i + 1));
978 print_args.Append(print_callback_id);
979 base::Value print_ticket = GetPrintTicket(type);
980 std::string json;
981 base::JSONWriter::Write(print_ticket, &json);
982 print_args.Append(json);
983 std::unique_ptr<base::ListValue> print_list_args = base::ListValue::From(
984 base::Value::ToUniquePtrValue(std::move(print_args)));
985 handler()->HandlePrint(print_list_args.get());
986
987 CheckHistograms(histograms, type);
988
989 // Verify correct PrinterHandler was called or that no handler was requested
990 // for cloud printers.
991 if (type == PrinterType::kCloud) {
992 EXPECT_TRUE(handler()->NotCalled());
993 } else {
994 EXPECT_TRUE(handler()->CalledOnlyForType(type));
995 }
996
997 // Verify print promise was resolved successfully.
998 const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
999 CheckWebUIResponse(data, print_callback_id, true);
1000
1001 // For cloud print, should also get the encoded data back as a string.
1002 if (type == PrinterType::kCloud) {
1003 std::string print_data;
1004 ASSERT_TRUE(data.arg3()->GetAsString(&print_data));
1005 std::string expected_data;
1006 base::Base64Encode(kTestData, &expected_data);
1007 EXPECT_EQ(print_data, expected_data);
1008 }
1009 }
1010 }
1011
TEST_F(PrintPreviewHandlerTest,GetPreview)1012 TEST_F(PrintPreviewHandlerTest, GetPreview) {
1013 Initialize();
1014
1015 base::RunLoop run_loop;
1016 TestPrintPreviewPrintRenderFrame print_render_frame(
1017 GetInitiatorAssociatedInterfaceProvider());
1018 print_render_frame.SetCompletionClosure(run_loop.QuitClosure());
1019
1020 base::Value print_ticket = GetPrintPreviewTicket();
1021 std::unique_ptr<base::ListValue> list_args =
1022 ConstructPreviewArgs("test-callback-id-1", print_ticket);
1023 handler()->HandleGetPreview(list_args.get());
1024 run_loop.Run();
1025
1026 // Verify that the preview was requested from the renderer with the
1027 // appropriate settings.
1028 const base::Value& preview_params = print_render_frame.GetSettings();
1029 bool preview_id_found = false;
1030 for (const auto& it : preview_params.DictItems()) {
1031 if (it.first == kPreviewUIID) { // This is added by the handler.
1032 preview_id_found = true;
1033 continue;
1034 }
1035 const base::Value* value_in = print_ticket.FindKey(it.first);
1036 ASSERT_TRUE(value_in);
1037 EXPECT_EQ(*value_in, it.second);
1038 }
1039 EXPECT_TRUE(preview_id_found);
1040 }
1041
TEST_F(PrintPreviewHandlerTest,SendPreviewUpdates)1042 TEST_F(PrintPreviewHandlerTest, SendPreviewUpdates) {
1043 Initialize();
1044
1045 base::RunLoop run_loop;
1046 TestPrintPreviewPrintRenderFrame print_render_frame(
1047 GetInitiatorAssociatedInterfaceProvider());
1048 print_render_frame.SetCompletionClosure(run_loop.QuitClosure());
1049
1050 const char callback_id_in[] = "test-callback-id-1";
1051 base::Value print_ticket = GetPrintPreviewTicket();
1052 std::unique_ptr<base::ListValue> list_args =
1053 ConstructPreviewArgs(callback_id_in, print_ticket);
1054 handler()->HandleGetPreview(list_args.get());
1055 run_loop.Run();
1056 const base::Value& preview_params = print_render_frame.GetSettings();
1057
1058 // Read the preview UI ID and request ID
1059 base::Optional<int> request_value =
1060 preview_params.FindIntKey(kPreviewRequestID);
1061 ASSERT_TRUE(request_value.has_value());
1062 int preview_request_id = request_value.value();
1063
1064 base::Optional<int> ui_value = preview_params.FindIntKey(kPreviewUIID);
1065 ASSERT_TRUE(ui_value.has_value());
1066 int preview_ui_id = ui_value.value();
1067
1068 // Simulate renderer responses: PageLayoutReady, PageCountReady,
1069 // PagePreviewReady, and OnPrintPreviewReady will be called in that order.
1070 base::Value layout(base::Value::Type::DICTIONARY);
1071 layout.SetDoubleKey(kSettingMarginTop, 34.0);
1072 layout.SetDoubleKey(kSettingMarginLeft, 34.0);
1073 layout.SetDoubleKey(kSettingMarginBottom, 34.0);
1074 layout.SetDoubleKey(kSettingMarginRight, 34.0);
1075 layout.SetDoubleKey(kSettingContentWidth, 544.0);
1076 layout.SetDoubleKey(kSettingContentHeight, 700.0);
1077 layout.SetIntKey(kSettingPrintableAreaX, 17);
1078 layout.SetIntKey(kSettingPrintableAreaY, 17);
1079 layout.SetIntKey(kSettingPrintableAreaWidth, 578);
1080 layout.SetIntKey(kSettingPrintableAreaHeight, 734);
1081 handler()->SendPageLayoutReady(base::Value::AsDictionaryValue(layout),
1082 /*has_custom_page_size_style,=*/false,
1083 preview_request_id);
1084
1085 // Verify that page-layout-ready webUI event was fired.
1086 AssertWebUIEventFired(*web_ui()->call_data().back(), "page-layout-ready");
1087
1088 // 1 page document. Modifiable so send default 100 scaling.
1089 handler()->SendPageCountReady(1, 100, preview_request_id);
1090 AssertWebUIEventFired(*web_ui()->call_data().back(), "page-count-ready");
1091
1092 // Page at index 0 is ready.
1093 handler()->SendPagePreviewReady(0, preview_ui_id, preview_request_id);
1094 AssertWebUIEventFired(*web_ui()->call_data().back(), "page-preview-ready");
1095
1096 // Print preview is ready.
1097 handler()->OnPrintPreviewReady(preview_ui_id, preview_request_id);
1098 CheckWebUIResponse(*web_ui()->call_data().back(), callback_id_in, true);
1099
1100 // Renderer responses have been as expected.
1101 EXPECT_EQ(handler()->bad_messages(), 0);
1102
1103 // None of these should work since there has been no new preview request.
1104 // Check that there are no new web UI messages sent.
1105 size_t message_count = web_ui()->call_data().size();
1106 handler()->SendPageLayoutReady(base::DictionaryValue(),
1107 /*has_custom_page_size_style,=*/false,
1108 preview_request_id);
1109 EXPECT_EQ(message_count, web_ui()->call_data().size());
1110 handler()->SendPageCountReady(1, -1, 0);
1111 EXPECT_EQ(message_count, web_ui()->call_data().size());
1112 handler()->OnPrintPreviewReady(0, 0);
1113 EXPECT_EQ(message_count, web_ui()->call_data().size());
1114
1115 // Handler should have tried to kill the renderer for each of these.
1116 EXPECT_EQ(handler()->bad_messages(), 3);
1117 }
1118
1119 class FailingTestPrinterHandler : public TestPrinterHandler {
1120 public:
FailingTestPrinterHandler(const std::vector<PrinterInfo> & printers)1121 explicit FailingTestPrinterHandler(const std::vector<PrinterInfo>& printers)
1122 : TestPrinterHandler(printers) {}
1123
1124 ~FailingTestPrinterHandler() override = default;
1125
StartGetCapability(const std::string & destination_id,GetCapabilityCallback callback)1126 void StartGetCapability(const std::string& destination_id,
1127 GetCapabilityCallback callback) override {
1128 std::move(callback).Run(base::Value());
1129 }
1130
1131 private:
1132 DISALLOW_COPY_AND_ASSIGN(FailingTestPrinterHandler);
1133 };
1134
1135 class PrintPreviewHandlerFailingTest : public PrintPreviewHandlerTest {
1136 public:
1137 PrintPreviewHandlerFailingTest() = default;
1138 ~PrintPreviewHandlerFailingTest() override = default;
1139
CreatePrinterHandler(const std::vector<PrinterInfo> & printers)1140 std::unique_ptr<TestPrinterHandler> CreatePrinterHandler(
1141 const std::vector<PrinterInfo>& printers) override {
1142 return std::make_unique<FailingTestPrinterHandler>(printers);
1143 }
1144
1145 private:
1146 DISALLOW_COPY_AND_ASSIGN(PrintPreviewHandlerFailingTest);
1147 };
1148
1149 // This test is similar to PrintPreviewHandlerTest.GetPrinterCapabilities, but
1150 // uses FailingTestPrinterHandler instead of TestPrinterHandler. As a result,
1151 // StartGetCapability() always fails, to exercise its callback's failure
1152 // handling path. Failure is different from getting no capabilities.
TEST_F(PrintPreviewHandlerFailingTest,GetPrinterCapabilities)1153 TEST_F(PrintPreviewHandlerFailingTest, GetPrinterCapabilities) {
1154 // Add an empty printer to the handler.
1155 printers().push_back(GetEmptyPrinterInfo());
1156 printer_handler()->SetPrinters(printers());
1157
1158 // Initial settings first to enable javascript.
1159 Initialize();
1160
1161 // Check all four printer types that implement
1162 // PrinterHandler::StartGetCapability().
1163 for (size_t i = 0; i < base::size(kAllSupportedTypes); i++) {
1164 PrinterType type = kAllSupportedTypes[i];
1165 handler()->reset_calls();
1166 base::Value args(base::Value::Type::LIST);
1167 std::string callback_id_in =
1168 "test-callback-id-" + base::NumberToString(i + 1);
1169 args.Append(callback_id_in);
1170 args.Append(kDummyPrinterName);
1171 args.Append(static_cast<int>(type));
1172 std::unique_ptr<base::ListValue> list_args =
1173 base::ListValue::From(base::Value::ToUniquePtrValue(std::move(args)));
1174 handler()->HandleGetPrinterCapabilities(list_args.get());
1175 EXPECT_TRUE(handler()->CalledOnlyForType(type));
1176
1177 // Start with 1 call from initial settings, then add 1 more for each loop
1178 // iteration.
1179 ASSERT_EQ(1u + (i + 1), web_ui()->call_data().size());
1180
1181 // Verify printer capabilities promise was rejected.
1182 const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
1183 CheckWebUIResponse(data, callback_id_in, false);
1184 const base::Value* settings = data.arg3();
1185 ASSERT_TRUE(settings);
1186 EXPECT_TRUE(settings->is_none());
1187 }
1188 }
1189
1190 } // namespace printing
1191