You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
903 lines
40 KiB
903 lines
40 KiB
// Copyright 2019 The Chromium 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 "discovery/mdns/mdns_querier.h"
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "discovery/common/config.h"
|
|
#include "discovery/common/testing/mock_reporting_client.h"
|
|
#include "discovery/mdns/mdns_random.h"
|
|
#include "discovery/mdns/mdns_receiver.h"
|
|
#include "discovery/mdns/mdns_record_changed_callback.h"
|
|
#include "discovery/mdns/mdns_sender.h"
|
|
#include "discovery/mdns/mdns_trackers.h"
|
|
#include "discovery/mdns/mdns_writer.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
#include "platform/base/udp_packet.h"
|
|
#include "platform/test/fake_clock.h"
|
|
#include "platform/test/fake_task_runner.h"
|
|
#include "platform/test/mock_udp_socket.h"
|
|
|
|
namespace openscreen {
|
|
namespace discovery {
|
|
|
|
using testing::_;
|
|
using testing::Args;
|
|
using testing::Invoke;
|
|
using testing::Return;
|
|
using testing::StrictMock;
|
|
using testing::WithArgs;
|
|
|
|
// Only compare NAME, CLASS, TYPE and RDATA
|
|
ACTION_P(PartialCompareRecords, expected) {
|
|
const MdnsRecord& actual = arg0;
|
|
EXPECT_TRUE(actual.name() == expected.name());
|
|
EXPECT_TRUE(actual.dns_class() == expected.dns_class());
|
|
EXPECT_TRUE(actual.dns_type() == expected.dns_type());
|
|
EXPECT_TRUE(actual.rdata() == expected.rdata());
|
|
return std::vector<PendingQueryChange>{};
|
|
}
|
|
|
|
class MockRecordChangedCallback : public MdnsRecordChangedCallback {
|
|
public:
|
|
MOCK_METHOD(std::vector<PendingQueryChange>,
|
|
OnRecordChanged,
|
|
(const MdnsRecord&, RecordChangedEvent event),
|
|
(override));
|
|
};
|
|
|
|
class MdnsQuerierTest : public testing::Test {
|
|
public:
|
|
MdnsQuerierTest()
|
|
: clock_(Clock::now()),
|
|
task_runner_(&clock_),
|
|
sender_(&socket_),
|
|
receiver_(config_),
|
|
record0_created_(DomainName{"testing", "local"},
|
|
DnsType::kA,
|
|
DnsClass::kIN,
|
|
RecordType::kUnique,
|
|
std::chrono::seconds(120),
|
|
ARecordRdata(IPAddress{172, 0, 0, 1})),
|
|
record0_updated_(DomainName{"testing", "local"},
|
|
DnsType::kA,
|
|
DnsClass::kIN,
|
|
RecordType::kUnique,
|
|
std::chrono::seconds(120),
|
|
ARecordRdata(IPAddress{172, 0, 0, 2})),
|
|
record0_deleted_(DomainName{"testing", "local"},
|
|
DnsType::kA,
|
|
DnsClass::kIN,
|
|
RecordType::kUnique,
|
|
std::chrono::seconds(0), // a goodbye record
|
|
ARecordRdata(IPAddress{172, 0, 0, 2})),
|
|
record1_created_(DomainName{"poking", "local"},
|
|
DnsType::kA,
|
|
DnsClass::kIN,
|
|
RecordType::kShared,
|
|
std::chrono::seconds(120),
|
|
ARecordRdata(IPAddress{192, 168, 0, 1})),
|
|
record1_deleted_(DomainName{"poking", "local"},
|
|
DnsType::kA,
|
|
DnsClass::kIN,
|
|
RecordType::kShared,
|
|
std::chrono::seconds(0), // a goodbye record
|
|
ARecordRdata(IPAddress{192, 168, 0, 1})),
|
|
record2_created_(DomainName{"testing", "local"},
|
|
DnsType::kAAAA,
|
|
DnsClass::kIN,
|
|
RecordType::kUnique,
|
|
std::chrono::seconds(120),
|
|
AAAARecordRdata(IPAddress{1, 2, 3, 4, 5, 6, 7, 8})),
|
|
nsec_record_created_(
|
|
DomainName{"testing", "local"},
|
|
DnsType::kNSEC,
|
|
DnsClass::kIN,
|
|
RecordType::kUnique,
|
|
std::chrono::seconds(120),
|
|
NsecRecordRdata(DomainName{"testing", "local"}, DnsType::kA)) {
|
|
receiver_.Start();
|
|
}
|
|
|
|
std::unique_ptr<MdnsQuerier> CreateQuerier() {
|
|
return std::make_unique<MdnsQuerier>(&sender_, &receiver_, &task_runner_,
|
|
&FakeClock::now, &random_,
|
|
&reporting_client_, config_);
|
|
}
|
|
|
|
protected:
|
|
template <typename... DnsTypes>
|
|
MdnsRecord CreateNsec(DomainName name, DnsTypes... types) {
|
|
NsecRecordRdata rdata(name, types...);
|
|
return MdnsRecord(std::move(name), nsec_record_created_.dns_type(),
|
|
nsec_record_created_.dns_class(),
|
|
nsec_record_created_.record_type(),
|
|
nsec_record_created_.ttl(), std::move(rdata));
|
|
}
|
|
|
|
UdpPacket CreatePacketWithRecords(
|
|
const std::vector<MdnsRecord::ConstRef>& records,
|
|
std::vector<MdnsRecord::ConstRef> additional_records) {
|
|
MdnsMessage message(CreateMessageId(), MessageType::Response);
|
|
for (const MdnsRecord& record : records) {
|
|
message.AddAnswer(record);
|
|
}
|
|
for (const MdnsRecord& additional_record : additional_records) {
|
|
message.AddAdditionalRecord(additional_record);
|
|
}
|
|
UdpPacket packet(message.MaxWireSize());
|
|
MdnsWriter writer(packet.data(), packet.size());
|
|
EXPECT_TRUE(writer.Write(message));
|
|
packet.resize(writer.offset());
|
|
return packet;
|
|
}
|
|
|
|
UdpPacket CreatePacketWithRecords(
|
|
const std::vector<MdnsRecord::ConstRef>& records) {
|
|
return CreatePacketWithRecords(records, {});
|
|
}
|
|
|
|
UdpPacket CreatePacketWithRecord(const MdnsRecord& record) {
|
|
return CreatePacketWithRecords({MdnsRecord::ConstRef(record)});
|
|
}
|
|
|
|
// NSEC records are never exposed to outside callers, so the below methods are
|
|
// necessary to validate that they are functioning as expected.
|
|
bool ContainsRecord(MdnsQuerier* querier,
|
|
const MdnsRecord& record,
|
|
DnsType type = DnsType::kANY) {
|
|
auto record_trackers =
|
|
querier->records_.Find(record.name(), type, record.dns_class());
|
|
|
|
return std::find_if(record_trackers.begin(), record_trackers.end(),
|
|
[&record](const MdnsRecordTracker& tracker) {
|
|
return tracker.rdata() == record.rdata() &&
|
|
tracker.ttl() == record.ttl();
|
|
}) != record_trackers.end();
|
|
}
|
|
|
|
size_t RecordCount(MdnsQuerier* querier) { return querier->records_.size(); }
|
|
|
|
Config config_;
|
|
FakeClock clock_;
|
|
FakeTaskRunner task_runner_;
|
|
testing::NiceMock<MockUdpSocket> socket_;
|
|
MdnsSender sender_;
|
|
MdnsReceiver receiver_;
|
|
MdnsRandom random_;
|
|
StrictMock<MockReportingClient> reporting_client_;
|
|
|
|
MdnsRecord record0_created_;
|
|
MdnsRecord record0_updated_;
|
|
MdnsRecord record0_deleted_;
|
|
MdnsRecord record1_created_;
|
|
MdnsRecord record1_deleted_;
|
|
MdnsRecord record2_created_;
|
|
MdnsRecord nsec_record_created_;
|
|
};
|
|
|
|
TEST_F(MdnsQuerierTest, UniqueRecordCreatedUpdatedDeleted) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kUpdated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_updated_)));
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_deleted_)));
|
|
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
// Receiving the same record should only reset TTL, no callback
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_deleted_));
|
|
|
|
// Advance clock for expiration to happen, since it's delayed by 1 second as
|
|
// per RFC 6762.
|
|
clock_.Advance(std::chrono::seconds(1));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, WildcardQuery) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kANY,
|
|
DnsClass::kANY, &callback);
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record1_created_)));
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record1_deleted_)));
|
|
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_deleted_));
|
|
|
|
// Advance clock for expiration to happen, since it's delayed by 1 second as
|
|
// per RFC 6762.
|
|
clock_.Advance(std::chrono::seconds(1));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, SharedRecordCreatedDeleted) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record1_created_)));
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kExpired))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record1_deleted_)));
|
|
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
// Receiving the same record should only reset TTL, no callback
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_deleted_));
|
|
|
|
// Advance clock for expiration to happen, since it's delayed by 1 second as
|
|
// per RFC 6762.
|
|
clock_.Advance(std::chrono::seconds(1));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, StartQueryTwice) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
|
|
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, MultipleCallbacks) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback_1;
|
|
MockRecordChangedCallback callback_2;
|
|
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback_1);
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback_2);
|
|
|
|
EXPECT_CALL(callback_1, OnRecordChanged(_, _)).Times(1);
|
|
EXPECT_CALL(callback_2, OnRecordChanged(_, _)).Times(2);
|
|
|
|
// Both callbacks will be invoked.
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback_1);
|
|
|
|
// Only callback_2 will be invoked.
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback_2);
|
|
// No callbacks will be invoked as all have been stopped.
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NoRecordChangesAfterStop) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, OnRecordChangeCallbacksGetRun) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
DomainName name = DomainName{"testing", "local"};
|
|
querier->StartQuery(name, DnsType::kA, DnsClass::kIN, &callback);
|
|
PendingQueryChange result{name, DnsType::kA, DnsClass::kIN, &callback,
|
|
PendingQueryChange::kStopQuery};
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _))
|
|
.WillOnce(Return(std::vector<PendingQueryChange>{result}));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, StopQueryTwice) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(0);
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, StopNonExistingQuery) {
|
|
// Just making sure nothing crashes.
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, IrrelevantRecordReceived) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(1);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, DifferentCallersSameQuestion) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback1;
|
|
MockRecordChangedCallback callback2;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback1);
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback2);
|
|
EXPECT_CALL(callback1, OnRecordChanged(_, _)).Times(1);
|
|
EXPECT_CALL(callback2, OnRecordChanged(_, _)).Times(1);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, DifferentCallersDifferentQuestions) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback1;
|
|
MockRecordChangedCallback callback2;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback1);
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback2);
|
|
EXPECT_CALL(callback1, OnRecordChanged(_, _)).Times(1);
|
|
EXPECT_CALL(callback2, OnRecordChanged(_, _)).Times(1);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, SameCallerDifferentQuestions) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
EXPECT_CALL(callback, OnRecordChanged(_, _)).Times(2);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, ReinitializeQueries) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
|
|
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
// Receiving the same record should only reset TTL, no callback
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
testing::Mock::VerifyAndClearExpectations(&receiver_);
|
|
|
|
// Queries should still be ongoing but all received records should have been
|
|
// deleted.
|
|
querier->ReinitializeQueries(DomainName{"testing", "local"});
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
testing::Mock::VerifyAndClearExpectations(&receiver_);
|
|
|
|
// Reinitializing a different domain should not affect other queries.
|
|
querier->ReinitializeQueries(DomainName{"testing2", "local"});
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, MessagesForUnknownQueriesDropped) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
// Message for unknown query does not get processed.
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record1_created_));
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
|
|
querier->StopQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
|
|
// Only known records from the message are processed.
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.Times(1);
|
|
receiver_.OnRead(
|
|
&socket_, CreatePacketWithRecords({record0_created_, record1_created_}));
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, MessagesForKnownRecordsAllowed) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
// Store a message for a known query.
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_created_));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
|
|
// Stop the query and validate that record updates are still received.
|
|
querier->StopQuery(DomainName{"testing", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecord(record0_updated_));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
|
|
querier->StopQuery(DomainName{"poking", "local"}, DnsType::kA, DnsClass::kIN,
|
|
&callback);
|
|
|
|
// Only known records from the message are processed.
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_updated_, RecordChangedEvent::kCreated))
|
|
.Times(1);
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, MessagesForUnknownKnownRecordsAllowsAdditionalRecords) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MockRecordChangedCallback callback;
|
|
|
|
// Store a message for a known query.
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kCreated))
|
|
.Times(1);
|
|
receiver_.OnRead(&socket_, CreatePacketWithRecords({record1_created_},
|
|
{record0_created_}));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecDroppedWhenCorrespondsToNonNsec) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecords(
|
|
{record0_created_, nsec_record_created_, record2_created_});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record2_created_)));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{2});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record2_created_, DnsType::kAAAA));
|
|
|
|
// Do it again in the another record order.
|
|
querier = CreateQuerier();
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
packet = CreatePacketWithRecords(
|
|
{nsec_record_created_, record2_created_, record0_created_});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record2_created_)));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{2});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record2_created_, DnsType::kAAAA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, MultipleNsecCombinedWhenSameName) {
|
|
DomainName alternate_name{"poking", "local"};
|
|
MdnsRecord multi_type_nsec =
|
|
CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
|
|
MdnsRecord aaaa_nsec =
|
|
CreateNsec(nsec_record_created_.name(), DnsType::kAAAA);
|
|
MdnsRecord srv_nsec = CreateNsec(alternate_name, DnsType::kSRV);
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
auto packet =
|
|
CreatePacketWithRecords({nsec_record_created_, srv_nsec, aaaa_nsec});
|
|
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{3});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), srv_nsec, DnsType::kSRV));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecBitsUnSetWhenCorrespondsToExistingRecord) {
|
|
MdnsRecord multi_type_nsec =
|
|
CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
|
|
MdnsRecord aaaa_nsec =
|
|
CreateNsec(nsec_record_created_.name(), DnsType::kAAAA);
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecords({multi_type_nsec, record0_created_});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{2});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa_nsec, DnsType::kAAAA));
|
|
|
|
// Do it again in the another record order.
|
|
querier = CreateQuerier();
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
packet = CreatePacketWithRecords({record0_created_, multi_type_nsec});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{2});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa_nsec, DnsType::kAAAA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecDroppedWhenAllBitsUnset) {
|
|
MdnsRecord multi_type_nsec =
|
|
CreateNsec(nsec_record_created_.name(), DnsType::kA, DnsType::kAAAA);
|
|
MdnsRecord aaaa(record0_created_.name(), DnsType::kAAAA,
|
|
record0_created_.dns_class(), record0_created_.record_type(),
|
|
record0_created_.ttl(),
|
|
AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
auto packet =
|
|
CreatePacketWithRecords({multi_type_nsec, record0_created_, aaaa});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(record0_created_)))
|
|
.WillOnce(WithArgs<0>(PartialCompareRecords(aaaa)));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{2});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecUpdatesMultipleRecords) {
|
|
const DomainName& first_name = record0_created_.name();
|
|
const DomainName alternate_name{"poking", "local"};
|
|
const DomainName third_name{"third", "local"};
|
|
MdnsRecord nsec_first_name =
|
|
CreateNsec(first_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
|
|
MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
|
|
MdnsRecord nsec_second_name =
|
|
CreateNsec(alternate_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
|
|
|
|
MdnsRecord srv(third_name, DnsType::kSRV, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
SrvRecordRdata(1, 2, 3, third_name));
|
|
MdnsRecord nsec_third_name =
|
|
CreateNsec(third_name, DnsType::kA, DnsType::kAAAA, DnsType::kSRV);
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
querier->StartQuery(third_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
auto packet =
|
|
CreatePacketWithRecords({nsec_first_name, nsec_second_name,
|
|
nsec_third_name, record0_created_, aaaa, srv});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.Times(3);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{9});
|
|
|
|
MdnsRecord new_first_nsec =
|
|
CreateNsec(first_name, DnsType::kAAAA, DnsType::kSRV);
|
|
MdnsRecord new_second_nsec =
|
|
CreateNsec(alternate_name, DnsType::kA, DnsType::kSRV);
|
|
MdnsRecord new_third_nsec =
|
|
CreateNsec(third_name, DnsType::kA, DnsType::kAAAA);
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_first_nsec, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_first_nsec, DnsType::kSRV));
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_second_nsec, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_second_nsec, DnsType::kSRV));
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_third_nsec, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), new_third_nsec, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecDeletesMultipleRecords) {
|
|
const DomainName& first_name = record0_created_.name();
|
|
const DomainName alternate_name{"poking", "local"};
|
|
MdnsRecord nsec_first = CreateNsec(first_name, DnsType::kA);
|
|
|
|
MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
|
|
MdnsRecord srv(alternate_name, DnsType::kSRV, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
SrvRecordRdata(1, 2, 3, first_name));
|
|
MdnsRecord nsec_second =
|
|
CreateNsec(alternate_name, DnsType::kAAAA, DnsType::kSRV);
|
|
MdnsRecord nsec_third = CreateNsec(alternate_name, DnsType::kAAAA);
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecords(
|
|
{record0_created_, aaaa, srv, nsec_first, nsec_second, nsec_third});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.Times(3);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{3});
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NsecCreatesUpdatesAndDeletesMultipleRecords) {
|
|
const DomainName& first_name = record0_created_.name();
|
|
const DomainName alternate_name{"poking", "local"};
|
|
const DomainName third_name{"third", "local"};
|
|
MdnsRecord nsec_first_name = CreateNsec(first_name, DnsType::kA);
|
|
|
|
MdnsRecord aaaa(alternate_name, DnsType::kAAAA, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
AAAARecordRdata(IPAddress{172, 0, 0, 0, 0, 0, 0, 1}));
|
|
MdnsRecord nsec_second_name =
|
|
CreateNsec(alternate_name, DnsType::kAAAA, DnsType::kSRV);
|
|
MdnsRecord srv(alternate_name, DnsType::kSRV, record0_created_.dns_class(),
|
|
record0_created_.record_type(), record0_created_.ttl(),
|
|
SrvRecordRdata(1, 2, 3, third_name));
|
|
|
|
MdnsRecord nsec_third_name = CreateNsec(third_name, DnsType::kA);
|
|
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(first_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
querier->StartQuery(alternate_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
querier->StartQuery(third_name, DnsType::kANY, DnsClass::kIN, &callback);
|
|
auto packet =
|
|
CreatePacketWithRecords({nsec_first_name, nsec_second_name,
|
|
nsec_third_name, record0_created_, aaaa, srv});
|
|
|
|
EXPECT_CALL(callback, OnRecordChanged(_, RecordChangedEvent::kCreated))
|
|
.Times(3);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{4});
|
|
|
|
MdnsRecord new_second_nsec = CreateNsec(alternate_name, DnsType::kSRV);
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), aaaa, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), srv, DnsType::kSRV));
|
|
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), nsec_third_name, DnsType::kA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, CallbackNotCalledOnStartQueryForNsecRecords) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
// Set up so an NSEC record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecord(nsec_record_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{1});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
|
|
// Start new query
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, ReceiveNsecRecordFansOutToEachType) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
MdnsRecord multi_type_nsec =
|
|
MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
|
|
nsec_record_created_.dns_class(),
|
|
nsec_record_created_.record_type(), nsec_record_created_.ttl(),
|
|
NsecRecordRdata(nsec_record_created_.name(), DnsType::kA,
|
|
DnsType::kSRV, DnsType::kAAAA));
|
|
auto packet = CreatePacketWithRecord(multi_type_nsec);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{3});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kSRV));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, ReceiveNsecKAnyRecordFansOutToAllTypes) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
MdnsRecord any_type_nsec =
|
|
MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
|
|
nsec_record_created_.dns_class(),
|
|
nsec_record_created_.record_type(), nsec_record_created_.ttl(),
|
|
NsecRecordRdata(nsec_record_created_.name(), DnsType::kANY));
|
|
auto packet = CreatePacketWithRecord(any_type_nsec);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{5});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kAAAA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kSRV));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kTXT));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), any_type_nsec, DnsType::kPTR));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNsecRecordReplacesNonNsec) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
// Set up so an A record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
|
|
auto packet = CreatePacketWithRecord(record0_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
ASSERT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_FALSE(
|
|
ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kExpired));
|
|
packet = CreatePacketWithRecord(nsec_record_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest,
|
|
NoCallbackCalledWhenNsecRecordWouldReplaceNonNsecButNsecDisabled) {
|
|
config_.ignore_nsec_responses = true;
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
// Set up so an A record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
|
|
auto packet = CreatePacketWithRecord(record0_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
ASSERT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_FALSE(
|
|
ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
|
|
packet = CreatePacketWithRecord(nsec_record_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_FALSE(
|
|
ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, CorrectCallbackCalledWhenNonNsecRecordReplacesNsec) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
// Set up so an A record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecord(nsec_record_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
|
|
packet = CreatePacketWithRecord(record0_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
EXPECT_FALSE(
|
|
ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, NoCallbackCalledWhenSecondNsecRecordReceived) {
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
MdnsRecord multi_type_nsec =
|
|
MdnsRecord(nsec_record_created_.name(), nsec_record_created_.dns_type(),
|
|
nsec_record_created_.dns_class(),
|
|
nsec_record_created_.record_type(), nsec_record_created_.ttl(),
|
|
NsecRecordRdata(nsec_record_created_.name(), DnsType::kA,
|
|
DnsType::kSRV, DnsType::kAAAA));
|
|
|
|
// Set up so an A record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kA,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecord(nsec_record_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_TRUE(ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
EXPECT_FALSE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
|
|
|
|
packet = CreatePacketWithRecord(multi_type_nsec);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
EXPECT_FALSE(
|
|
ContainsRecord(querier.get(), nsec_record_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), multi_type_nsec, DnsType::kA));
|
|
}
|
|
|
|
TEST_F(MdnsQuerierTest, TestMaxRecordsRespected) {
|
|
config_.querier_max_records_cached = 1;
|
|
std::unique_ptr<MdnsQuerier> querier = CreateQuerier();
|
|
|
|
// Set up so an A record has been received
|
|
StrictMock<MockRecordChangedCallback> callback;
|
|
querier->StartQuery(DomainName{"testing", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
querier->StartQuery(DomainName{"poking", "local"}, DnsType::kANY,
|
|
DnsClass::kIN, &callback);
|
|
auto packet = CreatePacketWithRecord(record0_created_);
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kCreated));
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{1});
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_FALSE(ContainsRecord(querier.get(), record1_created_, DnsType::kA));
|
|
testing::Mock::VerifyAndClearExpectations(&callback);
|
|
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record0_created_, RecordChangedEvent::kExpired));
|
|
EXPECT_CALL(callback,
|
|
OnRecordChanged(record1_created_, RecordChangedEvent::kCreated));
|
|
packet = CreatePacketWithRecord(record1_created_);
|
|
receiver_.OnRead(&socket_, std::move(packet));
|
|
ASSERT_EQ(RecordCount(querier.get()), size_t{1});
|
|
EXPECT_FALSE(ContainsRecord(querier.get(), record0_created_, DnsType::kA));
|
|
EXPECT_TRUE(ContainsRecord(querier.get(), record1_created_, DnsType::kA));
|
|
}
|
|
|
|
} // namespace discovery
|
|
} // namespace openscreen
|