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/message_loop/message_loop.h"
6#include "chrome/browser/local_discovery/privet_local_printer_lister.h"
7#include "chrome/browser/local_discovery/test_service_discovery_client.h"
8#include "net/url_request/test_url_fetcher_factory.h"
9#include "net/url_request/url_request_test_util.h"
10
11#include "testing/gmock/include/gmock/gmock.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14using testing::StrictMock;
15using testing::AtLeast;
16using testing::_;
17
18namespace local_discovery {
19
20namespace {
21
22const uint8 kAnnouncePacket[] = {
23    // Header
24    0x00, 0x00,  // ID is zeroed out
25    0x80, 0x00,  // Standard query response, no error
26    0x00, 0x00,  // No questions (for simplicity)
27    0x00, 0x05,  // 5 RR (answers)
28    0x00, 0x00,  // 0 authority RRs
29    0x00, 0x00,  // 0 additional RRs
30    0x07, '_',  'p',  'r',  'i',  'v',  'e',  't',  0x04, '_',
31    't',  'c',  'p',  0x05, 'l',  'o',  'c',  'a',  'l',  0x00,
32    0x00, 0x0c,              // TYPE is PTR.
33    0x00, 0x01,              // CLASS is IN.
34    0x00, 0x00,              // TTL (4 bytes) is 32768 second.
35    0x10, 0x00, 0x00, 0x0c,  // RDLENGTH is 12 bytes.
36    0x09, 'm',  'y',  'S',  'e',  'r',  'v',  'i',  'c',  'e',
37    0xc0, 0x0c, 0x09, 'm',  'y',  'S',  'e',  'r',  'v',  'i',
38    'c',  'e',  0xc0, 0x0c, 0x00, 0x10,  // TYPE is TXT.
39    0x00, 0x01,                          // CLASS is IN.
40    0x00, 0x00,                          // TTL (4 bytes) is 32768 seconds.
41    0x01, 0x00, 0x00, 0x44,              // RDLENGTH is 55 bytes.
42    0x06, 'i',  'd',  '=',  'r',  'e',  'g',  0x10, 't',  'y',
43    '=',  'S',  'a',  'm',  'p',  'l',  'e',  ' ',  'd',  'e',
44    'v',  'i',  'c',  'e',  0x1e, 'n',  'o',  't',  'e',  '=',
45    'S',  'a',  'm',  'p',  'l',  'e',  ' ',  'd',  'e',  'v',
46    'i',  'c',  'e',  ' ',  'd',  'e',  's',  'c',  'r',  'i',
47    'p',  't',  'i',  'o',  'n',  0x0c, 't',  'y',  'p',  'e',
48    '=',  'p',  'r',  'i',  'n',  't',  'e',  'r',  0x09, 'm',
49    'y',  'S',  'e',  'r',  'v',  'i',  'c',  'e',  0xc0, 0x0c,
50    0x00, 0x21,                          // Type is SRV
51    0x00, 0x01,                          // CLASS is IN
52    0x00, 0x00,                          // TTL (4 bytes) is 32768 second.
53    0x10, 0x00, 0x00, 0x17,              // RDLENGTH is 23
54    0x00, 0x00, 0x00, 0x00, 0x22, 0xb8,  // port 8888
55    0x09, 'm',  'y',  'S',  'e',  'r',  'v',  'i',  'c',  'e',
56    0x05, 'l',  'o',  'c',  'a',  'l',  0x00, 0x09, 'm',  'y',
57    'S',  'e',  'r',  'v',  'i',  'c',  'e',  0x05, 'l',  'o',
58    'c',  'a',  'l',  0x00, 0x00, 0x01,  // Type is A
59    0x00, 0x01,                          // CLASS is IN
60    0x00, 0x00,                          // TTL (4 bytes) is 32768 second.
61    0x10, 0x00, 0x00, 0x04,              // RDLENGTH is 4
62    0x01, 0x02, 0x03, 0x04,              // 1.2.3.4
63    0x09, 'm',  'y',  'S',  'e',  'r',  'v',  'i',  'c',  'e',
64    0x05, 'l',  'o',  'c',  'a',  'l',  0x00, 0x00, 0x1C,  // Type is AAAA
65    0x00, 0x01,                                            // CLASS is IN
66    0x00, 0x00,              // TTL (4 bytes) is 32768 second.
67    0x10, 0x00, 0x00, 0x10,  // RDLENGTH is 16
68    0x01, 0x02, 0x03, 0x04,  // 1.2.3.4
69    0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
70    0x03, 0x04, };
71
72const char kInfoIsLocalPrinter[] = "{"
73    "\"api\" : [ \"/privet/printer/submitdoc\" ],"
74    "\"x-privet-token\" : \"sample\""
75    "}";
76
77const char kInfoIsNotLocalPrinter[] = "{"
78    "\"api\" : [ \"/privet/register\" ],"
79    "\"x-privet-token\" : \"sample\""
80    "}";
81
82const char kServiceName[] = "myService._privet._tcp.local";
83
84const char kPrivetInfoURL[] = "http://1.2.3.4:8888/privet/info";
85
86class MockLocalPrinterListerDelegate
87    : public PrivetLocalPrinterLister::Delegate {
88 public:
89  MockLocalPrinterListerDelegate() {
90  }
91
92  virtual ~MockLocalPrinterListerDelegate() {
93  }
94
95  MOCK_METHOD4(LocalPrinterChanged, void(bool added,
96                                         const std::string& name,
97                                         bool has_local_printing,
98                                         const DeviceDescription& description));
99
100  MOCK_METHOD1(LocalPrinterRemoved, void(const std::string& name));
101
102  MOCK_METHOD0(LocalPrinterCacheFlushed, void());
103};
104
105class PrivetLocalPrinterListerTest : public testing::Test {
106 public:
107  PrivetLocalPrinterListerTest() {
108    test_service_discovery_client_ = new TestServiceDiscoveryClient();
109    test_service_discovery_client_->Start();
110    url_request_context_ = new net::TestURLRequestContextGetter(
111        base::MessageLoopProxy::current());
112    local_printer_lister_.reset(new PrivetLocalPrinterLister(
113        test_service_discovery_client_.get(),
114        url_request_context_.get(),
115        &delegate_));
116  }
117
118  ~PrivetLocalPrinterListerTest() {
119  }
120
121  bool SuccessfulResponseToURL(const GURL& url,
122                               const std::string& response) {
123    net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
124    EXPECT_TRUE(fetcher);
125    EXPECT_EQ(url, fetcher->GetOriginalURL());
126
127    if (!fetcher || url != fetcher->GetOriginalURL())
128      return false;
129
130    fetcher->SetResponseString(response);
131    fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::SUCCESS,
132                                              net::OK));
133    fetcher->set_response_code(200);
134    fetcher->delegate()->OnURLFetchComplete(fetcher);
135    return true;
136  }
137
138  void SimulateReceive(const uint8* packet, size_t size) {
139    test_service_discovery_client_->SimulateReceive(packet, size);
140    message_loop_.RunUntilIdle();
141  }
142
143  void ExpectAnyPacket() {
144    EXPECT_CALL(*test_service_discovery_client_.get(), OnSendTo(_))
145        .Times(AtLeast(2));
146  }
147
148 protected:
149  base::MessageLoop message_loop_;
150  scoped_refptr<TestServiceDiscoveryClient> test_service_discovery_client_;
151  scoped_refptr<net::TestURLRequestContextGetter> url_request_context_;
152  scoped_ptr<PrivetLocalPrinterLister> local_printer_lister_;
153  net::TestURLFetcherFactory fetcher_factory_;
154  StrictMock<MockLocalPrinterListerDelegate> delegate_;
155};
156
157TEST_F(PrivetLocalPrinterListerTest, PrinterAddedTest) {
158  ExpectAnyPacket();
159
160  local_printer_lister_->Start();
161
162  SimulateReceive(kAnnouncePacket, sizeof(kAnnouncePacket));
163
164  EXPECT_CALL(delegate_, LocalPrinterChanged(true, kServiceName, true, _));
165
166  EXPECT_TRUE(SuccessfulResponseToURL(
167      GURL(kPrivetInfoURL),
168      std::string(kInfoIsLocalPrinter)));
169};
170
171TEST_F(PrivetLocalPrinterListerTest, NonPrinterAddedTest) {
172  ExpectAnyPacket();
173
174  local_printer_lister_->Start();
175
176  SimulateReceive(kAnnouncePacket, sizeof(kAnnouncePacket));
177
178  EXPECT_CALL(delegate_, LocalPrinterChanged(true, kServiceName, false, _));
179
180  EXPECT_TRUE(SuccessfulResponseToURL(
181      GURL(kPrivetInfoURL),
182      std::string(kInfoIsNotLocalPrinter)));
183};
184
185}  // namespace
186
187}  // namespace local_discovery
188