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