blob: 726683d72255fcfbf46e510d2ed83046c995c35a [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/connectivity/network/mdns/service/agents/host_name_requestor.h"
#include <lib/zx/time.h>
#include <gtest/gtest.h>
#include "src/connectivity/network/mdns/service/test/agent_test.h"
#include "src/connectivity/network/mdns/service/test/fake_clock.h"
namespace mdns {
namespace test {
class HostNameRequestorTest : public AgentTest {
public:
HostNameRequestorTest() = default;
protected:
class Subscriber : public Mdns::HostNameSubscriber {
public:
void AddressesChanged(std::vector<HostAddress> addresses) override {
addresses_changed_called_ = true;
addresses_ = std::move(addresses);
}
bool addresses_changed_called() {
bool result = addresses_changed_called_;
addresses_changed_called_ = false;
return result;
}
std::vector<HostAddress> addresses() { return std::move(addresses_); }
private:
bool addresses_changed_called_ = false;
std::vector<HostAddress> addresses_;
};
};
bool VerifyAddresses(std::vector<inet::IpAddress> expected, std::vector<HostAddress> value) {
for (const auto& host_address : value) {
auto iter = std::find(expected.begin(), expected.end(), host_address.address());
if (iter == expected.end()) {
std::cerr << "Address " << host_address.address() << " was not expected.\n";
return false;
}
expected.erase(iter);
}
if (!expected.empty()) {
std::cerr << expected.size() << " expected addresses not found.\n";
return false;
}
return true;
}
bool VerifyAddresses(std::vector<HostAddress> expected, std::vector<HostAddress> value) {
for (const auto& host_address : value) {
auto iter = std::find(expected.begin(), expected.end(), host_address);
if (iter == expected.end()) {
std::cerr << "Address " << host_address.address() << " was not expected.\n";
return false;
}
expected.erase(iter);
}
if (!expected.empty()) {
std::cerr << expected.size() << " expected addresses not found.\n";
return false;
}
return true;
}
constexpr char kHostName[] = "testhostname";
constexpr char kHostFullName[] = "testhostname.local.";
const std::vector<inet::IpAddress> kAddresses{inet::IpAddress(192, 168, 1, 200),
inet::IpAddress(0xfe80, 200)};
const std::vector<inet::IpAddress> kOtherAddresses{inet::IpAddress(192, 168, 1, 201),
inet::IpAddress(0xfe80, 201)};
const std::vector<HostAddress> kHostAddresses{
HostAddress(inet::IpAddress(192, 168, 1, 200), 1, zx::sec(450)),
HostAddress(inet::IpAddress(0xfe80, 200), 1, zx::sec(450))};
constexpr uint32_t kInterfaceId = 1;
constexpr bool kIncludeLocal = true;
constexpr bool kExcludeLocal = false;
constexpr bool kIncludeLocalProxies = true;
constexpr bool kExcludeLocalProxies = false;
// Tests nominal startup behavior of the requestor.
TEST_F(HostNameRequestorTest, Nominal) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
}
// Tests behavior of the requestor when a host responds to the initial questions.
TEST_F(HostNameRequestorTest, Response) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond.
ReplyAddress sender_address(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect to see the addresses from the response.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when a host responds multiple times to the initial questions.
TEST_F(HostNameRequestorTest, Duplicate) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond 4 times.
ReplyAddress sender_address(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (size_t i = 0; i < 4; ++i) {
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
}
under_test.EndOfMessage();
// Expect to see the addresses just once. The renewals happen for each response.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (size_t i = 0; i < 4; ++i) {
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
}
ExpectNoOther();
// Respond again with the same addresses.
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect no new addresses. We still see the renewals.
EXPECT_FALSE(subscriber.addresses_changed_called());
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when the addresses change.
TEST_F(HostNameRequestorTest, Change) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond.
ReplyAddress sender_address(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect to get the addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
// Respond with different addresses.
for (const auto& address : kOtherAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect to see the new addresses and the old ones.
auto combined_addresses = kAddresses;
std::copy(kOtherAddresses.begin(), kOtherAddresses.end(), std::back_inserter(combined_addresses));
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(combined_addresses, subscriber.addresses()));
for (const auto& address : kOtherAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests the behavior of the requestor when an address record indicates addresses should be flushed.
TEST_F(HostNameRequestorTest, AddressCacheFlush) {
FakeClock kayfabe;
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond.
ReplyAddress sender_address(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect to get the addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
// Make sure the above addresses are more than one second old.
FakeClock::Advance(zx::sec(2));
// Respond with different addresses with the first cache flush bit set for each resource type.
bool cache_flush_a = true;
bool cache_flush_aaaa = true;
for (const auto& address : kOtherAddresses) {
auto resource = DnsResource(kHostFullName, address);
if (resource.type_ == DnsType::kA) {
resource.cache_flush_ = cache_flush_a;
cache_flush_a = false;
} else {
FX_DCHECK(resource.type_ == DnsType::kAaaa);
resource.cache_flush_ = cache_flush_aaaa;
cache_flush_aaaa = false;
}
under_test.ReceiveResource(resource, MdnsResourceSection::kAnswer, sender_address);
}
under_test.EndOfMessage();
// Expect to see the new addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kOtherAddresses, subscriber.addresses()));
for (const auto& address : kOtherAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when host address records expire.
TEST_F(HostNameRequestorTest, Expired) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond.
ReplyAddress sender_address(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address);
}
under_test.EndOfMessage();
// Expect to get the addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
// Send expirations for received response.
for (const auto& address : kAddresses) {
auto resource = DnsResource(kHostFullName, address);
resource.time_to_live_ = 0;
under_test.ReceiveResource(resource, MdnsResourceSection::kExpired, sender_address);
}
under_test.EndOfMessage();
// Expect an empty address list.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(subscriber.addresses().empty());
ExpectNoOther();
}
// Tests the the requestor quits after the last subscriber is removed.
TEST_F(HostNameRequestorTest, Quit) {
// Need to |make_shared|, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<HostNameRequestor>(
this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal, kExcludeLocalProxies);
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
// Add and remove a subscriber.
Subscriber subscriber;
under_test->AddSubscriber(&subscriber);
under_test->RemoveSubscriber(&subscriber);
// Expect the requestor to remove itself.
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests behavior of the requestor when configured for wireless operation only.
TEST_F(HostNameRequestorTest, WirelessOnly) {
HostNameRequestor under_test(this, kHostName, Media::kWireless, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message =
ExpectOutboundMessage(ReplyAddress::Multicast(Media::kWireless, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on wired.
ReplyAddress sender_address0(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWired, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address0);
}
under_test.EndOfMessage();
// Expect no addresses.
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on wireless.
ReplyAddress sender_address1(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address1);
}
under_test.EndOfMessage();
// Expect addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when configured for wired operation only.
TEST_F(HostNameRequestorTest, WiredOnly) {
HostNameRequestor under_test(this, kHostName, Media::kWired, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kWired, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on wireless.
ReplyAddress sender_address0(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address0);
}
under_test.EndOfMessage();
// Expect no addresses.
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on wired.
ReplyAddress sender_address1(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWired, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address1);
}
under_test.EndOfMessage();
// Expect addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when configured for IPv4 operation only.
TEST_F(HostNameRequestorTest, V4Only) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kV4, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kV4));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on IPv6.
ReplyAddress sender_address0(inet::SocketAddress(0xfe80, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(0xfe80, 100), kInterfaceId, Media::kWireless,
IpVersions::kV6);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address0);
}
under_test.EndOfMessage();
// Expect no addresses.
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on IPv4.
ReplyAddress sender_address1(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWired, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address1);
}
under_test.EndOfMessage();
// Expect addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests behavior of the requestor when configured for IPv6 operation only.
TEST_F(HostNameRequestorTest, V6Only) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kV6, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kV6));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on IPv4.
ReplyAddress sender_address0(
inet::SocketAddress(192, 168, 1, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address0);
}
under_test.EndOfMessage();
// Expect no addresses.
EXPECT_FALSE(subscriber.addresses_changed_called());
// Respond on IPv6.
ReplyAddress sender_address1(inet::SocketAddress(0xfe80, 200, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(0xfe80, 100), kInterfaceId, Media::kWired,
IpVersions::kV6);
for (const auto& address : kAddresses) {
under_test.ReceiveResource(DnsResource(kHostFullName, address), MdnsResourceSection::kAnswer,
sender_address1);
}
under_test.EndOfMessage();
// Expect addresses.
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kAddresses, subscriber.addresses()));
for (const auto& address : kAddresses) {
ExpectRenewCall(DnsResource(kHostFullName, address));
}
ExpectNoOther();
}
// Tests discovery of the local host.
TEST_F(HostNameRequestorTest, LocalHost) {
HostNameRequestor under_test(this, kLocalHostName, Media::kBoth, IpVersions::kBoth, kIncludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
SetLocalHostAddresses(kHostAddresses);
under_test.Start(kLocalHostFullName);
// Expect no questions, because we're requesting the local host.
ExpectNoOther();
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kHostAddresses, subscriber.addresses()));
}
// Tests discovery of a local proxy host.
TEST_F(HostNameRequestorTest, LocalProxyHost) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kIncludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
under_test.OnAddProxyHost(kHostFullName, kHostAddresses);
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(kHostAddresses, subscriber.addresses()));
under_test.OnRemoveProxyHost(kHostFullName);
EXPECT_TRUE(subscriber.addresses_changed_called());
EXPECT_TRUE(VerifyAddresses(std::vector<HostAddress>(), subscriber.addresses()));
}
// Tests that a local proxy host is not discovered if that feature is off.
TEST_F(HostNameRequestorTest, NoLocalProxyHost) {
HostNameRequestor under_test(this, kHostName, Media::kBoth, IpVersions::kBoth, kExcludeLocal,
kExcludeLocalProxies);
SetAgent(under_test);
under_test.Start(kLocalHostFullName);
// Expect A and AAAA questions on start.
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(Media::kBoth, IpVersions::kBoth));
ExpectQuestion(message.get(), kHostFullName, DnsType::kA);
ExpectQuestion(message.get(), kHostFullName, DnsType::kAaaa);
ExpectNoOtherQuestionOrResource(message.get());
ExpectNoOther();
Subscriber subscriber;
under_test.AddSubscriber(&subscriber);
EXPECT_FALSE(subscriber.addresses_changed_called());
under_test.OnAddProxyHost(kHostFullName, kHostAddresses);
EXPECT_FALSE(subscriber.addresses_changed_called());
}
} // namespace test
} // namespace mdns