1 // Copyright (c) 2013 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 "base/files/file_path.h"
6 #include "base/md5.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/common/cloud_print/cloud_print_constants.h"
13 #include "chrome/service/cloud_print/cloud_print_service_helpers.h"
14 #include "chrome/service/cloud_print/cloud_print_token_store.h"
15 #include "chrome/service/cloud_print/print_system.h"
16 #include "chrome/service/cloud_print/printer_job_handler.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_status_code.h"
19 #include "net/url_request/test_url_fetcher_factory.h"
20 #include "net/url_request/url_request_status.h"
21 #include "net/url_request/url_request_test_util.h"
22 #include "printing/backend/print_backend.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using ::testing::AtLeast;
27 using ::testing::DoAll;
28 using ::testing::Exactly;
29 using ::testing::Invoke;
30 using ::testing::InvokeWithoutArgs;
31 using ::testing::NiceMock;
32 using ::testing::Return;
33 using ::testing::SaveArg;
34 using ::testing::Sequence;
35 using ::testing::SetArgPointee;
36 using ::testing::StrictMock;
37 using ::testing::_;
38
39 namespace cloud_print {
40
41 namespace {
42
43 using base::StringPrintf;
44
45 const char kExampleCloudPrintServerURL[] = "https://www.google.com/cloudprint/";
46
47 const char kExamplePrintTicket[] = "{\"MediaType\":\"plain\","
48 "\"Resolution\":\"300x300dpi\",\"PageRegion\":\"Letter\","
49 "\"InputSlot\":\"auto\",\"PageSize\":\"Letter\",\"EconoMode\":\"off\"}";
50
51
52 // The fillowing constants will all be constructed with StringPrintf. The
53 // following types of parameters are possible:
54 // job number(int): ID # of job from given job list. All job IDs follow the
55 // format __example_job_idN for some N.
56 // fetch reason(string): Fetch reason used by the code. The job list URL
57 // requested by PrinterJobHandler has an extra parameter that signifies when
58 // the request was triggered.
59 // status string(string): Status of print job, one of IN_PROGRESS, DONE or ERROR
60 // job object list(string/JSON formatted): a comma-separated list of job objects
61
62 // StringPrintf parameters: job number, job number, job number, job number
63 const char kExampleJobObject[] = "{"
64 " \"tags\": ["
65 " \"^own\""
66 " ],"
67 " \"printerName\": \"Example Printer\","
68 " \"status\": \"QUEUED\","
69 " \"ownerId\": \"sampleuser@gmail.com\","
70 " \"ticketUrl\": \"https://www.google.com/cloudprint/ticket?exampleURI%d\","
71 " \"printerid\": \"__example_printer_id\","
72 " \"printerType\": \"GOOGLE\","
73 " \"contentType\": \"text/html\","
74 " \"fileUrl\": \"https://www.google.com/cloudprint/download?exampleURI%d\","
75 " \"id\": \"__example_job_id%d\","
76 " \"message\": \"\","
77 " \"title\": \"Example Job %d\","
78 " \"errorCode\": \"\","
79 " \"numberOfPages\": 3"
80 " }";
81
82 // StringPrintf parameters: job object list
83 const char kExampleJobListResponse[] = "{"
84 " \"success\": true,"
85 " \"jobs\": ["
86 " %s"
87 " ],"
88 " \"xsrf_token\": \"AIp06DjUd3AV6BO0aujB9NvM2a9ZbogxOQ:1360021066932\","
89 " \"request\": {"
90 " \"time\": \"0\","
91 " \"users\": ["
92 " \"sampleuser@gmail.com\""
93 " ],"
94 " \"params\": {"
95 " \"printerid\": ["
96 " \"__example_printer_id\""
97 " ]"
98 " },"
99 " \"user\": \"sampleuser@gmail.com\""
100 " }"
101 "}";
102
103
104 // StringPrintf parameters: job number
105 const char kExampleJobID[] = "__example_job_id%d";
106
107 // StringPrintf parameters: job number
108 const char kExamplePrintTicketURI[] =
109 "https://www.google.com/cloudprint/ticket?exampleURI%d";
110
111 // StringPrintf parameters: job number
112 const char kExamplePrintDownloadURI[] =
113 "https://www.google.com/cloudprint/download?exampleURI%d";
114
115 // StringPrintf parameters: job number
116 const char kExampleUpdateDoneURI[] =
117 "https://www.google.com/cloudprint/control?jobid=__example_job_id%d"
118 "&status=DONE&code=0&message=&numpages=0&pagesprinted=0";
119
120 // StringPrintf parameters: job number
121 const char kExampleUpdateErrorURI[] =
122 "https://www.google.com/cloudprint/control?jobid=__example_job_id%d"
123 "&status=ERROR";
124
125 // StringPrintf parameters: fetch reason
126 const char kExamplePrinterJobListURI[] =
127 "https://www.google.com/cloudprint/fetch"
128 "?printerid=__example_printer_id&deb=%s";
129
130 // StringPrintf parameters: status string, job number, status string (repeat)
131 const char kExampleControlResponse[] = "{"
132 " \"success\": true,"
133 " \"message\": \"Print job updated successfully.\","
134 " \"xsrf_token\": \"AIp06DjKgbfGalbqzj23V1bU6i-vtR2B4w:1360023068789\","
135 " \"request\": {"
136 " \"time\": \"0\","
137 " \"users\": ["
138 " \"sampleuser@gmail.com\""
139 " ],"
140 " \"params\": {"
141 " \"xsrf\": ["
142 " \"AIp06DgeGIETs42Cj28QWmxGPWVDiaXwVQ:1360023041852\""
143 " ],"
144 " \"status\": ["
145 " \"%s\""
146 " ],"
147 " \"jobid\": ["
148 " \"__example_job_id%d\""
149 " ]"
150 " },"
151 " \"user\": \"sampleuser@gmail.com\""
152 " },"
153 " \"job\": {"
154 " \"tags\": ["
155 " \"^own\""
156 " ],"
157 " \"printerName\": \"Example Printer\","
158 " \"status\": \"%s\","
159 " \"ownerId\": \"sampleuser@gmail.com\","
160 " \"ticketUrl\": \"https://www.google.com/cloudprint/ticket?exampleURI1\","
161 " \"printerid\": \"__example_printer_id\","
162 " \"contentType\": \"text/html\","
163 " \"fileUrl\": \"https://www.google.com/cloudprint/download?exampleURI1\","
164 " \"id\": \"__example_job_id1\","
165 " \"message\": \"\","
166 " \"title\": \"Example Job\","
167 " \"errorCode\": \"\","
168 " \"numberOfPages\": 3"
169 " }"
170 "}";
171
172 const char kExamplePrinterID[] = "__example_printer_id";
173
174 const char kExamplePrinterCapabilities[] = "";
175
176 const char kExampleCapsMimeType[] = "";
177
178 // These can stay empty
179 const char kExampleDefaults[] = "";
180
181 const char kExampleDefaultMimeType[] = "";
182
183 // Since we're not connecting to the server, this can be any non-empty string.
184 const char kExampleCloudPrintOAuthToken[] = "__SAMPLE_TOKEN";
185
186
187 // Not actually printing, no need for real PDF.
188 const char kExamplePrintData[] = "__EXAMPLE_PRINT_DATA";
189
190 const char kExampleJobDownloadResponseHeaders[] =
191 "Content-Type: Application/PDF\n";
192
193 const char kExampleTicketDownloadResponseHeaders[] =
194 "Content-Type: application/json\n";
195
196 const char kExamplePrinterName[] = "Example Printer";
197
198 const char kExamplePrinterDescription[] = "Example Description";
199
200 // These are functions used to construct the various sample strings.
JobListResponse(int num_jobs)201 std::string JobListResponse(int num_jobs) {
202 std::string job_objects;
203 for (int i = 0; i < num_jobs; i++) {
204 job_objects = job_objects + StringPrintf(kExampleJobObject, i+1, i+1, i+1,
205 i+1);
206 if (i != num_jobs-1) job_objects = job_objects + ",";
207 }
208 return StringPrintf(kExampleJobListResponse, job_objects.c_str());
209 }
210
JobListURI(const char * reason)211 GURL JobListURI(const char* reason) {
212 return GURL(StringPrintf(kExamplePrinterJobListURI, reason));
213 }
214
DoneURI(int job_num)215 GURL DoneURI(int job_num) {
216 return GURL(StringPrintf(kExampleUpdateDoneURI, job_num));
217 }
218
ErrorURI(int job_num)219 GURL ErrorURI(int job_num) {
220 return GURL(StringPrintf(kExampleUpdateErrorURI, job_num));
221 }
222
TicketURI(int job_num)223 GURL TicketURI(int job_num) {
224 return GURL(StringPrintf(kExamplePrintTicketURI, job_num));
225 }
226
DownloadURI(int job_num)227 GURL DownloadURI(int job_num) {
228 return GURL(StringPrintf(kExamplePrintDownloadURI, job_num));
229 }
230
InProgressURI(int job_num)231 GURL InProgressURI(int job_num) {
232 return GetUrlForJobStatusUpdate(GURL(kExampleCloudPrintServerURL),
233 StringPrintf(kExampleJobID, job_num),
234 PRINT_JOB_STATUS_IN_PROGRESS,
235 0);
236 }
237
StatusResponse(int job_num,const char * status_string)238 std::string StatusResponse(int job_num, const char* status_string) {
239 return StringPrintf(kExampleControlResponse,
240 status_string,
241 job_num,
242 status_string);
243 }
244
245 } // namespace
246
247 class CloudPrintURLFetcherNoServiceProcess
248 : public CloudPrintURLFetcher {
249 public:
CloudPrintURLFetcherNoServiceProcess()250 CloudPrintURLFetcherNoServiceProcess() :
251 context_getter_(new net::TestURLRequestContextGetter(
252 base::MessageLoopProxy::current())) {}
253 protected:
GetRequestContextGetter()254 virtual net::URLRequestContextGetter* GetRequestContextGetter() OVERRIDE {
255 return context_getter_.get();
256 }
257
~CloudPrintURLFetcherNoServiceProcess()258 virtual ~CloudPrintURLFetcherNoServiceProcess() {}
259 private:
260 scoped_refptr<net::URLRequestContextGetter> context_getter_;
261 };
262
263
264 class CloudPrintURLFetcherNoServiceProcessFactory
265 : public CloudPrintURLFetcherFactory {
266 public:
CreateCloudPrintURLFetcher()267 virtual CloudPrintURLFetcher* CreateCloudPrintURLFetcher() OVERRIDE {
268 return new CloudPrintURLFetcherNoServiceProcess;
269 }
270
~CloudPrintURLFetcherNoServiceProcessFactory()271 virtual ~CloudPrintURLFetcherNoServiceProcessFactory() {}
272 };
273
274
275 // This class handles the callback from FakeURLFetcher
276 // It is a separate class because callback methods must be
277 // on RefCounted classes
278
279 class TestURLFetcherCallback {
280 public:
CreateURLFetcher(const GURL & url,net::URLFetcherDelegate * d,const std::string & response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)281 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher(
282 const GURL& url,
283 net::URLFetcherDelegate* d,
284 const std::string& response_data,
285 net::HttpStatusCode response_code,
286 net::URLRequestStatus::Status status) {
287 scoped_ptr<net::FakeURLFetcher> fetcher(
288 new net::FakeURLFetcher(url, d, response_data, response_code, status));
289 OnRequestCreate(url, fetcher.get());
290 return fetcher.Pass();
291 }
292 MOCK_METHOD2(OnRequestCreate,
293 void(const GURL&, net::FakeURLFetcher*));
294 };
295
296
297 class MockPrinterJobHandlerDelegate
298 : public PrinterJobHandler::Delegate {
299 public:
300 MOCK_METHOD0(OnAuthError, void());
301 MOCK_METHOD1(OnPrinterDeleted, void(const std::string& str));
302
~MockPrinterJobHandlerDelegate()303 virtual ~MockPrinterJobHandlerDelegate() {}
304 };
305
306
307 class MockPrintServerWatcher
308 : public PrintSystem::PrintServerWatcher {
309 public:
310 MOCK_METHOD1(StartWatching,
311 bool(PrintSystem::PrintServerWatcher::Delegate* d));
312 MOCK_METHOD0(StopWatching, bool());
313
314 MockPrintServerWatcher();
delegate() const315 PrintSystem::PrintServerWatcher::Delegate* delegate() const {
316 return delegate_;
317 }
318
319 friend class scoped_refptr<NiceMock<MockPrintServerWatcher> >;
320 friend class scoped_refptr<StrictMock<MockPrintServerWatcher> >;
321 friend class scoped_refptr<MockPrintServerWatcher>;
322
323 protected:
~MockPrintServerWatcher()324 virtual ~MockPrintServerWatcher() {}
325
326 private:
327 PrintSystem::PrintServerWatcher::Delegate* delegate_;
328 };
329
330 class MockPrinterWatcher : public PrintSystem::PrinterWatcher {
331 public:
332 MOCK_METHOD1(StartWatching, bool(PrintSystem::PrinterWatcher::Delegate* d));
333 MOCK_METHOD0(StopWatching, bool());
334 MOCK_METHOD1(GetCurrentPrinterInfo,
335 bool(printing::PrinterBasicInfo* printer_info));
336
337 MockPrinterWatcher();
delegate() const338 PrintSystem::PrinterWatcher::Delegate* delegate() const { return delegate_; }
339
340 friend class scoped_refptr<NiceMock<MockPrinterWatcher> >;
341 friend class scoped_refptr<StrictMock<MockPrinterWatcher> >;
342 friend class scoped_refptr<MockPrinterWatcher>;
343
344 protected:
~MockPrinterWatcher()345 virtual ~MockPrinterWatcher() {}
346
347 private:
348 PrintSystem::PrinterWatcher::Delegate* delegate_;
349 };
350
351
352 class MockJobSpooler : public PrintSystem::JobSpooler {
353 public:
354 MOCK_METHOD8(Spool, bool(
355 const std::string& print_ticket,
356 const std::string& print_ticket_mime_type,
357 const base::FilePath& print_data_file_path,
358 const std::string& print_data_mime_type,
359 const std::string& printer_name,
360 const std::string& job_title,
361 const std::vector<std::string>& tags,
362 PrintSystem::JobSpooler::Delegate* delegate));
363
364 MockJobSpooler();
delegate() const365 PrintSystem::JobSpooler::Delegate* delegate() const { return delegate_; }
366
367 friend class scoped_refptr<NiceMock<MockJobSpooler> >;
368 friend class scoped_refptr<StrictMock<MockJobSpooler> >;
369 friend class scoped_refptr<MockJobSpooler>;
370
371 protected:
~MockJobSpooler()372 virtual ~MockJobSpooler() {}
373
374 private:
375 PrintSystem::JobSpooler::Delegate* delegate_;
376 };
377
378
379
380 class MockPrintSystem : public PrintSystem {
381 public:
382 MockPrintSystem();
succeed()383 PrintSystem::PrintSystemResult succeed() {
384 return PrintSystem::PrintSystemResult(true, "success");
385 }
386
fail()387 PrintSystem::PrintSystemResult fail() {
388 return PrintSystem::PrintSystemResult(false, "failure");
389 }
390
JobSpooler()391 MockJobSpooler& JobSpooler() { return *job_spooler_.get(); }
392
PrinterWatcher()393 MockPrinterWatcher& PrinterWatcher() { return *printer_watcher_.get(); }
394
PrintServerWatcher()395 MockPrintServerWatcher& PrintServerWatcher() {
396 return *print_server_watcher_.get();
397 }
398
399 MOCK_METHOD0(Init, PrintSystem::PrintSystemResult());
400 MOCK_METHOD1(EnumeratePrinters, PrintSystem::PrintSystemResult(
401 printing::PrinterList* printer_list));
402
403 MOCK_METHOD2(
404 GetPrinterCapsAndDefaults,
405 void(const std::string& printer_name,
406 const PrintSystem::PrinterCapsAndDefaultsCallback& callback));
407
408 MOCK_METHOD1(IsValidPrinter, bool(const std::string& printer_name));
409
410 MOCK_METHOD3(ValidatePrintTicket,
411 bool(const std::string& printer_name,
412 const std::string& print_ticket_data,
413 const std::string& print_ticket_mime_type));
414
415 MOCK_METHOD3(GetJobDetails, bool(const std::string& printer_name,
416 PlatformJobId job_id,
417 PrintJobDetails* job_details));
418
419 MOCK_METHOD0(CreatePrintServerWatcher, PrintSystem::PrintServerWatcher*());
420 MOCK_METHOD1(CreatePrinterWatcher,
421 PrintSystem::PrinterWatcher*(const std::string& printer_name));
422 MOCK_METHOD0(CreateJobSpooler, PrintSystem::JobSpooler*());
423
424 MOCK_METHOD0(UseCddAndCjt, bool());
425 MOCK_METHOD0(GetSupportedMimeTypes, std::string());
426
427 friend class scoped_refptr<NiceMock<MockPrintSystem> >;
428 friend class scoped_refptr<StrictMock<MockPrintSystem> >;
429 friend class scoped_refptr<MockPrintSystem>;
430
431 protected:
~MockPrintSystem()432 virtual ~MockPrintSystem() {}
433
434 private:
435 scoped_refptr<MockJobSpooler> job_spooler_;
436 scoped_refptr<MockPrinterWatcher> printer_watcher_;
437 scoped_refptr<MockPrintServerWatcher> print_server_watcher_;
438 };
439
440
441 class PrinterJobHandlerTest : public ::testing::Test {
442 public:
443 PrinterJobHandlerTest();
444 virtual void SetUp() OVERRIDE;
445 virtual void TearDown() OVERRIDE;
446 void IdleOut();
447 bool GetPrinterInfo(printing::PrinterBasicInfo* info);
448 void SendCapsAndDefaults(
449 const std::string& printer_name,
450 const PrintSystem::PrinterCapsAndDefaultsCallback& callback);
451 void AddMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher);
452 void AddTicketMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher);
453 bool PostSpoolSuccess();
454 void SetUpJobSuccessTest(int job_num);
455 void BeginTest(int timeout_seconds);
456 void MakeJobFetchReturnNoJobs();
457
458 static void MessageLoopQuitNowHelper(base::MessageLoop* message_loop);
459 static void MessageLoopQuitSoonHelper(base::MessageLoop* message_loop);
460
461 base::MessageLoopForIO loop_;
462 TestURLFetcherCallback url_callback_;
463 MockPrinterJobHandlerDelegate jobhandler_delegate_;
464 CloudPrintTokenStore token_store_;
465 CloudPrintURLFetcherNoServiceProcessFactory cloud_print_factory_;
466 scoped_refptr<PrinterJobHandler> job_handler_;
467 scoped_refptr<NiceMock<MockPrintSystem> > print_system_;
468 net::FakeURLFetcherFactory factory_;
469 printing::PrinterBasicInfo basic_info_;
470 printing::PrinterCapsAndDefaults caps_and_defaults_;
471 PrinterJobHandler::PrinterInfoFromCloud info_from_cloud_;
472 };
473
474
SetUp()475 void PrinterJobHandlerTest::SetUp() {
476 basic_info_.printer_name = kExamplePrinterName;
477 basic_info_.printer_description = kExamplePrinterDescription;
478 basic_info_.is_default = 0;
479
480 info_from_cloud_.printer_id = kExamplePrinterID;
481 info_from_cloud_.tags_hash = GetHashOfPrinterInfo(basic_info_);
482
483 info_from_cloud_.caps_hash = base::MD5String(kExamplePrinterCapabilities);
484 info_from_cloud_.current_xmpp_timeout = 300;
485 info_from_cloud_.pending_xmpp_timeout = 0;
486
487 caps_and_defaults_.printer_capabilities = kExamplePrinterCapabilities;
488 caps_and_defaults_.caps_mime_type = kExampleCapsMimeType;
489 caps_and_defaults_.printer_defaults = kExampleDefaults;
490 caps_and_defaults_.defaults_mime_type = kExampleDefaultMimeType;
491
492 print_system_ = new NiceMock<MockPrintSystem>();
493
494 token_store_.SetToken(kExampleCloudPrintOAuthToken);
495
496 ON_CALL(print_system_->PrinterWatcher(), GetCurrentPrinterInfo(_))
497 .WillByDefault(Invoke(this, &PrinterJobHandlerTest::GetPrinterInfo));
498
499 ON_CALL(*print_system_.get(), GetPrinterCapsAndDefaults(_, _))
500 .WillByDefault(Invoke(this, &PrinterJobHandlerTest::SendCapsAndDefaults));
501
502 CloudPrintURLFetcher::set_factory(&cloud_print_factory_);
503 }
504
MakeJobFetchReturnNoJobs()505 void PrinterJobHandlerTest::MakeJobFetchReturnNoJobs() {
506 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup),
507 JobListResponse(0), net::HTTP_OK,
508 net::URLRequestStatus::SUCCESS);
509 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure),
510 JobListResponse(0), net::HTTP_OK,
511 net::URLRequestStatus::SUCCESS);
512 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry),
513 JobListResponse(0), net::HTTP_OK,
514 net::URLRequestStatus::SUCCESS);
515 }
516
MessageLoopQuitNowHelper(base::MessageLoop * message_loop)517 void PrinterJobHandlerTest::MessageLoopQuitNowHelper(
518 base::MessageLoop* message_loop) {
519 message_loop->QuitWhenIdle();
520 }
521
MessageLoopQuitSoonHelper(base::MessageLoop * message_loop)522 void PrinterJobHandlerTest::MessageLoopQuitSoonHelper(
523 base::MessageLoop* message_loop) {
524 message_loop->message_loop_proxy()->PostTask(
525 FROM_HERE, base::Bind(&MessageLoopQuitNowHelper, message_loop));
526 }
527
PrinterJobHandlerTest()528 PrinterJobHandlerTest::PrinterJobHandlerTest()
529 : factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher,
530 base::Unretained(&url_callback_))) {
531 }
532
PostSpoolSuccess()533 bool PrinterJobHandlerTest::PostSpoolSuccess() {
534 base::MessageLoop::current()->PostTask(
535 FROM_HERE,
536 base::Bind(&PrinterJobHandler::OnJobSpoolSucceeded, job_handler_, 0));
537
538 // Everything that would be posted on the printer thread queue
539 // has been posted, we can tell the main message loop to quit when idle
540 // and not worry about it idling while the print thread does work
541 base::MessageLoop::current()->PostTask(
542 FROM_HERE, base::Bind(&MessageLoopQuitSoonHelper, &loop_));
543 return true;
544 }
545
AddMimeHeader(const GURL & url,net::FakeURLFetcher * fetcher)546 void PrinterJobHandlerTest::AddMimeHeader(const GURL& url,
547 net::FakeURLFetcher* fetcher) {
548 scoped_refptr<net::HttpResponseHeaders> download_headers =
549 new net::HttpResponseHeaders(kExampleJobDownloadResponseHeaders);
550 fetcher->set_response_headers(download_headers);
551 }
552
AddTicketMimeHeader(const GURL & url,net::FakeURLFetcher * fetcher)553 void PrinterJobHandlerTest::AddTicketMimeHeader(const GURL& url,
554 net::FakeURLFetcher* fetcher) {
555 scoped_refptr<net::HttpResponseHeaders> download_headers =
556 new net::HttpResponseHeaders(kExampleTicketDownloadResponseHeaders);
557 fetcher->set_response_headers(download_headers);
558 }
559
560
SetUpJobSuccessTest(int job_num)561 void PrinterJobHandlerTest::SetUpJobSuccessTest(int job_num) {
562 factory_.SetFakeResponse(TicketURI(job_num),
563 kExamplePrintTicket, net::HTTP_OK,
564 net::URLRequestStatus::SUCCESS);
565 factory_.SetFakeResponse(DownloadURI(job_num),
566 kExamplePrintData, net::HTTP_OK,
567 net::URLRequestStatus::SUCCESS);
568
569 factory_.SetFakeResponse(DoneURI(job_num),
570 StatusResponse(job_num, "DONE"),
571 net::HTTP_OK,
572 net::URLRequestStatus::SUCCESS);
573 factory_.SetFakeResponse(InProgressURI(job_num),
574 StatusResponse(job_num, "IN_PROGRESS"),
575 net::HTTP_OK,
576 net::URLRequestStatus::SUCCESS);
577
578 // The times requirement is relaxed for the ticket URI
579 // in order to accommodate TicketDownloadFailureTest
580 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(job_num), _))
581 .Times(AtLeast(1))
582 .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddTicketMimeHeader));
583
584 EXPECT_CALL(url_callback_, OnRequestCreate(DownloadURI(job_num), _))
585 .Times(Exactly(1))
586 .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddMimeHeader));
587
588 EXPECT_CALL(url_callback_, OnRequestCreate(InProgressURI(job_num), _))
589 .Times(Exactly(1));
590
591 EXPECT_CALL(url_callback_, OnRequestCreate(DoneURI(job_num), _))
592 .Times(Exactly(1));
593
594 EXPECT_CALL(print_system_->JobSpooler(),
595 Spool(kExamplePrintTicket, _, _, _, _, _, _, _))
596 .Times(Exactly(1))
597 .WillOnce(InvokeWithoutArgs(this,
598 &PrinterJobHandlerTest::PostSpoolSuccess));
599 }
600
BeginTest(int timeout_seconds)601 void PrinterJobHandlerTest::BeginTest(int timeout_seconds) {
602 job_handler_ = new PrinterJobHandler(basic_info_,
603 info_from_cloud_,
604 GURL(kExampleCloudPrintServerURL),
605 print_system_.get(),
606 &jobhandler_delegate_);
607
608 job_handler_->Initialize();
609
610 base::MessageLoop::current()->PostDelayedTask(
611 FROM_HERE,
612 base::Bind(&PrinterJobHandlerTest::MessageLoopQuitSoonHelper,
613 base::MessageLoop::current()),
614 base::TimeDelta::FromSeconds(timeout_seconds));
615
616 base::MessageLoop::current()->Run();
617 }
618
SendCapsAndDefaults(const std::string & printer_name,const PrintSystem::PrinterCapsAndDefaultsCallback & callback)619 void PrinterJobHandlerTest::SendCapsAndDefaults(
620 const std::string& printer_name,
621 const PrintSystem::PrinterCapsAndDefaultsCallback& callback) {
622 callback.Run(true, printer_name, caps_and_defaults_);
623 }
624
GetPrinterInfo(printing::PrinterBasicInfo * info)625 bool PrinterJobHandlerTest::GetPrinterInfo(printing::PrinterBasicInfo* info) {
626 *info = basic_info_;
627 return true;
628 }
629
TearDown()630 void PrinterJobHandlerTest::TearDown() {
631 IdleOut();
632 CloudPrintURLFetcher::set_factory(NULL);
633 }
634
IdleOut()635 void PrinterJobHandlerTest::IdleOut() {
636 base::MessageLoop::current()->RunUntilIdle();
637 }
638
MockPrintServerWatcher()639 MockPrintServerWatcher::MockPrintServerWatcher() : delegate_(NULL) {
640 ON_CALL(*this, StartWatching(_))
641 .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true)));
642 ON_CALL(*this, StopWatching()).WillByDefault(Return(true));
643 }
644
645
MockPrinterWatcher()646 MockPrinterWatcher::MockPrinterWatcher() : delegate_(NULL) {
647 ON_CALL(*this, StartWatching(_))
648 .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true)));
649 ON_CALL(*this, StopWatching()).WillByDefault(Return(true));
650 }
651
MockJobSpooler()652 MockJobSpooler::MockJobSpooler() : delegate_(NULL) {
653 ON_CALL(*this, Spool(_, _, _, _, _, _, _, _))
654 .WillByDefault(DoAll(SaveArg<7>(&delegate_), Return(true)));
655 }
656
MockPrintSystem()657 MockPrintSystem::MockPrintSystem()
658 : job_spooler_(new NiceMock<MockJobSpooler>()),
659 printer_watcher_(new NiceMock<MockPrinterWatcher>()),
660 print_server_watcher_(new NiceMock<MockPrintServerWatcher>()) {
661 ON_CALL(*this, CreateJobSpooler()).WillByDefault(Return(job_spooler_.get()));
662
663 ON_CALL(*this, CreatePrinterWatcher(_))
664 .WillByDefault(Return(printer_watcher_.get()));
665
666 ON_CALL(*this, CreatePrintServerWatcher())
667 .WillByDefault(Return(print_server_watcher_.get()));
668
669 ON_CALL(*this, IsValidPrinter(_)).
670 WillByDefault(Return(true));
671
672 ON_CALL(*this, ValidatePrintTicket(_, _, _)).
673 WillByDefault(Return(true));
674 };
675
676 // This test simulates an end-to-end printing of a document
677 // but tests only non-failure cases.
678 // Disabled - http://crbug.com/184245
TEST_F(PrinterJobHandlerTest,DISABLED_HappyPathTest)679 TEST_F(PrinterJobHandlerTest, DISABLED_HappyPathTest) {
680 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup),
681 JobListResponse(1), net::HTTP_OK,
682 net::URLRequestStatus::SUCCESS);
683 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore),
684 JobListResponse(0), net::HTTP_OK,
685 net::URLRequestStatus::SUCCESS);
686
687 EXPECT_CALL(url_callback_,
688 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _))
689 .Times(Exactly(1));
690 EXPECT_CALL(url_callback_,
691 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _))
692 .Times(Exactly(1));
693
694 SetUpJobSuccessTest(1);
695 BeginTest(20);
696 }
697
TEST_F(PrinterJobHandlerTest,TicketDownloadFailureTest)698 TEST_F(PrinterJobHandlerTest, TicketDownloadFailureTest) {
699 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup),
700 JobListResponse(2), net::HTTP_OK,
701 net::URLRequestStatus::SUCCESS);
702 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure),
703 JobListResponse(2), net::HTTP_OK,
704 net::URLRequestStatus::SUCCESS);
705 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore),
706 JobListResponse(0), net::HTTP_OK,
707 net::URLRequestStatus::SUCCESS);
708 factory_.SetFakeResponse(TicketURI(1), std::string(),
709 net::HTTP_INTERNAL_SERVER_ERROR,
710 net::URLRequestStatus::FAILED);
711
712 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _))
713 .Times(AtLeast(1))
714 .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddTicketMimeHeader));
715
716 EXPECT_CALL(url_callback_,
717 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _))
718 .Times(AtLeast(1));
719
720 EXPECT_CALL(url_callback_,
721 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _))
722 .Times(AtLeast(1));
723
724 EXPECT_CALL(url_callback_,
725 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _))
726 .Times(AtLeast(1));
727
728 SetUpJobSuccessTest(2);
729 BeginTest(20);
730 }
731
732 // TODO(noamsml): Figure out how to make this test not take 1 second and
733 // re-enable it
TEST_F(PrinterJobHandlerTest,DISABLED_ManyFailureTest)734 TEST_F(PrinterJobHandlerTest, DISABLED_ManyFailureTest) {
735 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup),
736 JobListResponse(1), net::HTTP_OK,
737 net::URLRequestStatus::SUCCESS);
738 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure),
739 JobListResponse(1), net::HTTP_OK,
740 net::URLRequestStatus::SUCCESS);
741 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry),
742 JobListResponse(1), net::HTTP_OK,
743 net::URLRequestStatus::SUCCESS);
744 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore),
745 JobListResponse(0), net::HTTP_OK,
746 net::URLRequestStatus::SUCCESS);
747
748 EXPECT_CALL(url_callback_,
749 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _))
750 .Times(AtLeast(1));
751
752 EXPECT_CALL(url_callback_,
753 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _))
754 .Times(AtLeast(1));
755
756 EXPECT_CALL(url_callback_,
757 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _))
758 .Times(AtLeast(1));
759
760 EXPECT_CALL(url_callback_,
761 OnRequestCreate(JobListURI(kJobFetchReasonRetry), _))
762 .Times(AtLeast(1));
763
764 SetUpJobSuccessTest(1);
765
766 factory_.SetFakeResponse(TicketURI(1),
767 std::string(),
768 net::HTTP_INTERNAL_SERVER_ERROR,
769 net::URLRequestStatus::FAILED);
770
771 loop_.PostDelayedTask(FROM_HERE,
772 base::Bind(&net::FakeURLFetcherFactory::SetFakeResponse,
773 base::Unretained(&factory_),
774 TicketURI(1),
775 kExamplePrintTicket,
776 net::HTTP_OK,
777 net::URLRequestStatus::SUCCESS),
778 base::TimeDelta::FromSeconds(1));
779
780
781 BeginTest(5);
782 }
783
784
785 // TODO(noamsml): Figure out how to make this test not take ~64-~2048 (depending
786 // constant values) seconds and re-enable it
TEST_F(PrinterJobHandlerTest,DISABLED_CompleteFailureTest)787 TEST_F(PrinterJobHandlerTest, DISABLED_CompleteFailureTest) {
788 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup),
789 JobListResponse(1), net::HTTP_OK,
790 net::URLRequestStatus::SUCCESS);
791 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure),
792 JobListResponse(1), net::HTTP_OK,
793 net::URLRequestStatus::SUCCESS);
794 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry),
795 JobListResponse(1), net::HTTP_OK,
796 net::URLRequestStatus::SUCCESS);
797 factory_.SetFakeResponse(ErrorURI(1), StatusResponse(1, "ERROR"),
798 net::HTTP_OK, net::URLRequestStatus::SUCCESS);
799 factory_.SetFakeResponse(TicketURI(1), std::string(),
800 net::HTTP_INTERNAL_SERVER_ERROR,
801 net::URLRequestStatus::FAILED);
802
803 EXPECT_CALL(url_callback_,
804 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _))
805 .Times(AtLeast(1));
806
807 EXPECT_CALL(url_callback_,
808 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _))
809 .Times(AtLeast(1));
810
811 EXPECT_CALL(url_callback_,
812 OnRequestCreate(JobListURI(kJobFetchReasonRetry), _))
813 .Times(AtLeast(1));
814
815 EXPECT_CALL(url_callback_, OnRequestCreate(ErrorURI(1), _))
816 .Times(Exactly(1))
817 .WillOnce(InvokeWithoutArgs(
818 this, &PrinterJobHandlerTest::MakeJobFetchReturnNoJobs));
819
820 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _))
821 .Times(AtLeast(kNumRetriesBeforeAbandonJob));
822
823 BeginTest(70);
824 }
825
826 } // namespace cloud_print
827