privet_http_unittest.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
1// Copyright 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/bind.h"
6#include "base/json/json_reader.h"
7#include "base/json/json_writer.h"
8#include "base/message_loop/message_loop.h"
9#include "chrome/browser/local_discovery/privet_http_impl.h"
10#include "net/base/host_port_pair.h"
11#include "net/base/net_errors.h"
12#include "net/url_request/test_url_fetcher_factory.h"
13#include "net/url_request/url_request_test_util.h"
14#include "printing/pwg_raster_settings.h"
15#include "testing/gmock/include/gmock/gmock.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18using testing::StrictMock;
19using testing::NiceMock;
20
21namespace local_discovery {
22
23namespace {
24
25const char kSampleInfoResponse[] = "{"
26    "       \"version\": \"1.0\","
27    "       \"name\": \"Common printer\","
28    "       \"description\": \"Printer connected through Chrome connector\","
29    "       \"url\": \"https://www.google.com/cloudprint\","
30    "       \"type\": ["
31    "               \"printer\""
32    "       ],"
33    "       \"id\": \"\","
34    "       \"device_state\": \"idle\","
35    "       \"connection_state\": \"online\","
36    "       \"manufacturer\": \"Google\","
37    "       \"model\": \"Google Chrome\","
38    "       \"serial_number\": \"1111-22222-33333-4444\","
39    "       \"firmware\": \"24.0.1312.52\","
40    "       \"uptime\": 600,"
41    "       \"setup_url\": \"http://support.google.com/\","
42    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
43    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
44    "       \"x-privet-token\": \"SampleTokenForTesting\","
45    "       \"api\": ["
46    "               \"/privet/accesstoken\","
47    "               \"/privet/capabilities\","
48    "               \"/privet/printer/submitdoc\","
49    "       ]"
50    "}";
51
52const char kSampleInfoResponseRegistered[] = "{"
53    "       \"version\": \"1.0\","
54    "       \"name\": \"Common printer\","
55    "       \"description\": \"Printer connected through Chrome connector\","
56    "       \"url\": \"https://www.google.com/cloudprint\","
57    "       \"type\": ["
58    "               \"printer\""
59    "       ],"
60    "       \"id\": \"MyDeviceID\","
61    "       \"device_state\": \"idle\","
62    "       \"connection_state\": \"online\","
63    "       \"manufacturer\": \"Google\","
64    "       \"model\": \"Google Chrome\","
65    "       \"serial_number\": \"1111-22222-33333-4444\","
66    "       \"firmware\": \"24.0.1312.52\","
67    "       \"uptime\": 600,"
68    "       \"setup_url\": \"http://support.google.com/\","
69    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
70    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
71    "       \"x-privet-token\": \"SampleTokenForTesting\","
72    "       \"api\": ["
73    "               \"/privet/accesstoken\","
74    "               \"/privet/capabilities\","
75    "               \"/privet/printer/submitdoc\","
76    "       ]"
77    "}";
78
79const char kSampleInfoResponseWithCreatejob[] = "{"
80    "       \"version\": \"1.0\","
81    "       \"name\": \"Common printer\","
82    "       \"description\": \"Printer connected through Chrome connector\","
83    "       \"url\": \"https://www.google.com/cloudprint\","
84    "       \"type\": ["
85    "               \"printer\""
86    "       ],"
87    "       \"id\": \"\","
88    "       \"device_state\": \"idle\","
89    "       \"connection_state\": \"online\","
90    "       \"manufacturer\": \"Google\","
91    "       \"model\": \"Google Chrome\","
92    "       \"serial_number\": \"1111-22222-33333-4444\","
93    "       \"firmware\": \"24.0.1312.52\","
94    "       \"uptime\": 600,"
95    "       \"setup_url\": \"http://support.google.com/\","
96    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
97    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
98    "       \"x-privet-token\": \"SampleTokenForTesting\","
99    "       \"api\": ["
100    "               \"/privet/accesstoken\","
101    "               \"/privet/capabilities\","
102    "               \"/privet/printer/createjob\","
103    "               \"/privet/printer/submitdoc\","
104    "       ]"
105    "}";
106
107const char kSampleRegisterStartResponse[] = "{"
108    "\"user\": \"example@google.com\","
109    "\"action\": \"start\""
110    "}";
111
112const char kSampleRegisterGetClaimTokenResponse[] = "{"
113    "       \"action\": \"getClaimToken\","
114    "       \"user\": \"example@google.com\","
115    "       \"token\": \"MySampleToken\","
116    "       \"claim_url\": \"https://domain.com/SoMeUrL\""
117    "}";
118
119const char kSampleRegisterCompleteResponse[] = "{"
120    "\"user\": \"example@google.com\","
121    "\"action\": \"complete\","
122    "\"device_id\": \"MyDeviceID\""
123    "}";
124
125const char kSampleXPrivetErrorResponse[] =
126    "{ \"error\": \"invalid_x_privet_token\" }";
127
128const char kSampleRegisterErrorTransient[] =
129    "{ \"error\": \"device_busy\", \"timeout\": 1}";
130
131const char kSampleRegisterErrorPermanent[] =
132    "{ \"error\": \"user_cancel\" }";
133
134const char kSampleInfoResponseBadJson[] = "{";
135
136const char kSampleRegisterCancelResponse[] = "{"
137    "\"user\": \"example@google.com\","
138    "\"action\": \"cancel\""
139    "}";
140
141const char kSampleLocalPrintResponse[] = "{"
142    "\"job_id\": \"123\","
143    "\"expires_in\": 500,"
144    "\"job_type\": \"application/pdf\","
145    "\"job_size\": 16,"
146    "\"job_name\": \"Sample job name\","
147    "}";
148
149const char kSampleCapabilitiesResponse[] = "{"
150    "\"version\" : \"1.0\","
151    "\"printer\" : {"
152    "  \"supported_content_type\" : ["
153    "   { \"content_type\" : \"application/pdf\" },"
154    "   { \"content_type\" : \"image/pwg-raster\" }"
155    "  ]"
156    "}"
157    "}";
158
159const char kSampleCapabilitiesResponsePWGOnly[] = "{"
160    "\"version\" : \"1.0\","
161    "\"printer\" : {"
162    "  \"supported_content_type\" : ["
163    "   { \"content_type\" : \"image/pwg-raster\" }"
164    "  ]"
165    "}"
166    "}";
167
168const char kSampleCapabilitiesResponseWithAnyMimetype[] = "{"
169    "\"version\" : \"1.0\","
170    "\"printer\" : {"
171    "  \"supported_content_type\" : ["
172    "   { \"content_type\" : \"*/*\" },"
173    "   { \"content_type\" : \"image/pwg-raster\" }"
174    "  ]"
175    "}"
176    "}";
177
178const char kSampleErrorResponsePrinterBusy[] = "{"
179    "\"error\": \"invalid_print_job\","
180    "\"timeout\": 1 "
181    "}";
182
183const char kSampleInvalidDocumentTypeResponse[] = "{"
184    "\"error\" : \"invalid_document_type\""
185    "}";
186
187const char kSampleCreatejobResponse[] = "{ \"job_id\": \"1234\" }";
188
189const char kSampleEmptyJSONResponse[] = "{}";
190
191const char kSampleCJT[] = "{ \"version\" : \"1.0\" }";
192
193const char kSampleCapabilitiesResponsePWGSettings[] =
194    "{"
195    "\"version\" : \"1.0\","
196    "\"printer\" : {"
197    " \"pwg_raster_config\" : {"
198    "   \"document_sheet_back\" : \"MANUAL_TUMBLE\","
199    "   \"reverse_order_streaming\": true"
200    "  },"
201    "  \"supported_content_type\" : ["
202    "   { \"content_type\" : \"image/pwg-raster\" }"
203    "  ]"
204    "}"
205    "}";
206
207const char kSampleCJTDuplex[] =
208    "{"
209    "\"version\" : \"1.0\","
210    "\"print\": { \"duplex\": {\"type\": \"SHORT_EDGE\"} }"
211    "}";
212
213const char kSampleCJTDuplexPWGSettings[] =
214    "{"
215    "\"version\" : \"1.0\","
216    "\"print\": {"
217    "  \"pwg_raster_config\" : {"
218    "    \"document_sheet_back\" : \"MANUAL_TUMBLE\","
219    "    \"reverse_order_streaming\": true"
220    "   },"
221    "  \"duplex\": {\"type\": \"SHORT_EDGE\"} }"
222    "}";
223
224// Return the representation of the given JSON that would be outputted by
225// JSONWriter. This ensures the same JSON values are represented by the same
226// string.
227std::string NormalizeJson(const std::string& json) {
228  std::string result = json;
229  scoped_ptr<base::Value> value(base::JSONReader::Read(result));
230  DCHECK(value);
231  base::JSONWriter::Write(value.get(), &result);
232  return result;
233}
234
235class MockTestURLFetcherFactoryDelegate
236    : public net::TestURLFetcher::DelegateForTests {
237 public:
238  // Callback issued correspondingly to the call to the |Start()| method.
239  MOCK_METHOD1(OnRequestStart, void(int fetcher_id));
240
241  // Callback issued correspondingly to the call to |AppendChunkToUpload|.
242  // Uploaded chunks can be retrieved with the |upload_chunks()| getter.
243  MOCK_METHOD1(OnChunkUpload, void(int fetcher_id));
244
245  // Callback issued correspondingly to the destructor.
246  MOCK_METHOD1(OnRequestEnd, void(int fetcher_id));
247};
248
249class PrivetHTTPTest : public ::testing::Test {
250 public:
251  PrivetHTTPTest() {
252    PrivetURLFetcher::ResetTokenMapForTests();
253
254    request_context_= new net::TestURLRequestContextGetter(
255        base::MessageLoopProxy::current());
256    privet_client_.reset(new PrivetHTTPClientImpl(
257        "sampleDevice._privet._tcp.local",
258        net::HostPortPair("10.0.0.8", 6006),
259        request_context_.get()));
260    fetcher_factory_.SetDelegateForTests(&fetcher_delegate_);
261  }
262
263  virtual ~PrivetHTTPTest() {
264  }
265
266  bool SuccessfulResponseToURL(const GURL& url,
267                               const std::string& response) {
268    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
269    EXPECT_TRUE(fetcher);
270    EXPECT_EQ(url, fetcher->GetOriginalURL());
271
272    if (!fetcher || url != fetcher->GetOriginalURL())
273      return false;
274
275    fetcher->SetResponseString(response);
276    fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
277                                              net::OK));
278    fetcher->set_response_code(200);
279    fetcher->delegate()->OnURLFetchComplete(fetcher);
280    return true;
281  }
282
283  bool SuccessfulResponseToURLAndData(const GURL& url,
284                                      const std::string& data,
285                                      const std::string& response) {
286    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
287    EXPECT_TRUE(fetcher);
288    EXPECT_EQ(url, fetcher->GetOriginalURL());
289
290    if (!fetcher) return false;
291
292    EXPECT_EQ(data, fetcher->upload_data());
293    if (data != fetcher->upload_data()) return false;
294
295    return SuccessfulResponseToURL(url, response);
296  }
297
298  bool SuccessfulResponseToURLAndJSONData(const GURL& url,
299                                          const std::string& data,
300                                          const std::string& response) {
301    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
302    EXPECT_TRUE(fetcher);
303    EXPECT_EQ(url, fetcher->GetOriginalURL());
304
305    if (!fetcher)
306      return false;
307
308    std::string normalized_data = NormalizeJson(data);
309    std::string normalized_upload_data = NormalizeJson(fetcher->upload_data());
310    EXPECT_EQ(normalized_data, normalized_upload_data);
311    if (normalized_data != normalized_upload_data)
312      return false;
313
314    return SuccessfulResponseToURL(url, response);
315  }
316
317  bool SuccessfulResponseToURLAndFilePath(const GURL& url,
318                                          const base::FilePath& file_path,
319                                          const std::string& response) {
320    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
321    EXPECT_TRUE(fetcher);
322    EXPECT_EQ(url, fetcher->GetOriginalURL());
323
324    if (!fetcher) return false;
325
326    EXPECT_EQ(file_path, fetcher->upload_file_path());
327    if (file_path != fetcher->upload_file_path()) return false;
328
329    return SuccessfulResponseToURL(url, response);
330  }
331
332
333  void RunFor(base::TimeDelta time_period) {
334    base::CancelableCallback<void()> callback(base::Bind(
335        &PrivetHTTPTest::Stop, base::Unretained(this)));
336    base::MessageLoop::current()->PostDelayedTask(
337        FROM_HERE, callback.callback(), time_period);
338
339    base::MessageLoop::current()->Run();
340    callback.Cancel();
341  }
342
343  void Stop() {
344    base::MessageLoop::current()->Quit();
345  }
346
347 protected:
348  base::MessageLoop loop_;
349  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
350  net::TestURLFetcherFactory fetcher_factory_;
351  scoped_ptr<PrivetHTTPClient> privet_client_;
352  NiceMock<MockTestURLFetcherFactoryDelegate> fetcher_delegate_;
353};
354
355class MockJSONCallback{
356 public:
357  MockJSONCallback() {}
358  ~MockJSONCallback() {}
359
360  void OnPrivetJSONDone(const base::DictionaryValue* value) {
361    if (!value) {
362      value_.reset();
363    } else {
364      value_.reset(value->DeepCopy());
365    }
366
367    OnPrivetJSONDoneInternal();
368  }
369
370  MOCK_METHOD0(OnPrivetJSONDoneInternal, void());
371
372  const base::DictionaryValue* value() { return value_.get(); }
373  PrivetJSONOperation::ResultCallback callback() {
374    return base::Bind(&MockJSONCallback::OnPrivetJSONDone,
375                      base::Unretained(this));
376  }
377 protected:
378  scoped_ptr<base::DictionaryValue> value_;
379};
380
381class MockRegisterDelegate : public PrivetRegisterOperation::Delegate {
382 public:
383  MockRegisterDelegate() {
384  }
385  ~MockRegisterDelegate() {
386  }
387
388  virtual void OnPrivetRegisterClaimToken(
389      PrivetRegisterOperation* operation,
390      const std::string& token,
391      const GURL& url) OVERRIDE {
392    OnPrivetRegisterClaimTokenInternal(token, url);
393  }
394
395  MOCK_METHOD2(OnPrivetRegisterClaimTokenInternal, void(
396      const std::string& token,
397      const GURL& url));
398
399  virtual void OnPrivetRegisterError(
400      PrivetRegisterOperation* operation,
401      const std::string& action,
402      PrivetRegisterOperation::FailureReason reason,
403      int printer_http_code,
404      const base::DictionaryValue* json) OVERRIDE {
405    // TODO(noamsml): Save and test for JSON?
406    OnPrivetRegisterErrorInternal(action, reason, printer_http_code);
407  }
408
409  MOCK_METHOD3(OnPrivetRegisterErrorInternal,
410               void(const std::string& action,
411                    PrivetRegisterOperation::FailureReason reason,
412                    int printer_http_code));
413
414  virtual void OnPrivetRegisterDone(
415      PrivetRegisterOperation* operation,
416      const std::string& device_id) OVERRIDE {
417    OnPrivetRegisterDoneInternal(device_id);
418  }
419
420  MOCK_METHOD1(OnPrivetRegisterDoneInternal,
421               void(const std::string& device_id));
422};
423
424class MockLocalPrintDelegate : public PrivetLocalPrintOperation::Delegate {
425 public:
426  MockLocalPrintDelegate() {}
427  ~MockLocalPrintDelegate() {}
428
429  virtual void OnPrivetPrintingDone(
430      const PrivetLocalPrintOperation* print_operation) {
431    OnPrivetPrintingDoneInternal();
432  }
433
434  MOCK_METHOD0(OnPrivetPrintingDoneInternal, void());
435
436  virtual void OnPrivetPrintingError(
437      const PrivetLocalPrintOperation* print_operation, int http_code) {
438    OnPrivetPrintingErrorInternal(http_code);
439  }
440
441  MOCK_METHOD1(OnPrivetPrintingErrorInternal, void(int http_code));
442};
443
444// A note on PWG raster conversion: The PWG raster converter used simply
445// converts strings to file paths based on them by appending "test.pdf", since
446// it's easier to test that way. Instead of using a mock, we simply check if the
447// request is uploading a file that is based on this pattern.
448class FakePWGRasterConverter : public PWGRasterConverter {
449 public:
450  FakePWGRasterConverter() {
451  }
452
453  virtual ~FakePWGRasterConverter() {
454  }
455
456  virtual void Start(base::RefCountedMemory* data,
457                     const printing::PdfRenderSettings& conversion_settings,
458                     const printing::PwgRasterSettings& bitmap_settings,
459                     const ResultCallback& callback) OVERRIDE {
460    bitmap_settings_ = bitmap_settings;
461    std::string data_str(data->front_as<char>(), data->size());
462    callback.Run(true, base::FilePath().AppendASCII(data_str + "test.pdf"));
463  }
464
465  const printing::PwgRasterSettings& bitmap_settings() {
466    return bitmap_settings_;
467  }
468
469 private:
470  printing::PwgRasterSettings bitmap_settings_;
471};
472
473TEST_F(PrivetHTTPTest, CreatePrivetStorageList) {
474  MockJSONCallback mock_callback;
475  scoped_ptr<PrivetJSONOperation> storage_list_operation =
476      privet_client_->CreateStorageListOperation(
477          "/path/to/nothing",
478          mock_callback.callback());
479  storage_list_operation->Start();
480
481  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
482                                      kSampleInfoResponse));
483
484  EXPECT_CALL(mock_callback, OnPrivetJSONDoneInternal());
485
486  EXPECT_TRUE(SuccessfulResponseToURL(
487      GURL("http://10.0.0.8:6006/privet/storage/list?path=/path/to/nothing"),
488      kSampleEmptyJSONResponse));
489}
490
491class PrivetInfoTest : public PrivetHTTPTest {
492 public:
493  PrivetInfoTest() {}
494
495  virtual ~PrivetInfoTest() {}
496
497  virtual void SetUp() OVERRIDE {
498    info_operation_ = privet_client_->CreateInfoOperation(
499        info_callback_.callback());
500  }
501
502 protected:
503  scoped_ptr<PrivetJSONOperation> info_operation_;
504  StrictMock<MockJSONCallback> info_callback_;
505};
506
507TEST_F(PrivetInfoTest, SuccessfulInfo) {
508  info_operation_->Start();
509
510  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
511  ASSERT_TRUE(fetcher != NULL);
512  EXPECT_EQ(GURL("http://10.0.0.8:6006/privet/info"),
513            fetcher->GetOriginalURL());
514
515  fetcher->SetResponseString(kSampleInfoResponse);
516  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
517                                            net::OK));
518  fetcher->set_response_code(200);
519
520  EXPECT_CALL(info_callback_, OnPrivetJSONDoneInternal());
521  fetcher->delegate()->OnURLFetchComplete(fetcher);
522};
523
524TEST_F(PrivetInfoTest, InfoFailureHTTP) {
525  info_operation_->Start();
526
527  net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
528  ASSERT_TRUE(fetcher != NULL);
529  fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
530                                            net::OK));
531  fetcher->set_response_code(404);
532
533  EXPECT_CALL(info_callback_, OnPrivetJSONDoneInternal());
534  fetcher->delegate()->OnURLFetchComplete(fetcher);
535};
536
537class PrivetRegisterTest : public PrivetHTTPTest {
538 public:
539  PrivetRegisterTest() {
540  }
541  virtual ~PrivetRegisterTest() {
542  }
543
544  virtual void SetUp() OVERRIDE {
545    info_operation_ = privet_client_->CreateInfoOperation(
546        info_callback_.callback());
547    register_operation_ =
548        privet_client_->CreateRegisterOperation("example@google.com",
549                                                &register_delegate_);
550  }
551
552 protected:
553  bool SuccessfulResponseToURL(const GURL& url,
554                               const std::string& response) {
555    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
556    EXPECT_TRUE(fetcher);
557    EXPECT_EQ(url, fetcher->GetOriginalURL());
558    if (!fetcher || url != fetcher->GetOriginalURL())
559      return false;
560
561    fetcher->SetResponseString(response);
562    fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
563                                              net::OK));
564    fetcher->set_response_code(200);
565    fetcher->delegate()->OnURLFetchComplete(fetcher);
566    return true;
567  }
568
569  scoped_ptr<PrivetJSONOperation> info_operation_;
570  NiceMock<MockJSONCallback> info_callback_;
571  scoped_ptr<PrivetRegisterOperation> register_operation_;
572  StrictMock<MockRegisterDelegate> register_delegate_;
573};
574
575TEST_F(PrivetRegisterTest, RegisterSuccessSimple) {
576  register_operation_->Start();
577
578  EXPECT_TRUE(SuccessfulResponseToURL(
579      GURL("http://10.0.0.8:6006/privet/info"),
580      kSampleInfoResponse));
581
582  EXPECT_TRUE(SuccessfulResponseToURL(
583      GURL("http://10.0.0.8:6006/privet/register?"
584           "action=start&user=example%40google.com"),
585      kSampleRegisterStartResponse));
586
587  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimTokenInternal(
588      "MySampleToken",
589      GURL("https://domain.com/SoMeUrL")));
590
591  EXPECT_TRUE(SuccessfulResponseToURL(
592      GURL("http://10.0.0.8:6006/privet/register?"
593           "action=getClaimToken&user=example%40google.com"),
594      kSampleRegisterGetClaimTokenResponse));
595
596  register_operation_->CompleteRegistration();
597
598  EXPECT_TRUE(SuccessfulResponseToURL(
599      GURL("http://10.0.0.8:6006/privet/register?"
600           "action=complete&user=example%40google.com"),
601      kSampleRegisterCompleteResponse));
602
603  EXPECT_CALL(register_delegate_, OnPrivetRegisterDoneInternal(
604      "MyDeviceID"));
605
606  EXPECT_TRUE(SuccessfulResponseToURL(
607      GURL("http://10.0.0.8:6006/privet/info"),
608      kSampleInfoResponseRegistered));
609}
610
611TEST_F(PrivetRegisterTest, RegisterXSRFFailure) {
612  register_operation_->Start();
613
614  EXPECT_TRUE(SuccessfulResponseToURL(
615      GURL("http://10.0.0.8:6006/privet/info"),
616      kSampleInfoResponse));
617
618  EXPECT_TRUE(SuccessfulResponseToURL(
619      GURL("http://10.0.0.8:6006/privet/register?"
620           "action=start&user=example%40google.com"),
621      kSampleRegisterStartResponse));
622
623  EXPECT_TRUE(SuccessfulResponseToURL(
624      GURL("http://10.0.0.8:6006/privet/register?"
625           "action=getClaimToken&user=example%40google.com"),
626      kSampleXPrivetErrorResponse));
627
628  EXPECT_TRUE(SuccessfulResponseToURL(
629      GURL("http://10.0.0.8:6006/privet/info"),
630      kSampleInfoResponse));
631
632  EXPECT_CALL(register_delegate_, OnPrivetRegisterClaimTokenInternal(
633      "MySampleToken", GURL("https://domain.com/SoMeUrL")));
634
635  EXPECT_TRUE(SuccessfulResponseToURL(
636      GURL("http://10.0.0.8:6006/privet/register?"
637           "action=getClaimToken&user=example%40google.com"),
638      kSampleRegisterGetClaimTokenResponse));
639}
640
641TEST_F(PrivetRegisterTest, TransientFailure) {
642  register_operation_->Start();
643
644  EXPECT_TRUE(SuccessfulResponseToURL(
645      GURL("http://10.0.0.8:6006/privet/info"),
646      kSampleInfoResponse));
647
648  EXPECT_TRUE(SuccessfulResponseToURL(
649      GURL("http://10.0.0.8:6006/privet/register?"
650           "action=start&user=example%40google.com"),
651      kSampleRegisterErrorTransient));
652
653  EXPECT_CALL(fetcher_delegate_, OnRequestStart(0));
654
655  RunFor(base::TimeDelta::FromSeconds(2));
656
657  testing::Mock::VerifyAndClearExpectations(&fetcher_delegate_);
658
659  EXPECT_TRUE(SuccessfulResponseToURL(
660      GURL("http://10.0.0.8:6006/privet/register?"
661           "action=start&user=example%40google.com"),
662      kSampleRegisterStartResponse));
663}
664
665TEST_F(PrivetRegisterTest, PermanentFailure) {
666  register_operation_->Start();
667
668  EXPECT_TRUE(SuccessfulResponseToURL(
669      GURL("http://10.0.0.8:6006/privet/info"),
670      kSampleInfoResponse));
671
672  EXPECT_TRUE(SuccessfulResponseToURL(
673      GURL("http://10.0.0.8:6006/privet/register?"
674           "action=start&user=example%40google.com"),
675      kSampleRegisterStartResponse));
676
677  EXPECT_CALL(register_delegate_,
678              OnPrivetRegisterErrorInternal(
679                  "getClaimToken",
680                  PrivetRegisterOperation::FAILURE_JSON_ERROR,
681                  200));
682
683  EXPECT_TRUE(SuccessfulResponseToURL(
684      GURL("http://10.0.0.8:6006/privet/register?"
685           "action=getClaimToken&user=example%40google.com"),
686      kSampleRegisterErrorPermanent));
687}
688
689TEST_F(PrivetRegisterTest, InfoFailure) {
690  register_operation_->Start();
691
692  EXPECT_CALL(register_delegate_,
693              OnPrivetRegisterErrorInternal(
694                  "start",
695                  PrivetRegisterOperation::FAILURE_TOKEN,
696                  -1));
697
698  EXPECT_TRUE(SuccessfulResponseToURL(
699      GURL("http://10.0.0.8:6006/privet/info"),
700      kSampleInfoResponseBadJson));
701}
702
703TEST_F(PrivetRegisterTest, RegisterCancel) {
704  register_operation_->Start();
705
706  EXPECT_TRUE(SuccessfulResponseToURL(
707      GURL("http://10.0.0.8:6006/privet/info"),
708      kSampleInfoResponse));
709
710  EXPECT_TRUE(SuccessfulResponseToURL(
711      GURL("http://10.0.0.8:6006/privet/register?"
712           "action=start&user=example%40google.com"),
713      kSampleRegisterStartResponse));
714
715  register_operation_->Cancel();
716
717  EXPECT_TRUE(SuccessfulResponseToURL(
718      GURL("http://10.0.0.8:6006/privet/register?"
719           "action=cancel&user=example%40google.com"),
720      kSampleRegisterCancelResponse));
721
722  // Must keep mocks alive for 3 seconds so the cancelation object can be
723  // deleted.
724  RunFor(base::TimeDelta::FromSeconds(3));
725}
726
727class PrivetCapabilitiesTest : public PrivetHTTPTest {
728 public:
729  PrivetCapabilitiesTest() {}
730
731  virtual ~PrivetCapabilitiesTest() {}
732
733  virtual void SetUp() OVERRIDE {
734    capabilities_operation_ = privet_client_->CreateCapabilitiesOperation(
735        capabilities_callback_.callback());
736  }
737
738 protected:
739  scoped_ptr<PrivetJSONOperation> capabilities_operation_;
740  StrictMock<MockJSONCallback> capabilities_callback_;
741};
742
743TEST_F(PrivetCapabilitiesTest, SuccessfulCapabilities) {
744  capabilities_operation_->Start();
745
746  EXPECT_TRUE(SuccessfulResponseToURL(
747      GURL("http://10.0.0.8:6006/privet/info"),
748      kSampleInfoResponse));
749
750  EXPECT_CALL(capabilities_callback_, OnPrivetJSONDoneInternal());
751
752  EXPECT_TRUE(SuccessfulResponseToURL(
753      GURL("http://10.0.0.8:6006/privet/capabilities"),
754      kSampleCapabilitiesResponse));
755
756  std::string version;
757  EXPECT_TRUE(capabilities_callback_.value()->GetString("version", &version));
758  EXPECT_EQ("1.0", version);
759};
760
761TEST_F(PrivetCapabilitiesTest, CacheToken) {
762  capabilities_operation_->Start();
763
764  EXPECT_TRUE(SuccessfulResponseToURL(
765      GURL("http://10.0.0.8:6006/privet/info"),
766      kSampleInfoResponse));
767
768  EXPECT_CALL(capabilities_callback_, OnPrivetJSONDoneInternal());
769
770  EXPECT_TRUE(SuccessfulResponseToURL(
771      GURL("http://10.0.0.8:6006/privet/capabilities"),
772      kSampleCapabilitiesResponse));
773
774  capabilities_operation_ = privet_client_->CreateCapabilitiesOperation(
775      capabilities_callback_.callback());
776
777  capabilities_operation_->Start();
778
779  EXPECT_CALL(capabilities_callback_, OnPrivetJSONDoneInternal());
780
781  EXPECT_TRUE(SuccessfulResponseToURL(
782      GURL("http://10.0.0.8:6006/privet/capabilities"),
783      kSampleCapabilitiesResponse));
784};
785
786TEST_F(PrivetCapabilitiesTest, BadToken) {
787  capabilities_operation_->Start();
788
789  EXPECT_TRUE(SuccessfulResponseToURL(
790      GURL("http://10.0.0.8:6006/privet/info"),
791      kSampleInfoResponse));
792
793  EXPECT_TRUE(SuccessfulResponseToURL(
794      GURL("http://10.0.0.8:6006/privet/capabilities"),
795      kSampleXPrivetErrorResponse));
796
797  EXPECT_TRUE(SuccessfulResponseToURL(
798      GURL("http://10.0.0.8:6006/privet/info"),
799      kSampleInfoResponse));
800
801  EXPECT_CALL(capabilities_callback_, OnPrivetJSONDoneInternal());
802
803  EXPECT_TRUE(SuccessfulResponseToURL(
804      GURL("http://10.0.0.8:6006/privet/capabilities"),
805      kSampleCapabilitiesResponse));
806};
807
808class PrivetLocalPrintTest : public PrivetHTTPTest {
809 public:
810  PrivetLocalPrintTest() {}
811
812  virtual ~PrivetLocalPrintTest() {}
813
814  virtual void SetUp() OVERRIDE {
815    PrivetURLFetcher::ResetTokenMapForTests();
816
817    local_print_operation_ = privet_client_->CreateLocalPrintOperation(
818        &local_print_delegate_);
819
820    scoped_ptr<FakePWGRasterConverter> pwg_converter(
821        new FakePWGRasterConverter);
822    pwg_converter_ = pwg_converter.get();
823    local_print_operation_->SetPWGRasterConverterForTesting(
824        pwg_converter.PassAs<PWGRasterConverter>());
825  }
826
827  scoped_refptr<base::RefCountedBytes> RefCountedBytesFromString(
828      std::string str) {
829    std::vector<unsigned char> str_vec;
830    str_vec.insert(str_vec.begin(), str.begin(), str.end());
831    return scoped_refptr<base::RefCountedBytes>(
832        base::RefCountedBytes::TakeVector(&str_vec));
833  }
834
835 protected:
836  scoped_ptr<PrivetLocalPrintOperation> local_print_operation_;
837  StrictMock<MockLocalPrintDelegate> local_print_delegate_;
838  FakePWGRasterConverter* pwg_converter_;
839};
840
841TEST_F(PrivetLocalPrintTest, SuccessfulLocalPrint) {
842  local_print_operation_->SetUsername("sample@gmail.com");
843  local_print_operation_->SetJobname("Sample job name");
844  local_print_operation_->SetData(RefCountedBytesFromString(
845      "Sample print data"));
846  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponse);
847  local_print_operation_->Start();
848
849  EXPECT_TRUE(SuccessfulResponseToURL(
850      GURL("http://10.0.0.8:6006/privet/info"),
851      kSampleInfoResponse));
852
853  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
854                                      kSampleInfoResponse));
855
856  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
857
858  // TODO(noamsml): Is encoding spaces as pluses standard?
859  EXPECT_TRUE(SuccessfulResponseToURLAndData(
860      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
861           "client_name=Chrome&user_name=sample%40gmail.com&"
862           "job_name=Sample+job+name"),
863      "Sample print data",
864      kSampleLocalPrintResponse));
865};
866
867TEST_F(PrivetLocalPrintTest, SuccessfulLocalPrintWithAnyMimetype) {
868  local_print_operation_->SetUsername("sample@gmail.com");
869  local_print_operation_->SetJobname("Sample job name");
870  local_print_operation_->SetData(
871      RefCountedBytesFromString("Sample print data"));
872  local_print_operation_->SetCapabilities(
873      kSampleCapabilitiesResponseWithAnyMimetype);
874  local_print_operation_->Start();
875
876  EXPECT_TRUE(SuccessfulResponseToURL(
877      GURL("http://10.0.0.8:6006/privet/info"),
878      kSampleInfoResponse));
879
880  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
881                                      kSampleInfoResponse));
882
883  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
884
885  // TODO(noamsml): Is encoding spaces as pluses standard?
886  EXPECT_TRUE(SuccessfulResponseToURLAndData(
887      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
888           "client_name=Chrome&user_name=sample%40gmail.com&"
889           "job_name=Sample+job+name"),
890      "Sample print data",
891      kSampleLocalPrintResponse));
892};
893
894TEST_F(PrivetLocalPrintTest, SuccessfulPWGLocalPrint) {
895  local_print_operation_->SetUsername("sample@gmail.com");
896  local_print_operation_->SetJobname("Sample job name");
897  local_print_operation_->SetData(
898      RefCountedBytesFromString("path/to/"));
899  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponsePWGOnly);
900  local_print_operation_->Start();
901
902  EXPECT_TRUE(SuccessfulResponseToURL(
903      GURL("http://10.0.0.8:6006/privet/info"),
904      kSampleInfoResponse));
905
906  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
907                                      kSampleInfoResponse));
908
909  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
910
911  // TODO(noamsml): Is encoding spaces as pluses standard?
912  EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
913      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
914           "client_name=Chrome&user_name=sample%40gmail.com"
915           "&job_name=Sample+job+name"),
916      base::FilePath(FILE_PATH_LITERAL("path/to/test.pdf")),
917      kSampleLocalPrintResponse));
918
919  EXPECT_EQ(printing::TRANSFORM_NORMAL,
920            pwg_converter_->bitmap_settings().odd_page_transform);
921  EXPECT_FALSE(pwg_converter_->bitmap_settings().rotate_all_pages);
922  EXPECT_FALSE(pwg_converter_->bitmap_settings().reverse_page_order);
923};
924
925TEST_F(PrivetLocalPrintTest, SuccessfulPWGLocalPrintDuplex) {
926  local_print_operation_->SetUsername("sample@gmail.com");
927  local_print_operation_->SetJobname("Sample job name");
928  local_print_operation_->SetData(RefCountedBytesFromString("path/to/"));
929  local_print_operation_->SetTicket(kSampleCJTDuplex);
930  local_print_operation_->SetCapabilities(
931      kSampleCapabilitiesResponsePWGSettings);
932  local_print_operation_->Start();
933
934  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
935                                      kSampleInfoResponseWithCreatejob));
936
937  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
938                                      kSampleInfoResponse));
939
940  EXPECT_TRUE(SuccessfulResponseToURLAndJSONData(
941      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
942      kSampleCJTDuplexPWGSettings,
943      kSampleCreatejobResponse));
944
945  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
946
947  // TODO(noamsml): Is encoding spaces as pluses standard?
948  EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
949      GURL(
950          "http://10.0.0.8:6006/privet/printer/submitdoc?"
951          "client_name=Chrome&user_name=sample%40gmail.com"
952          "&job_name=Sample+job+name&job_id=1234"),
953      base::FilePath(FILE_PATH_LITERAL("path/to/test.pdf")),
954      kSampleLocalPrintResponse));
955
956  EXPECT_EQ(printing::TRANSFORM_ROTATE_180,
957            pwg_converter_->bitmap_settings().odd_page_transform);
958  EXPECT_FALSE(pwg_converter_->bitmap_settings().rotate_all_pages);
959  EXPECT_TRUE(pwg_converter_->bitmap_settings().reverse_page_order);
960};
961
962TEST_F(PrivetLocalPrintTest, SuccessfulLocalPrintWithCreatejob) {
963  local_print_operation_->SetUsername("sample@gmail.com");
964  local_print_operation_->SetJobname("Sample job name");
965  local_print_operation_->SetTicket(kSampleCJT);
966  local_print_operation_->SetData(
967      RefCountedBytesFromString("Sample print data"));
968  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponse);
969  local_print_operation_->Start();
970
971  EXPECT_TRUE(SuccessfulResponseToURL(
972      GURL("http://10.0.0.8:6006/privet/info"),
973      kSampleInfoResponseWithCreatejob));
974
975  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
976                                      kSampleInfoResponse));
977
978  EXPECT_TRUE(SuccessfulResponseToURLAndJSONData(
979      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
980      kSampleCJT,
981      kSampleCreatejobResponse));
982
983  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
984
985  // TODO(noamsml): Is encoding spaces as pluses standard?
986  EXPECT_TRUE(SuccessfulResponseToURLAndData(
987      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
988           "client_name=Chrome&user_name=sample%40gmail.com&"
989           "job_name=Sample+job+name&job_id=1234"),
990      "Sample print data",
991      kSampleLocalPrintResponse));
992};
993
994TEST_F(PrivetLocalPrintTest, SuccessfulLocalPrintWithOverlongName) {
995  local_print_operation_->SetUsername("sample@gmail.com");
996  local_print_operation_->SetJobname(
997      "123456789:123456789:123456789:123456789:123456789:123456789:123456789:");
998  local_print_operation_->SetTicket(kSampleCJT);
999  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponse);
1000  local_print_operation_->SetData(
1001      RefCountedBytesFromString("Sample print data"));
1002  local_print_operation_->Start();
1003
1004  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
1005                                      kSampleInfoResponseWithCreatejob));
1006
1007  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
1008                                      kSampleInfoResponse));
1009
1010  EXPECT_TRUE(SuccessfulResponseToURLAndJSONData(
1011      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
1012      kSampleCJT,
1013      kSampleCreatejobResponse));
1014
1015  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
1016
1017  // TODO(noamsml): Is encoding spaces as pluses standard?
1018  EXPECT_TRUE(SuccessfulResponseToURLAndData(
1019      GURL(
1020          "http://10.0.0.8:6006/privet/printer/submitdoc?"
1021          "client_name=Chrome&user_name=sample%40gmail.com&"
1022          "job_name=123456789%3A123456789%3A123456789%3A1...123456789"
1023          "%3A123456789%3A123456789%3A&job_id=1234"),
1024      "Sample print data",
1025      kSampleLocalPrintResponse));
1026};
1027
1028TEST_F(PrivetLocalPrintTest, PDFPrintInvalidDocumentTypeRetry) {
1029  local_print_operation_->SetUsername("sample@gmail.com");
1030  local_print_operation_->SetJobname("Sample job name");
1031  local_print_operation_->SetTicket(kSampleCJT);
1032  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponse);
1033  local_print_operation_->SetData(
1034      RefCountedBytesFromString("sample/path/"));
1035  local_print_operation_->Start();
1036
1037  EXPECT_TRUE(SuccessfulResponseToURL(
1038      GURL("http://10.0.0.8:6006/privet/info"),
1039      kSampleInfoResponseWithCreatejob));
1040
1041  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
1042                                      kSampleInfoResponse));
1043
1044  EXPECT_TRUE(SuccessfulResponseToURLAndJSONData(
1045      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
1046      kSampleCJT,
1047      kSampleCreatejobResponse));
1048
1049  // TODO(noamsml): Is encoding spaces as pluses standard?
1050  EXPECT_TRUE(SuccessfulResponseToURLAndData(
1051      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
1052           "client_name=Chrome&user_name=sample%40gmail.com&"
1053           "job_name=Sample+job+name&job_id=1234"),
1054      "sample/path/",
1055      kSampleInvalidDocumentTypeResponse));
1056
1057  EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
1058
1059  EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
1060      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
1061           "client_name=Chrome&user_name=sample%40gmail.com&"
1062           "job_name=Sample+job+name&job_id=1234"),
1063      base::FilePath(FILE_PATH_LITERAL("sample/path/test.pdf")),
1064      kSampleLocalPrintResponse));
1065};
1066
1067TEST_F(PrivetLocalPrintTest, LocalPrintRetryOnInvalidJobID) {
1068  local_print_operation_->SetUsername("sample@gmail.com");
1069  local_print_operation_->SetJobname("Sample job name");
1070  local_print_operation_->SetTicket(kSampleCJT);
1071  local_print_operation_->SetCapabilities(kSampleCapabilitiesResponse);
1072  local_print_operation_->SetData(
1073      RefCountedBytesFromString("Sample print data"));
1074  local_print_operation_->Start();
1075
1076  EXPECT_TRUE(SuccessfulResponseToURL(
1077      GURL("http://10.0.0.8:6006/privet/info"),
1078      kSampleInfoResponseWithCreatejob));
1079
1080  EXPECT_TRUE(SuccessfulResponseToURL(GURL("http://10.0.0.8:6006/privet/info"),
1081                                      kSampleInfoResponse));
1082
1083  EXPECT_TRUE(SuccessfulResponseToURLAndJSONData(
1084      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
1085      kSampleCJT,
1086      kSampleCreatejobResponse));
1087
1088  EXPECT_TRUE(SuccessfulResponseToURLAndData(
1089      GURL("http://10.0.0.8:6006/privet/printer/submitdoc?"
1090           "client_name=Chrome&user_name=sample%40gmail.com&"
1091           "job_name=Sample+job+name&job_id=1234"),
1092      "Sample print data",
1093      kSampleErrorResponsePrinterBusy));
1094
1095  RunFor(base::TimeDelta::FromSeconds(3));
1096
1097  EXPECT_TRUE(SuccessfulResponseToURL(
1098      GURL("http://10.0.0.8:6006/privet/printer/createjob"),
1099      kSampleCreatejobResponse));
1100};
1101
1102
1103}  // namespace
1104
1105}  // namespace local_discovery
1106