};
class Iterator : public ZoneIterator {
public:
- Iterator(const Name& origin) :
+ Iterator(const Name& origin, bool include_ns) :
origin_(origin),
- finished_(false),
- soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(), RRTTL(3600)))
+ soa_(new RRset(origin_, RRClass::IN(), RRType::SOA(),
+ RRTTL(3600)))
{
// The RData here is bogus, but it is not used to anything. There
// just needs to be some.
soa_->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
Name::ROOT_NAME(),
0, 0, 0, 0, 0));
+ rrsets_.push_back(soa_);
+
+ if (include_ns) {
+ ns_.reset(new RRset(origin_, RRClass::IN(), RRType::NS(),
+ RRTTL(3600)));
+ ns_->addRdata(rdata::generic::NS(Name::ROOT_NAME()));
+ rrsets_.push_back(ns_);
+ }
+ rrsets_.push_back(ConstRRsetPtr());
+
+ it_ = rrsets_.begin();
}
virtual isc::dns::ConstRRsetPtr getNextRRset() {
- if (finished_) {
- return (ConstRRsetPtr());
- } else {
- finished_ = true;
- return (soa_);
- }
+ ConstRRsetPtr result = *it_;
+ ++it_;
+ return (result);
}
virtual isc::dns::ConstRRsetPtr getSOA() const {
return (soa_);
}
private:
const Name origin_;
- bool finished_;
- const isc::dns::RRsetPtr soa_;
+ const RRsetPtr soa_;
+ RRsetPtr ns_;
+ std::vector<ConstRRsetPtr> rrsets_;
+ std::vector<ConstRRsetPtr>::const_iterator it_;
};
// Constructor from a list of zones.
- MockDataSourceClient(const char* zone_names[]) {
+ MockDataSourceClient(const char* zone_names[]) :
+ have_ns_(true), use_baditerator_(true)
+ {
for (const char** zone(zone_names); *zone; ++zone) {
zones.insert(Name(*zone));
}
MockDataSourceClient(const string& type,
const ConstElementPtr& configuration) :
type_(type),
- configuration_(configuration)
+ configuration_(configuration),
+ have_ns_(true), use_baditerator_(true)
{
EXPECT_NE("MasterFiles", type) << "MasterFiles is a special case "
"and it never should be created as a data source client";
isc_throw(isc::NotImplemented, "Not implemented");
}
virtual ZoneIteratorPtr getIterator(const Name& name, bool) const {
- if (name == Name("noiter.org")) {
+ if (use_baditerator_ && name == Name("noiter.org")) {
isc_throw(isc::NotImplemented, "Asked not to be implemented");
- } else if (name == Name("null.org")) {
+ } else if (use_baditerator_ && name == Name("null.org")) {
return (ZoneIteratorPtr());
} else {
FindResult result(findZone(name));
if (result.code == isc::datasrc::result::SUCCESS) {
- return (ZoneIteratorPtr(new Iterator(name)));
+ return (ZoneIteratorPtr(new Iterator(name, have_ns_)));
} else {
isc_throw(DataSourceError, "No such zone");
}
}
}
+ void disableNS() { have_ns_ = false; }
+ void disableBadIterator() { use_baditerator_ = false; }
const string type_;
const ConstElementPtr configuration_;
private:
set<Name> zones;
+ bool have_ns_; // control the iterator behavior wrt whether to include NS
+ bool use_baditerator_; // whether to use bogus zone iterators for tests
};
false, rrclass_, mem_sgmt_));
}
}
- void prepareCache(size_t index, const Name& zone, bool prefill = false) {
+
+ // Install a "fake" cached zone using a temporary underlying data source
+ // client.
+ void prepareCache(size_t index, const Name& zone) {
+ // Prepare the temporary data source client
+ const char* zones[2];
+ const std::string zonename_txt = zone.toText();
+ zones[0] = zonename_txt.c_str();
+ zones[1] = NULL;
+ MockDataSourceClient mock_client(zones);
+ // Disable some default features of the mock to distinguish the
+ // temporary case from normal case.
+ mock_client.disableNS();
+ mock_client.disableBadIterator();
+
+ // Create cache from the temporary data source, and push it to the
+ // client list.
const shared_ptr<InMemoryClient> cache(new InMemoryClient(mem_sgmt_,
rrclass_));
- if (prefill) {
- RRsetPtr soa(new RRset(zone, RRClass::IN(), RRType::SOA(),
- RRTTL(3600)));
- // The RData here is bogus, but it is not used to anything. There
- // just needs to be some.
- soa->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
- Name::ROOT_NAME(),
- 0, 0, 0, 0, 0));
- cache->add(zone, soa);
- }
- // If we don't do prefill, we leave the zone empty. This way,
- // we can check when it was reloaded.
- list_->getDataSources()[index].cache_ = cache;
+ cache->load(zone, *mock_client.getIterator(zone, false));
+
+ ConfigurableClientList::DataSourceInfo& dsrc_info =
+ list_->getDataSources()[index];
+ dsrc_info.cache_ = cache;
}
// Check the positive result is as we expect it.
void positiveResult(const ClientList::FindResult& result,
list_->configure(config_elem_zones_, true);
const Name name("example.org");
prepareCache(0, name);
- // Not there yet. It would be NXDOMAIN, but it is in apex and
- // it returns NXRRSET instead.
+ // The cache currently contains a tweaked version of zone, which doesn't
+ // have apex NS. So the lookup should result in NXRRSET.
EXPECT_EQ(ZoneFinder::NXRRSET,
- list_->find(name).finder_->find(name, RRType::SOA())->code);
- // Now reload. It should be there now.
+ list_->find(name).finder_->find(name, RRType::NS())->code);
+ // Now reload the full zone. It should be there now.
EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
EXPECT_EQ(ZoneFinder::SUCCESS,
- list_->find(name).finder_->find(name, RRType::SOA())->code);
+ list_->find(name).finder_->find(name, RRType::NS())->code);
}
// The cache is not enabled. The load should be rejected.
const Name name("example.org");
// We put the cache in even when not enabled. This won't confuse the thing.
prepareCache(0, name);
- // Not there yet. It would be NXDOMAIN, but it is in apex and
- // it returns NXRRSET instead.
+ // See the reloadSuccess test. This should result in NXRRSET.
EXPECT_EQ(ZoneFinder::NXRRSET,
- list_->find(name).finder_->find(name, RRType::SOA())->code);
+ list_->find(name).finder_->find(name, RRType::NS())->code);
// Now reload. It should reject it.
EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
// Nothing changed here
EXPECT_EQ(ZoneFinder::NXRRSET,
- list_->find(name).finder_->find(name, RRType::SOA())->code);
+ list_->find(name).finder_->find(name, RRType::NS())->code);
}
// Test several cases when the zone does not exist
list_->find(Name("example.cz")).dsrc_client_);
EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
list_->find(Name("sub.example.com"), true).dsrc_client_);
- // Not reloaded
+ // Not reloaded, so NS shouldn't be visible yet.
EXPECT_EQ(ZoneFinder::NXRRSET,
list_->find(Name("example.com")).finder_->
- find(Name("example.com"), RRType::SOA())->code);
+ find(Name("example.com"), RRType::NS())->code);
}
// Check we gracefuly throw an exception when a zone disappeared in
// We put in a cache for non-existant zone. This emulates being loaded
// and then the zone disappearing. We prefill the cache, so we can check
// it.
- prepareCache(0, name, true);
- // The zone contains something
+ prepareCache(0, name);
+ // The (cached) zone contains zone's SOA
EXPECT_EQ(ZoneFinder::SUCCESS,
list_->find(name).finder_->find(name, RRType::SOA())->code);
// The zone is not there, so abort the reload.
EXPECT_THROW(list_->reload(name), DataSourceError);
- // The zone is not hurt.
+ // The (cached) zone is not hurt.
EXPECT_EQ(ZoneFinder::SUCCESS,
list_->find(name).finder_->find(name, RRType::SOA())->code);
}
TEST_F(ListTest, reloadZoneThrow) {
list_->configure(config_elem_zones_, true);
const Name name("noiter.org");
- prepareCache(0, name, true);
+ prepareCache(0, name);
// The zone contains stuff now
EXPECT_EQ(ZoneFinder::SUCCESS,
list_->find(name).finder_->find(name, RRType::SOA())->code);
TEST_F(ListTest, reloadNullIterator) {
list_->configure(config_elem_zones_, true);
const Name name("null.org");
- prepareCache(0, name, true);
+ prepareCache(0, name);
// The zone contains stuff now
EXPECT_EQ(ZoneFinder::SUCCESS,
list_->find(name).finder_->find(name, RRType::SOA())->code);