Home | History | Annotate | Download | only in cloud_print
      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