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