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 (at) 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 (at) gmail.com\"" 93 " ]," 94 " \"params\": {" 95 " \"printerid\": [" 96 " \"__example_printer_id\"" 97 " ]" 98 " }," 99 " \"user\": \"sampleuser (at) 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 (at) 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 (at) gmail.com\"" 152 " }," 153 " \"job\": {" 154 " \"tags\": [" 155 " \"^own\"" 156 " ]," 157 " \"printerName\": \"Example Printer\"," 158 " \"status\": \"%s\"," 159 " \"ownerId\": \"sampleuser (at) 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. 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 211 GURL JobListURI(const char* reason) { 212 return GURL(StringPrintf(kExamplePrinterJobListURI, reason)); 213 } 214 215 GURL DoneURI(int job_num) { 216 return GURL(StringPrintf(kExampleUpdateDoneURI, job_num)); 217 } 218 219 GURL ErrorURI(int job_num) { 220 return GURL(StringPrintf(kExampleUpdateErrorURI, job_num)); 221 } 222 223 GURL TicketURI(int job_num) { 224 return GURL(StringPrintf(kExamplePrintTicketURI, job_num)); 225 } 226 227 GURL DownloadURI(int job_num) { 228 return GURL(StringPrintf(kExamplePrintDownloadURI, job_num)); 229 } 230 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 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: 250 CloudPrintURLFetcherNoServiceProcess() : 251 context_getter_(new net::TestURLRequestContextGetter( 252 base::MessageLoopProxy::current())) {} 253 protected: 254 virtual net::URLRequestContextGetter* GetRequestContextGetter() OVERRIDE { 255 return context_getter_.get(); 256 } 257 258 virtual ~CloudPrintURLFetcherNoServiceProcess() {} 259 private: 260 scoped_refptr<net::URLRequestContextGetter> context_getter_; 261 }; 262 263 264 class CloudPrintURLFetcherNoServiceProcessFactory 265 : public CloudPrintURLFetcherFactory { 266 public: 267 virtual CloudPrintURLFetcher* CreateCloudPrintURLFetcher() OVERRIDE { 268 return new CloudPrintURLFetcherNoServiceProcess; 269 } 270 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: 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 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(); 315 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: 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(); 338 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: 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(); 365 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: 372 virtual ~MockJobSpooler() {} 373 374 private: 375 PrintSystem::JobSpooler::Delegate* delegate_; 376 }; 377 378 379 380 class MockPrintSystem : public PrintSystem { 381 public: 382 MockPrintSystem(); 383 PrintSystem::PrintSystemResult succeed() { 384 return PrintSystem::PrintSystemResult(true, "success"); 385 } 386 387 PrintSystem::PrintSystemResult fail() { 388 return PrintSystem::PrintSystemResult(false, "failure"); 389 } 390 391 MockJobSpooler& JobSpooler() { return *job_spooler_.get(); } 392 393 MockPrinterWatcher& PrinterWatcher() { return *printer_watcher_.get(); } 394 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: 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 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 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 517 void PrinterJobHandlerTest::MessageLoopQuitNowHelper( 518 base::MessageLoop* message_loop) { 519 message_loop->QuitWhenIdle(); 520 } 521 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 528 PrinterJobHandlerTest::PrinterJobHandlerTest() 529 : factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, 530 base::Unretained(&url_callback_))) { 531 } 532 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 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 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 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 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 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 625 bool PrinterJobHandlerTest::GetPrinterInfo(printing::PrinterBasicInfo* info) { 626 *info = basic_info_; 627 return true; 628 } 629 630 void PrinterJobHandlerTest::TearDown() { 631 IdleOut(); 632 CloudPrintURLFetcher::set_factory(NULL); 633 } 634 635 void PrinterJobHandlerTest::IdleOut() { 636 base::MessageLoop::current()->RunUntilIdle(); 637 } 638 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 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 652 MockJobSpooler::MockJobSpooler() : delegate_(NULL) { 653 ON_CALL(*this, Spool(_, _, _, _, _, _, _, _)) 654 .WillByDefault(DoAll(SaveArg<7>(&delegate_), Return(true))); 655 } 656 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 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 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 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 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