blob: 43914ee894bd57c01b19dc1b8a31c8ccc8e0eaca [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// 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/memory/weak_ptr.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +01006#include "base/run_loop.h"
7#include "chrome/utility/local_discovery/service_discovery_client_impl.h"
Ben Murdocheb525c52013-07-10 11:40:50 +01008#include "net/base/net_errors.h"
9#include "net/dns/dns_protocol.h"
10#include "net/dns/mdns_client_impl.h"
11#include "net/dns/mock_mdns_socket_factory.h"
12#include "testing/gmock/include/gmock/gmock.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15using ::testing::_;
16using ::testing::Invoke;
17using ::testing::StrictMock;
18using ::testing::NiceMock;
19using ::testing::Mock;
20using ::testing::SaveArg;
21using ::testing::SetArgPointee;
22using ::testing::Return;
23using ::testing::Exactly;
24
25namespace local_discovery {
26
27namespace {
28
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010029const uint8 kSamplePacketPTR[] = {
Ben Murdocheb525c52013-07-10 11:40:50 +010030 // Header
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010031 0x00, 0x00, // ID is zeroed out
32 0x81, 0x80, // Standard query response, RA, no error
33 0x00, 0x00, // No questions (for simplicity)
34 0x00, 0x01, // 1 RR (answers)
35 0x00, 0x00, // 0 authority RRs
36 0x00, 0x00, // 0 additional RRs
Ben Murdocheb525c52013-07-10 11:40:50 +010037
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010038 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
39 0x04, '_', 't', 'c', 'p',
40 0x05, 'l', 'o', 'c', 'a', 'l',
41 0x00,
42 0x00, 0x0c, // TYPE is PTR.
43 0x00, 0x01, // CLASS is IN.
44 0x00, 0x00, // TTL (4 bytes) is 1 second.
45 0x00, 0x01,
46 0x00, 0x08, // RDLENGTH is 8 bytes.
47 0x05, 'h', 'e', 'l', 'l', 'o',
48 0xc0, 0x0c
Ben Murdocheb525c52013-07-10 11:40:50 +010049};
50
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010051const uint8 kSamplePacketSRV[] = {
Ben Murdocheb525c52013-07-10 11:40:50 +010052 // Header
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010053 0x00, 0x00, // ID is zeroed out
54 0x81, 0x80, // Standard query response, RA, no error
55 0x00, 0x00, // No questions (for simplicity)
56 0x00, 0x01, // 1 RR (answers)
57 0x00, 0x00, // 0 authority RRs
58 0x00, 0x00, // 0 additional RRs
Ben Murdocheb525c52013-07-10 11:40:50 +010059
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010060 0x05, 'h', 'e', 'l', 'l', 'o',
61 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
62 0x04, '_', 't', 'c', 'p',
63 0x05, 'l', 'o', 'c', 'a', 'l',
64 0x00,
65 0x00, 0x21, // TYPE is SRV.
66 0x00, 0x01, // CLASS is IN.
67 0x00, 0x00, // TTL (4 bytes) is 1 second.
68 0x00, 0x01,
69 0x00, 0x15, // RDLENGTH is 21 bytes.
70 0x00, 0x00,
71 0x00, 0x00,
72 0x22, 0xb8, // port 8888
73 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
74 0x05, 'l', 'o', 'c', 'a', 'l',
75 0x00,
Ben Murdocheb525c52013-07-10 11:40:50 +010076};
77
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010078const uint8 kSamplePacketTXT[] = {
Ben Murdocheb525c52013-07-10 11:40:50 +010079 // Header
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010080 0x00, 0x00, // ID is zeroed out
81 0x81, 0x80, // Standard query response, RA, no error
82 0x00, 0x00, // No questions (for simplicity)
83 0x00, 0x01, // 1 RR (answers)
84 0x00, 0x00, // 0 authority RRs
85 0x00, 0x00, // 0 additional RRs
Ben Murdocheb525c52013-07-10 11:40:50 +010086
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010087 0x05, 'h', 'e', 'l', 'l', 'o',
88 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
89 0x04, '_', 't', 'c', 'p',
90 0x05, 'l', 'o', 'c', 'a', 'l',
91 0x00,
92 0x00, 0x10, // TYPE is PTR.
93 0x00, 0x01, // CLASS is IN.
94 0x00, 0x00, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
95 0x00, 0x01,
96 0x00, 0x06, // RDLENGTH is 21 bytes.
97 0x05, 'h', 'e', 'l', 'l', 'o'
Ben Murdocheb525c52013-07-10 11:40:50 +010098};
99
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100100const uint8 kSamplePacketSRVA[] = {
Ben Murdocheb525c52013-07-10 11:40:50 +0100101 // Header
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100102 0x00, 0x00, // ID is zeroed out
103 0x81, 0x80, // Standard query response, RA, no error
104 0x00, 0x00, // No questions (for simplicity)
105 0x00, 0x02, // 2 RR (answers)
106 0x00, 0x00, // 0 authority RRs
107 0x00, 0x00, // 0 additional RRs
Ben Murdocheb525c52013-07-10 11:40:50 +0100108
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100109 0x05, 'h', 'e', 'l', 'l', 'o',
110 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
111 0x04, '_', 't', 'c', 'p',
112 0x05, 'l', 'o', 'c', 'a', 'l',
113 0x00,
114 0x00, 0x21, // TYPE is SRV.
115 0x00, 0x01, // CLASS is IN.
116 0x00, 0x00, // TTL (4 bytes) is 16 seconds.
117 0x00, 0x10,
118 0x00, 0x15, // RDLENGTH is 21 bytes.
119 0x00, 0x00,
120 0x00, 0x00,
121 0x22, 0xb8, // port 8888
122 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
123 0x05, 'l', 'o', 'c', 'a', 'l',
124 0x00,
Ben Murdocheb525c52013-07-10 11:40:50 +0100125
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100126 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
127 0x05, 'l', 'o', 'c', 'a', 'l',
128 0x00,
129 0x00, 0x01, // TYPE is A.
130 0x00, 0x01, // CLASS is IN.
131 0x00, 0x00, // TTL (4 bytes) is 16 seconds.
132 0x00, 0x10,
133 0x00, 0x04, // RDLENGTH is 4 bytes.
134 0x01, 0x02,
135 0x03, 0x04,
Ben Murdocheb525c52013-07-10 11:40:50 +0100136};
137
Ben Murdochbb1529c2013-08-08 10:24:53 +0100138const uint8 kSamplePacketPTR2[] = {
139 // Header
140 0x00, 0x00, // ID is zeroed out
141 0x81, 0x80, // Standard query response, RA, no error
142 0x00, 0x00, // No questions (for simplicity)
143 0x00, 0x02, // 2 RR (answers)
144 0x00, 0x00, // 0 authority RRs
145 0x00, 0x00, // 0 additional RRs
146
147 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
148 0x04, '_', 't', 'c', 'p',
149 0x05, 'l', 'o', 'c', 'a', 'l',
150 0x00,
151 0x00, 0x0c, // TYPE is PTR.
152 0x00, 0x01, // CLASS is IN.
153 0x02, 0x00, // TTL (4 bytes) is 1 second.
154 0x00, 0x01,
155 0x00, 0x08, // RDLENGTH is 8 bytes.
156 0x05, 'g', 'd', 'b', 'y', 'e',
157 0xc0, 0x0c,
158
159 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
160 0x04, '_', 't', 'c', 'p',
161 0x05, 'l', 'o', 'c', 'a', 'l',
162 0x00,
163 0x00, 0x0c, // TYPE is PTR.
164 0x00, 0x01, // CLASS is IN.
165 0x02, 0x00, // TTL (4 bytes) is 1 second.
166 0x00, 0x01,
167 0x00, 0x08, // RDLENGTH is 8 bytes.
168 0x05, 'h', 'e', 'l', 'l', 'o',
169 0xc0, 0x0c
170};
171
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100172class MockServiceWatcherClient {
Ben Murdocheb525c52013-07-10 11:40:50 +0100173 public:
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100174 MOCK_METHOD2(OnServiceUpdated,
175 void(ServiceWatcher::UpdateType, const std::string&));
Ben Murdocheb525c52013-07-10 11:40:50 +0100176
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100177 ServiceWatcher::UpdatedCallback GetCallback() {
178 return base::Bind(&MockServiceWatcherClient::OnServiceUpdated,
179 base::Unretained(this));
180 }
Ben Murdocheb525c52013-07-10 11:40:50 +0100181};
182
183class ServiceDiscoveryTest : public ::testing::Test {
184 public:
185 ServiceDiscoveryTest()
186 : socket_factory_(new net::MockMDnsSocketFactory),
187 mdns_client_(
188 scoped_ptr<net::MDnsConnection::SocketFactory>(
189 socket_factory_)),
190 service_discovery_client_(&mdns_client_) {
191 mdns_client_.StartListening();
192 }
193
194 virtual ~ServiceDiscoveryTest() {
195 }
196
197 protected:
198 void RunFor(base::TimeDelta time_period) {
199 base::CancelableCallback<void()> callback(base::Bind(
200 &ServiceDiscoveryTest::Stop, base::Unretained(this)));
201 base::MessageLoop::current()->PostDelayedTask(
202 FROM_HERE, callback.callback(), time_period);
203
204 base::MessageLoop::current()->Run();
205 callback.Cancel();
206 }
207
208 void Stop() {
209 base::MessageLoop::current()->Quit();
210 }
211
212 net::MockMDnsSocketFactory* socket_factory_;
213 net::MDnsClientImpl mdns_client_;
214 ServiceDiscoveryClientImpl service_discovery_client_;
215 base::MessageLoop loop_;
216};
217
218TEST_F(ServiceDiscoveryTest, AddRemoveService) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100219 StrictMock<MockServiceWatcherClient> delegate;
Ben Murdocheb525c52013-07-10 11:40:50 +0100220
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100221 scoped_ptr<ServiceWatcher> watcher(
222 service_discovery_client_.CreateServiceWatcher(
223 "_privet._tcp.local", delegate.GetCallback()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100224
225 watcher->Start();
226
227 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
228 "hello._privet._tcp.local"))
229 .Times(Exactly(1));
230
231 socket_factory_->SimulateReceive(
232 kSamplePacketPTR, sizeof(kSamplePacketPTR));
233
234 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_REMOVED,
235 "hello._privet._tcp.local"))
236 .Times(Exactly(1));
237
238 RunFor(base::TimeDelta::FromSeconds(2));
239};
240
241TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100242 StrictMock<MockServiceWatcherClient> delegate;
Ben Murdocheb525c52013-07-10 11:40:50 +0100243
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100244 scoped_ptr<ServiceWatcher> watcher(
245 service_discovery_client_.CreateServiceWatcher(
246 "_privet._tcp.local", delegate.GetCallback()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100247
248 watcher->Start();
249
250 EXPECT_CALL(*socket_factory_, OnSendTo(_))
251 .Times(2);
252
253 watcher->DiscoverNewServices(false);
254};
255
Ben Murdocheb525c52013-07-10 11:40:50 +0100256TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100257 socket_factory_->SimulateReceive(
258 kSamplePacketPTR, sizeof(kSamplePacketPTR));
259
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100260 StrictMock<MockServiceWatcherClient> delegate;
261
262 scoped_ptr<ServiceWatcher> watcher(
Ben Murdocheb525c52013-07-10 11:40:50 +0100263 service_discovery_client_.CreateServiceWatcher(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100264 "_privet._tcp.local", delegate.GetCallback()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100265
266 watcher->Start();
267
268 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
269 "hello._privet._tcp.local"))
270 .Times(Exactly(1));
271
Ben Murdocheb525c52013-07-10 11:40:50 +0100272 base::MessageLoop::current()->RunUntilIdle();
273};
274
Ben Murdochbb1529c2013-08-08 10:24:53 +0100275
276TEST_F(ServiceDiscoveryTest, ReadCachedServicesMultiple) {
277 socket_factory_->SimulateReceive(
278 kSamplePacketPTR2, sizeof(kSamplePacketPTR2));
279
280 StrictMock<MockServiceWatcherClient> delegate;
281 scoped_ptr<ServiceWatcher> watcher =
282 service_discovery_client_.CreateServiceWatcher(
283 "_privet._tcp.local", delegate.GetCallback());
284
285 watcher->Start();
286
287 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
288 "hello._privet._tcp.local"))
289 .Times(Exactly(1));
290
291 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
292 "gdbye._privet._tcp.local"))
293 .Times(Exactly(1));
294
295 base::MessageLoop::current()->RunUntilIdle();
296};
297
298
Ben Murdocheb525c52013-07-10 11:40:50 +0100299TEST_F(ServiceDiscoveryTest, OnServiceChanged) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100300 StrictMock<MockServiceWatcherClient> delegate;
301 scoped_ptr<ServiceWatcher> watcher(
Ben Murdocheb525c52013-07-10 11:40:50 +0100302 service_discovery_client_.CreateServiceWatcher(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100303 "_privet._tcp.local", delegate.GetCallback()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100304
305 watcher->Start();
306
307 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
308 "hello._privet._tcp.local"))
309 .Times(Exactly(1));
310
311 socket_factory_->SimulateReceive(
312 kSamplePacketPTR, sizeof(kSamplePacketPTR));
313
314 base::MessageLoop::current()->RunUntilIdle();
315
316 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_CHANGED,
317 "hello._privet._tcp.local"))
318 .Times(Exactly(1));
319
320 socket_factory_->SimulateReceive(
321 kSamplePacketSRV, sizeof(kSamplePacketSRV));
322
323 socket_factory_->SimulateReceive(
324 kSamplePacketTXT, sizeof(kSamplePacketTXT));
325
326 base::MessageLoop::current()->RunUntilIdle();
327};
328
329TEST_F(ServiceDiscoveryTest, SinglePacket) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100330 StrictMock<MockServiceWatcherClient> delegate;
331 scoped_ptr<ServiceWatcher> watcher(
Ben Murdocheb525c52013-07-10 11:40:50 +0100332 service_discovery_client_.CreateServiceWatcher(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100333 "_privet._tcp.local", delegate.GetCallback()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100334
335 watcher->Start();
336
337 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
338 "hello._privet._tcp.local"))
339 .Times(Exactly(1));
340
341 socket_factory_->SimulateReceive(
342 kSamplePacketPTR, sizeof(kSamplePacketPTR));
343
344 // Reset the "already updated" flag.
345 base::MessageLoop::current()->RunUntilIdle();
346
347 EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_CHANGED,
348 "hello._privet._tcp.local"))
349 .Times(Exactly(1));
350
351 socket_factory_->SimulateReceive(
352 kSamplePacketSRV, sizeof(kSamplePacketSRV));
353
354 socket_factory_->SimulateReceive(
355 kSamplePacketTXT, sizeof(kSamplePacketTXT));
356
357 base::MessageLoop::current()->RunUntilIdle();
358};
359
360class ServiceResolverTest : public ServiceDiscoveryTest {
361 public:
362 ServiceResolverTest() {
363 metadata_expected_.push_back("hello");
364 address_expected_ = net::HostPortPair("myhello.local", 8888);
365 ip_address_expected_.push_back(1);
366 ip_address_expected_.push_back(2);
367 ip_address_expected_.push_back(3);
368 ip_address_expected_.push_back(4);
369 }
370
371 ~ServiceResolverTest() {
372 }
373
374 void SetUp() {
375 resolver_ = service_discovery_client_.CreateServiceResolver(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100376 "hello._privet._tcp.local",
377 base::Bind(&ServiceResolverTest::OnFinishedResolving,
378 base::Unretained(this)));
Ben Murdocheb525c52013-07-10 11:40:50 +0100379 }
380
381 void OnFinishedResolving(ServiceResolver::RequestStatus request_status,
382 const ServiceDescription& service_description) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100383 OnFinishedResolvingInternal(request_status,
384 service_description.address.ToString(),
385 service_description.metadata,
386 service_description.ip_address);
Ben Murdocheb525c52013-07-10 11:40:50 +0100387 }
388
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100389 MOCK_METHOD4(OnFinishedResolvingInternal,
390 void(ServiceResolver::RequestStatus,
391 const std::string&,
392 const std::vector<std::string>&,
393 const net::IPAddressNumber&));
Ben Murdocheb525c52013-07-10 11:40:50 +0100394
395 protected:
396 scoped_ptr<ServiceResolver> resolver_;
397 net::IPAddressNumber ip_address_;
398 net::HostPortPair address_expected_;
399 std::vector<std::string> metadata_expected_;
400 net::IPAddressNumber ip_address_expected_;
401};
402
403TEST_F(ServiceResolverTest, TxtAndSrvButNoA) {
404 EXPECT_CALL(*socket_factory_, OnSendTo(_))
405 .Times(4);
406
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100407 resolver_->StartResolving();
Ben Murdocheb525c52013-07-10 11:40:50 +0100408
409 socket_factory_->SimulateReceive(
410 kSamplePacketSRV, sizeof(kSamplePacketSRV));
411
412 base::MessageLoop::current()->RunUntilIdle();
413
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100414 EXPECT_CALL(*this,
415 OnFinishedResolvingInternal(ServiceResolver::STATUS_SUCCESS,
416 address_expected_.ToString(),
417 metadata_expected_,
418 net::IPAddressNumber()));
Ben Murdocheb525c52013-07-10 11:40:50 +0100419
420 socket_factory_->SimulateReceive(
421 kSamplePacketTXT, sizeof(kSamplePacketTXT));
Ben Murdocheb525c52013-07-10 11:40:50 +0100422};
423
424TEST_F(ServiceResolverTest, TxtSrvAndA) {
425 EXPECT_CALL(*socket_factory_, OnSendTo(_))
426 .Times(4);
427
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100428 resolver_->StartResolving();
Ben Murdocheb525c52013-07-10 11:40:50 +0100429
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100430 EXPECT_CALL(*this,
431 OnFinishedResolvingInternal(ServiceResolver::STATUS_SUCCESS,
432 address_expected_.ToString(),
433 metadata_expected_,
434 ip_address_expected_));
Ben Murdocheb525c52013-07-10 11:40:50 +0100435
436 socket_factory_->SimulateReceive(
437 kSamplePacketTXT, sizeof(kSamplePacketTXT));
438
439 socket_factory_->SimulateReceive(
440 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
Ben Murdocheb525c52013-07-10 11:40:50 +0100441};
442
443TEST_F(ServiceResolverTest, JustSrv) {
444 EXPECT_CALL(*socket_factory_, OnSendTo(_))
445 .Times(4);
446
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100447 resolver_->StartResolving();
Ben Murdocheb525c52013-07-10 11:40:50 +0100448
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100449 EXPECT_CALL(*this,
450 OnFinishedResolvingInternal(ServiceResolver::STATUS_SUCCESS,
451 address_expected_.ToString(),
452 std::vector<std::string>(),
453 ip_address_expected_));
Ben Murdocheb525c52013-07-10 11:40:50 +0100454
455 socket_factory_->SimulateReceive(
456 kSamplePacketSRVA, sizeof(kSamplePacketSRVA));
457
458 // TODO(noamsml): When NSEC record support is added, change this to use an
459 // NSEC record.
460 RunFor(base::TimeDelta::FromSeconds(4));
Ben Murdocheb525c52013-07-10 11:40:50 +0100461};
462
463TEST_F(ServiceResolverTest, WithNothing) {
464 EXPECT_CALL(*socket_factory_, OnSendTo(_))
465 .Times(4);
466
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100467 resolver_->StartResolving();
Ben Murdocheb525c52013-07-10 11:40:50 +0100468
469 EXPECT_CALL(*this, OnFinishedResolvingInternal(
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100470 ServiceResolver::STATUS_REQUEST_TIMEOUT, _, _, _));
Ben Murdocheb525c52013-07-10 11:40:50 +0100471
472 // TODO(noamsml): When NSEC record support is added, change this to use an
473 // NSEC record.
474 RunFor(base::TimeDelta::FromSeconds(4));
475};
476
477} // namespace
478
479} // namespace local_discovery