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 26using ::testing::AtLeast; 27using ::testing::DoAll; 28using ::testing::Exactly; 29using ::testing::Invoke; 30using ::testing::InvokeWithoutArgs; 31using ::testing::NiceMock; 32using ::testing::Return; 33using ::testing::SaveArg; 34using ::testing::Sequence; 35using ::testing::SetArgPointee; 36using ::testing::StrictMock; 37using ::testing::_; 38 39namespace cloud_print { 40 41namespace { 42 43using base::StringPrintf; 44 45const char kExampleCloudPrintServerURL[] = "https://www.google.com/cloudprint/"; 46 47const 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 63const 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 83const 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 105const char kExampleJobID[] = "__example_job_id%d"; 106 107// StringPrintf parameters: job number 108const char kExamplePrintTicketURI[] = 109 "https://www.google.com/cloudprint/ticket?exampleURI%d"; 110 111// StringPrintf parameters: job number 112const char kExamplePrintDownloadURI[] = 113 "https://www.google.com/cloudprint/download?exampleURI%d"; 114 115// StringPrintf parameters: job number 116const 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 121const char kExampleUpdateErrorURI[] = 122 "https://www.google.com/cloudprint/control?jobid=__example_job_id%d" 123 "&status=ERROR"; 124 125// StringPrintf parameters: fetch reason 126const 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) 131const 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 172const char kExamplePrinterID[] = "__example_printer_id"; 173 174const char kExamplePrinterCapabilities[] = ""; 175 176const char kExampleCapsMimeType[] = ""; 177 178// These can stay empty 179const char kExampleDefaults[] = ""; 180 181const char kExampleDefaultMimeType[] = ""; 182 183// Since we're not connecting to the server, this can be any non-empty string. 184const char kExampleCloudPrintOAuthToken[] = "__SAMPLE_TOKEN"; 185 186 187// Not actually printing, no need for real PDF. 188const char kExamplePrintData[] = "__EXAMPLE_PRINT_DATA"; 189 190const char kExampleJobDownloadResponseHeaders[] = 191 "Content-Type: Application/PDF\n"; 192 193const char kExampleTicketDownloadResponseHeaders[] = 194 "Content-Type: application/json\n"; 195 196const char kExamplePrinterName[] = "Example Printer"; 197 198const char kExamplePrinterDescription[] = "Example Description"; 199 200// These are functions used to construct the various sample strings. 201std::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 211GURL JobListURI(const char* reason) { 212 return GURL(StringPrintf(kExamplePrinterJobListURI, reason)); 213} 214 215GURL DoneURI(int job_num) { 216 return GURL(StringPrintf(kExampleUpdateDoneURI, job_num)); 217} 218 219GURL ErrorURI(int job_num) { 220 return GURL(StringPrintf(kExampleUpdateErrorURI, job_num)); 221} 222 223GURL TicketURI(int job_num) { 224 return GURL(StringPrintf(kExamplePrintTicketURI, job_num)); 225} 226 227GURL DownloadURI(int job_num) { 228 return GURL(StringPrintf(kExamplePrintDownloadURI, job_num)); 229} 230 231GURL InProgressURI(int job_num) { 232 return GetUrlForJobStatusUpdate(GURL(kExampleCloudPrintServerURL), 233 StringPrintf(kExampleJobID, job_num), 234 PRINT_JOB_STATUS_IN_PROGRESS, 235 0); 236} 237 238std::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 247class 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 264class 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 279class 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 297class 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 307class 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 330class 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 352class 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 380class 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 441class 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 475void 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 505void 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 517void PrinterJobHandlerTest::MessageLoopQuitNowHelper( 518 base::MessageLoop* message_loop) { 519 message_loop->QuitWhenIdle(); 520} 521 522void PrinterJobHandlerTest::MessageLoopQuitSoonHelper( 523 base::MessageLoop* message_loop) { 524 message_loop->message_loop_proxy()->PostTask( 525 FROM_HERE, base::Bind(&MessageLoopQuitNowHelper, message_loop)); 526} 527 528PrinterJobHandlerTest::PrinterJobHandlerTest() 529 : factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, 530 base::Unretained(&url_callback_))) { 531} 532 533bool 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 546void 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 553void 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 561void 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 601void 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 619void PrinterJobHandlerTest::SendCapsAndDefaults( 620 const std::string& printer_name, 621 const PrintSystem::PrinterCapsAndDefaultsCallback& callback) { 622 callback.Run(true, printer_name, caps_and_defaults_); 623} 624 625bool PrinterJobHandlerTest::GetPrinterInfo(printing::PrinterBasicInfo* info) { 626 *info = basic_info_; 627 return true; 628} 629 630void PrinterJobHandlerTest::TearDown() { 631 IdleOut(); 632 CloudPrintURLFetcher::set_factory(NULL); 633} 634 635void PrinterJobHandlerTest::IdleOut() { 636 base::MessageLoop::current()->RunUntilIdle(); 637} 638 639MockPrintServerWatcher::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 646MockPrinterWatcher::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 652MockJobSpooler::MockJobSpooler() : delegate_(NULL) { 653 ON_CALL(*this, Spool(_, _, _, _, _, _, _, _)) 654 .WillByDefault(DoAll(SaveArg<7>(&delegate_), Return(true))); 655} 656 657MockPrintSystem::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 679TEST_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 698TEST_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 734TEST_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 787TEST_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