Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: chrome/browser/local_discovery/service_discovery_client_unittest.cc

Issue 16272006: In-browser DNS-based service discovery system (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@mdns_implementation
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 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"
6 #include "chrome/browser/local_discovery/service_discovery_client_impl.h"
7 #include "net/base/net_errors.h"
8 #include "net/dns/dns_protocol.h"
9 #include "net/dns/mdns_client_impl.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 using ::testing::_;
14 using ::testing::Invoke;
15 using ::testing::StrictMock;
16 using ::testing::NiceMock;
17 using ::testing::Mock;
18 using ::testing::SaveArg;
19 using ::testing::SetArgPointee;
20 using ::testing::Return;
21 using ::testing::Exactly;
22
23 namespace local_discovery {
24
25 namespace {
26
27 const char kSamplePacketPTR[] = {
28 // Header
29 0x00, 0x00, // ID is zeroed out
30 0x81, 0x80, // Standard query response, RA, no error
31 0x00, 0x00, // No questions (for simplicity)
32 0x00, 0x01, // 1 RR (answers)
33 0x00, 0x00, // 0 authority RRs
34 0x00, 0x00, // 0 additional RRs
35
36 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
37 0x04, '_', 't', 'c', 'p',
38 0x05, 'l', 'o', 'c', 'a', 'l',
39 0x00,
40 0x00, 0x0c, // TYPE is PTR.
41 0x00, 0x01, // CLASS is IN.
42 0x00, 0x00, // TTL (4 bytes) is 1 second.
43 0x00, 0x01,
44 0x00, 0x08, // RDLENGTH is 8 bytes.
45 0x05, 'h', 'e', 'l', 'l', 'o',
46 0xc0, 0x0c
47 };
48
49 const char kSamplePacketSRV[] = {
50 // Header
51 0x00, 0x00, // ID is zeroed out
52 0x81, 0x80, // Standard query response, RA, no error
53 0x00, 0x00, // No questions (for simplicity)
54 0x00, 0x01, // 1 RR (answers)
55 0x00, 0x00, // 0 authority RRs
56 0x00, 0x00, // 0 additional RRs
57
58 0x05, 'h', 'e', 'l', 'l', 'o',
59 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
60 0x04, '_', 't', 'c', 'p',
61 0x05, 'l', 'o', 'c', 'a', 'l',
62 0x00,
63 0x00, 0x21, // TYPE is SRV.
64 0x00, 0x01, // CLASS is IN.
65 0x00, 0x00, // TTL (4 bytes) is 1 second.
66 0x00, 0x01,
67 0x00, 0x15, // RDLENGTH is 21 bytes.
68 0x00, 0x00,
69 0x00, 0x00,
70 0x22, 0xb8, // port 8888
71 0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o',
72 0x05, 'l', 'o', 'c', 'a', 'l',
73 0x00,
74 };
75
76 const char kSamplePacketTXT[] = {
77 // Header
78 0x00, 0x00, // ID is zeroed out
79 0x81, 0x80, // Standard query response, RA, no error
80 0x00, 0x00, // No questions (for simplicity)
81 0x00, 0x01, // 1 RR (answers)
82 0x00, 0x00, // 0 authority RRs
83 0x00, 0x00, // 0 additional RRs
84
85 0x05, 'h', 'e', 'l', 'l', 'o',
86 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
87 0x04, '_', 't', 'c', 'p',
88 0x05, 'l', 'o', 'c', 'a', 'l',
89 0x00,
90 0x00, 0x10, // TYPE is PTR.
91 0x00, 0x01, // CLASS is IN.
92 0x00, 0x00, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds.
93 0x00, 0x01,
94 0x00, 0x06, // RDLENGTH is 21 bytes.
95 0x05, 'h', 'e', 'l', 'l', 'o'
96 };
97
98 class MockSocketFactory : public net::DatagramServerSocket {
99 public:
100 int Listen(const net::IPEndPoint& address) {
101 return ListenInternal(address.ToString());
102 }
103
104 MOCK_METHOD1(ListenInternal, int(const std::string& address));
105
106 MOCK_METHOD4(RecvFrom, int(net::IOBuffer* buffer, int size,
107 net::IPEndPoint* address,
108 const net::CompletionCallback& callback));
109
110 int SendTo(net::IOBuffer* buf, int buf_len, const net::IPEndPoint& address,
111 const net::CompletionCallback& callback) {
112 return SendToInternal(std::string(buf->data(), buf_len), address.ToString(),
113 callback);
114 }
115
116 MOCK_METHOD3(SendToInternal, int(const std::string& packet,
117 const std::string address,
118 const net::CompletionCallback& callback));
119
120 MOCK_METHOD1(SetReceiveBufferSize, bool(int32 size));
121 MOCK_METHOD1(SetSendBufferSize, bool(int32 size));
122
123 MOCK_METHOD0(Close, void());
124
125 MOCK_CONST_METHOD1(GetPeerAddress, int(net::IPEndPoint* address));
126 MOCK_CONST_METHOD1(GetLocalAddress, int(net::IPEndPoint* address));
127 MOCK_CONST_METHOD0(NetLog, const net::BoundNetLog&());
128
129 MOCK_METHOD0(AllowAddressReuse, void());
130 MOCK_METHOD0(AllowBroadcast, void());
131
132 int JoinGroup(const net::IPAddressNumber& group_address) const {
133 return JoinGroupInternal(net::IPAddressToString(group_address));
134 }
135
136 MOCK_CONST_METHOD1(JoinGroupInternal, int(const std::string& group));
137
138 int LeaveGroup(const net::IPAddressNumber& group_address) const {
139 return LeaveGroupInternal(net::IPAddressToString(group_address));
140 }
141
142 MOCK_CONST_METHOD1(LeaveGroupInternal, int(const std::string& group));
143
144 MOCK_METHOD1(SetMulticastTimeToLive, int(int ttl));
145
146 MOCK_METHOD1(SetMulticastLoopbackMode, int(bool loopback));
147 };
148
149 class MockSocketFactoryFactory
150 : public net::MDnsConnection::SocketFactory {
151 public:
152 MockSocketFactoryFactory() {
153 }
154
155 virtual ~MockSocketFactoryFactory() {
156 }
157
158 virtual scoped_ptr<net::DatagramServerSocket> CreateSocket() OVERRIDE {
159 scoped_ptr<MockSocketFactory> new_socket(
160 new NiceMock<MockSocketFactory>);
161
162 ON_CALL(*new_socket, SendToInternal(_, _, _))
163 .WillByDefault(Invoke(
164 this,
165 &MockSocketFactoryFactory::SendToInternal));
166
167 ON_CALL(*new_socket, RecvFrom(_, _, _, _))
168 .WillByDefault(Invoke(
169 this,
170 &MockSocketFactoryFactory::RecvFromInternal));
171
172 return new_socket.PassAs<net::DatagramServerSocket>();
173 }
174
175 int SendToInternal(const std::string& packet, const std::string& address,
176 const net::CompletionCallback& callback) {
177 OnSendTo(packet);
178 return packet.size();
179 }
180
181 // The latest recieve callback is always saved, since the net::MDnsConnection
182 // does not care which socket a packet is received on.
183 int RecvFromInternal(net::IOBuffer* buffer, int size,
184 net::IPEndPoint* address,
185 const net::CompletionCallback& callback) {
186 recv_buffer_ = buffer;
187 recv_buffer_size_ = size;
188 recv_callback_ = callback;
189 return net::ERR_IO_PENDING;
190 }
191
192 void SimulateReceive(const char* packet, int size) {
193 DCHECK(recv_buffer_size_ >= size);
194 DCHECK(recv_buffer_.get());
195 DCHECK(!recv_callback_.is_null());
196
197 memcpy(recv_buffer_->data(), packet, size);
198 net::CompletionCallback recv_callback = recv_callback_;
199 recv_callback_.Reset();
200 recv_callback.Run(size);
201 }
202
203 MOCK_METHOD1(OnSendTo, void(const std::string&));
204
205 private:
206 scoped_refptr<net::IOBuffer> recv_buffer_;
207 int recv_buffer_size_;
208 net::CompletionCallback recv_callback_;
209 };
210
211 class MockServiceTypeWatcherDelegate : public ServiceTypeWatcher::Delegate {
212 public:
213 MockServiceTypeWatcherDelegate() {}
214 virtual ~MockServiceTypeWatcherDelegate() {}
215
216 MOCK_METHOD2(OnServiceStatusChanged, void(bool, const std::string&));
217 };
218
219 class ServiceDiscoveryTest : public ::testing::Test {
220 public:
221 ServiceDiscoveryTest() : socket_factory_(new MockSocketFactoryFactory),
222 mdns_client_(
223 scoped_ptr<net::MDnsConnection::SocketFactory>(
224 socket_factory_)) {
225 net::MDnsClient::SetInstance(&mdns_client_);
226 }
227
228 virtual ~ServiceDiscoveryTest() {
229 net::MDnsClient::SetInstance(NULL);
230 }
231
232 protected:
233 void RunFor(base::TimeDelta time_period) {
234 base::CancelableCallback<void()> callback(base::Bind(
235 &ServiceDiscoveryTest::Stop, base::Unretained(this)));
236 base::MessageLoop::current()->PostDelayedTask(
237 FROM_HERE, callback.callback(), time_period);
238
239 base::MessageLoop::current()->Run();
240 callback.Cancel();
241 }
242
243 void Stop() {
244 base::MessageLoop::current()->Quit();
245 }
246
247 MockSocketFactoryFactory* socket_factory_;
248 net::MDnsClientImpl mdns_client_;
249 ServiceDiscoveryClientImpl service_discovery_client_;
250 base::MessageLoop loop_;
251 };
252
253 TEST_F(ServiceDiscoveryTest, AddRemoveService) {
254 scoped_ptr<ServiceTypeWatcher> watcher;
255 StrictMock<MockServiceTypeWatcherDelegate> delegate;
256
257 watcher = service_discovery_client_.CreateServiceTypeWatcher(
258 "_privet._tcp.local", true, false, &delegate);
259
260 EXPECT_CALL(*socket_factory_, OnSendTo(_))
261 .Times(2);
262
263 watcher->Start();
264
265 EXPECT_CALL(delegate,
266 OnServiceStatusChanged(true, "hello._privet._tcp.local"))
267 .Times(Exactly(1));
268
269 socket_factory_->SimulateReceive(
270 kSamplePacketPTR, sizeof(kSamplePacketPTR));
271
272 EXPECT_CALL(delegate,
273 OnServiceStatusChanged(false, "hello._privet._tcp.local"))
274 .Times(Exactly(1));
275
276 RunFor(base::TimeDelta::FromSeconds(2));
277 };
278
279 TEST_F(ServiceDiscoveryTest, DiscoverNewServices) {
280 scoped_ptr<ServiceTypeWatcher> watcher;
281 StrictMock<MockServiceTypeWatcherDelegate> delegate;
282
283 watcher = service_discovery_client_.CreateServiceTypeWatcher(
284 "_privet._tcp.local", false, false, &delegate);
285
286 watcher->Start();
287
288 EXPECT_CALL(*socket_factory_, OnSendTo(_))
289 .Times(2);
290
291 watcher->DiscoverNewServices();
292 };
293
294 TEST_F(ServiceDiscoveryTest, GetAvailableServices) {
295 NiceMock<MockServiceTypeWatcherDelegate> delegate;
296
297 std::vector<std::string> data_expected;
298 std::vector<std::string> data;
299
300 data_expected.push_back("hello._privet._tcp.local");
301
302 scoped_ptr<ServiceTypeWatcher> watcher =
303 service_discovery_client_.CreateServiceTypeWatcher(
304 "_privet._tcp.local", false, false, &delegate);
305
306 watcher->Start();
307
308 socket_factory_->SimulateReceive(
309 kSamplePacketPTR, sizeof(kSamplePacketPTR));
310
311 watcher->GetAvailableServices(&data);
312
313 EXPECT_EQ(data, data_expected);
314 };
315
316 class MockServiceReaderDelegate
317 : public ServiceReader::Delegate {
318 public:
319 MockServiceReaderDelegate() {}
320 virtual ~MockServiceReaderDelegate() {}
321
322 virtual void OnAddressChanged(
323 const std::string& service_name,
324 const net::HostPortPair& address) OVERRIDE {
325 OnAddressChangedInternal(service_name, address.ToString());
326 }
327
328 MOCK_METHOD2(OnAddressChangedInternal, void(const std::string& service_name,
329 const std::string& address));
330 MOCK_METHOD2(OnMetadataChanged,
331 void(const std::string& service_name,
332 const std::vector<std::string>& metadata));
333 };
334
335 class ServiceReaderTest : public ServiceDiscoveryTest {
336 public:
337 ServiceReaderTest() {
338 metadata_expected_.push_back("hello");
339 address_expected_ = net::HostPortPair("myhello.local", 8888);
340 }
341
342 ~ServiceReaderTest() {
343 }
344
345 void SetUp() {
346 reader_ = service_discovery_client_.CreateServiceReader(
347 "hello._privet._tcp.local", &delegate_);
348
349 EXPECT_CALL(*socket_factory_, OnSendTo(_))
350 .Times(4); // Two queries.
351
352 reader_->Start();
353
354 Mock::VerifyAndClear(&socket_factory_);
355 }
356
357 void OnReceiveAddress(ServiceReader::RequestStatus status,
358 const net::HostPortPair& address) {
359 OnReceiveAddressInternal(status, address.ToString());
360 }
361
362 MOCK_METHOD2(OnReceiveAddressInternal, void(ServiceReader::RequestStatus,
363 const std::string&));
364 MOCK_METHOD2(OnReceiveMetadata,
365 void(ServiceReader::RequestStatus,
366 const std::vector<std::string>&));
367 MOCK_METHOD1(OnReceiveTime, void(base::Time));
368
369 protected:
370 StrictMock<MockServiceReaderDelegate> delegate_;
371 scoped_ptr<ServiceReader> reader_;
372 net::HostPortPair address_expected_;
373 std::vector<std::string> metadata_expected_;
374 net::HostPortPair address_recieved_;
375 std::vector<std::string> metadata_recieved_;
376 };
377
378 TEST_F(ServiceReaderTest, ServiceWatcherUpdateDelegate) {
379 EXPECT_CALL(delegate_,
380 OnMetadataChanged("hello._privet._tcp.local",
381 metadata_expected_));
382
383 socket_factory_->SimulateReceive(
384 kSamplePacketTXT, sizeof(kSamplePacketTXT));
385
386 Mock::VerifyAndClear(&delegate_);
387
388 EXPECT_CALL(delegate_,
389 OnAddressChangedInternal("hello._privet._tcp.local",
390 address_expected_.ToString()));
391
392 socket_factory_->SimulateReceive(
393 kSamplePacketSRV, sizeof(kSamplePacketSRV));
394
395 Mock::VerifyAndClear(&delegate_);
396
397 EXPECT_TRUE(reader_->GetAddress(&address_recieved_));
398
399 EXPECT_TRUE(address_expected_.Equals(address_recieved_));
400
401 EXPECT_TRUE(reader_->GetMetadata(&metadata_recieved_));
402
403 EXPECT_EQ(metadata_expected_, metadata_recieved_);
404 };
405
406 TEST_F(ServiceReaderTest, NoData) {
407 Mock::VerifyAndClear(&socket_factory_);
408
409 EXPECT_FALSE(reader_->GetAddress(&address_recieved_));
410 EXPECT_FALSE(reader_->GetMetadata(&metadata_recieved_));
411 }
412
413 TEST_F(ServiceReaderTest, ServiceWatcherReadWithCallback) {
414 EXPECT_CALL(delegate_,
415 OnMetadataChanged("hello._privet._tcp.local",
416 metadata_expected_));
417 EXPECT_CALL(delegate_,
418 OnAddressChangedInternal("hello._privet._tcp.local",
419 address_expected_.ToString()));
420
421 // Test that double calls to ReadAddress/Metadata get double responses.
422 reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
423 base::Unretained(this)), false);
424 reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
425 base::Unretained(this)), false);
426 reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
427 base::Unretained(this)), false);
428 reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
429 base::Unretained(this)), false);
430
431 Mock::VerifyAndClear(socket_factory_);
432
433 EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_SUCCESS,
434 address_expected_.ToString()))
435 .Times(Exactly(2));
436
437 EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_SUCCESS,
438 metadata_expected_))
439 .Times(Exactly(2));
440
441 socket_factory_->SimulateReceive(
442 kSamplePacketSRV, sizeof(kSamplePacketSRV));
443
444 socket_factory_->SimulateReceive(
445 kSamplePacketTXT, sizeof(kSamplePacketTXT));
446
447 Mock::VerifyAndClear(this);
448
449 // Test that a successful read doesn't clobber read-ability, and reads from
450 // from cache.
451 EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_SUCCESS,
452 address_expected_.ToString()))
453 .Times(Exactly(1));
454
455 EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_SUCCESS,
456 metadata_expected_))
457 .Times(Exactly(1));
458
459 reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
460 base::Unretained(this)), false);
461 reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
462 base::Unretained(this)), false);
463 };
464
465 TEST_F(ServiceReaderTest, ServiceWatcherReadWithTimeout) {
466 reader_->ReadAddress(base::Bind(&ServiceReaderTest::OnReceiveAddress,
467 base::Unretained(this)), false);
468 reader_->ReadMetadata(base::Bind(&ServiceReaderTest::OnReceiveMetadata,
469 base::Unretained(this)), false);
470
471 EXPECT_CALL(*this, OnReceiveAddressInternal(ServiceReader::STATUS_TIMEOUT, _))
472 .Times(Exactly(1));
473
474 EXPECT_CALL(*this, OnReceiveMetadata(ServiceReader::STATUS_TIMEOUT, _))
475 .Times(Exactly(1));
476
477 RunFor(base::TimeDelta::FromSeconds(4));
478 };
479
480 TEST_F(ServiceReaderTest, ServiceWatcherExpiration) {
481 EXPECT_CALL(delegate_,
482 OnMetadataChanged("hello._privet._tcp.local",
483 metadata_expected_));
484 EXPECT_CALL(delegate_,
485 OnAddressChangedInternal("hello._privet._tcp.local",
486 address_expected_.ToString()));
487
488 socket_factory_->SimulateReceive(
489 kSamplePacketSRV, sizeof(kSamplePacketSRV));
490
491 socket_factory_->SimulateReceive(
492 kSamplePacketTXT, sizeof(kSamplePacketTXT));
493
494 EXPECT_TRUE(reader_->GetAddress(&address_recieved_));
495 EXPECT_TRUE(reader_->GetMetadata(&metadata_recieved_));
496
497 EXPECT_CALL(delegate_,
498 OnMetadataChanged("hello._privet._tcp.local",
499 std::vector<std::string>() ));
500 EXPECT_CALL(delegate_,
501 OnAddressChangedInternal("hello._privet._tcp.local",
502 net::HostPortPair().ToString()));
503
504 RunFor(base::TimeDelta::FromSeconds(2));
505
506 EXPECT_FALSE(reader_->GetAddress(&address_recieved_));
507 EXPECT_FALSE(reader_->GetMetadata(&metadata_recieved_));
508 };
509
510 TEST_F(ServiceReaderTest, Names) {
511 EXPECT_EQ("hello", reader_->GetHumanReadableName());
512 EXPECT_EQ("_privet._tcp.local", reader_->GetType());
513
514 reader_ = service_discovery_client_.CreateServiceReader(
515 "hello", &delegate_);
516 EXPECT_EQ("hello", reader_->GetHumanReadableName());
517 EXPECT_EQ("", reader_->GetType());
518 }
519
520 TEST_F(ServiceReaderTest, LastSeen) {
521 base::Time time_last_seen;
522 EXPECT_CALL(*this, OnReceiveTime(base::Time()));
523 reader_->ReadLastSeen(base::Bind(&ServiceReaderTest::OnReceiveTime,
524 base::Unretained(this)));
525 EXPECT_CALL(delegate_,
526 OnAddressChangedInternal("hello._privet._tcp.local",
527 address_expected_.ToString()));
528
529 socket_factory_->SimulateReceive(
530 kSamplePacketSRV, sizeof(kSamplePacketSRV));
531
532 EXPECT_CALL(*this, OnReceiveTime(_))
533 .WillOnce(SaveArg<0>(&time_last_seen));
534
535 reader_->ReadLastSeen(base::Bind(&ServiceReaderTest::OnReceiveTime,
536 base::Unretained(this)));
537
538 base::TimeDelta timediff = base::Time::Now() - time_last_seen;
539 if (timediff < base::TimeDelta()) timediff = -timediff;
540 EXPECT_TRUE(timediff < base::TimeDelta::FromSeconds(5));
541 }
542
543 } // namespace
544
545 } // namespace local_discovery
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698