|
@@ -32,7 +32,9 @@
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
+#include <boost/format.hpp>
|
|
|
#include <boost/shared_ptr.hpp>
|
|
|
+#include <boost/interprocess/file_mapping.hpp>
|
|
|
|
|
|
#include <set>
|
|
|
#include <fstream>
|
|
@@ -105,7 +107,18 @@ const char* ds_zones[][3] = {
|
|
|
|
|
|
const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
|
|
|
|
|
|
-class ListTest : public ::testing::Test {
|
|
|
+class SegmentType {
|
|
|
+public:
|
|
|
+ virtual ~SegmentType() {}
|
|
|
+ virtual ConstElementPtr getCacheConfig(bool enabled, const Name& zone)
|
|
|
+ const = 0;
|
|
|
+ virtual void reset(ConfigurableClientList& list,
|
|
|
+ const std::string& datasrc_name,
|
|
|
+ ZoneTableSegment::MemorySegmentOpenMode mode,
|
|
|
+ ConstElementPtr config_params) = 0;
|
|
|
+};
|
|
|
+
|
|
|
+class ListTest : public ::testing::TestWithParam<SegmentType*> {
|
|
|
public:
|
|
|
ListTest() :
|
|
|
rrclass_(RRClass::IN()),
|
|
@@ -121,8 +134,7 @@ public:
|
|
|
" \"type\": \"test_type\","
|
|
|
" \"params\": [\"example.org\", \"example.com\", "
|
|
|
" \"noiter.org\", \"null.org\"]"
|
|
|
- "}]")),
|
|
|
- ztable_segment_(ZoneTableSegment::create(rrclass_, "local"))
|
|
|
+ "}]"))
|
|
|
{
|
|
|
for (size_t i(0); i < ds_count; ++ i) {
|
|
|
shared_ptr<MockDataSourceClient>
|
|
@@ -135,6 +147,24 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ ~ListTest() {
|
|
|
+ ds_info_.clear();
|
|
|
+ for (size_t i(0); i < ds_count; ++ i) {
|
|
|
+ ds_[i].reset();
|
|
|
+ }
|
|
|
+ ds_.clear();
|
|
|
+
|
|
|
+ for (size_t i(0); i < ds_count; ++ i) {
|
|
|
+ boost::interprocess::file_mapping::remove(
|
|
|
+ getMappedFilename(i).c_str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static std::string getMappedFilename(size_t index) {
|
|
|
+ return (boost::str(boost::format(TEST_DATA_BUILDDIR "/test%d.mapped")
|
|
|
+ % index));
|
|
|
+ }
|
|
|
+
|
|
|
// Install a "fake" cached zone using a temporary underlying data source
|
|
|
// client. If 'enabled' is set to false, emulate a disabled cache, in
|
|
|
// which case there will be no data in memory.
|
|
@@ -152,11 +182,7 @@ public:
|
|
|
// Build new cache config to load the specified zone, and replace
|
|
|
// the data source info with the new config.
|
|
|
ConstElementPtr cache_conf_elem =
|
|
|
- Element::fromJSON("{\"type\": \"mock\","
|
|
|
- " \"cache-enable\": " +
|
|
|
- string(enabled ? "true," : "false,") +
|
|
|
- " \"cache-zones\": "
|
|
|
- " [\"" + zone.toText() + "\"]}");
|
|
|
+ GetParam()->getCacheConfig(enabled, zone);
|
|
|
boost::shared_ptr<internal::CacheConfig> cache_conf(
|
|
|
new internal::CacheConfig("mock", mock_client, *cache_conf_elem,
|
|
|
true));
|
|
@@ -167,6 +193,15 @@ public:
|
|
|
|
|
|
// Load the data into the zone table.
|
|
|
if (enabled) {
|
|
|
+ const ConstElementPtr config_ztable_segment(
|
|
|
+ Element::fromJSON("{\"mapped-file\": \"" +
|
|
|
+ getMappedFilename(index) +
|
|
|
+ "\"}"));
|
|
|
+
|
|
|
+ GetParam()->reset(*list_, dsrc_info.name_,
|
|
|
+ memory::ZoneTableSegment::CREATE,
|
|
|
+ config_ztable_segment);
|
|
|
+
|
|
|
boost::scoped_ptr<memory::ZoneWriter> writer(
|
|
|
new memory::ZoneWriter(
|
|
|
*dsrc_info.ztable_segment_,
|
|
@@ -175,6 +210,10 @@ public:
|
|
|
writer->load();
|
|
|
writer->install();
|
|
|
writer->cleanup(); // not absolutely necessary, but just in case
|
|
|
+
|
|
|
+ GetParam()->reset(*list_, dsrc_info.name_,
|
|
|
+ memory::ZoneTableSegment::READ_WRITE,
|
|
|
+ config_ztable_segment);
|
|
|
}
|
|
|
|
|
|
// On completion of load revert to the previous state of underlying
|
|
@@ -275,11 +314,64 @@ public:
|
|
|
vector<shared_ptr<MockDataSourceClient> > ds_;
|
|
|
vector<ConfigurableClientList::DataSourceInfo> ds_info_;
|
|
|
const ConstElementPtr config_elem_, config_elem_zones_;
|
|
|
- shared_ptr<ZoneTableSegment> ztable_segment_;
|
|
|
};
|
|
|
|
|
|
+class LocalSegmentType : public SegmentType {
|
|
|
+public:
|
|
|
+ virtual ConstElementPtr getCacheConfig(bool enabled, const Name& zone)
|
|
|
+ const
|
|
|
+ {
|
|
|
+ return (Element::fromJSON("{\"type\": \"mock\","
|
|
|
+ " \"cache-enable\": " +
|
|
|
+ string(enabled ? "true," : "false,") +
|
|
|
+ " \"cache-zones\": "
|
|
|
+ " [\"" + zone.toText() + "\"]}"));
|
|
|
+ }
|
|
|
+ virtual void reset(ConfigurableClientList&, const std::string&,
|
|
|
+ ZoneTableSegment::MemorySegmentOpenMode,
|
|
|
+ ConstElementPtr) {
|
|
|
+ // We must not call reset on local ZoneTableSegments.
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+LocalSegmentType local_segment_type;
|
|
|
+
|
|
|
+INSTANTIATE_TEST_CASE_P(ListTestLocal, ListTest,
|
|
|
+ ::testing::Values(static_cast<SegmentType*>(
|
|
|
+ &local_segment_type)));
|
|
|
+
|
|
|
+#ifdef USE_SHARED_MEMORY
|
|
|
+
|
|
|
+class MappedSegmentType : public SegmentType {
|
|
|
+public:
|
|
|
+ virtual ConstElementPtr getCacheConfig(bool enabled, const Name& zone)
|
|
|
+ const
|
|
|
+ {
|
|
|
+ return (Element::fromJSON("{\"type\": \"mock\","
|
|
|
+ " \"cache-enable\": " +
|
|
|
+ string(enabled ? "true," : "false,") +
|
|
|
+ " \"cache-type\": \"mapped\"," +
|
|
|
+ " \"cache-zones\": "
|
|
|
+ " [\"" + zone.toText() + "\"]}"));
|
|
|
+ }
|
|
|
+ virtual void reset(ConfigurableClientList& list,
|
|
|
+ const std::string& datasrc_name,
|
|
|
+ ZoneTableSegment::MemorySegmentOpenMode mode,
|
|
|
+ ConstElementPtr config_params) {
|
|
|
+ list.resetMemorySegment(datasrc_name, mode, config_params);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+MappedSegmentType mapped_segment_type;
|
|
|
+
|
|
|
+INSTANTIATE_TEST_CASE_P(ListTestMapped, ListTest,
|
|
|
+ ::testing::Values(static_cast<SegmentType*>(
|
|
|
+ &mapped_segment_type)));
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
// Test the test itself
|
|
|
-TEST_F(ListTest, selfTest) {
|
|
|
+TEST_P(ListTest, selfTest) {
|
|
|
EXPECT_EQ(result::SUCCESS, ds_[0]->findZone(Name("example.org")).code);
|
|
|
EXPECT_EQ(result::PARTIALMATCH,
|
|
|
ds_[0]->findZone(Name("sub.example.org")).code);
|
|
@@ -293,14 +385,14 @@ TEST_F(ListTest, selfTest) {
|
|
|
}
|
|
|
|
|
|
// Test the list we create with empty configuration is, in fact, empty
|
|
|
-TEST_F(ListTest, emptyList) {
|
|
|
+TEST_P(ListTest, emptyList) {
|
|
|
EXPECT_TRUE(list_->getDataSources().empty());
|
|
|
}
|
|
|
|
|
|
// Check the values returned by a find on an empty list. It should be
|
|
|
// a negative answer (nothing found) no matter if we want an exact or inexact
|
|
|
// match.
|
|
|
-TEST_F(ListTest, emptySearch) {
|
|
|
+TEST_P(ListTest, emptySearch) {
|
|
|
// No matter what we try, we don't get an answer.
|
|
|
|
|
|
// Note: we don't have operator<< for the result class, so we cannot use
|
|
@@ -317,7 +409,7 @@ TEST_F(ListTest, emptySearch) {
|
|
|
|
|
|
// Put a single data source inside the list and check it can find an
|
|
|
// exact match if there's one.
|
|
|
-TEST_F(ListTest, singleDSExactMatch) {
|
|
|
+TEST_P(ListTest, singleDSExactMatch) {
|
|
|
list_->getDataSources().push_back(ds_info_[0]);
|
|
|
// This zone is not there
|
|
|
EXPECT_TRUE(negative_result_ == list_->find(Name("org."), true));
|
|
@@ -331,7 +423,7 @@ TEST_F(ListTest, singleDSExactMatch) {
|
|
|
}
|
|
|
|
|
|
// When asking for a partial match, we get all that the exact one, but more.
|
|
|
-TEST_F(ListTest, singleDSBestMatch) {
|
|
|
+TEST_P(ListTest, singleDSBestMatch) {
|
|
|
list_->getDataSources().push_back(ds_info_[0]);
|
|
|
// This zone is not there
|
|
|
EXPECT_TRUE(negative_result_ == list_->find(Name("org.")));
|
|
@@ -351,7 +443,7 @@ const char* const test_names[] = {
|
|
|
"With a duplicity"
|
|
|
};
|
|
|
|
|
|
-TEST_F(ListTest, multiExactMatch) {
|
|
|
+TEST_P(ListTest, multiExactMatch) {
|
|
|
// Run through all the multi-configurations
|
|
|
for (size_t i(0); i < sizeof(test_names) / sizeof(*test_names); ++i) {
|
|
|
SCOPED_TRACE(test_names[i]);
|
|
@@ -370,7 +462,7 @@ TEST_F(ListTest, multiExactMatch) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, multiBestMatch) {
|
|
|
+TEST_P(ListTest, multiBestMatch) {
|
|
|
// Run through all the multi-configurations
|
|
|
for (size_t i(0); i < 4; ++ i) {
|
|
|
SCOPED_TRACE(test_names[i]);
|
|
@@ -391,7 +483,7 @@ TEST_F(ListTest, multiBestMatch) {
|
|
|
}
|
|
|
|
|
|
// Check the configuration is empty when the list is empty
|
|
|
-TEST_F(ListTest, configureEmpty) {
|
|
|
+TEST_P(ListTest, configureEmpty) {
|
|
|
const ConstElementPtr elem(new ListElement);
|
|
|
list_->configure(elem, true);
|
|
|
EXPECT_TRUE(list_->getDataSources().empty());
|
|
@@ -400,7 +492,7 @@ TEST_F(ListTest, configureEmpty) {
|
|
|
}
|
|
|
|
|
|
// Check we can get multiple data sources and they are in the right order.
|
|
|
-TEST_F(ListTest, configureMulti) {
|
|
|
+TEST_P(ListTest, configureMulti) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"type1\","
|
|
@@ -422,7 +514,7 @@ TEST_F(ListTest, configureMulti) {
|
|
|
}
|
|
|
|
|
|
// Check we can pass whatever we want to the params
|
|
|
-TEST_F(ListTest, configureParams) {
|
|
|
+TEST_P(ListTest, configureParams) {
|
|
|
const char* params[] = {
|
|
|
"true",
|
|
|
"false",
|
|
@@ -447,7 +539,7 @@ TEST_F(ListTest, configureParams) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, status) {
|
|
|
+TEST_P(ListTest, status) {
|
|
|
EXPECT_TRUE(list_->getStatus().empty());
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
@@ -474,7 +566,7 @@ TEST_F(ListTest, status) {
|
|
|
EXPECT_EQ("local", statuses[1].getSegmentType());
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, wrongConfig) {
|
|
|
+TEST_P(ListTest, wrongConfig) {
|
|
|
const char* configs[] = {
|
|
|
// A lot of stuff missing from there
|
|
|
"[{\"type\": \"test_type\", \"params\": 13}, {}]",
|
|
@@ -572,7 +664,7 @@ TEST_F(ListTest, wrongConfig) {
|
|
|
}
|
|
|
|
|
|
// The param thing defaults to null. Cache is not used yet.
|
|
|
-TEST_F(ListTest, defaults) {
|
|
|
+TEST_P(ListTest, defaults) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"type1\""
|
|
@@ -583,7 +675,7 @@ TEST_F(ListTest, defaults) {
|
|
|
}
|
|
|
|
|
|
// Check we can call the configure multiple times, to change the configuration
|
|
|
-TEST_F(ListTest, reconfigure) {
|
|
|
+TEST_P(ListTest, reconfigure) {
|
|
|
const ConstElementPtr empty(new ListElement);
|
|
|
list_->configure(config_elem_, true);
|
|
|
checkDS(0, "test_type", "{}", false);
|
|
@@ -594,7 +686,7 @@ TEST_F(ListTest, reconfigure) {
|
|
|
}
|
|
|
|
|
|
// Make sure the data source error exception from the factory is propagated
|
|
|
-TEST_F(ListTest, dataSrcError) {
|
|
|
+TEST_P(ListTest, dataSrcError) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"error\""
|
|
@@ -606,7 +698,7 @@ TEST_F(ListTest, dataSrcError) {
|
|
|
}
|
|
|
|
|
|
// Check we can get the cache
|
|
|
-TEST_F(ListTest, configureCacheEmpty) {
|
|
|
+TEST_P(ListTest, configureCacheEmpty) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"type1\","
|
|
@@ -628,7 +720,7 @@ TEST_F(ListTest, configureCacheEmpty) {
|
|
|
}
|
|
|
|
|
|
// But no cache if we disallow it globally
|
|
|
-TEST_F(ListTest, configureCacheDisabled) {
|
|
|
+TEST_P(ListTest, configureCacheDisabled) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"type1\","
|
|
@@ -650,7 +742,7 @@ TEST_F(ListTest, configureCacheDisabled) {
|
|
|
}
|
|
|
|
|
|
// Put some zones into the cache
|
|
|
-TEST_F(ListTest, cacheZones) {
|
|
|
+TEST_P(ListTest, cacheZones) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"type1\","
|
|
@@ -684,7 +776,7 @@ TEST_F(ListTest, cacheZones) {
|
|
|
|
|
|
// Check the caching handles misbehaviour from the data source and
|
|
|
// misconfiguration gracefully
|
|
|
-TEST_F(ListTest, badCache) {
|
|
|
+TEST_P(ListTest, badCache) {
|
|
|
list_->configure(config_elem_, true);
|
|
|
checkDS(0, "test_type", "{}", false);
|
|
|
// First, the zone is not in the data source. configure() should still
|
|
@@ -733,7 +825,7 @@ TEST_F(ListTest, badCache) {
|
|
|
}
|
|
|
|
|
|
// This test relies on the property of mapped type of cache.
|
|
|
-TEST_F(ListTest,
|
|
|
+TEST_P(ListTest,
|
|
|
#ifdef USE_SHARED_MEMORY
|
|
|
cacheInNonWritableSegment
|
|
|
#else
|
|
@@ -760,7 +852,7 @@ TEST_F(ListTest,
|
|
|
doReload(Name("example.org")));
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, masterFiles) {
|
|
|
+TEST_P(ListTest, masterFiles) {
|
|
|
const ConstElementPtr elem(Element::fromJSON("["
|
|
|
"{"
|
|
|
" \"type\": \"MasterFiles\","
|
|
@@ -785,7 +877,7 @@ TEST_F(ListTest, masterFiles) {
|
|
|
}
|
|
|
|
|
|
// Test the names are set correctly and collission is detected.
|
|
|
-TEST_F(ListTest, names) {
|
|
|
+TEST_P(ListTest, names) {
|
|
|
// Explicit name
|
|
|
const ConstElementPtr elem1(Element::fromJSON("["
|
|
|
"{"
|
|
@@ -832,7 +924,7 @@ TEST_F(ListTest, names) {
|
|
|
ConfigurableClientList::ConfigurationError);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, BadMasterFile) {
|
|
|
+TEST_P(ListTest, BadMasterFile) {
|
|
|
// Configuration should succeed, and the good zones in the list
|
|
|
// below should be loaded. Bad zones won't be "loaded" in its usual sense,
|
|
|
// but are still recognized with conceptual "empty" data.
|
|
@@ -908,7 +1000,7 @@ ListTest::doReload(const Name& origin, const string& datasrc_name) {
|
|
|
}
|
|
|
|
|
|
// Test we can reload a zone
|
|
|
-TEST_F(ListTest, reloadSuccess) {
|
|
|
+TEST_P(ListTest, reloadSuccess) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("example.org");
|
|
|
prepareCache(0, name);
|
|
@@ -928,7 +1020,7 @@ TEST_F(ListTest, reloadSuccess) {
|
|
|
}
|
|
|
|
|
|
// The cache is not enabled. The load should be rejected.
|
|
|
-TEST_F(ListTest, reloadNotAllowed) {
|
|
|
+TEST_P(ListTest, reloadNotAllowed) {
|
|
|
list_->configure(config_elem_zones_, false);
|
|
|
const Name name("example.org");
|
|
|
// We put the cache in even when not enabled. This won't confuse the thing.
|
|
@@ -948,7 +1040,7 @@ TEST_F(ListTest, reloadNotAllowed) {
|
|
|
}
|
|
|
|
|
|
// Similar to the previous case, but the cache is disabled in config.
|
|
|
-TEST_F(ListTest, reloadNotEnabled) {
|
|
|
+TEST_P(ListTest, reloadNotEnabled) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("example.org");
|
|
|
// We put the cache, actually disabling it.
|
|
@@ -959,7 +1051,7 @@ TEST_F(ListTest, reloadNotEnabled) {
|
|
|
}
|
|
|
|
|
|
// Test several cases when the zone does not exist
|
|
|
-TEST_F(ListTest, reloadNoSuchZone) {
|
|
|
+TEST_P(ListTest, reloadNoSuchZone) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("example.org");
|
|
|
// We put the cache in even when not enabled. This won't confuse the
|
|
@@ -990,7 +1082,7 @@ TEST_F(ListTest, reloadNoSuchZone) {
|
|
|
|
|
|
// Check we gracefully reject reloading (i.e. no exception) when a zone
|
|
|
// disappeared in the underlying data source when we want to reload it
|
|
|
-TEST_F(ListTest, reloadZoneGone) {
|
|
|
+TEST_P(ListTest, reloadZoneGone) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("example.org");
|
|
|
// We put in a cache for non-existent zone. This emulates being loaded
|
|
@@ -1011,7 +1103,7 @@ TEST_F(ListTest, reloadZoneGone) {
|
|
|
list_->find(name).finder_->find(name, RRType::SOA())->code);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, reloadNewZone) {
|
|
|
+TEST_P(ListTest, reloadNewZone) {
|
|
|
// Test the case where a zone to be cached originally doesn't exist
|
|
|
// in the underlying data source and is added later. reload() will
|
|
|
// succeed once it's available in the data source.
|
|
@@ -1038,7 +1130,7 @@ TEST_F(ListTest, reloadNewZone) {
|
|
|
}
|
|
|
|
|
|
// The underlying data source throws. Check we don't modify the state.
|
|
|
-TEST_F(ListTest, reloadZoneThrow) {
|
|
|
+TEST_P(ListTest, reloadZoneThrow) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("noiter.org");
|
|
|
prepareCache(0, name);
|
|
@@ -1052,7 +1144,7 @@ TEST_F(ListTest, reloadZoneThrow) {
|
|
|
list_->find(name).finder_->find(name, RRType::SOA())->code);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, reloadNullIterator) {
|
|
|
+TEST_P(ListTest, reloadNullIterator) {
|
|
|
list_->configure(config_elem_zones_, true);
|
|
|
const Name name("null.org");
|
|
|
prepareCache(0, name);
|
|
@@ -1067,7 +1159,7 @@ TEST_F(ListTest, reloadNullIterator) {
|
|
|
}
|
|
|
|
|
|
// Test we can reload the master files too (special-cased)
|
|
|
-TEST_F(ListTest, reloadMasterFile) {
|
|
|
+TEST_P(ListTest, reloadMasterFile) {
|
|
|
const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_DIR
|
|
|
"/root.zone " TEST_DATA_BUILDDIR "/root.zone.copied";
|
|
|
if (system(install_cmd) != 0) {
|
|
@@ -1102,7 +1194,7 @@ TEST_F(ListTest, reloadMasterFile) {
|
|
|
RRType::TXT())->code);
|
|
|
}
|
|
|
|
|
|
-TEST_F(ListTest, reloadByDataSourceName) {
|
|
|
+TEST_P(ListTest, reloadByDataSourceName) {
|
|
|
// We use three data sources (and their clients). 2nd and 3rd have
|
|
|
// the same name of the zones.
|
|
|
const ConstElementPtr config_elem = Element::fromJSON(
|