blob: 2a7c52fc3f4e4138e3491fa055aa6fe2f0369558 [file] [log] [blame]
// Copyright 2020 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/address_prober.h"
#include <lib/zx/time.h>
#include <gtest/gtest.h>
#include "src/connectivity/network/mdns/service/test/agent_test.h"
namespace mdns {
namespace test {
class AddressProberTest : public AgentTest {
public:
AddressProberTest() {}
protected:
// Expects that a probe for the local host name has been sent.
void ExpectProbe(Media media, IpVersions ip_versions) {
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(media, ip_versions));
ExpectQuestion(message.get(), kLocalHostFullName, DnsType::kAny, DnsClass::kIn, true);
ExpectAddressPlaceholder(message.get(), MdnsResourceSection::kAuthority);
ExpectNoOtherQuestionOrResource(message.get());
}
// Expects that a probe for the specified host name and addresses has been sent.
void ExpectProbe(const std::string& host_full_name, const std::vector<inet::IpAddress>& addresses,
Media media, IpVersions ip_versions) {
auto message = ExpectOutboundMessage(ReplyAddress::Multicast(media, ip_versions));
ExpectQuestion(message.get(), host_full_name, DnsType::kAny, DnsClass::kIn, true);
ExpectAddresses(message.get(), MdnsResourceSection::kAuthority, host_full_name, addresses);
ExpectNoOtherQuestionOrResource(message.get());
}
};
constexpr char kHostFullName[] = "test2host.local.";
constexpr char kAlternateCaseHostFullName[] = "tEst2hOsT.lOcaL.";
const std::vector<inet::IpAddress> kAddresses{inet::IpAddress(192, 168, 1, 200),
inet::IpAddress(192, 168, 1, 201)};
constexpr uint32_t kInterfaceId = 1;
// Tests nominal behavior of the prober when there are no conflicts.
TEST_F(AddressProberTest, Nominal) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, Media::kBoth, IpVersions::kBoth, [&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests behavior of the prober when there is a conflict.
TEST_F(AddressProberTest, Conflict) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, Media::kBoth, IpVersions::kBoth, [&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect the first probe message after a delay of 0~250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kBoth);
ExpectPostTaskForTime(zx::msec(250), zx::msec(250));
EXPECT_FALSE(callback_called);
// Send a reply.
ReplyAddress sender_address0(
inet::SocketAddress(192, 168, 1, kInterfaceId, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
under_test->ReceiveResource(DnsResource(kLocalHostFullName, inet::IpAddress(192, 168, 1, 1)),
MdnsResourceSection::kAnswer, sender_address0);
// Callback and removal are run in a task.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(0));
// Expect the probe to fail (conflict).
EXPECT_TRUE(callback_called);
EXPECT_FALSE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
// Redoing test with a case insensitive conflict
callback_called = false;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
under_test = std::make_shared<AddressProber>(this, Media::kBoth, IpVersions::kBoth,
[&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect the first probe message after a delay of 0~250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kBoth);
ExpectPostTaskForTime(zx::msec(250), zx::msec(250));
EXPECT_FALSE(callback_called);
// Send a reply.
ReplyAddress sender_address1(
inet::SocketAddress(192, 168, 1, kInterfaceId, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWireless, IpVersions::kV4);
under_test->ReceiveResource(
DnsResource(kAlternateCaseLocalHostFullName, inet::IpAddress(192, 168, 1, 1)),
MdnsResourceSection::kAnswer, sender_address1);
// Callback and removal are run in a task.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(0));
// Expect the probe to fail (conflict).
EXPECT_TRUE(callback_called);
EXPECT_FALSE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests nominal behavior of the prober configured for wired-only.
TEST_F(AddressProberTest, NominalWiredOnly) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, Media::kWired, IpVersions::kBoth, [&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kWired, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kWired, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kWired, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests nominal behavior of the prober configured for wireless-only.
TEST_F(AddressProberTest, NominalWirelessOnly) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test =
std::make_shared<AddressProber>(this, Media::kWireless, IpVersions::kBoth,
[&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kWireless, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kWireless, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kWireless, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests nominal behavior of the prober configured for IPv4 only.
TEST_F(AddressProberTest, NominalV4) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, Media::kBoth, IpVersions::kV4, [&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV4);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV4);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV4);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests nominal behavior of the prober configured for IPv6 only.
TEST_F(AddressProberTest, NominalV6) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, Media::kBoth, IpVersions::kV6, [&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV6);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV6);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(Media::kBoth, IpVersions::kV6);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests nominal behavior of the prober created with explicit host name and addresses..
TEST_F(AddressProberTest, HostNameAndAddresses) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, kHostFullName, kAddresses, Media::kBoth, IpVersions::kBoth,
[&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect three probe messages, the first after a delay of 0~250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(kHostFullName, kAddresses, Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...the second after a delay of 250ms...
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(kHostFullName, kAddresses, Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
// ...and the third after a delay of 250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
ExpectProbe(kHostFullName, kAddresses, Media::kBoth, IpVersions::kBoth);
EXPECT_FALSE(callback_called);
ExpectPostTaskForTimeAndInvoke(zx::msec(250), zx::msec(250));
EXPECT_TRUE(callback_called);
EXPECT_TRUE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
// Tests behavior of a wired-only/IPv6-only prober when there is a conflict.
TEST_F(AddressProberTest, ConflictWiredV6) {
bool callback_called = false;
bool callback_success;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
auto under_test = std::make_shared<AddressProber>(
this, kHostFullName, kAddresses, Media::kWired, IpVersions::kV6,
[&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect the first probe message after a delay of 0~250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(kHostFullName, kAddresses, Media::kWired, IpVersions::kV6);
ExpectPostTaskForTime(zx::msec(250), zx::msec(250));
EXPECT_FALSE(callback_called);
// Send a reply wired/V4. Expect it to be ignored, because it's V4
ReplyAddress sender_address0(
inet::SocketAddress(192, 168, 1, 1, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(192, 168, 1, 100), kInterfaceId, Media::kWired, IpVersions::kV4);
under_test->ReceiveResource(DnsResource(kHostFullName, inet::IpAddress(192, 168, 1, 1)),
MdnsResourceSection::kAnswer, sender_address0);
EXPECT_FALSE(callback_called);
ExpectNoOther();
// Send a reply wireless/V6. Expect it to be ignored, because it's wireless
ReplyAddress sender_address1(inet::SocketAddress(0xfe80, 1, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(0xfe80, 100), kInterfaceId, Media::kWireless,
IpVersions::kV6);
under_test->ReceiveResource(DnsResource(kHostFullName, inet::IpAddress(0xfe80, 1)),
MdnsResourceSection::kAnswer, sender_address1);
EXPECT_FALSE(callback_called);
ExpectNoOther();
// Send a reply wired/V6. Expect it to be ignored, because it's wireless
ReplyAddress sender_address2(inet::SocketAddress(0xfe80, 1, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(0xfe80, 100), kInterfaceId, Media::kWired,
IpVersions::kV6);
under_test->ReceiveResource(DnsResource(kHostFullName, inet::IpAddress(0xfe80, 1)),
MdnsResourceSection::kAnswer, sender_address2);
// Callback and removal are run in a task.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(0));
// Expect the probe to fail (conflict).
EXPECT_TRUE(callback_called);
EXPECT_FALSE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
// Reset Variables and test case insensitive hostname conflict
callback_called = false;
// We need to make_shared here, because |RemoveSelf| calls |shared_from_this|.
under_test = std::make_shared<AddressProber>(this, kHostFullName, kAddresses, Media::kWired,
IpVersions::kV6,
[&callback_called, &callback_success](bool success) {
callback_called = true;
callback_success = success;
});
SetAgent(*under_test);
under_test->Start(kLocalHostFullName);
// Expect the first probe message after a delay of 0~250ms.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(250));
ExpectProbe(kHostFullName, kAddresses, Media::kWired, IpVersions::kV6);
ExpectPostTaskForTime(zx::msec(250), zx::msec(250));
EXPECT_FALSE(callback_called);
// Send a reply wired/V6.
ReplyAddress sender_address3(inet::SocketAddress(0xfe80, 1, inet::IpPort::From_uint16_t(5353)),
inet::IpAddress(0xfe80, 100), kInterfaceId, Media::kWired,
IpVersions::kV6);
under_test->ReceiveResource(DnsResource(kAlternateCaseHostFullName, inet::IpAddress(0xfe80, 1)),
MdnsResourceSection::kAnswer, sender_address3);
// Callback and removal are run in a task.
ExpectPostTaskForTimeAndInvoke(zx::msec(0), zx::msec(0));
// Expect the probe to fail (conflict).
EXPECT_TRUE(callback_called);
EXPECT_FALSE(callback_success);
ExpectRemoveAgentCall();
ExpectNoOther();
}
} // namespace test
} // namespace mdns