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