// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/files/file_path.h" #include "base/md5.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop_proxy.h" #include "base/strings/stringprintf.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "chrome/service/cloud_print/cloud_print_service_helpers.h" #include "chrome/service/cloud_print/cloud_print_token_store.h" #include "chrome/service/cloud_print/print_system.h" #include "chrome/service/cloud_print/printer_job_handler.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_status.h" #include "net/url_request/url_request_test_util.h" #include "printing/backend/print_backend.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using ::testing::AtLeast; using ::testing::DoAll; using ::testing::Exactly; using ::testing::Invoke; using ::testing::InvokeWithoutArgs; using ::testing::NiceMock; using ::testing::Return; using ::testing::SaveArg; using ::testing::Sequence; using ::testing::SetArgPointee; using ::testing::StrictMock; using ::testing::_; namespace cloud_print { namespace { using base::StringPrintf; const char kExampleCloudPrintServerURL[] = "https://www.google.com/cloudprint/"; const char kExamplePrintTicket[] = "{\"MediaType\":\"plain\"," "\"Resolution\":\"300x300dpi\",\"PageRegion\":\"Letter\"," "\"InputSlot\":\"auto\",\"PageSize\":\"Letter\",\"EconoMode\":\"off\"}"; // The fillowing constants will all be constructed with StringPrintf. The // following types of parameters are possible: // job number(int): ID # of job from given job list. All job IDs follow the // format __example_job_idN for some N. // fetch reason(string): Fetch reason used by the code. The job list URL // requested by PrinterJobHandler has an extra parameter that signifies when // the request was triggered. // status string(string): Status of print job, one of IN_PROGRESS, DONE or ERROR // job object list(string/JSON formatted): a comma-separated list of job objects // StringPrintf parameters: job number, job number, job number, job number const char kExampleJobObject[] = "{" " \"tags\": [" " \"^own\"" " ]," " \"printerName\": \"Example Printer\"," " \"status\": \"QUEUED\"," " \"ownerId\": \"sampleuser@gmail.com\"," " \"ticketUrl\": \"https://www.google.com/cloudprint/ticket?exampleURI%d\"," " \"printerid\": \"__example_printer_id\"," " \"printerType\": \"GOOGLE\"," " \"contentType\": \"text/html\"," " \"fileUrl\": \"https://www.google.com/cloudprint/download?exampleURI%d\"," " \"id\": \"__example_job_id%d\"," " \"message\": \"\"," " \"title\": \"Example Job %d\"," " \"errorCode\": \"\"," " \"numberOfPages\": 3" " }"; // StringPrintf parameters: job object list const char kExampleJobListResponse[] = "{" " \"success\": true," " \"jobs\": [" " %s" " ]," " \"xsrf_token\": \"AIp06DjUd3AV6BO0aujB9NvM2a9ZbogxOQ:1360021066932\"," " \"request\": {" " \"time\": \"0\"," " \"users\": [" " \"sampleuser@gmail.com\"" " ]," " \"params\": {" " \"printerid\": [" " \"__example_printer_id\"" " ]" " }," " \"user\": \"sampleuser@gmail.com\"" " }" "}"; // StringPrintf parameters: job number const char kExampleJobID[] = "__example_job_id%d"; // StringPrintf parameters: job number const char kExamplePrintTicketURI[] = "https://www.google.com/cloudprint/ticket?exampleURI%d"; // StringPrintf parameters: job number const char kExamplePrintDownloadURI[] = "https://www.google.com/cloudprint/download?exampleURI%d"; // StringPrintf parameters: job number const char kExampleUpdateDoneURI[] = "https://www.google.com/cloudprint/control?jobid=__example_job_id%d" "&status=DONE&code=0&message=&numpages=0&pagesprinted=0"; // StringPrintf parameters: job number const char kExampleUpdateErrorURI[] = "https://www.google.com/cloudprint/control?jobid=__example_job_id%d" "&status=ERROR"; // StringPrintf parameters: fetch reason const char kExamplePrinterJobListURI[] = "https://www.google.com/cloudprint/fetch" "?printerid=__example_printer_id&deb=%s"; // StringPrintf parameters: status string, job number, status string (repeat) const char kExampleControlResponse[] = "{" " \"success\": true," " \"message\": \"Print job updated successfully.\"," " \"xsrf_token\": \"AIp06DjKgbfGalbqzj23V1bU6i-vtR2B4w:1360023068789\"," " \"request\": {" " \"time\": \"0\"," " \"users\": [" " \"sampleuser@gmail.com\"" " ]," " \"params\": {" " \"xsrf\": [" " \"AIp06DgeGIETs42Cj28QWmxGPWVDiaXwVQ:1360023041852\"" " ]," " \"status\": [" " \"%s\"" " ]," " \"jobid\": [" " \"__example_job_id%d\"" " ]" " }," " \"user\": \"sampleuser@gmail.com\"" " }," " \"job\": {" " \"tags\": [" " \"^own\"" " ]," " \"printerName\": \"Example Printer\"," " \"status\": \"%s\"," " \"ownerId\": \"sampleuser@gmail.com\"," " \"ticketUrl\": \"https://www.google.com/cloudprint/ticket?exampleURI1\"," " \"printerid\": \"__example_printer_id\"," " \"contentType\": \"text/html\"," " \"fileUrl\": \"https://www.google.com/cloudprint/download?exampleURI1\"," " \"id\": \"__example_job_id1\"," " \"message\": \"\"," " \"title\": \"Example Job\"," " \"errorCode\": \"\"," " \"numberOfPages\": 3" " }" "}"; const char kExamplePrinterID[] = "__example_printer_id"; const char kExamplePrinterCapabilities[] = ""; const char kExampleCapsMimeType[] = ""; // These can stay empty const char kExampleDefaults[] = ""; const char kExampleDefaultMimeType[] = ""; // Since we're not connecting to the server, this can be any non-empty string. const char kExampleCloudPrintOAuthToken[] = "__SAMPLE_TOKEN"; // Not actually printing, no need for real PDF. const char kExamplePrintData[] = "__EXAMPLE_PRINT_DATA"; const char kExampleJobDownloadResponseHeaders[] = "Content-Type: Application/PDF\n"; const char kExampleTicketDownloadResponseHeaders[] = "Content-Type: application/json\n"; const char kExamplePrinterName[] = "Example Printer"; const char kExamplePrinterDescription[] = "Example Description"; // These are functions used to construct the various sample strings. std::string JobListResponse(int num_jobs) { std::string job_objects; for (int i = 0; i < num_jobs; i++) { job_objects = job_objects + StringPrintf(kExampleJobObject, i+1, i+1, i+1, i+1); if (i != num_jobs-1) job_objects = job_objects + ","; } return StringPrintf(kExampleJobListResponse, job_objects.c_str()); } GURL JobListURI(const char* reason) { return GURL(StringPrintf(kExamplePrinterJobListURI, reason)); } GURL DoneURI(int job_num) { return GURL(StringPrintf(kExampleUpdateDoneURI, job_num)); } GURL ErrorURI(int job_num) { return GURL(StringPrintf(kExampleUpdateErrorURI, job_num)); } GURL TicketURI(int job_num) { return GURL(StringPrintf(kExamplePrintTicketURI, job_num)); } GURL DownloadURI(int job_num) { return GURL(StringPrintf(kExamplePrintDownloadURI, job_num)); } GURL InProgressURI(int job_num) { return GetUrlForJobStatusUpdate(GURL(kExampleCloudPrintServerURL), StringPrintf(kExampleJobID, job_num), PRINT_JOB_STATUS_IN_PROGRESS, 0); } std::string StatusResponse(int job_num, const char* status_string) { return StringPrintf(kExampleControlResponse, status_string, job_num, status_string); } } // namespace class CloudPrintURLFetcherNoServiceProcess : public CloudPrintURLFetcher { public: CloudPrintURLFetcherNoServiceProcess() : context_getter_(new net::TestURLRequestContextGetter( base::MessageLoopProxy::current())) {} protected: virtual net::URLRequestContextGetter* GetRequestContextGetter() OVERRIDE { return context_getter_.get(); } virtual ~CloudPrintURLFetcherNoServiceProcess() {} private: scoped_refptr context_getter_; }; class CloudPrintURLFetcherNoServiceProcessFactory : public CloudPrintURLFetcherFactory { public: virtual CloudPrintURLFetcher* CreateCloudPrintURLFetcher() OVERRIDE { return new CloudPrintURLFetcherNoServiceProcess; } virtual ~CloudPrintURLFetcherNoServiceProcessFactory() {} }; // This class handles the callback from FakeURLFetcher // It is a separate class because callback methods must be // on RefCounted classes class TestURLFetcherCallback { public: scoped_ptr CreateURLFetcher( const GURL& url, net::URLFetcherDelegate* d, const std::string& response_data, net::HttpStatusCode response_code, net::URLRequestStatus::Status status) { scoped_ptr fetcher( new net::FakeURLFetcher(url, d, response_data, response_code, status)); OnRequestCreate(url, fetcher.get()); return fetcher.Pass(); } MOCK_METHOD2(OnRequestCreate, void(const GURL&, net::FakeURLFetcher*)); }; class MockPrinterJobHandlerDelegate : public PrinterJobHandler::Delegate { public: MOCK_METHOD0(OnAuthError, void()); MOCK_METHOD1(OnPrinterDeleted, void(const std::string& str)); virtual ~MockPrinterJobHandlerDelegate() {} }; class MockPrintServerWatcher : public PrintSystem::PrintServerWatcher { public: MOCK_METHOD1(StartWatching, bool(PrintSystem::PrintServerWatcher::Delegate* d)); MOCK_METHOD0(StopWatching, bool()); MockPrintServerWatcher(); PrintSystem::PrintServerWatcher::Delegate* delegate() const { return delegate_; } friend class scoped_refptr >; friend class scoped_refptr >; friend class scoped_refptr; protected: virtual ~MockPrintServerWatcher() {} private: PrintSystem::PrintServerWatcher::Delegate* delegate_; }; class MockPrinterWatcher : public PrintSystem::PrinterWatcher { public: MOCK_METHOD1(StartWatching, bool(PrintSystem::PrinterWatcher::Delegate* d)); MOCK_METHOD0(StopWatching, bool()); MOCK_METHOD1(GetCurrentPrinterInfo, bool(printing::PrinterBasicInfo* printer_info)); MockPrinterWatcher(); PrintSystem::PrinterWatcher::Delegate* delegate() const { return delegate_; } friend class scoped_refptr >; friend class scoped_refptr >; friend class scoped_refptr; protected: virtual ~MockPrinterWatcher() {} private: PrintSystem::PrinterWatcher::Delegate* delegate_; }; class MockJobSpooler : public PrintSystem::JobSpooler { public: MOCK_METHOD8(Spool, bool( const std::string& print_ticket, const std::string& print_ticket_mime_type, const base::FilePath& print_data_file_path, const std::string& print_data_mime_type, const std::string& printer_name, const std::string& job_title, const std::vector& tags, PrintSystem::JobSpooler::Delegate* delegate)); MockJobSpooler(); PrintSystem::JobSpooler::Delegate* delegate() const { return delegate_; } friend class scoped_refptr >; friend class scoped_refptr >; friend class scoped_refptr; protected: virtual ~MockJobSpooler() {} private: PrintSystem::JobSpooler::Delegate* delegate_; }; class MockPrintSystem : public PrintSystem { public: MockPrintSystem(); PrintSystem::PrintSystemResult succeed() { return PrintSystem::PrintSystemResult(true, "success"); } PrintSystem::PrintSystemResult fail() { return PrintSystem::PrintSystemResult(false, "failure"); } MockJobSpooler& JobSpooler() { return *job_spooler_.get(); } MockPrinterWatcher& PrinterWatcher() { return *printer_watcher_.get(); } MockPrintServerWatcher& PrintServerWatcher() { return *print_server_watcher_.get(); } MOCK_METHOD0(Init, PrintSystem::PrintSystemResult()); MOCK_METHOD1(EnumeratePrinters, PrintSystem::PrintSystemResult( printing::PrinterList* printer_list)); MOCK_METHOD2( GetPrinterCapsAndDefaults, void(const std::string& printer_name, const PrintSystem::PrinterCapsAndDefaultsCallback& callback)); MOCK_METHOD1(IsValidPrinter, bool(const std::string& printer_name)); MOCK_METHOD3(ValidatePrintTicket, bool(const std::string& printer_name, const std::string& print_ticket_data, const std::string& print_ticket_mime_type)); MOCK_METHOD3(GetJobDetails, bool(const std::string& printer_name, PlatformJobId job_id, PrintJobDetails* job_details)); MOCK_METHOD0(CreatePrintServerWatcher, PrintSystem::PrintServerWatcher*()); MOCK_METHOD1(CreatePrinterWatcher, PrintSystem::PrinterWatcher*(const std::string& printer_name)); MOCK_METHOD0(CreateJobSpooler, PrintSystem::JobSpooler*()); MOCK_METHOD0(GetSupportedMimeTypes, std::string()); friend class scoped_refptr >; friend class scoped_refptr >; friend class scoped_refptr; protected: virtual ~MockPrintSystem() {} private: scoped_refptr job_spooler_; scoped_refptr printer_watcher_; scoped_refptr print_server_watcher_; }; class PrinterJobHandlerTest : public ::testing::Test { public: PrinterJobHandlerTest(); virtual void SetUp() OVERRIDE; virtual void TearDown() OVERRIDE; void IdleOut(); bool GetPrinterInfo(printing::PrinterBasicInfo* info); void SendCapsAndDefaults( const std::string& printer_name, const PrintSystem::PrinterCapsAndDefaultsCallback& callback); void AddMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher); void AddTicketMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher); bool PostSpoolSuccess(); void SetUpJobSuccessTest(int job_num); void BeginTest(int timeout_seconds); void MakeJobFetchReturnNoJobs(); static void MessageLoopQuitNowHelper(base::MessageLoop* message_loop); static void MessageLoopQuitSoonHelper(base::MessageLoop* message_loop); base::MessageLoopForIO loop_; TestURLFetcherCallback url_callback_; MockPrinterJobHandlerDelegate jobhandler_delegate_; CloudPrintTokenStore token_store_; CloudPrintURLFetcherNoServiceProcessFactory cloud_print_factory_; scoped_refptr job_handler_; scoped_refptr > print_system_; net::FakeURLFetcherFactory factory_; printing::PrinterBasicInfo basic_info_; printing::PrinterCapsAndDefaults caps_and_defaults_; PrinterJobHandler::PrinterInfoFromCloud info_from_cloud_; }; void PrinterJobHandlerTest::SetUp() { basic_info_.printer_name = kExamplePrinterName; basic_info_.printer_description = kExamplePrinterDescription; basic_info_.is_default = 0; info_from_cloud_.printer_id = kExamplePrinterID; info_from_cloud_.tags_hash = GetHashOfPrinterInfo(basic_info_); info_from_cloud_.caps_hash = base::MD5String(kExamplePrinterCapabilities); info_from_cloud_.current_xmpp_timeout = 300; info_from_cloud_.pending_xmpp_timeout = 0; caps_and_defaults_.printer_capabilities = kExamplePrinterCapabilities; caps_and_defaults_.caps_mime_type = kExampleCapsMimeType; caps_and_defaults_.printer_defaults = kExampleDefaults; caps_and_defaults_.defaults_mime_type = kExampleDefaultMimeType; print_system_ = new NiceMock(); token_store_.SetToken(kExampleCloudPrintOAuthToken); ON_CALL(print_system_->PrinterWatcher(), GetCurrentPrinterInfo(_)) .WillByDefault(Invoke(this, &PrinterJobHandlerTest::GetPrinterInfo)); ON_CALL(*print_system_.get(), GetPrinterCapsAndDefaults(_, _)) .WillByDefault(Invoke(this, &PrinterJobHandlerTest::SendCapsAndDefaults)); CloudPrintURLFetcher::set_factory(&cloud_print_factory_); } void PrinterJobHandlerTest::MakeJobFetchReturnNoJobs() { factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); } void PrinterJobHandlerTest::MessageLoopQuitNowHelper( base::MessageLoop* message_loop) { message_loop->QuitWhenIdle(); } void PrinterJobHandlerTest::MessageLoopQuitSoonHelper( base::MessageLoop* message_loop) { message_loop->message_loop_proxy()->PostTask( FROM_HERE, base::Bind(&MessageLoopQuitNowHelper, message_loop)); } PrinterJobHandlerTest::PrinterJobHandlerTest() : factory_(NULL, base::Bind(&TestURLFetcherCallback::CreateURLFetcher, base::Unretained(&url_callback_))) { } bool PrinterJobHandlerTest::PostSpoolSuccess() { base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&PrinterJobHandler::OnJobSpoolSucceeded, job_handler_, 0)); // Everything that would be posted on the printer thread queue // has been posted, we can tell the main message loop to quit when idle // and not worry about it idling while the print thread does work base::MessageLoop::current()->PostTask( FROM_HERE, base::Bind(&MessageLoopQuitSoonHelper, &loop_)); return true; } void PrinterJobHandlerTest::AddMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher) { scoped_refptr download_headers = new net::HttpResponseHeaders(kExampleJobDownloadResponseHeaders); fetcher->set_response_headers(download_headers); } void PrinterJobHandlerTest::AddTicketMimeHeader(const GURL& url, net::FakeURLFetcher* fetcher) { scoped_refptr download_headers = new net::HttpResponseHeaders(kExampleTicketDownloadResponseHeaders); fetcher->set_response_headers(download_headers); } void PrinterJobHandlerTest::SetUpJobSuccessTest(int job_num) { factory_.SetFakeResponse(TicketURI(job_num), kExamplePrintTicket, net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(DownloadURI(job_num), kExamplePrintData, net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(DoneURI(job_num), StatusResponse(job_num, "DONE"), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(InProgressURI(job_num), StatusResponse(job_num, "IN_PROGRESS"), net::HTTP_OK, net::URLRequestStatus::SUCCESS); // The times requirement is relaxed for the ticket URI // in order to accommodate TicketDownloadFailureTest EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(job_num), _)) .Times(AtLeast(1)) .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddTicketMimeHeader)); EXPECT_CALL(url_callback_, OnRequestCreate(DownloadURI(job_num), _)) .Times(Exactly(1)) .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddMimeHeader)); EXPECT_CALL(url_callback_, OnRequestCreate(InProgressURI(job_num), _)) .Times(Exactly(1)); EXPECT_CALL(url_callback_, OnRequestCreate(DoneURI(job_num), _)) .Times(Exactly(1)); EXPECT_CALL(print_system_->JobSpooler(), Spool(kExamplePrintTicket, _, _, _, _, _, _, _)) .Times(Exactly(1)) .WillOnce(InvokeWithoutArgs(this, &PrinterJobHandlerTest::PostSpoolSuccess)); } void PrinterJobHandlerTest::BeginTest(int timeout_seconds) { job_handler_ = new PrinterJobHandler(basic_info_, info_from_cloud_, GURL(kExampleCloudPrintServerURL), print_system_.get(), &jobhandler_delegate_); job_handler_->Initialize(); base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&PrinterJobHandlerTest::MessageLoopQuitSoonHelper, base::MessageLoop::current()), base::TimeDelta::FromSeconds(timeout_seconds)); base::MessageLoop::current()->Run(); } void PrinterJobHandlerTest::SendCapsAndDefaults( const std::string& printer_name, const PrintSystem::PrinterCapsAndDefaultsCallback& callback) { callback.Run(true, printer_name, caps_and_defaults_); } bool PrinterJobHandlerTest::GetPrinterInfo(printing::PrinterBasicInfo* info) { *info = basic_info_; return true; } void PrinterJobHandlerTest::TearDown() { IdleOut(); CloudPrintURLFetcher::set_factory(NULL); } void PrinterJobHandlerTest::IdleOut() { base::MessageLoop::current()->RunUntilIdle(); } MockPrintServerWatcher::MockPrintServerWatcher() : delegate_(NULL) { ON_CALL(*this, StartWatching(_)) .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true))); ON_CALL(*this, StopWatching()).WillByDefault(Return(true)); } MockPrinterWatcher::MockPrinterWatcher() : delegate_(NULL) { ON_CALL(*this, StartWatching(_)) .WillByDefault(DoAll(SaveArg<0>(&delegate_), Return(true))); ON_CALL(*this, StopWatching()).WillByDefault(Return(true)); } MockJobSpooler::MockJobSpooler() : delegate_(NULL) { ON_CALL(*this, Spool(_, _, _, _, _, _, _, _)) .WillByDefault(DoAll(SaveArg<7>(&delegate_), Return(true))); } MockPrintSystem::MockPrintSystem() : job_spooler_(new NiceMock()), printer_watcher_(new NiceMock()), print_server_watcher_(new NiceMock()) { ON_CALL(*this, CreateJobSpooler()).WillByDefault(Return(job_spooler_.get())); ON_CALL(*this, CreatePrinterWatcher(_)) .WillByDefault(Return(printer_watcher_.get())); ON_CALL(*this, CreatePrintServerWatcher()) .WillByDefault(Return(print_server_watcher_.get())); ON_CALL(*this, IsValidPrinter(_)). WillByDefault(Return(true)); ON_CALL(*this, ValidatePrintTicket(_, _, _)). WillByDefault(Return(true)); }; // This test simulates an end-to-end printing of a document // but tests only non-failure cases. // Disabled - http://crbug.com/184245 TEST_F(PrinterJobHandlerTest, DISABLED_HappyPathTest) { factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) .Times(Exactly(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) .Times(Exactly(1)); SetUpJobSuccessTest(1); BeginTest(20); } TEST_F(PrinterJobHandlerTest, TicketDownloadFailureTest) { factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), JobListResponse(2), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), JobListResponse(2), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(TicketURI(1), std::string(), net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _)) .Times(AtLeast(1)) .WillOnce(Invoke(this, &PrinterJobHandlerTest::AddTicketMimeHeader)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) .Times(AtLeast(1)); SetUpJobSuccessTest(2); BeginTest(20); } // TODO(noamsml): Figure out how to make this test not take 1 second and // re-enable it TEST_F(PrinterJobHandlerTest, DISABLED_ManyFailureTest) { factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonQueryMore), JobListResponse(0), net::HTTP_OK, net::URLRequestStatus::SUCCESS); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonQueryMore), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonRetry), _)) .Times(AtLeast(1)); SetUpJobSuccessTest(1); factory_.SetFakeResponse(TicketURI(1), std::string(), net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); loop_.PostDelayedTask(FROM_HERE, base::Bind(&net::FakeURLFetcherFactory::SetFakeResponse, base::Unretained(&factory_), TicketURI(1), kExamplePrintTicket, net::HTTP_OK, net::URLRequestStatus::SUCCESS), base::TimeDelta::FromSeconds(1)); BeginTest(5); } // TODO(noamsml): Figure out how to make this test not take ~64-~2048 (depending // constant values) seconds and re-enable it TEST_F(PrinterJobHandlerTest, DISABLED_CompleteFailureTest) { factory_.SetFakeResponse(JobListURI(kJobFetchReasonStartup), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonFailure), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(JobListURI(kJobFetchReasonRetry), JobListResponse(1), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(ErrorURI(1), StatusResponse(1, "ERROR"), net::HTTP_OK, net::URLRequestStatus::SUCCESS); factory_.SetFakeResponse(TicketURI(1), std::string(), net::HTTP_INTERNAL_SERVER_ERROR, net::URLRequestStatus::FAILED); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonStartup), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonFailure), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(JobListURI(kJobFetchReasonRetry), _)) .Times(AtLeast(1)); EXPECT_CALL(url_callback_, OnRequestCreate(ErrorURI(1), _)) .Times(Exactly(1)) .WillOnce(InvokeWithoutArgs( this, &PrinterJobHandlerTest::MakeJobFetchReturnNoJobs)); EXPECT_CALL(url_callback_, OnRequestCreate(TicketURI(1), _)) .Times(AtLeast(kNumRetriesBeforeAbandonJob)); BeginTest(70); } } // namespace cloud_print