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 "chrome/browser/local_discovery/privet_device_lister_impl.h"
7#include "testing/gmock/include/gmock/gmock.h"
8#include "testing/gtest/include/gtest/gtest.h"
9
10using testing::SaveArg;
11using testing::_;
12
13namespace local_discovery {
14
15namespace {
16
17class MockServiceResolver;
18class MockServiceWatcher;
19
20class ServiceDiscoveryMockDelegate {
21 public:
22  virtual void ServiceWatcherStarted(const std::string& service_type,
23                                     MockServiceWatcher* watcher) = 0;
24  virtual void ServiceResolverStarted(const std::string& service_type,
25                                      MockServiceResolver* resolver) = 0;
26};
27
28class MockServiceWatcher : public ServiceWatcher {
29 public:
30  MockServiceWatcher(const std::string& service_type,
31                     const ServiceWatcher::UpdatedCallback& callback,
32                     ServiceDiscoveryMockDelegate* mock_delegate)
33      : started_(false), service_type_(service_type),  callback_(callback),
34        mock_delegate_(mock_delegate) {
35  }
36
37  virtual ~MockServiceWatcher() {
38  }
39
40  virtual void Start() {
41    DCHECK(!started_);
42    started_ = true;
43    mock_delegate_->ServiceWatcherStarted(service_type_, this);
44  }
45
46  MOCK_METHOD1(DiscoverNewServices, void(bool force_update));
47
48  MOCK_METHOD1(SetActivelyRefreshServices, void(
49      bool actively_refresh_services));
50
51  virtual std::string GetServiceType() const {
52    return service_type_;
53  }
54
55  bool started() {
56    return started_;
57  }
58
59  ServiceWatcher::UpdatedCallback callback() {
60    return callback_;
61  }
62
63 private:
64  bool started_;
65  std::string service_type_;
66  ServiceWatcher::UpdatedCallback callback_;
67  ServiceDiscoveryMockDelegate* mock_delegate_;
68};
69
70class MockServiceResolver : public ServiceResolver {
71 public:
72  MockServiceResolver(const std::string& service_name,
73                      const ServiceResolver::ResolveCompleteCallback& callback,
74                      ServiceDiscoveryMockDelegate* mock_delegate)
75      : started_resolving_(false), service_name_(service_name),
76        callback_(callback), mock_delegate_(mock_delegate) {
77  }
78
79  virtual ~MockServiceResolver() {
80  }
81
82  virtual void StartResolving() OVERRIDE {
83    started_resolving_ = true;
84    mock_delegate_->ServiceResolverStarted(service_name_, this);
85  }
86
87  bool IsResolving() const {
88    return started_resolving_;
89  }
90
91  virtual std::string GetName() const OVERRIDE {
92    return service_name_;
93  }
94
95  const ServiceResolver::ResolveCompleteCallback& callback() {
96    return callback_; }
97
98 private:
99  bool started_resolving_;
100  std::string service_name_;
101  ServiceResolver::ResolveCompleteCallback callback_;
102  ServiceDiscoveryMockDelegate* mock_delegate_;
103};
104
105class MockServiceDiscoveryClient : public ServiceDiscoveryClient {
106 public:
107  explicit MockServiceDiscoveryClient(
108      ServiceDiscoveryMockDelegate* mock_delegate)
109      : mock_delegate_(mock_delegate) {
110  }
111
112  virtual ~MockServiceDiscoveryClient() {
113  }
114
115  // Create a service watcher object listening for DNS-SD service announcements
116  // on service type |service_type|.
117  virtual scoped_ptr<ServiceWatcher> CreateServiceWatcher(
118      const std::string& service_type,
119      const ServiceWatcher::UpdatedCallback& callback) OVERRIDE {
120    scoped_ptr<MockServiceWatcher> mock_service_watcher(
121        new MockServiceWatcher(service_type, callback, mock_delegate_));
122    return mock_service_watcher.PassAs<ServiceWatcher>();
123  }
124
125  // Create a service resolver object for getting detailed service information
126  // for the service called |service_name|.
127  virtual scoped_ptr<ServiceResolver> CreateServiceResolver(
128      const std::string& service_name,
129      const ServiceResolver::ResolveCompleteCallback& callback) OVERRIDE {
130    scoped_ptr<MockServiceResolver> mock_service_resolver(
131        new MockServiceResolver(service_name, callback, mock_delegate_));
132    return mock_service_resolver.PassAs<ServiceResolver>();
133  }
134
135  // Not used in this test.
136  virtual scoped_ptr<LocalDomainResolver> CreateLocalDomainResolver(
137    const std::string& domain,
138    net::AddressFamily address_family,
139    const LocalDomainResolver::IPAddressCallback& callback) OVERRIDE {
140    NOTREACHED();
141    return scoped_ptr<LocalDomainResolver>();
142  }
143
144 private:
145  ServiceDiscoveryMockDelegate* mock_delegate_;
146};
147
148class MockServiceDiscoveryMockDelegate : public ServiceDiscoveryMockDelegate {
149 public:
150  MOCK_METHOD2(ServiceWatcherStarted, void(const std::string& service_type,
151                                           MockServiceWatcher* watcher));
152  MOCK_METHOD2(ServiceResolverStarted, void(const std::string& service_type,
153                                            MockServiceResolver* resolver));
154};
155
156class MockDeviceListerDelegate : public PrivetDeviceLister::Delegate {
157 public:
158  MockDeviceListerDelegate() {
159  }
160
161  virtual ~MockDeviceListerDelegate() {
162  }
163
164  MOCK_METHOD3(DeviceChanged, void(bool added,
165                                   const std::string& name,
166                                   const DeviceDescription& description));
167
168  MOCK_METHOD1(DeviceRemoved, void(const std::string& name));
169
170  MOCK_METHOD0(DeviceCacheFlushed, void());
171};
172
173class PrivetDeviceListerTest : public testing::Test {
174 public:
175  PrivetDeviceListerTest() : mock_client_(&mock_delegate_) {
176  }
177
178  virtual ~PrivetDeviceListerTest() {
179  }
180
181  virtual void SetUp() OVERRIDE {
182    example_attrs_.push_back("tXtvers=1");
183    example_attrs_.push_back("ty=My Printer");
184    example_attrs_.push_back("nOte=This is my Printer");
185    example_attrs_.push_back("CS=ONlInE");
186    example_attrs_.push_back("id=");
187
188    service_description_.service_name = "myprinter._privet._tcp.local";
189    service_description_.address = net::HostPortPair("myprinter.local", 6006);
190    service_description_.metadata = example_attrs_;
191    service_description_.last_seen = base::Time() +
192        base::TimeDelta::FromSeconds(5);
193    service_description_.ip_address.push_back(1);
194    service_description_.ip_address.push_back(2);
195    service_description_.ip_address.push_back(3);
196    service_description_.ip_address.push_back(4);
197  }
198
199 protected:
200  testing::StrictMock<MockServiceDiscoveryMockDelegate> mock_delegate_;
201  MockServiceDiscoveryClient mock_client_;
202  MockDeviceListerDelegate delegate_;
203  std::vector<std::string> example_attrs_;
204  ServiceDescription service_description_;
205};
206
207TEST_F(PrivetDeviceListerTest, SimpleUpdateTest) {
208  DeviceDescription outgoing_description;
209
210  MockServiceWatcher* service_watcher;
211  MockServiceResolver* service_resolver;
212
213  EXPECT_CALL(mock_delegate_,
214              ServiceWatcherStarted("_privet._tcp.local", _))
215      .WillOnce(SaveArg<1>(&service_watcher));
216  PrivetDeviceListerImpl privet_lister(&mock_client_, &delegate_);
217  privet_lister.Start();
218  testing::Mock::VerifyAndClear(&mock_delegate_);
219
220  EXPECT_CALL(mock_delegate_,
221              ServiceResolverStarted("myprinter._privet._tcp.local", _))
222      .WillOnce(SaveArg<1>(&service_resolver));
223  service_watcher->callback().Run(ServiceWatcher::UPDATE_ADDED,
224                                  "myprinter._privet._tcp.local");
225  testing::Mock::VerifyAndClear(&mock_delegate_);
226
227  EXPECT_CALL(delegate_, DeviceChanged(true,
228                                       "myprinter._privet._tcp.local",
229                                       _))
230              .WillOnce(SaveArg<2>(&outgoing_description));
231
232  service_resolver->callback().Run(ServiceResolver::STATUS_SUCCESS,
233                                   service_description_);
234
235  EXPECT_EQ(service_description_.address.host(),
236            outgoing_description.address.host());
237  EXPECT_EQ(service_description_.address.port(),
238            outgoing_description.address.port());
239  EXPECT_EQ(service_description_.ip_address, outgoing_description.ip_address);
240  EXPECT_EQ(service_description_.last_seen, outgoing_description.last_seen);
241  EXPECT_EQ("My Printer", outgoing_description.name);
242  EXPECT_EQ("This is my Printer", outgoing_description.description);
243  EXPECT_EQ("", outgoing_description.id);
244  EXPECT_EQ(DeviceDescription::ONLINE, outgoing_description.connection_state);
245
246  EXPECT_CALL(delegate_, DeviceRemoved("myprinter._privet._tcp.local"));
247
248  service_watcher->callback().Run(ServiceWatcher::UPDATE_REMOVED,
249                                  "myprinter._privet._tcp.local");
250}
251
252TEST_F(PrivetDeviceListerTest, MultipleUpdatesPostResolve) {
253  MockServiceWatcher* service_watcher;
254  MockServiceResolver* service_resolver;
255
256  EXPECT_CALL(mock_delegate_,
257              ServiceWatcherStarted("_privet._tcp.local", _))
258      .WillOnce(SaveArg<1>(&service_watcher));
259  PrivetDeviceListerImpl privet_lister(&mock_client_, &delegate_);
260  privet_lister.Start();
261  testing::Mock::VerifyAndClear(&mock_delegate_);
262
263  EXPECT_CALL(mock_delegate_,
264              ServiceResolverStarted("myprinter._privet._tcp.local", _))
265      .WillOnce(SaveArg<1>(&service_resolver));
266
267  service_watcher->callback().Run(ServiceWatcher::UPDATE_CHANGED,
268                                  "myprinter._privet._tcp.local");
269  testing::Mock::VerifyAndClear(&mock_delegate_);
270
271  EXPECT_CALL(delegate_, DeviceChanged(false,
272                                       "myprinter._privet._tcp.local",
273                                       _));
274  service_resolver->callback().Run(ServiceResolver::STATUS_SUCCESS,
275                                   service_description_);
276
277  EXPECT_CALL(mock_delegate_,
278              ServiceResolverStarted("myprinter._privet._tcp.local", _));
279  service_watcher->callback().Run(ServiceWatcher::UPDATE_CHANGED,
280                                  "myprinter._privet._tcp.local");
281  testing::Mock::VerifyAndClear(&mock_delegate_);
282}
283
284// Check that the device lister does not create a still-working resolver
285TEST_F(PrivetDeviceListerTest, MultipleUpdatesPreResolve) {
286  MockServiceWatcher* service_watcher;
287
288  EXPECT_CALL(mock_delegate_,
289              ServiceWatcherStarted("_privet._tcp.local", _))
290      .WillOnce(SaveArg<1>(&service_watcher));
291  PrivetDeviceListerImpl privet_lister(&mock_client_, &delegate_);
292  privet_lister.Start();
293  testing::Mock::VerifyAndClear(&mock_delegate_);
294
295  EXPECT_CALL(mock_delegate_,
296              ServiceResolverStarted("myprinter._privet._tcp.local", _))
297      .Times(1);
298  service_watcher->callback().Run(ServiceWatcher::UPDATE_CHANGED,
299                                  "myprinter._privet._tcp.local");
300  service_watcher->callback().Run(ServiceWatcher::UPDATE_CHANGED,
301                                  "myprinter._privet._tcp.local");
302}
303
304TEST_F(PrivetDeviceListerTest, DiscoverNewDevices) {
305  MockServiceWatcher* service_watcher;
306
307  EXPECT_CALL(mock_delegate_,
308              ServiceWatcherStarted("_privet._tcp.local", _))
309      .WillOnce(SaveArg<1>(&service_watcher));
310  PrivetDeviceListerImpl privet_lister(&mock_client_, &delegate_);
311  privet_lister.Start();
312  testing::Mock::VerifyAndClear(&mock_delegate_);
313
314  EXPECT_CALL(*service_watcher, DiscoverNewServices(false));
315  privet_lister.DiscoverNewDevices(false);
316}
317
318
319}  // namespace
320
321}  // namespace local_discovery
322