Commit b2da8d97 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

[1483] Implement findAll on database

parent 90c77658
......@@ -177,7 +177,8 @@ private:
DatabaseClient::Finder::FoundRRsets
DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
bool check_ns, const string* construct_name)
bool check_ns, const string* construct_name,
bool any)
{
RRsigStore sig_store;
bool records_found = false;
......@@ -222,7 +223,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
columns[DatabaseAccessor::RDATA_COLUMN]));
}
if (types.find(cur_type) != types.end()) {
if (types.find(cur_type) != types.end() || any) {
// This type is requested, so put it into result
const RRTTL cur_ttl(columns[DatabaseAccessor::TTL_COLUMN]);
// Ths sigtype column was an optimization for finding the
......@@ -287,6 +288,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
sig_store.appendSignatures(i->second);
}
if (records_found && any) {
result[RRType::ANY()] = RRsetPtr();
// These will be sitting on the other RRsets.
result.erase(RRType::RRSIG());
}
return (FoundRRsets(records_found, result));
}
......@@ -391,17 +398,27 @@ DatabaseClient::Finder::findNSECCover(const Name& name) {
}
ZoneFinder::FindResult
DatabaseClient::Finder::findAll(const isc::dns::Name&,
std::vector<isc::dns::ConstRRsetPtr>&,
const FindOptions)
DatabaseClient::Finder::findAll(const isc::dns::Name& name,
std::vector<isc::dns::ConstRRsetPtr>& target,
const FindOptions options)
{
isc_throw(isc::NotImplemented, "Not implemented");
return (findInternal(name, RRType::ANY(), &target, options));
}
ZoneFinder::FindResult
DatabaseClient::Finder::find(const isc::dns::Name& name,
const isc::dns::RRType& type,
const FindOptions options)
{
return (findInternal(name, type, NULL, options));
}
ZoneFinder::FindResult
DatabaseClient::Finder::findInternal(const isc::dns::Name& name,
const isc::dns::RRType& type,
std::vector<isc::dns::ConstRRsetPtr>*
target,
const FindOptions options)
{
// This variable is used to determine the difference between
// NXDOMAIN and NXRRSET
......@@ -409,6 +426,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
bool glue_ok((options & FIND_GLUE_OK) != 0);
const bool dnssec_data((options & FIND_DNSSEC) != 0);
bool get_cover(false);
bool any(type == RRType::ANY());
isc::dns::RRsetPtr result_rrset;
ZoneFinder::Result result_status = SUCCESS;
FoundRRsets found;
......@@ -479,7 +497,8 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
found = getRRsets(name.toText(), final_types, name != origin);
found = getRRsets(name.toText(), final_types, name != origin, NULL,
any);
records_found = found.first;
// NS records, CNAME record and Wanted Type records
......@@ -505,7 +524,18 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
}
} else if (wti != found.second.end()) {
// Just get the answer
// TODO update here
result_rrset = wti->second;
if (any) {
for (FoundIterator it(found.second.begin());
it != found.second.end(); ++it) {
if (it->second) {
// Skip over the empty ANY
target->push_back(it->second);
}
}
return (FindResult(result_status, result_rrset));
}
} else if (!records_found) {
// Nothing lives here.
// But check if something lives below this
......@@ -535,7 +565,7 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
// TODO What do we do about DNAME here?
// The types are the same as with original query
found = getRRsets(wildcard, final_types, true,
&construct_name);
&construct_name, any);
if (found.first) {
if (first_ns) {
// In case we are under NS, we don't
......@@ -572,7 +602,20 @@ DatabaseClient::Finder::find(const isc::dns::Name& name,
result_status = DELEGATION;
} else if (wti != found.second.end()) {
result_rrset = wti->second;
// TODO Update here
result_status = WILDCARD;
if (any) {
for (FoundIterator
it(found.second.begin());
it != found.second.end(); ++it) {
if (it->second) {
// Skip over the empty ANY
target->push_back(it->second);
}
}
return (FindResult(result_status,
result_rrset));
}
} else {
// NXRRSET case in the wildcard
result_status = WILDCARD_NXRRSET;
......
......@@ -822,12 +822,26 @@ public:
boost::shared_ptr<DatabaseAccessor> accessor_;
const int zone_id_;
const isc::dns::Name origin_;
//
/// \brief Shortcut name for the result of getRRsets
typedef std::pair<bool, std::map<dns::RRType, dns::RRsetPtr> >
FoundRRsets;
/// \brief Just shortcut for set of types
typedef std::set<dns::RRType> WantedTypes;
/**
* \brief Internal logit of find and findAll methods.
*
* Most of their handling is in the "error" cases and delegations
* and so on. So they share the logic here and find and findAll provide
* just an interface for it.
*
* Parameters and behaviour is like of those combined together.
* Unexpected parameters, like type != ANY and having the target, are
* just that - unexpected and not checked.
*/
FindResult findInternal(const isc::dns::Name& name,
const isc::dns::RRType& type,
std::vector<isc::dns::ConstRRsetPtr>* target,
const FindOptions options = FIND_DEFAULT);
/**
* \brief Searches database for RRsets of one domain.
*
......@@ -846,6 +860,10 @@ public:
* their name set to name. If it is not NULL, it overrides the name
* and uses this one (this can be used for wildcard synthesized
* records).
* \param any If this is true, it records all the types, not only the
* ones requested by types. It also puts a NULL pointer under the
* ANY type into the result, if it finds any RRs at all, to easy the
* identification of success.
* \return A pair, where the first element indicates if the domain
* contains any RRs at all (not only the requested, it may happen
* this is set to true, but the second part is empty). The second
......@@ -857,7 +875,8 @@ public:
*/
FoundRRsets getRRsets(const std::string& name,
const WantedTypes& types, bool check_ns,
const std::string* construct_name = NULL);
const std::string* construct_name = NULL,
bool any = false);
/**
* \brief Checks if something lives below this domain.
*
......
......@@ -1443,6 +1443,39 @@ doFindTest(ZoneFinder& finder,
}
}
void
doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
ZoneFinder::Result expected_result,
const isc::dns::RRType expected_type,
std::vector<std::string> expected_rdata,
const isc::dns::Name& expected_name =
isc::dns::Name::ROOT_NAME(),
const ZoneFinder::FindOptions options =
ZoneFinder::FIND_DEFAULT)
{
SCOPED_TRACE("All test for " + name.toText());
std::vector<ConstRRsetPtr> target;
ZoneFinder::FindResult result(finder.findAll(name, target, options));
EXPECT_TRUE(target.empty());
EXPECT_EQ(expected_result, result.code);
EXPECT_EQ(expected_type, result.rrset->getType());
RdataIteratorPtr it(result.rrset->getRdataIterator());
std::vector<std::string> rdata;
while (!it->isLast()) {
rdata.push_back(it->getCurrent().toText());
it->next();
}
std::sort(rdata.begin(), rdata.end());
std::sort(expected_rdata.begin(), expected_rdata.end());
ASSERT_EQ(expected_rdata.size(), rdata.size());
for (size_t i(0); i < expected_rdata.size(); ++ i) {
EXPECT_EQ(expected_rdata[i], rdata[i]);
}
EXPECT_TRUE(expected_rdata == rdata);
EXPECT_EQ(expected_name == isc::dns::Name::ROOT_NAME() ? name :
expected_name, result.rrset->getName());
}
// When asking for an RRset where RRs somehow have different TTLs, it should
// convert to the lowest one.
TEST_F(MockDatabaseClientTest, ttldiff) {
......@@ -2254,6 +2287,94 @@ TYPED_TEST(DatabaseClientTest, emptyNonterminalNSEC) {
Name::ROOT_NAME(), ZoneFinder::FIND_DNSSEC));
}
// Test the findAll method.
TYPED_TEST(DatabaseClientTest, getAll) {
// The domain doesn't exist, so we must get the right NSEC
shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
// It should act the same on the "failures"
std::vector<ConstRRsetPtr> target;
EXPECT_EQ(ZoneFinder::NXDOMAIN,
finder->findAll(isc::dns::Name("nothere.example.org."),
target).code);
EXPECT_TRUE(target.empty());
EXPECT_EQ(ZoneFinder::NXRRSET,
finder->findAll(isc::dns::Name("here.wild.example.org."),
target).code);
this->expected_rdatas_.push_back("ns.delegation.example.org.");
this->expected_rdatas_.push_back("ns.example.com.");
doFindAllTestResult(*finder, isc::dns::Name("xx.delegation.example.org."),
ZoneFinder::DELEGATION, RRType::NS(),
this->expected_rdatas_,
isc::dns::Name("delegation.example.org."));
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("www.example.org.");
doFindAllTestResult(*finder, isc::dns::Name("cname.example.org"),
ZoneFinder::CNAME, RRType::CNAME(),
this->expected_rdatas_);
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("dname.example.com.");
doFindAllTestResult(*finder, isc::dns::Name("a.dname.example.org"),
ZoneFinder::DNAME, RRType::DNAME(),
this->expected_rdatas_,
isc::dns::Name("dname.example.org."));
// It should get the data on success
EXPECT_EQ(ZoneFinder::SUCCESS,
finder->findAll(isc::dns::Name("www2.example.org."),
target).code);
ASSERT_EQ(2, target.size());
size_t a_idx(target[1]->getType() == RRType::A());
EXPECT_EQ(RRType::A(), target[a_idx]->getType());
std::string previous;
size_t count(0);
for (RdataIteratorPtr it(target[a_idx]->getRdataIterator());
!it->isLast(); it->next()) {
count ++;
EXPECT_NE(previous, it->getCurrent().toText());
EXPECT_TRUE(it->getCurrent().toText() == "192.0.2.1" ||
it->getCurrent().toText() == "192.0.2.2");
previous = it->getCurrent().toText();
}
EXPECT_EQ(2, count);
EXPECT_EQ(RRType::AAAA(), target[1 - a_idx]->getType());
RdataIteratorPtr it(target[1 - a_idx]->getRdataIterator());
ASSERT_FALSE(it->isLast());
EXPECT_EQ("2001:db8::1", it->getCurrent().toText());
it->next();
EXPECT_TRUE(it->isLast());
// And on wildcard. Check the signatures as well.
target.clear();
EXPECT_EQ(ZoneFinder::WILDCARD,
finder->findAll(isc::dns::Name("a.wild.example.org"),
target, ZoneFinder::FIND_DNSSEC).code);
ASSERT_EQ(2, target.size());
a_idx = target[1]->getType() == RRType::A();
EXPECT_EQ(RRType::A(), target[a_idx]->getType());
it = target[a_idx]->getRdataIterator();
ASSERT_FALSE(it->isLast());
EXPECT_EQ("192.0.2.5", it->getCurrent().toText());
it->next();
EXPECT_TRUE(it->isLast());
ConstRRsetPtr sig(target[a_idx]->getRRsig());
ASSERT_TRUE(sig);
EXPECT_EQ(RRType::RRSIG(), sig->getType());
EXPECT_EQ("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
sig->getRdataIterator()->getCurrent().toText());
EXPECT_EQ(RRType::NSEC(), target[1 - a_idx]->getType());
it = target[1 - a_idx]->getRdataIterator();
ASSERT_FALSE(it->isLast());
EXPECT_EQ("cancel.here.wild.example.org. A RRSIG NSEC",
it->getCurrent().toText());
it->next();
EXPECT_TRUE(it->isLast());
sig = target[1 - a_idx]->getRRsig();
ASSERT_TRUE(sig);
EXPECT_EQ(RRType::RRSIG(), sig->getType());
EXPECT_EQ("NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE",
sig->getRdataIterator()->getCurrent().toText());
}
TYPED_TEST(DatabaseClientTest, getOrigin) {
DataSourceClient::FindResult
zone(this->client_->findZone(Name("example.org")));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment