blob: aa640e9971dd9a73c7d3614735e0c6e30b12ab49 [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/test/agent_test.h"
#include <iostream>
namespace mdns {
std::ostream& operator<<(std::ostream& os, DnsType value) {
switch (value) {
case DnsType::kA:
return os << "A";
case DnsType::kNs:
return os << "NS";
case DnsType::kCName:
return os << "CNAME";
case DnsType::kPtr:
return os << "PTR";
case DnsType::kTxt:
return os << "TXT";
case DnsType::kAaaa:
return os << "AAAA";
case DnsType::kSrv:
return os << "SRV";
case DnsType::kOpt:
return os << "OPT";
case DnsType::kNSec:
return os << "NSEC";
case DnsType::kAny:
return os << "any";
default:
return os << "TYPE " << static_cast<uint16_t>(value);
}
}
std::ostream& operator<<(std::ostream& os, MdnsResourceSection value) {
switch (value) {
case MdnsResourceSection::kAnswer:
return os << "answer";
case MdnsResourceSection::kAuthority:
return os << "authority";
case MdnsResourceSection::kAdditional:
return os << "additional";
case MdnsResourceSection::kExpired:
return os << "EXPIRED";
}
}
namespace test {
const std::string AgentTest::kHostFullName = "testhost.local.";
void AgentTest::PostTaskForTime(MdnsAgent* agent, fit::closure task, zx::time target_time) {
EXPECT_EQ(agent_, agent);
post_task_for_time_calls_.push(
PostTaskForTimeCall{.task_ = std::move(task), .target_time_ = target_time});
}
void AgentTest::SendQuestion(std::shared_ptr<DnsQuestion> question) {
EXPECT_NE(nullptr, question);
auto& message = outbound_messages_by_reply_address_[addresses_.multicast_reply()];
if (message == nullptr) {
message = std::make_unique<DnsMessage>();
}
message->questions_.push_back(question);
}
void AgentTest::SendResource(std::shared_ptr<DnsResource> resource, MdnsResourceSection section,
const ReplyAddress& reply_address) {
EXPECT_NE(nullptr, resource);
auto& message = outbound_messages_by_reply_address_[addresses_.multicast_reply()];
if (message == nullptr) {
message = std::make_unique<DnsMessage>();
}
switch (section) {
case MdnsResourceSection::kAnswer:
message->answers_.push_back(resource);
break;
case MdnsResourceSection::kAuthority:
message->authorities_.push_back(resource);
break;
case MdnsResourceSection::kAdditional:
message->additionals_.push_back(resource);
break;
case MdnsResourceSection::kExpired:
EXPECT_TRUE(false);
break;
}
}
void AgentTest::SendAddresses(MdnsResourceSection section, const ReplyAddress& reply_address) {
SendResource(address_placeholder_, section, reply_address);
}
void AgentTest::Renew(const DnsResource& resource) {
renew_calls_.push(RenewCall{.resource_ = resource});
}
void AgentTest::RemoveAgent(const MdnsAgent* agent,
const std::string& published_instance_full_name) {
EXPECT_EQ(agent_, agent);
remove_agent_called_ = true;
}
void AgentTest::AdvanceTo(zx::time time) {
EXPECT_LE(now_, time);
now_ = time;
}
std::pair<fit::closure, zx::time> AgentTest::ExpectPostTaskForTime(zx::duration earliest,
zx::duration latest) {
EXPECT_FALSE(post_task_for_time_calls_.empty());
auto task = std::move(post_task_for_time_calls_.front().task_);
EXPECT_NE(nullptr, task);
auto time = post_task_for_time_calls_.front().target_time_;
post_task_for_time_calls_.pop();
EXPECT_LE(now_ + earliest, time);
EXPECT_GE(now_ + latest, time);
return std::pair(std::move(task), time);
}
void AgentTest::ExpectPostTaskForTimeAndInvoke(zx::duration earliest, zx::duration latest) {
auto [task, time] = ExpectPostTaskForTime(earliest, latest);
ExpectNoOther();
AdvanceTo(time);
task();
}
std::unique_ptr<DnsMessage> AgentTest::ExpectOutboundMessage(ReplyAddress reply_address) {
auto message = std::move(outbound_messages_by_reply_address_[reply_address]);
EXPECT_NE(nullptr, message);
outbound_messages_by_reply_address_.erase(reply_address);
return message;
}
void AgentTest::ExpectNoOther() {
ExpectNoPostTaskForTime();
ExpectNoOutboundMessage();
ExpectNoRenewCalls();
ExpectNoRemoveAgentCall();
}
void AgentTest::ExpectQuestion(DnsMessage* message, const std::string& name, DnsType type,
DnsClass dns_class, bool unicast_response) {
EXPECT_NE(nullptr, message);
for (auto i = message->questions_.begin(); i != message->questions_.end(); ++i) {
if ((*i)->name_.dotted_string_.compare(name) == 0 && (*i)->type_ == type &&
(*i)->class_ == dns_class && (*i)->unicast_response_ == unicast_response) {
message->questions_.erase(i);
return;
}
}
EXPECT_TRUE(false) << "No matching question with name " << name << " and type " << type
<< " in message.";
}
std::shared_ptr<DnsResource> AgentTest::ExpectResource(DnsMessage* message,
MdnsResourceSection section,
const std::string& name, DnsType type,
DnsClass dns_class, bool cache_flush) {
EXPECT_NE(nullptr, message);
std::vector<std::shared_ptr<DnsResource>>* collection;
switch (section) {
case MdnsResourceSection::kAnswer:
collection = &message->answers_;
break;
case MdnsResourceSection::kAuthority:
collection = &message->authorities_;
break;
case MdnsResourceSection::kAdditional:
collection = &message->additionals_;
break;
case MdnsResourceSection::kExpired:
EXPECT_TRUE(false);
return nullptr;
}
for (auto i = collection->begin(); i != collection->end(); ++i) {
if ((*i)->name_.dotted_string_.compare(name) == 0 && (*i)->type_ == type &&
(*i)->class_ == dns_class && (*i)->cache_flush_ == cache_flush) {
auto result = std::move(*i);
collection->erase(i);
return result;
}
}
EXPECT_TRUE(false) << "No matching resource with name " << name << " and type " << type
<< " in section " << section << " of message.";
return nullptr;
}
void AgentTest::ExpectAddressPlaceholder(DnsMessage* message, MdnsResourceSection section) {
ExpectResource(message, section, kHostFullName, DnsType::kA);
}
void AgentTest::ExpectNoOtherQuestionOrResource(DnsMessage* message) {
EXPECT_NE(nullptr, message);
EXPECT_TRUE(message->questions_.empty());
EXPECT_TRUE(message->answers_.empty());
EXPECT_TRUE(message->authorities_.empty());
EXPECT_TRUE(message->additionals_.empty());
}
} // namespace test
} // namespace mdns