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 10 using testing::SaveArg; 11 using testing::_; 12 13 namespace local_discovery { 14 15 namespace { 16 17 class MockServiceResolver; 18 class MockServiceWatcher; 19 20 class 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 28 class 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 70 class 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 105 class 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 148 class 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 156 class 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 173 class 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 207 TEST_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 252 TEST_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 285 TEST_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 304 TEST_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