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 <queue> 6 7#include "base/memory/ref_counted.h" 8#include "base/message_loop/message_loop.h" 9#include "net/base/rand_callback.h" 10#include "net/base/test_completion_callback.h" 11#include "net/dns/mdns_client_impl.h" 12#include "net/dns/mock_mdns_socket_factory.h" 13#include "net/dns/record_rdata.h" 14#include "net/udp/udp_client_socket.h" 15#include "testing/gmock/include/gmock/gmock.h" 16#include "testing/gtest/include/gtest/gtest.h" 17 18using ::testing::Invoke; 19using ::testing::InvokeWithoutArgs; 20using ::testing::StrictMock; 21using ::testing::NiceMock; 22using ::testing::Exactly; 23using ::testing::Return; 24using ::testing::SaveArg; 25using ::testing::_; 26 27namespace net { 28 29namespace { 30 31const uint8 kSamplePacket1[] = { 32 // Header 33 0x00, 0x00, // ID is zeroed out 34 0x81, 0x80, // Standard query response, RA, no error 35 0x00, 0x00, // No questions (for simplicity) 36 0x00, 0x02, // 2 RRs (answers) 37 0x00, 0x00, // 0 authority RRs 38 0x00, 0x00, // 0 additional RRs 39 40 // Answer 1 41 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 42 0x04, '_', 't', 'c', 'p', 43 0x05, 'l', 'o', 'c', 'a', 'l', 44 0x00, 45 0x00, 0x0c, // TYPE is PTR. 46 0x00, 0x01, // CLASS is IN. 47 0x00, 0x00, // TTL (4 bytes) is 1 second; 48 0x00, 0x01, 49 0x00, 0x08, // RDLENGTH is 8 bytes. 50 0x05, 'h', 'e', 'l', 'l', 'o', 51 0xc0, 0x0c, 52 53 // Answer 2 54 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 55 0xc0, 0x14, // Pointer to "._tcp.local" 56 0x00, 0x0c, // TYPE is PTR. 57 0x00, 0x01, // CLASS is IN. 58 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds. 59 0x24, 0x75, 60 0x00, 0x08, // RDLENGTH is 8 bytes. 61 0x05, 'h', 'e', 'l', 'l', 'o', 62 0xc0, 0x32 63}; 64 65const uint8 kCorruptedPacketBadQuestion[] = { 66 // Header 67 0x00, 0x00, // ID is zeroed out 68 0x81, 0x80, // Standard query response, RA, no error 69 0x00, 0x01, // One question 70 0x00, 0x02, // 2 RRs (answers) 71 0x00, 0x00, // 0 authority RRs 72 0x00, 0x00, // 0 additional RRs 73 74 // Question is corrupted and cannot be read. 75 0x99, 'h', 'e', 'l', 'l', 'o', 76 0x00, 77 0x00, 0x00, 78 0x00, 0x00, 79 80 // Answer 1 81 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 82 0x04, '_', 't', 'c', 'p', 83 0x05, 'l', 'o', 'c', 'a', 'l', 84 0x00, 85 0x00, 0x0c, // TYPE is PTR. 86 0x00, 0x01, // CLASS is IN. 87 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 88 0x24, 0x74, 89 0x00, 0x99, // RDLENGTH is impossible 90 0x05, 'h', 'e', 'l', 'l', 'o', 91 0xc0, 0x0c, 92 93 // Answer 2 94 0x08, '_', 'p', 'r', // Useless trailing data. 95}; 96 97const uint8 kCorruptedPacketUnsalvagable[] = { 98 // Header 99 0x00, 0x00, // ID is zeroed out 100 0x81, 0x80, // Standard query response, RA, no error 101 0x00, 0x00, // No questions (for simplicity) 102 0x00, 0x02, // 2 RRs (answers) 103 0x00, 0x00, // 0 authority RRs 104 0x00, 0x00, // 0 additional RRs 105 106 // Answer 1 107 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 108 0x04, '_', 't', 'c', 'p', 109 0x05, 'l', 'o', 'c', 'a', 'l', 110 0x00, 111 0x00, 0x0c, // TYPE is PTR. 112 0x00, 0x01, // CLASS is IN. 113 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 114 0x24, 0x74, 115 0x00, 0x99, // RDLENGTH is impossible 116 0x05, 'h', 'e', 'l', 'l', 'o', 117 0xc0, 0x0c, 118 119 // Answer 2 120 0x08, '_', 'p', 'r', // Useless trailing data. 121}; 122 123const uint8 kCorruptedPacketDoubleRecord[] = { 124 // Header 125 0x00, 0x00, // ID is zeroed out 126 0x81, 0x80, // Standard query response, RA, no error 127 0x00, 0x00, // No questions (for simplicity) 128 0x00, 0x02, // 2 RRs (answers) 129 0x00, 0x00, // 0 authority RRs 130 0x00, 0x00, // 0 additional RRs 131 132 // Answer 1 133 0x06, 'p', 'r', 'i', 'v', 'e', 't', 134 0x05, 'l', 'o', 'c', 'a', 'l', 135 0x00, 136 0x00, 0x01, // TYPE is A. 137 0x00, 0x01, // CLASS is IN. 138 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 139 0x24, 0x74, 140 0x00, 0x04, // RDLENGTH is 4 141 0x05, 0x03, 142 0xc0, 0x0c, 143 144 // Answer 2 -- Same key 145 0x06, 'p', 'r', 'i', 'v', 'e', 't', 146 0x05, 'l', 'o', 'c', 'a', 'l', 147 0x00, 148 0x00, 0x01, // TYPE is A. 149 0x00, 0x01, // CLASS is IN. 150 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 151 0x24, 0x74, 152 0x00, 0x04, // RDLENGTH is 4 153 0x02, 0x03, 154 0x04, 0x05, 155}; 156 157const uint8 kCorruptedPacketSalvagable[] = { 158 // Header 159 0x00, 0x00, // ID is zeroed out 160 0x81, 0x80, // Standard query response, RA, no error 161 0x00, 0x00, // No questions (for simplicity) 162 0x00, 0x02, // 2 RRs (answers) 163 0x00, 0x00, // 0 authority RRs 164 0x00, 0x00, // 0 additional RRs 165 166 // Answer 1 167 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 168 0x04, '_', 't', 'c', 'p', 169 0x05, 'l', 'o', 'c', 'a', 'l', 170 0x00, 171 0x00, 0x0c, // TYPE is PTR. 172 0x00, 0x01, // CLASS is IN. 173 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 174 0x24, 0x74, 175 0x00, 0x08, // RDLENGTH is 8 bytes. 176 0x99, 'h', 'e', 'l', 'l', 'o', // Bad RDATA format. 177 0xc0, 0x0c, 178 179 // Answer 2 180 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 181 0xc0, 0x14, // Pointer to "._tcp.local" 182 0x00, 0x0c, // TYPE is PTR. 183 0x00, 0x01, // CLASS is IN. 184 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 49 seconds. 185 0x24, 0x75, 186 0x00, 0x08, // RDLENGTH is 8 bytes. 187 0x05, 'h', 'e', 'l', 'l', 'o', 188 0xc0, 0x32 189}; 190 191const uint8 kSamplePacket2[] = { 192 // Header 193 0x00, 0x00, // ID is zeroed out 194 0x81, 0x80, // Standard query response, RA, no error 195 0x00, 0x00, // No questions (for simplicity) 196 0x00, 0x02, // 2 RRs (answers) 197 0x00, 0x00, // 0 authority RRs 198 0x00, 0x00, // 0 additional RRs 199 200 // Answer 1 201 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 202 0x04, '_', 't', 'c', 'p', 203 0x05, 'l', 'o', 'c', 'a', 'l', 204 0x00, 205 0x00, 0x0c, // TYPE is PTR. 206 0x00, 0x01, // CLASS is IN. 207 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 208 0x24, 0x74, 209 0x00, 0x08, // RDLENGTH is 8 bytes. 210 0x05, 'z', 'z', 'z', 'z', 'z', 211 0xc0, 0x0c, 212 213 // Answer 2 214 0x08, '_', 'p', 'r', 'i', 'n', 't', 'e', 'r', 215 0xc0, 0x14, // Pointer to "._tcp.local" 216 0x00, 0x0c, // TYPE is PTR. 217 0x00, 0x01, // CLASS is IN. 218 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 219 0x24, 0x74, 220 0x00, 0x08, // RDLENGTH is 8 bytes. 221 0x05, 'z', 'z', 'z', 'z', 'z', 222 0xc0, 0x32 223}; 224 225const uint8 kQueryPacketPrivet[] = { 226 // Header 227 0x00, 0x00, // ID is zeroed out 228 0x00, 0x00, // No flags. 229 0x00, 0x01, // One question. 230 0x00, 0x00, // 0 RRs (answers) 231 0x00, 0x00, // 0 authority RRs 232 0x00, 0x00, // 0 additional RRs 233 234 // Question 235 // This part is echoed back from the respective query. 236 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 237 0x04, '_', 't', 'c', 'p', 238 0x05, 'l', 'o', 'c', 'a', 'l', 239 0x00, 240 0x00, 0x0c, // TYPE is PTR. 241 0x00, 0x01, // CLASS is IN. 242}; 243 244const uint8 kSamplePacketAdditionalOnly[] = { 245 // Header 246 0x00, 0x00, // ID is zeroed out 247 0x81, 0x80, // Standard query response, RA, no error 248 0x00, 0x00, // No questions (for simplicity) 249 0x00, 0x00, // 2 RRs (answers) 250 0x00, 0x00, // 0 authority RRs 251 0x00, 0x01, // 0 additional RRs 252 253 // Answer 1 254 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 255 0x04, '_', 't', 'c', 'p', 256 0x05, 'l', 'o', 'c', 'a', 'l', 257 0x00, 258 0x00, 0x0c, // TYPE is PTR. 259 0x00, 0x01, // CLASS is IN. 260 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 261 0x24, 0x74, 262 0x00, 0x08, // RDLENGTH is 8 bytes. 263 0x05, 'h', 'e', 'l', 'l', 'o', 264 0xc0, 0x0c, 265}; 266 267const uint8 kSamplePacketNsec[] = { 268 // Header 269 0x00, 0x00, // ID is zeroed out 270 0x81, 0x80, // Standard query response, RA, no error 271 0x00, 0x00, // No questions (for simplicity) 272 0x00, 0x01, // 1 RR (answers) 273 0x00, 0x00, // 0 authority RRs 274 0x00, 0x00, // 0 additional RRs 275 276 // Answer 1 277 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 278 0x04, '_', 't', 'c', 'p', 279 0x05, 'l', 'o', 'c', 'a', 'l', 280 0x00, 281 0x00, 0x2f, // TYPE is NSEC. 282 0x00, 0x01, // CLASS is IN. 283 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 284 0x24, 0x74, 285 0x00, 0x06, // RDLENGTH is 6 bytes. 286 0xc0, 0x0c, 287 0x00, 0x02, 0x00, 0x08 // Only A record present 288}; 289 290const uint8 kSamplePacketAPrivet[] = { 291 // Header 292 0x00, 0x00, // ID is zeroed out 293 0x81, 0x80, // Standard query response, RA, no error 294 0x00, 0x00, // No questions (for simplicity) 295 0x00, 0x01, // 1 RR (answers) 296 0x00, 0x00, // 0 authority RRs 297 0x00, 0x00, // 0 additional RRs 298 299 // Answer 1 300 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 301 0x04, '_', 't', 'c', 'p', 302 0x05, 'l', 'o', 'c', 'a', 'l', 303 0x00, 304 0x00, 0x01, // TYPE is A. 305 0x00, 0x01, // CLASS is IN. 306 0x00, 0x01, // TTL (4 bytes) is 20 hours, 47 minutes, 48 seconds. 307 0x24, 0x74, 308 0x00, 0x04, // RDLENGTH is 4 bytes. 309 0xc0, 0x0c, 310 0x00, 0x02, 311}; 312 313const uint8 kSamplePacketGoodbye[] = { 314 // Header 315 0x00, 0x00, // ID is zeroed out 316 0x81, 0x80, // Standard query response, RA, no error 317 0x00, 0x00, // No questions (for simplicity) 318 0x00, 0x01, // 2 RRs (answers) 319 0x00, 0x00, // 0 authority RRs 320 0x00, 0x00, // 0 additional RRs 321 322 // Answer 1 323 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 324 0x04, '_', 't', 'c', 'p', 325 0x05, 'l', 'o', 'c', 'a', 'l', 326 0x00, 327 0x00, 0x0c, // TYPE is PTR. 328 0x00, 0x01, // CLASS is IN. 329 0x00, 0x00, // TTL (4 bytes) is zero; 330 0x00, 0x00, 331 0x00, 0x08, // RDLENGTH is 8 bytes. 332 0x05, 'z', 'z', 'z', 'z', 'z', 333 0xc0, 0x0c, 334}; 335 336std::string MakeString(const uint8* data, unsigned size) { 337 return std::string(reinterpret_cast<const char*>(data), size); 338} 339 340class PtrRecordCopyContainer { 341 public: 342 PtrRecordCopyContainer() {} 343 ~PtrRecordCopyContainer() {} 344 345 bool is_set() const { return set_; } 346 347 void SaveWithDummyArg(int unused, const RecordParsed* value) { 348 Save(value); 349 } 350 351 void Save(const RecordParsed* value) { 352 set_ = true; 353 name_ = value->name(); 354 ptrdomain_ = value->rdata<PtrRecordRdata>()->ptrdomain(); 355 ttl_ = value->ttl(); 356 } 357 358 bool IsRecordWith(std::string name, std::string ptrdomain) { 359 return set_ && name_ == name && ptrdomain_ == ptrdomain; 360 } 361 362 const std::string& name() { return name_; } 363 const std::string& ptrdomain() { return ptrdomain_; } 364 int ttl() { return ttl_; } 365 366 private: 367 bool set_; 368 std::string name_; 369 std::string ptrdomain_; 370 int ttl_; 371}; 372 373class MDnsTest : public ::testing::Test { 374 public: 375 virtual void SetUp() OVERRIDE; 376 void DeleteTransaction(); 377 void DeleteBothListeners(); 378 void RunFor(base::TimeDelta time_period); 379 void Stop(); 380 381 MOCK_METHOD2(MockableRecordCallback, void(MDnsTransaction::Result result, 382 const RecordParsed* record)); 383 384 MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result, 385 const RecordParsed* record)); 386 387 388 protected: 389 void ExpectPacket(const uint8* packet, unsigned size); 390 void SimulatePacketReceive(const uint8* packet, unsigned size); 391 392 MDnsClientImpl test_client_; 393 IPEndPoint mdns_ipv4_endpoint_; 394 StrictMock<MockMDnsSocketFactory> socket_factory_; 395 396 // Transactions and listeners that can be deleted by class methods for 397 // reentrancy tests. 398 scoped_ptr<MDnsTransaction> transaction_; 399 scoped_ptr<MDnsListener> listener1_; 400 scoped_ptr<MDnsListener> listener2_; 401}; 402 403class MockListenerDelegate : public MDnsListener::Delegate { 404 public: 405 MOCK_METHOD2(OnRecordUpdate, 406 void(MDnsListener::UpdateType update, 407 const RecordParsed* records)); 408 MOCK_METHOD2(OnNsecRecord, void(const std::string&, unsigned)); 409 MOCK_METHOD0(OnCachePurged, void()); 410}; 411 412void MDnsTest::SetUp() { 413 test_client_.StartListening(&socket_factory_); 414} 415 416void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) { 417 socket_factory_.SimulateReceive(packet, size); 418} 419 420void MDnsTest::ExpectPacket(const uint8* packet, unsigned size) { 421 EXPECT_CALL(socket_factory_, OnSendTo(MakeString(packet, size))) 422 .Times(2); 423} 424 425void MDnsTest::DeleteTransaction() { 426 transaction_.reset(); 427} 428 429void MDnsTest::DeleteBothListeners() { 430 listener1_.reset(); 431 listener2_.reset(); 432} 433 434void MDnsTest::RunFor(base::TimeDelta time_period) { 435 base::CancelableCallback<void()> callback(base::Bind(&MDnsTest::Stop, 436 base::Unretained(this))); 437 base::MessageLoop::current()->PostDelayedTask( 438 FROM_HERE, callback.callback(), time_period); 439 440 base::MessageLoop::current()->Run(); 441 callback.Cancel(); 442} 443 444void MDnsTest::Stop() { 445 base::MessageLoop::current()->Quit(); 446} 447 448TEST_F(MDnsTest, PassiveListeners) { 449 StrictMock<MockListenerDelegate> delegate_privet; 450 StrictMock<MockListenerDelegate> delegate_printer; 451 452 PtrRecordCopyContainer record_privet; 453 PtrRecordCopyContainer record_printer; 454 455 scoped_ptr<MDnsListener> listener_privet = 456 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 457 &delegate_privet); 458 scoped_ptr<MDnsListener> listener_printer = 459 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", 460 &delegate_printer); 461 462 ASSERT_TRUE(listener_privet->Start()); 463 ASSERT_TRUE(listener_printer->Start()); 464 465 // Send the same packet twice to ensure no records are double-counted. 466 467 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 468 .Times(Exactly(1)) 469 .WillOnce(Invoke( 470 &record_privet, 471 &PtrRecordCopyContainer::SaveWithDummyArg)); 472 473 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 474 .Times(Exactly(1)) 475 .WillOnce(Invoke( 476 &record_printer, 477 &PtrRecordCopyContainer::SaveWithDummyArg)); 478 479 480 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 481 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 482 483 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 484 "hello._privet._tcp.local")); 485 486 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local", 487 "hello._printer._tcp.local")); 488 489 listener_privet.reset(); 490 listener_printer.reset(); 491} 492 493TEST_F(MDnsTest, PassiveListenersCacheCleanup) { 494 StrictMock<MockListenerDelegate> delegate_privet; 495 496 PtrRecordCopyContainer record_privet; 497 PtrRecordCopyContainer record_privet2; 498 499 scoped_ptr<MDnsListener> listener_privet = 500 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 501 &delegate_privet); 502 503 ASSERT_TRUE(listener_privet->Start()); 504 505 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 506 .Times(Exactly(1)) 507 .WillOnce(Invoke( 508 &record_privet, 509 &PtrRecordCopyContainer::SaveWithDummyArg)); 510 511 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 512 513 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 514 "hello._privet._tcp.local")); 515 516 // Expect record is removed when its TTL expires. 517 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) 518 .Times(Exactly(1)) 519 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::Stop), 520 Invoke(&record_privet2, 521 &PtrRecordCopyContainer::SaveWithDummyArg))); 522 523 RunFor(base::TimeDelta::FromSeconds(record_privet.ttl() + 1)); 524 525 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local", 526 "hello._privet._tcp.local")); 527} 528 529TEST_F(MDnsTest, MalformedPacket) { 530 StrictMock<MockListenerDelegate> delegate_printer; 531 532 PtrRecordCopyContainer record_printer; 533 534 scoped_ptr<MDnsListener> listener_printer = 535 test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local", 536 &delegate_printer); 537 538 ASSERT_TRUE(listener_printer->Start()); 539 540 EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 541 .Times(Exactly(1)) 542 .WillOnce(Invoke( 543 &record_printer, 544 &PtrRecordCopyContainer::SaveWithDummyArg)); 545 546 // First, send unsalvagable packet to ensure we can deal with it. 547 SimulatePacketReceive(kCorruptedPacketUnsalvagable, 548 sizeof(kCorruptedPacketUnsalvagable)); 549 550 // Regression test: send a packet where the question cannot be read. 551 SimulatePacketReceive(kCorruptedPacketBadQuestion, 552 sizeof(kCorruptedPacketBadQuestion)); 553 554 // Then send salvagable packet to ensure we can extract useful records. 555 SimulatePacketReceive(kCorruptedPacketSalvagable, 556 sizeof(kCorruptedPacketSalvagable)); 557 558 EXPECT_TRUE(record_printer.IsRecordWith("_printer._tcp.local", 559 "hello._printer._tcp.local")); 560} 561 562TEST_F(MDnsTest, TransactionWithEmptyCache) { 563 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); 564 565 scoped_ptr<MDnsTransaction> transaction_privet = 566 test_client_.CreateTransaction( 567 dns_protocol::kTypePTR, "_privet._tcp.local", 568 MDnsTransaction::QUERY_NETWORK | 569 MDnsTransaction::QUERY_CACHE | 570 MDnsTransaction::SINGLE_RESULT, 571 base::Bind(&MDnsTest::MockableRecordCallback, 572 base::Unretained(this))); 573 574 ASSERT_TRUE(transaction_privet->Start()); 575 576 PtrRecordCopyContainer record_privet; 577 578 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) 579 .Times(Exactly(1)) 580 .WillOnce(Invoke(&record_privet, 581 &PtrRecordCopyContainer::SaveWithDummyArg)); 582 583 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 584 585 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 586 "hello._privet._tcp.local")); 587} 588 589TEST_F(MDnsTest, TransactionCacheOnlyNoResult) { 590 scoped_ptr<MDnsTransaction> transaction_privet = 591 test_client_.CreateTransaction( 592 dns_protocol::kTypePTR, "_privet._tcp.local", 593 MDnsTransaction::QUERY_CACHE | 594 MDnsTransaction::SINGLE_RESULT, 595 base::Bind(&MDnsTest::MockableRecordCallback, 596 base::Unretained(this))); 597 598 EXPECT_CALL(*this, 599 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, _)) 600 .Times(Exactly(1)); 601 602 ASSERT_TRUE(transaction_privet->Start()); 603} 604 605TEST_F(MDnsTest, TransactionWithCache) { 606 // Listener to force the client to listen 607 StrictMock<MockListenerDelegate> delegate_irrelevant; 608 scoped_ptr<MDnsListener> listener_irrelevant = 609 test_client_.CreateListener(dns_protocol::kTypeA, 610 "codereview.chromium.local", 611 &delegate_irrelevant); 612 613 ASSERT_TRUE(listener_irrelevant->Start()); 614 615 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 616 617 618 PtrRecordCopyContainer record_privet; 619 620 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) 621 .WillOnce(Invoke(&record_privet, 622 &PtrRecordCopyContainer::SaveWithDummyArg)); 623 624 scoped_ptr<MDnsTransaction> transaction_privet = 625 test_client_.CreateTransaction( 626 dns_protocol::kTypePTR, "_privet._tcp.local", 627 MDnsTransaction::QUERY_NETWORK | 628 MDnsTransaction::QUERY_CACHE | 629 MDnsTransaction::SINGLE_RESULT, 630 base::Bind(&MDnsTest::MockableRecordCallback, 631 base::Unretained(this))); 632 633 ASSERT_TRUE(transaction_privet->Start()); 634 635 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 636 "hello._privet._tcp.local")); 637} 638 639TEST_F(MDnsTest, AdditionalRecords) { 640 StrictMock<MockListenerDelegate> delegate_privet; 641 642 PtrRecordCopyContainer record_privet; 643 644 scoped_ptr<MDnsListener> listener_privet = 645 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 646 &delegate_privet); 647 648 ASSERT_TRUE(listener_privet->Start()); 649 650 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 651 .Times(Exactly(1)) 652 .WillOnce(Invoke( 653 &record_privet, 654 &PtrRecordCopyContainer::SaveWithDummyArg)); 655 656 SimulatePacketReceive(kSamplePacketAdditionalOnly, 657 sizeof(kSamplePacketAdditionalOnly)); 658 659 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 660 "hello._privet._tcp.local")); 661} 662 663TEST_F(MDnsTest, TransactionTimeout) { 664 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); 665 666 scoped_ptr<MDnsTransaction> transaction_privet = 667 test_client_.CreateTransaction( 668 dns_protocol::kTypePTR, "_privet._tcp.local", 669 MDnsTransaction::QUERY_NETWORK | 670 MDnsTransaction::QUERY_CACHE | 671 MDnsTransaction::SINGLE_RESULT, 672 base::Bind(&MDnsTest::MockableRecordCallback, 673 base::Unretained(this))); 674 675 ASSERT_TRUE(transaction_privet->Start()); 676 677 EXPECT_CALL(*this, 678 MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, NULL)) 679 .Times(Exactly(1)) 680 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop)); 681 682 RunFor(base::TimeDelta::FromSeconds(4)); 683} 684 685TEST_F(MDnsTest, TransactionMultipleRecords) { 686 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); 687 688 scoped_ptr<MDnsTransaction> transaction_privet = 689 test_client_.CreateTransaction( 690 dns_protocol::kTypePTR, "_privet._tcp.local", 691 MDnsTransaction::QUERY_NETWORK | 692 MDnsTransaction::QUERY_CACHE , 693 base::Bind(&MDnsTest::MockableRecordCallback, 694 base::Unretained(this))); 695 696 ASSERT_TRUE(transaction_privet->Start()); 697 698 PtrRecordCopyContainer record_privet; 699 PtrRecordCopyContainer record_privet2; 700 701 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) 702 .Times(Exactly(2)) 703 .WillOnce(Invoke(&record_privet, 704 &PtrRecordCopyContainer::SaveWithDummyArg)) 705 .WillOnce(Invoke(&record_privet2, 706 &PtrRecordCopyContainer::SaveWithDummyArg)); 707 708 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 709 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2)); 710 711 EXPECT_TRUE(record_privet.IsRecordWith("_privet._tcp.local", 712 "hello._privet._tcp.local")); 713 714 EXPECT_TRUE(record_privet2.IsRecordWith("_privet._tcp.local", 715 "zzzzz._privet._tcp.local")); 716 717 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_DONE, NULL)) 718 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::Stop)); 719 720 RunFor(base::TimeDelta::FromSeconds(4)); 721} 722 723TEST_F(MDnsTest, TransactionReentrantDelete) { 724 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); 725 726 transaction_ = test_client_.CreateTransaction( 727 dns_protocol::kTypePTR, "_privet._tcp.local", 728 MDnsTransaction::QUERY_NETWORK | 729 MDnsTransaction::QUERY_CACHE | 730 MDnsTransaction::SINGLE_RESULT, 731 base::Bind(&MDnsTest::MockableRecordCallback, 732 base::Unretained(this))); 733 734 ASSERT_TRUE(transaction_->Start()); 735 736 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_NO_RESULTS, 737 NULL)) 738 .Times(Exactly(1)) 739 .WillOnce(DoAll(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction), 740 InvokeWithoutArgs(this, &MDnsTest::Stop))); 741 742 RunFor(base::TimeDelta::FromSeconds(4)); 743 744 EXPECT_EQ(NULL, transaction_.get()); 745} 746 747TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) { 748 StrictMock<MockListenerDelegate> delegate_irrelevant; 749 scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener( 750 dns_protocol::kTypeA, "codereview.chromium.local", 751 &delegate_irrelevant); 752 ASSERT_TRUE(listener_irrelevant->Start()); 753 754 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 755 756 transaction_ = test_client_.CreateTransaction( 757 dns_protocol::kTypePTR, "_privet._tcp.local", 758 MDnsTransaction::QUERY_NETWORK | 759 MDnsTransaction::QUERY_CACHE, 760 base::Bind(&MDnsTest::MockableRecordCallback, 761 base::Unretained(this))); 762 763 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _)) 764 .Times(Exactly(1)) 765 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteTransaction)); 766 767 ASSERT_TRUE(transaction_->Start()); 768 769 EXPECT_EQ(NULL, transaction_.get()); 770} 771 772TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) { 773 ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet)); 774 775 scoped_ptr<MDnsTransaction> transaction1 = 776 test_client_.CreateTransaction( 777 dns_protocol::kTypePTR, "_privet._tcp.local", 778 MDnsTransaction::QUERY_NETWORK | 779 MDnsTransaction::QUERY_CACHE | 780 MDnsTransaction::SINGLE_RESULT, 781 base::Bind(&MDnsTest::MockableRecordCallback, 782 base::Unretained(this))); 783 784 scoped_ptr<MDnsTransaction> transaction2 = 785 test_client_.CreateTransaction( 786 dns_protocol::kTypePTR, "_printer._tcp.local", 787 MDnsTransaction::QUERY_CACHE | 788 MDnsTransaction::SINGLE_RESULT, 789 base::Bind(&MDnsTest::MockableRecordCallback2, 790 base::Unretained(this))); 791 792 EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD, 793 _)) 794 .Times(Exactly(1)); 795 796 EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, 797 _)) 798 .Times(Exactly(1)) 799 .WillOnce(IgnoreResult(InvokeWithoutArgs(transaction2.get(), 800 &MDnsTransaction::Start))); 801 802 ASSERT_TRUE(transaction1->Start()); 803 804 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 805} 806 807TEST_F(MDnsTest, GoodbyePacketNotification) { 808 StrictMock<MockListenerDelegate> delegate_privet; 809 810 scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener( 811 dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet); 812 ASSERT_TRUE(listener_privet->Start()); 813 814 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye)); 815 816 RunFor(base::TimeDelta::FromSeconds(2)); 817} 818 819TEST_F(MDnsTest, GoodbyePacketRemoval) { 820 StrictMock<MockListenerDelegate> delegate_privet; 821 822 scoped_ptr<MDnsListener> listener_privet = 823 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 824 &delegate_privet); 825 ASSERT_TRUE(listener_privet->Start()); 826 827 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 828 .Times(Exactly(1)); 829 830 SimulatePacketReceive(kSamplePacket2, sizeof(kSamplePacket2)); 831 832 SimulatePacketReceive(kSamplePacketGoodbye, sizeof(kSamplePacketGoodbye)); 833 834 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) 835 .Times(Exactly(1)); 836 837 RunFor(base::TimeDelta::FromSeconds(2)); 838} 839 840// In order to reliably test reentrant listener deletes, we create two listeners 841// and have each of them delete both, so we're guaranteed to try and deliver a 842// callback to at least one deleted listener. 843 844TEST_F(MDnsTest, ListenerReentrantDelete) { 845 StrictMock<MockListenerDelegate> delegate_privet; 846 847 listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR, 848 "_privet._tcp.local", 849 &delegate_privet); 850 851 listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR, 852 "_privet._tcp.local", 853 &delegate_privet); 854 855 ASSERT_TRUE(listener1_->Start()); 856 857 ASSERT_TRUE(listener2_->Start()); 858 859 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 860 .Times(Exactly(1)) 861 .WillOnce(InvokeWithoutArgs(this, &MDnsTest::DeleteBothListeners)); 862 863 SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1)); 864 865 EXPECT_EQ(NULL, listener1_.get()); 866 EXPECT_EQ(NULL, listener2_.get()); 867} 868 869ACTION_P(SaveIPAddress, ip_container) { 870 ::testing::StaticAssertTypeEq<const RecordParsed*, arg1_type>(); 871 ::testing::StaticAssertTypeEq<IPAddressNumber*, ip_container_type>(); 872 873 *ip_container = arg1->template rdata<ARecordRdata>()->address(); 874} 875 876TEST_F(MDnsTest, DoubleRecordDisagreeing) { 877 IPAddressNumber address; 878 StrictMock<MockListenerDelegate> delegate_privet; 879 880 scoped_ptr<MDnsListener> listener_privet = 881 test_client_.CreateListener(dns_protocol::kTypeA, "privet.local", 882 &delegate_privet); 883 884 ASSERT_TRUE(listener_privet->Start()); 885 886 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 887 .Times(Exactly(1)) 888 .WillOnce(SaveIPAddress(&address)); 889 890 SimulatePacketReceive(kCorruptedPacketDoubleRecord, 891 sizeof(kCorruptedPacketDoubleRecord)); 892 893 EXPECT_EQ("2.3.4.5", IPAddressToString(address)); 894} 895 896TEST_F(MDnsTest, NsecWithListener) { 897 StrictMock<MockListenerDelegate> delegate_privet; 898 scoped_ptr<MDnsListener> listener_privet = 899 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", 900 &delegate_privet); 901 902 // Test to make sure nsec callback is NOT called for PTR 903 // (which is marked as existing). 904 StrictMock<MockListenerDelegate> delegate_privet2; 905 scoped_ptr<MDnsListener> listener_privet2 = 906 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 907 &delegate_privet2); 908 909 ASSERT_TRUE(listener_privet->Start()); 910 911 EXPECT_CALL(delegate_privet, 912 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA)); 913 914 SimulatePacketReceive(kSamplePacketNsec, 915 sizeof(kSamplePacketNsec)); 916} 917 918TEST_F(MDnsTest, NsecWithTransactionFromNetwork) { 919 scoped_ptr<MDnsTransaction> transaction_privet = 920 test_client_.CreateTransaction( 921 dns_protocol::kTypeA, "_privet._tcp.local", 922 MDnsTransaction::QUERY_NETWORK | 923 MDnsTransaction::QUERY_CACHE | 924 MDnsTransaction::SINGLE_RESULT, 925 base::Bind(&MDnsTest::MockableRecordCallback, 926 base::Unretained(this))); 927 928 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2); 929 930 ASSERT_TRUE(transaction_privet->Start()); 931 932 EXPECT_CALL(*this, 933 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL)); 934 935 SimulatePacketReceive(kSamplePacketNsec, 936 sizeof(kSamplePacketNsec)); 937} 938 939TEST_F(MDnsTest, NsecWithTransactionFromCache) { 940 // Force mDNS to listen. 941 StrictMock<MockListenerDelegate> delegate_irrelevant; 942 scoped_ptr<MDnsListener> listener_irrelevant = 943 test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local", 944 &delegate_irrelevant); 945 listener_irrelevant->Start(); 946 947 SimulatePacketReceive(kSamplePacketNsec, 948 sizeof(kSamplePacketNsec)); 949 950 EXPECT_CALL(*this, 951 MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL)); 952 953 scoped_ptr<MDnsTransaction> transaction_privet_a = 954 test_client_.CreateTransaction( 955 dns_protocol::kTypeA, "_privet._tcp.local", 956 MDnsTransaction::QUERY_NETWORK | 957 MDnsTransaction::QUERY_CACHE | 958 MDnsTransaction::SINGLE_RESULT, 959 base::Bind(&MDnsTest::MockableRecordCallback, 960 base::Unretained(this))); 961 962 ASSERT_TRUE(transaction_privet_a->Start()); 963 964 // Test that a PTR transaction does NOT consider the same NSEC record to be a 965 // valid answer to the query 966 967 scoped_ptr<MDnsTransaction> transaction_privet_ptr = 968 test_client_.CreateTransaction( 969 dns_protocol::kTypePTR, "_privet._tcp.local", 970 MDnsTransaction::QUERY_NETWORK | 971 MDnsTransaction::QUERY_CACHE | 972 MDnsTransaction::SINGLE_RESULT, 973 base::Bind(&MDnsTest::MockableRecordCallback, 974 base::Unretained(this))); 975 976 EXPECT_CALL(socket_factory_, OnSendTo(_)).Times(2); 977 978 ASSERT_TRUE(transaction_privet_ptr->Start()); 979} 980 981TEST_F(MDnsTest, NsecConflictRemoval) { 982 StrictMock<MockListenerDelegate> delegate_privet; 983 scoped_ptr<MDnsListener> listener_privet = 984 test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local", 985 &delegate_privet); 986 987 ASSERT_TRUE(listener_privet->Start()); 988 989 const RecordParsed* record1; 990 const RecordParsed* record2; 991 992 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _)) 993 .WillOnce(SaveArg<1>(&record1)); 994 995 SimulatePacketReceive(kSamplePacketAPrivet, 996 sizeof(kSamplePacketAPrivet)); 997 998 EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _)) 999 .WillOnce(SaveArg<1>(&record2)); 1000 1001 EXPECT_CALL(delegate_privet, 1002 OnNsecRecord("_privet._tcp.local", dns_protocol::kTypeA)); 1003 1004 SimulatePacketReceive(kSamplePacketNsec, 1005 sizeof(kSamplePacketNsec)); 1006 1007 EXPECT_EQ(record1, record2); 1008} 1009 1010 1011// Note: These tests assume that the ipv4 socket will always be created first. 1012// This is a simplifying assumption based on the way the code works now. 1013class SimpleMockSocketFactory : public MDnsSocketFactory { 1014 public: 1015 virtual void CreateSockets( 1016 ScopedVector<DatagramServerSocket>* sockets) OVERRIDE { 1017 sockets->clear(); 1018 sockets->swap(sockets_); 1019 } 1020 1021 void PushSocket(DatagramServerSocket* socket) { 1022 sockets_.push_back(socket); 1023 } 1024 1025 private: 1026 ScopedVector<DatagramServerSocket> sockets_; 1027}; 1028 1029class MockMDnsConnectionDelegate : public MDnsConnection::Delegate { 1030 public: 1031 virtual void HandlePacket(DnsResponse* response, int size) { 1032 HandlePacketInternal(std::string(response->io_buffer()->data(), size)); 1033 } 1034 1035 MOCK_METHOD1(HandlePacketInternal, void(std::string packet)); 1036 1037 MOCK_METHOD1(OnConnectionError, void(int error)); 1038}; 1039 1040class MDnsConnectionTest : public ::testing::Test { 1041 public: 1042 MDnsConnectionTest() : connection_(&delegate_) { 1043 } 1044 1045 protected: 1046 // Follow successful connection initialization. 1047 virtual void SetUp() OVERRIDE { 1048 socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4); 1049 socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6); 1050 factory_.PushSocket(socket_ipv6_); 1051 factory_.PushSocket(socket_ipv4_); 1052 } 1053 1054 bool InitConnection() { 1055 return connection_.Init(&factory_); 1056 } 1057 1058 StrictMock<MockMDnsConnectionDelegate> delegate_; 1059 1060 MockMDnsDatagramServerSocket* socket_ipv4_; 1061 MockMDnsDatagramServerSocket* socket_ipv6_; 1062 SimpleMockSocketFactory factory_; 1063 MDnsConnection connection_; 1064 TestCompletionCallback callback_; 1065}; 1066 1067TEST_F(MDnsConnectionTest, ReceiveSynchronous) { 1068 std::string sample_packet = MakeString(kSamplePacket1, 1069 sizeof(kSamplePacket1)); 1070 1071 socket_ipv6_->SetResponsePacket(sample_packet); 1072 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) 1073 .WillOnce(Return(ERR_IO_PENDING)); 1074 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) 1075 .WillOnce( 1076 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvNow)) 1077 .WillOnce(Return(ERR_IO_PENDING)); 1078 1079 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet)); 1080 1081 ASSERT_TRUE(InitConnection()); 1082} 1083 1084TEST_F(MDnsConnectionTest, ReceiveAsynchronous) { 1085 std::string sample_packet = MakeString(kSamplePacket1, 1086 sizeof(kSamplePacket1)); 1087 socket_ipv6_->SetResponsePacket(sample_packet); 1088 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) 1089 .WillOnce(Return(ERR_IO_PENDING)); 1090 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) 1091 .WillOnce( 1092 Invoke(socket_ipv6_, &MockMDnsDatagramServerSocket::HandleRecvLater)) 1093 .WillOnce(Return(ERR_IO_PENDING)); 1094 1095 ASSERT_TRUE(InitConnection()); 1096 1097 EXPECT_CALL(delegate_, HandlePacketInternal(sample_packet)); 1098 1099 base::MessageLoop::current()->RunUntilIdle(); 1100} 1101 1102TEST_F(MDnsConnectionTest, Send) { 1103 std::string sample_packet = MakeString(kSamplePacket1, 1104 sizeof(kSamplePacket1)); 1105 1106 scoped_refptr<IOBufferWithSize> buf( 1107 new IOBufferWithSize(sizeof kSamplePacket1)); 1108 memcpy(buf->data(), kSamplePacket1, sizeof(kSamplePacket1)); 1109 1110 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) 1111 .WillOnce(Return(ERR_IO_PENDING)); 1112 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) 1113 .WillOnce(Return(ERR_IO_PENDING)); 1114 1115 ASSERT_TRUE(InitConnection()); 1116 1117 EXPECT_CALL(*socket_ipv4_, 1118 SendToInternal(sample_packet, "224.0.0.251:5353", _)); 1119 EXPECT_CALL(*socket_ipv6_, 1120 SendToInternal(sample_packet, "[ff02::fb]:5353", _)); 1121 1122 connection_.Send(buf, buf->size()); 1123} 1124 1125TEST_F(MDnsConnectionTest, Error) { 1126 CompletionCallback callback; 1127 1128 EXPECT_CALL(*socket_ipv4_, RecvFrom(_, _, _, _)) 1129 .WillOnce(Return(ERR_IO_PENDING)); 1130 EXPECT_CALL(*socket_ipv6_, RecvFrom(_, _, _, _)) 1131 .WillOnce(DoAll(SaveArg<3>(&callback), Return(ERR_IO_PENDING))); 1132 1133 ASSERT_TRUE(InitConnection()); 1134 1135 EXPECT_CALL(delegate_, OnConnectionError(ERR_SOCKET_NOT_CONNECTED)); 1136 callback.Run(ERR_SOCKET_NOT_CONNECTED); 1137} 1138 1139} // namespace 1140 1141} // namespace net 1142