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 kExamplePrinterName[] = "Example Printer"; 194 195const char kExamplePrinterDescription[] = "Example Description"; 196 197// These are functions used to construct the various sample strings. 198std::string JobListResponse(int num_jobs) { 199 std::string job_objects; 200 for (int i = 0; i < num_jobs; i++) { 201 job_objects = job_objects + StringPrintf(kExampleJobObject, i+1, i+1, i+1, 202 i+1); 203 if (i != num_jobs-1) job_objects = job_objects + ","; 204 } 205 return StringPrintf(kExampleJobListResponse, job_objects.c_str()); 206} 207 208GURL JobListURI(const char* reason) { 209 return GURL(StringPrintf(kExamplePrinterJobListURI, reason)); 210} 211 212GURL DoneURI(int job_num) { 213 return GURL(StringPrintf(kExampleUpdateDoneURI, job_num)); 214} 215 216GURL ErrorURI(int job_num) { 217 return GURL(StringPrintf(kExampleUpdateErrorURI, job_num)); 218} 219 220GURL TicketURI(int job_num) { 221 return GURL(StringPrintf(kExamplePrintTicketURI, job_num)); 222} 223 224GURL DownloadURI(int job_num) { 225 return GURL(StringPrintf(kExamplePrintDownloadURI, job_num)); 226} 227 228GURL InProgressURI(int job_num) { 229 return GetUrlForJobStatusUpdate(GURL(kExampleCloudPrintServerURL), 230 StringPrintf(kExampleJobID, job_num), 231 PRINT_JOB_STATUS_IN_PROGRESS, 232 0); 233} 234 235std::string StatusResponse(int job_num, const char* status_string) { 236 return StringPrintf(kExampleControlResponse, 237 status_string, 238 job_num, 239 status_string); 240} 241 242} // namespace 243 244class CloudPrintURLFetcherNoServiceProcess 245 : public CloudPrintURLFetcher { 246 public: 247 CloudPrintURLFetcherNoServiceProcess() : 248 context_getter_(new net::TestURLRequestContextGetter( 249 base::MessageLoopProxy::current())) {} 250 protected: 251 virtual net::URLRequestContextGetter* GetRequestContextGetter() OVERRIDE { 252 return context_getter_.get(); 253 } 254 255 virtual ~CloudPrintURLFetcherNoServiceProcess() {} 256 private: 257 scoped_refptr<net::URLRequestContextGetter> context_getter_; 258}; 259 260 261class CloudPrintURLFetcherNoServiceProcessFactory 262 : public CloudPrintURLFetcherFactory { 263 public: 264 virtual CloudPrintURLFetcher* CreateCloudPrintURLFetcher() OVERRIDE { 265 return new CloudPrintURLFetcherNoServiceProcess; 266 } 267 268 virtual ~CloudPrintURLFetcherNoServiceProcessFactory() {} 269}; 270 271 272// This class handles the callback from FakeURLFetcher 273// It is a separate class because callback methods must be 274// on RefCounted classes 275 276class TestURLFetcherCallback { 277 public: 278 scoped_ptr<net::FakeURLFetcher> CreateURLFetcher( 279 const GURL& url, 280 net::URLFetcherDelegate* d, 281 const std::string& response_data, 282 net::HttpStatusCode response_code, 283 net::URLRequestStatus::Status status) { 284 scoped_ptr<net::FakeURLFetcher> fetcher( 285 new net::FakeURLFetcher(url, d, response_data, response_code, status)); 286 OnRequestCreate(url, fetcher.get()); 287 return fetcher.Pass(); 288 } 289 MOCK_METHOD2(OnRequestCreate, 290 void(const GURL&, net::FakeURLFetcher*)); 291}; 292 293 294class MockPrinterJobHandlerDelegate 295 : public PrinterJobHandler::Delegate { 296 public: 297 MOCK_METHOD0(OnAuthError, void()); 298 MOCK_METHOD1(OnPrinterDeleted, void(const std::string& str)); 299 300 virtual ~MockPrinterJobHandlerDelegate() {} 301}; 302 303 304class MockPrintServerWatcher 305 : public PrintSystem::PrintServerWatcher { 306 public: 307 MOCK_METHOD1(StartWatching, 308 bool(PrintSystem::PrintServerWatcher::Delegate* d)); 309 MOCK_METHOD0(StopWatching, bool()); 310 311 MockPrintServerWatcher(); 312 PrintSystem::PrintServerWatcher::Delegate* delegate() const { 313 return delegate_; 314 } 315 316 friend class scoped_refptr<NiceMock<MockPrintServerWatcher> >; 317 friend class scoped_refptr<StrictMock<MockPrintServerWatcher> >; 318 friend class scoped_refptr<MockPrintServerWatcher>; 319 320 protected: 321 virtual ~MockPrintServerWatcher() {} 322 323 private: 324 PrintSystem::PrintServerWatcher::Delegate* delegate_; 325}; 326 327class MockPrinterWatcher : public PrintSystem::PrinterWatcher { 328 public: 329 MOCK_METHOD1(StartWatching, bool(PrintSystem::PrinterWatcher::Delegate* d)); 330 MOCK_METHOD0(StopWatching, bool()); 331 MOCK_METHOD1(GetCurrentPrinterInfo, 332 bool(printing::PrinterBasicInfo* printer_info)); 333 334 MockPrinterWatcher(); 335 PrintSystem::PrinterWatcher::Delegate* delegate() const { return delegate_; } 336 337 friend class scoped_refptr<NiceMock<MockPrinterWatcher> >; 338 friend class scoped_refptr<StrictMock<MockPrinterWatcher> >; 339 friend class scoped_refptr<MockPrinterWatcher>; 340 341 protected: 342 virtual ~MockPrinterWatcher() {} 343 344 private: 345 PrintSystem::PrinterWatcher::Delegate* delegate_; 346}; 347 348 349class MockJobSpooler : public PrintSystem::JobSpooler { 350 public: 351 MOCK_METHOD7(Spool, bool( 352 const std::string& print_ticket, 353 const base::FilePath& print_data_file_path, 354 const std::string& print_data_mime_type, 355 const std::string& printer_name, 356 const std::string& job_title, 357 const std::vector<std::string>& tags, 358 PrintSystem::JobSpooler::Delegate* delegate)); 359 360 MockJobSpooler(); 361 PrintSystem::JobSpooler::Delegate* delegate() const { return delegate_; } 362 363 friend class scoped_refptr<NiceMock<MockJobSpooler> >; 364 friend class scoped_refptr<StrictMock<MockJobSpooler> >; 365 friend class scoped_refptr<MockJobSpooler>; 366 367 protected: 368 virtual ~MockJobSpooler() {} 369 370 private: 371 PrintSystem::JobSpooler::Delegate* delegate_; 372}; 373 374 375 376class MockPrintSystem : public PrintSystem { 377 public: 378 MockPrintSystem(); 379 PrintSystem::PrintSystemResult succeed() { 380 return PrintSystem::PrintSystemResult(true, "success"); 381 } 382 383 PrintSystem::PrintSystemResult fail() { 384 return PrintSystem::PrintSystemResult(false, "failure"); 385 } 386 387 MockJobSpooler& JobSpooler() { return *job_spooler_.get(); } 388 389 MockPrinterWatcher& PrinterWatcher() { return *printer_watcher_.get(); } 390 391 MockPrintServerWatcher& PrintServerWatcher() { 392 return *print_server_watcher_.get(); 393 } 394 395 MOCK_METHOD0(Init, PrintSystem::PrintSystemResult()); 396 MOCK_METHOD1(EnumeratePrinters, PrintSystem::PrintSystemResult( 397 printing::PrinterList* printer_list)); 398 399 MOCK_METHOD2( 400 GetPrinterCapsAndDefaults, 401 void(const std::string& printer_name, 402 const PrintSystem::PrinterCapsAndDefaultsCallback& callback)); 403 404 MOCK_METHOD1(IsValidPrinter, bool(const std::string& printer_name)); 405 406 MOCK_METHOD2(ValidatePrintTicket, bool(const std::string& printer_name, 407 const std::string& print_ticket_data)); 408 409 MOCK_METHOD3(GetJobDetails, bool(const std::string& printer_name, 410 PlatformJobId job_id, 411 PrintJobDetails* job_details)); 412 413 MOCK_METHOD0(CreatePrintServerWatcher, PrintSystem::PrintServerWatcher*()); 414 MOCK_METHOD1(CreatePrinterWatcher, 415 PrintSystem::PrinterWatcher*(const std::string& printer_name)); 416 MOCK_METHOD0(CreateJobSpooler, PrintSystem::JobSpooler*()); 417 418 MOCK_METHOD0(GetSupportedMimeTypes, std::string()); 419 420 friend class scoped_refptr<NiceMock<MockPrintSystem> >; 421 friend class scoped_refptr<StrictMock<MockPrintSystem> >; 422 friend class scoped_refptr<MockPrintSystem>; 423 424 protected: 425 virtual ~MockPrintSystem() {} 426 427 private: 428 scoped_refptr<MockJobSpooler> job_spooler_; 429 scoped_refptr<MockPrinterWatcher> printer_watcher_; 430 scoped_refptr<MockPrintServerWatcher> print_server_watcher_; 431}; 432 433 434class PrinterJobHandlerTest : public ::testing::Test { 435 public: 436 PrinterJobHandlerTest(); 437 virtual void SetUp() OVERRIDE; 438 virtual void TearDown() OVERRIDE; 439 void IdleOut(); 440 bool GetPrinterInfo(printing::PrinterBasicInfo* info); 441 void SendCapsAndDefaults( 442 const std::string& printer_name, 443 const PrintSystem::PrinterCapsAndDefaultsCallback& callback); 444 void AddMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher); 445 bool PostSpoolSuccess(); 446 void SetUpJobSuccessTest(int job_num); 447 void BeginTest(int timeout_seconds); 448 void MakeJobFetchReturnNoJobs(); 449 450 static void MessageLoopQuitNowHelper(base::MessageLoop* message_loop); 451 static void MessageLoopQuitSoonHelper(base::MessageLoop* message_loop); 452 453 base::MessageLoopForIO loop_; 454 TestURLFetcherCallback url_callback_; 455 MockPrinterJobHandlerDelegate jobhandler_delegate_; 456 CloudPrintTokenStore token_store_; 457 CloudPrintURLFetcherNoServiceProcessFactory cloud_print_factory_; 458 scoped_refptr<PrinterJobHandler> job_handler_; 459 scoped_refptr<NiceMock<MockPrintSystem> > print_system_; 460 net::FakeURLFetcherFactory factory_; 461 printing::PrinterBasicInfo basic_info_; 462 printing::PrinterCapsAndDefaults caps_and_defaults_; 463 PrinterJobHandler::PrinterInfoFromCloud info_from_cloud_; 464}; 465 466 467void PrinterJobHandlerTest::SetUp() { 468 basic_info_.printer_name = kExamplePrinterName; 469 basic_info_.printer_description = kExamplePrinterDescription; 470 basic_info_.is_default = 0; 471 472 info_from_cloud_.printer_id = kExamplePrinterID; 473 info_from_cloud_.tags_hash = GetHashOfPrinterInfo(basic_info_); 474 475 info_from_cloud_.caps_hash = base::MD5String(kExamplePrinterCapabilities); 476 info_from_cloud_.current_xmpp_timeout = 300; 477 info_from_cloud_.pending_xmpp_timeout = 0; 478 479 caps_and_defaults_.printer_capabilities = kExamplePrinterCapabilities; 480 caps_and_defaults_.caps_mime_type = kExampleCapsMimeType; 481 caps_and_defaults_.printer_defaults = kExampleDefaults; 482 caps_and_defaults_.defaults_mime_type = kExampleDefaultMimeType; 483 484 print_system_ = new NiceMock<MockPrintSystem>(); 485 486 token_store_.SetToken(kExampleCloudPrintOAuthToken); 487 488 ON_CALL(print_system_->PrinterWatcher(), GetCurrentPrinterInfo(_)) 489 .WillByDefault(Invoke(this, &PrinterJobHandlerTest::GetPrinterInfo)); 490 491 ON_CALL(*print_system_.get(), GetPrinterCapsAndDefaults(_, _)) 492 .WillByDefault(Invoke(this, &PrinterJobHandlerTest::SendCapsAndDefaults)); 493 494 CloudPrintURLFetcher::set_factory(&cloud_print_factory_); 495} 496 497void PrinterJobHandlerTest::MakeJobFetchReturnNoJobs() { 498 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), 499 JobListResponse(0), net::HTTP_OK, 500 net::URLRequestStatus::SUCCESS); 501 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), 502 JobListResponse(0), net::HTTP_OK, 503 net::URLRequestStatus::SUCCESS); 504 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), 505 JobListResponse(0), net::HTTP_OK, 506 net::URLRequestStatus::SUCCESS); 507} 508 509void PrinterJobHandlerTest::MessageLoopQuitNowHelper( 510 base::MessageLoop* message_loop) { 511 message_loop->QuitWhenIdle(); 512} 513 514void PrinterJobHandlerTest::MessageLoopQuitSoonHelper( 515 base::MessageLoop* message_loop) { 516 message_loop->message_loop_proxy()->PostTask( 517 FROM_HERE, base::Bind(&MessageLoopQuitNowHelper, message_loop)); 518} 519 520PrinterJobHandlerTest::PrinterJobHandlerTest() 521 : factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, 522 base::Unretained(&url_callback_))) { 523} 524 525bool PrinterJobHandlerTest::PostSpoolSuccess() { 526 base::MessageLoop::current()->PostTask( 527 FROM_HERE, 528 base::Bind(&PrinterJobHandler::OnJobSpoolSucceeded, job_handler_, 0)); 529 530 // Everything that would be posted on the printer thread queue 531 // has been posted, we can tell the main message loop to quit when idle 532 // and not worry about it idling while the print thread does work 533 base::MessageLoop::current()->PostTask( 534 FROM_HERE, base::Bind(&MessageLoopQuitSoonHelper, &loop_)); 535 return true; 536} 537 538void PrinterJobHandlerTest::AddMimeHeader(const GURL& url, 539 net::FakeURLFetcher* fetcher) { 540 scoped_refptr<net::HttpResponseHeaders> download_headers = 541 new net::HttpResponseHeaders(kExampleJobDownloadResponseHeaders); 542 fetcher->set_response_headers(download_headers); 543} 544 545 546void PrinterJobHandlerTest::SetUpJobSuccessTest(int job_num) { 547 factory_.SetFakeResponse(TicketURI(job_num), 548 kExamplePrintTicket, net::HTTP_OK, 549 net::URLRequestStatus::SUCCESS); 550 factory_.SetFakeResponse(DownloadURI(job_num), 551 kExamplePrintData, net::HTTP_OK, 552 net::URLRequestStatus::SUCCESS); 553 554 factory_.SetFakeResponse(DoneURI(job_num), 555 StatusResponse(job_num, "DONE"), 556 net::HTTP_OK, 557 net::URLRequestStatus::SUCCESS); 558 factory_.SetFakeResponse(InProgressURI(job_num), 559 StatusResponse(job_num, "IN_PROGRESS"), 560 net::HTTP_OK, 561 net::URLRequestStatus::SUCCESS); 562 563 // The times requirement is relaxed for the ticket URI 564 // in order to accommodate TicketDownloadFailureTest 565 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(job_num), _)) 566 .Times(AtLeast(1)); 567 568 EXPECT_CALL(url_callback_, OnRequestCreate(DownloadURI(job_num), _)) 569 .Times(Exactly(1)) 570 .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddMimeHeader)); 571 572 EXPECT_CALL(url_callback_, OnRequestCreate(InProgressURI(job_num), _)) 573 .Times(Exactly(1)); 574 575 EXPECT_CALL(url_callback_, OnRequestCreate(DoneURI(job_num), _)) 576 .Times(Exactly(1)); 577 578 EXPECT_CALL(print_system_->JobSpooler(), 579 Spool(kExamplePrintTicket, _, _, _, _, _, _)) 580 .Times(Exactly(1)) 581 .WillOnce(InvokeWithoutArgs(this, 582 &PrinterJobHandlerTest::PostSpoolSuccess)); 583} 584 585void PrinterJobHandlerTest::BeginTest(int timeout_seconds) { 586 job_handler_ = new PrinterJobHandler(basic_info_, 587 info_from_cloud_, 588 GURL(kExampleCloudPrintServerURL), 589 print_system_.get(), 590 &jobhandler_delegate_); 591 592 job_handler_->Initialize(); 593 594 base::MessageLoop::current()->PostDelayedTask( 595 FROM_HERE, 596 base::Bind(&PrinterJobHandlerTest::MessageLoopQuitSoonHelper, 597 base::MessageLoop::current()), 598 base::TimeDelta::FromSeconds(timeout_seconds)); 599 600 base::MessageLoop::current()->Run(); 601} 602 603void PrinterJobHandlerTest::SendCapsAndDefaults( 604 const std::string& printer_name, 605 const PrintSystem::PrinterCapsAndDefaultsCallback& callback) { 606 callback.Run(true, printer_name, caps_and_defaults_); 607} 608 609bool PrinterJobHandlerTest::GetPrinterInfo(printing::PrinterBasicInfo* info) { 610 *info = basic_info_; 611 return true; 612} 613 614void PrinterJobHandlerTest::TearDown() { 615 IdleOut(); 616 CloudPrintURLFetcher::set_factory(NULL); 617} 618 619void PrinterJobHandlerTest::IdleOut() { 620 base::MessageLoop::current()->RunUntilIdle(); 621} 622 623MockPrintServerWatcher::MockPrintServerWatcher() : delegate_(NULL) { 624 ON_CALL(*this, StartWatching(_)) 625 .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true))); 626 ON_CALL(*this, StopWatching()).WillByDefault(Return(true)); 627} 628 629 630MockPrinterWatcher::MockPrinterWatcher() : delegate_(NULL) { 631 ON_CALL(*this, StartWatching(_)) 632 .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true))); 633 ON_CALL(*this, StopWatching()).WillByDefault(Return(true)); 634} 635 636MockJobSpooler::MockJobSpooler() : delegate_(NULL) { 637 ON_CALL(*this, Spool(_, _, _, _, _, _, _)) 638 .WillByDefault(DoAll(SaveArg<6>(&delegate_), Return(true))); 639} 640 641MockPrintSystem::MockPrintSystem() 642 : job_spooler_(new NiceMock<MockJobSpooler>()), 643 printer_watcher_(new NiceMock<MockPrinterWatcher>()), 644 print_server_watcher_(new NiceMock<MockPrintServerWatcher>()) { 645 ON_CALL(*this, CreateJobSpooler()).WillByDefault(Return(job_spooler_.get())); 646 647 ON_CALL(*this, CreatePrinterWatcher(_)) 648 .WillByDefault(Return(printer_watcher_.get())); 649 650 ON_CALL(*this, CreatePrintServerWatcher()) 651 .WillByDefault(Return(print_server_watcher_.get())); 652 653 ON_CALL(*this, IsValidPrinter(_)). 654 WillByDefault(Return(true)); 655 656 ON_CALL(*this, ValidatePrintTicket(_, _)). 657 WillByDefault(Return(true)); 658}; 659 660// This test simulates an end-to-end printing of a document 661// but tests only non-failure cases. 662// Disabled - http://crbug.com/184245 663TEST_F(PrinterJobHandlerTest, DISABLED_HappyPathTest) { 664 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), 665 JobListResponse(1), net::HTTP_OK, 666 net::URLRequestStatus::SUCCESS); 667 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), 668 JobListResponse(0), net::HTTP_OK, 669 net::URLRequestStatus::SUCCESS); 670 671 EXPECT_CALL(url_callback_, 672 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) 673 .Times(Exactly(1)); 674 EXPECT_CALL(url_callback_, 675 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) 676 .Times(Exactly(1)); 677 678 SetUpJobSuccessTest(1); 679 BeginTest(20); 680} 681 682TEST_F(PrinterJobHandlerTest, TicketDownloadFailureTest) { 683 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), 684 JobListResponse(2), net::HTTP_OK, 685 net::URLRequestStatus::SUCCESS); 686 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), 687 JobListResponse(2), net::HTTP_OK, 688 net::URLRequestStatus::SUCCESS); 689 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), 690 JobListResponse(0), net::HTTP_OK, 691 net::URLRequestStatus::SUCCESS); 692 factory_.SetFakeResponse(TicketURI(1), std::string(), 693 net::HTTP_INTERNAL_SERVER_ERROR, 694 net::URLRequestStatus::FAILED); 695 696 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _)) 697 .Times(AtLeast(1)); 698 699 EXPECT_CALL(url_callback_, 700 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) 701 .Times(AtLeast(1)); 702 703 EXPECT_CALL(url_callback_, 704 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) 705 .Times(AtLeast(1)); 706 707 EXPECT_CALL(url_callback_, 708 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) 709 .Times(AtLeast(1)); 710 711 SetUpJobSuccessTest(2); 712 BeginTest(20); 713} 714 715// TODO(noamsml): Figure out how to make this test not take 1 second and 716// re-enable it 717TEST_F(PrinterJobHandlerTest, DISABLED_ManyFailureTest) { 718 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), 719 JobListResponse(1), net::HTTP_OK, 720 net::URLRequestStatus::SUCCESS); 721 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), 722 JobListResponse(1), net::HTTP_OK, 723 net::URLRequestStatus::SUCCESS); 724 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), 725 JobListResponse(1), net::HTTP_OK, 726 net::URLRequestStatus::SUCCESS); 727 factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), 728 JobListResponse(0), net::HTTP_OK, 729 net::URLRequestStatus::SUCCESS); 730 731 EXPECT_CALL(url_callback_, 732 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) 733 .Times(AtLeast(1)); 734 735 EXPECT_CALL(url_callback_, 736 OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) 737 .Times(AtLeast(1)); 738 739 EXPECT_CALL(url_callback_, 740 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) 741 .Times(AtLeast(1)); 742 743 EXPECT_CALL(url_callback_, 744 OnRequestCreate(JobListURI(kJobFetchReasonRetry), _)) 745 .Times(AtLeast(1)); 746 747 SetUpJobSuccessTest(1); 748 749 factory_.SetFakeResponse(TicketURI(1), 750 std::string(), 751 net::HTTP_INTERNAL_SERVER_ERROR, 752 net::URLRequestStatus::FAILED); 753 754 loop_.PostDelayedTask(FROM_HERE, 755 base::Bind(&net::FakeURLFetcherFactory::SetFakeResponse, 756 base::Unretained(&factory_), 757 TicketURI(1), 758 kExamplePrintTicket, 759 net::HTTP_OK, 760 net::URLRequestStatus::SUCCESS), 761 base::TimeDelta::FromSeconds(1)); 762 763 764 BeginTest(5); 765} 766 767 768// TODO(noamsml): Figure out how to make this test not take ~64-~2048 (depending 769// constant values) seconds and re-enable it 770TEST_F(PrinterJobHandlerTest, DISABLED_CompleteFailureTest) { 771 factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), 772 JobListResponse(1), net::HTTP_OK, 773 net::URLRequestStatus::SUCCESS); 774 factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), 775 JobListResponse(1), net::HTTP_OK, 776 net::URLRequestStatus::SUCCESS); 777 factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), 778 JobListResponse(1), net::HTTP_OK, 779 net::URLRequestStatus::SUCCESS); 780 factory_.SetFakeResponse(ErrorURI(1), StatusResponse(1, "ERROR"), 781 net::HTTP_OK, net::URLRequestStatus::SUCCESS); 782 factory_.SetFakeResponse(TicketURI(1), std::string(), 783 net::HTTP_INTERNAL_SERVER_ERROR, 784 net::URLRequestStatus::FAILED); 785 786 EXPECT_CALL(url_callback_, 787 OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) 788 .Times(AtLeast(1)); 789 790 EXPECT_CALL(url_callback_, 791 OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) 792 .Times(AtLeast(1)); 793 794 EXPECT_CALL(url_callback_, 795 OnRequestCreate(JobListURI(kJobFetchReasonRetry), _)) 796 .Times(AtLeast(1)); 797 798 EXPECT_CALL(url_callback_, OnRequestCreate(ErrorURI(1), _)) 799 .Times(Exactly(1)) 800 .WillOnce(InvokeWithoutArgs( 801 this, &PrinterJobHandlerTest::MakeJobFetchReturnNoJobs)); 802 803 EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _)) 804 .Times(AtLeast(kNumRetriesBeforeAbandonJob)); 805 806 BeginTest(70); 807} 808 809} // namespace cloud_print 810