Commit 00519912 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[2833] renamed ZoneTableConfig to CacheConfig

as details are implemented the latter now seems more appropriate for the
responsibility of this class.
parent 15962b4b
......@@ -133,16 +133,17 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
const DataSourcePair dsrc_pair = getDataSourceClient(type,
paramConf);
internal::ZoneTableConfig ztconfig(type, dsrc_pair.first, *dconf);
internal::CacheConfig cache_conf(type, dsrc_pair.first, *dconf);
shared_ptr<ZoneTableSegment> ztable_segment;
if (ztconfig.isEnabled()) {
ztable_segment.reset(ZoneTableSegment::create(rrclass_,
ztconfig));
if (cache_conf.isEnabled()) {
ztable_segment.reset(ZoneTableSegment::create(
rrclass_,
cache_conf.getSegmentType()));
}
new_data_sources.push_back(DataSourceInfo(dsrc_pair.first,
dsrc_pair.second,
allow_cache &&
ztconfig.isEnabled(),
cache_conf.isEnabled(),
rrclass_, ztable_segment,
name));
......@@ -212,7 +213,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
} catch (const TypeError& te) {
isc_throw(ConfigurationError, "Malformed configuration at data source "
"no. " << i << ": " << te.what());
} catch (const internal::ZoneTableConfigError& ex) {
} catch (const internal::CacheConfigError& ex) {
// convert to the "public" exception type.
isc_throw(ConfigurationError, ex.what());
}
......
......@@ -14,7 +14,6 @@
#include <datasrc/memory/zone_table_segment.h>
#include <datasrc/memory/zone_table_segment_local.h>
#include <datasrc/zone_table_config.h>
#include <string>
......@@ -25,19 +24,15 @@ namespace datasrc {
namespace memory {
ZoneTableSegment*
ZoneTableSegment::create(const RRClass& rrclass,
const internal::ZoneTableConfig& config)
{
const std::string& sgmt_type = config.getSegmentType();
ZoneTableSegment::create(const RRClass& rrclass, const std::string& type) {
// This will be a few sequences of if-else and hardcoded. Not really
// sophisticated, but we don't expect to have too many types at the moment.
// Until that it becomes a real issue we won't be too smart.
if (sgmt_type == "local") {
if (type == "local") {
return (new ZoneTableSegmentLocal(rrclass));
}
isc_throw(UnknownSegmentType, "Zone table segment type not supported: "
<< sgmt_type);
<< type);
}
void
......
......@@ -27,7 +27,8 @@
#include <boost/interprocess/offset_ptr.hpp>
#include <stdlib.h>
#include <cstdlib>
#include <string>
namespace isc {
// Some forward declarations
......@@ -36,9 +37,6 @@ class Name;
class RRClass;
}
namespace datasrc {
namespace internal {
class ZoneTableConfig;
}
namespace memory {
class ZoneWriter;
......@@ -120,9 +118,8 @@ public:
/// \param config The configuration based on which a derived object
/// is returned.
/// \return Returns a ZoneTableSegment object
static ZoneTableSegment* create(
const isc::dns::RRClass& rrclass,
const isc::datasrc::internal::ZoneTableConfig& config);
static ZoneTableSegment* create(const isc::dns::RRClass& rrclass,
const std::string& type);
/// \brief Destroy a ZoneTableSegment
///
......
......@@ -12,11 +12,8 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <datasrc/static_datasrc.h>
#include <datasrc/client.h>
#include <datasrc/zone_table_config.h>
#include <datasrc/memory/memory_client.h>
#include "client.h"
#include "static_datasrc.h"
#include <datasrc/memory/memory_client.h>
#include <datasrc/memory/zone_table_segment.h>
......@@ -33,64 +30,18 @@ using namespace std;
namespace isc {
namespace datasrc {
namespace {
// XXX: this is a hack: we need to make sure the zone table config is valid
// throughout the zone table segment, but there's no way to keep it alive
// within this factory. So we use a custom segment that internally creates
// and hold the config. Actually, we shouldn't need a separate data source
// client implementation for "static"; the generic "MasterFiles" data source
// with pre-generated configuration should suffice. When it's done, we can
// remove this loadable module with this hack.
class ZoneTableSegmentStatic : public memory::ZoneTableSegment {
public:
ZoneTableSegmentStatic(const string& zone_file) :
memory::ZoneTableSegment(RRClass::CH()),
ztconfig_("MasterFiles", 0, *data::Element::fromJSON(
"{\"cache-enable\": true,"
" \"params\": {\"BIND\": \"" + zone_file + "\"}}")),
ztsegment_(memory::ZoneTableSegment::create(RRClass::CH(), ztconfig_))
{}
virtual ~ZoneTableSegmentStatic() {
memory::ZoneTableSegment::destroy(ztsegment_);
}
virtual memory::ZoneTableHeader& getHeader() {
return (ztsegment_->getHeader());
}
virtual const memory::ZoneTableHeader& getHeader() const {
return (ztsegment_->getHeader());
}
virtual isc::util::MemorySegment& getMemorySegment() {
return (ztsegment_->getMemorySegment());
}
virtual memory::ZoneWriter* getZoneWriter(
const memory::LoadAction& load_action,
const dns::Name& origin,
const dns::RRClass& rrclass)
{
return (ztsegment_->getZoneWriter(load_action, origin, rrclass));
}
private:
const internal::ZoneTableConfig ztconfig_;
memory::ZoneTableSegment* ztsegment_; // actual segment
};
}
DataSourceClient*
createInstance(ConstElementPtr config, string& error) {
try {
// Set up the zone table.
const string path(config->stringValue());
shared_ptr<memory::ZoneTableSegment> ztable_segment(
new ZoneTableSegmentStatic(path));
memory::ZoneTableSegment::create(RRClass::CH(), "local"));
// Create the data source
auto_ptr<memory::InMemoryClient> client
(new memory::InMemoryClient(ztable_segment, RRClass::CH()));
// Fill it with data
const string path(config->stringValue());
client->load(Name("BIND"), path);
return (client.release());
......
......@@ -16,7 +16,6 @@
#include <datasrc/client.h>
#include <datasrc/zone_iterator.h>
#include <datasrc/data_source.h>
#include <datasrc/zone_table_config.h>
#include <datasrc/memory/memory_client.h>
#include <datasrc/memory/zone_table_segment.h>
#include <datasrc/memory/zone_finder.h>
......@@ -120,10 +119,7 @@ public:
" \"params\": [\"example.org\", \"example.com\", "
" \"noiter.org\", \"null.org\"]"
"}]")),
ztconfig_("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")),
ztable_segment_(ZoneTableSegment::create(rrclass_, ztconfig_))
ztable_segment_(ZoneTableSegment::create(rrclass_, "local"))
{
for (size_t i(0); i < ds_count; ++ i) {
shared_ptr<MockDataSourceClient>
......@@ -236,7 +232,6 @@ public:
vector<shared_ptr<MockDataSourceClient> > ds_;
vector<ConfigurableClientList::DataSourceInfo> ds_info_;
const ConstElementPtr config_elem_, config_elem_zones_;
const internal::ZoneTableConfig ztconfig_;
shared_ptr<ZoneTableSegment> ztable_segment_;
};
......
......@@ -14,7 +14,6 @@
#include <datasrc/memory/zone_writer_local.h>
#include <datasrc/memory/zone_table_segment_local.h>
#include <datasrc/zone_table_config.h>
#include <util/memory_segment_local.h>
#include <gtest/gtest.h>
......@@ -32,9 +31,7 @@ namespace {
class ZoneTableSegmentTest : public ::testing::Test {
protected:
ZoneTableSegmentTest() :
ztconf_("MasterFiles", 0, *Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")),
ztable_segment_(ZoneTableSegment::create(RRClass::IN(), ztconf_))
ztable_segment_(ZoneTableSegment::create(RRClass::IN(), "local"))
{}
void TearDown() {
......@@ -42,7 +39,6 @@ protected:
ztable_segment_ = NULL;
}
const isc::datasrc::internal::ZoneTableConfig ztconf_;
ZoneTableSegment* ztable_segment_;
};
......@@ -52,11 +48,7 @@ TEST_F(ZoneTableSegmentTest, create) {
EXPECT_NE(static_cast<void*>(NULL), ztable_segment_);
// Unknown types of segment are rejected.
const isc::datasrc::internal::ZoneTableConfig bad_ztconf(
"MasterFiles", 0, *Element::fromJSON("{\"cache-enable\": true,"
" \"cache-type\": \"unknown\","
" \"params\": {}}"));
EXPECT_THROW(ZoneTableSegment::create(RRClass::IN(), bad_ztconf),
EXPECT_THROW(ZoneTableSegment::create(RRClass::IN(), "unknown"),
UnknownSegmentType);
}
......
......@@ -15,9 +15,7 @@
#include <datasrc/memory/zone_writer_local.h>
#include <datasrc/memory/zone_table_segment_local.h>
#include <datasrc/memory/zone_data.h>
#include <datasrc/zone_table_config.h>
#include <cc/data.h>
#include <dns/rrclass.h>
#include <dns/name.h>
......@@ -30,7 +28,6 @@ using boost::scoped_ptr;
using boost::bind;
using isc::dns::RRClass;
using isc::dns::Name;
using isc::data::Element;
using namespace isc::datasrc::memory;
namespace {
......@@ -40,12 +37,7 @@ class TestException {};
class ZoneWriterLocalTest : public ::testing::Test {
public:
ZoneWriterLocalTest() :
// FIXME: The NullElement probably isn't the best one, but we don't
// know how the config will look, so it just fills the argument
// (which is currently ignored)
ztconf_("MasterFiles", 0, *Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")),
segment_(ZoneTableSegment::create(RRClass::IN(), ztconf_)),
segment_(ZoneTableSegment::create(RRClass::IN(), "local")),
writer_(new
ZoneWriterLocal(dynamic_cast<ZoneTableSegmentLocal*>(segment_.
get()),
......@@ -61,7 +53,6 @@ public:
writer_.reset();
}
protected:
const isc::datasrc::internal::ZoneTableConfig ztconf_;
scoped_ptr<ZoneTableSegment> segment_;
scoped_ptr<ZoneWriterLocal> writer_;
bool load_called_;
......
......@@ -23,7 +23,6 @@
#include <datasrc/memory/zone_table_segment.h>
#include <datasrc/database.h>
#include <datasrc/sqlite3_accessor.h>
#include <datasrc/zone_table_config.h>
#include "test_client.h"
#include <testutils/dnsmessage_test.h>
......@@ -47,7 +46,6 @@ using namespace isc::dns;
using namespace isc::datasrc;
using isc::datasrc::memory::InMemoryClient;
using isc::datasrc::memory::ZoneTableSegment;
using isc::datasrc::internal::ZoneTableConfig;
using namespace isc::testutils;
namespace {
......@@ -61,16 +59,13 @@ typedef shared_ptr<DataSourceClient> DataSourceClientPtr;
// This is the type used as the test parameter. Note that this is
// intentionally a plain old type (i.e. a function pointer), not a class;
// otherwise it could cause initialization fiasco at the instantiation time.
typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&,
const ZoneTableConfig&);
typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
// Creator for the in-memory client to be tested
DataSourceClientPtr
createInMemoryClient(RRClass zclass, const Name& zname,
const ZoneTableConfig& ztconfig)
{
createInMemoryClient(RRClass zclass, const Name& zname) {
shared_ptr<ZoneTableSegment> ztable_segment(
ZoneTableSegment::create(zclass, ztconfig));
ZoneTableSegment::create(zclass, "local"));
shared_ptr<InMemoryClient> client(new InMemoryClient(ztable_segment,
zclass));
client->load(zname, TEST_ZONE_FILE);
......@@ -103,11 +98,8 @@ createSQLite3Client(RRClass zclass, const Name& zname, stringstream& ss) {
return (client);
}
// ZoneTableConfig is in-memory specific, unused here.
DataSourceClientPtr
createSQLite3ClientWithNS(RRClass zclass, const Name& zname,
const ZoneTableConfig&)
{
createSQLite3ClientWithNS(RRClass zclass, const Name& zname) {
stringstream ss("ns.example.com. 3600 IN A 192.0.2.7");
return (createSQLite3Client(zclass, zname, ss));
}
......@@ -119,15 +111,9 @@ class ZoneFinderContextTest :
{
protected:
ZoneFinderContextTest() :
qclass_(RRClass::IN()), qzone_("example.org"),
ztconfig_("MasterFiles", 0, *Element::fromJSON(
"{\"cache-enable\": true,"
" \"params\": "
" {\"" + qzone_.toText() + "\": "
" \"" + TEST_ZONE_FILE + "\"}"
"}"))
qclass_(RRClass::IN()), qzone_("example.org")
{
client_ = (*GetParam())(qclass_, qzone_, ztconfig_);
client_ = (*GetParam())(qclass_, qzone_);
REQUESTED_A.push_back(RRType::A());
REQUESTED_AAAA.push_back(RRType::AAAA());
REQUESTED_BOTH.push_back(RRType::A());
......@@ -140,7 +126,6 @@ protected:
const RRClass qclass_;
const Name qzone_;
const ZoneTableConfig ztconfig_; // used for in-memory data source
DataSourceClientPtr client_;
ZoneFinderPtr finder_;
vector<RRType> requested_types_;
......
......@@ -14,7 +14,6 @@
#include <datasrc/zone_loader.h>
#include <datasrc/data_source.h>
#include <datasrc/zone_table_config.h>
#include <datasrc/rrset_collection_base.h>
#include <datasrc/memory/zone_table_segment.h>
......@@ -301,19 +300,11 @@ protected:
// Cleanup the existing data in the right order
source_client_.reset();
ztable_segment_.reset();
ztconfig_.reset();
// (re)configure zone table, then (re)construct the in-memory client
// with it.
string ztconf_txt = "{\"cache-enable\": true, \"params\": {";
if (filename) {
ztconf_txt += "\"" + zone.toText() + "\": \"" + filename + "\"";
}
ztconf_txt += "}}";
ztconfig_.reset(new internal::ZoneTableConfig(
"MasterFiles", 0, *Element::fromJSON(ztconf_txt)));
ztable_segment_.reset(memory::ZoneTableSegment::create(rrclass_,
*ztconfig_));
"local"));
source_client_.reset(new memory::InMemoryClient(ztable_segment_,
rrclass_));
if (filename) {
......@@ -326,8 +317,6 @@ private:
// from. It is still easier than setting up sqlite3 client, since
// we have this one in the linked library.
boost::scoped_ptr<internal::ZoneTableConfig> ztconfig_;
// FIXME: We should be destroying it by ZoneTableSegment::destroy.
// But the shared pointer won't let us, will it?
shared_ptr<memory::ZoneTableSegment> ztable_segment_;
......
......@@ -24,8 +24,8 @@ using namespace isc::datasrc;
using namespace isc::data;
using namespace isc::dns;
using isc::datasrc::unittest::MockDataSourceClient;
using isc::datasrc::internal::ZoneTableConfig;
using isc::datasrc::internal::ZoneTableConfigError;
using isc::datasrc::internal::CacheConfig;
using isc::datasrc::internal::CacheConfigError;
namespace {
......@@ -35,9 +35,9 @@ const char* zones[] = {
NULL
};
class ZoneTableConfigTest : public ::testing::Test {
class CacheConfigTest : public ::testing::Test {
protected:
ZoneTableConfigTest() :
CacheConfigTest() :
mock_client_(zones),
master_config_(Element::fromJSON(
"{\"cache-enable\": true,"
......@@ -53,15 +53,15 @@ protected:
const ConstElementPtr mock_config_; // valid config for MasterFiles
};
TEST_F(ZoneTableConfigTest, constructMasterFiles) {
TEST_F(CacheConfigTest, constructMasterFiles) {
// A simple case: configuring a MasterFiles table with a single zone
const ZoneTableConfig ztconf("MasterFiles", 0, *master_config_);
const CacheConfig cache_conf("MasterFiles", 0, *master_config_);
// getZoneConfig() returns a map containing exactly one entry
// corresponding to the root zone information in the configuration.
EXPECT_EQ(1, ztconf.getZoneConfig().size());
EXPECT_EQ(Name::ROOT_NAME(), ztconf.getZoneConfig().begin()->first);
EXPECT_EQ(1, cache_conf.getZoneConfig().size());
EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first);
EXPECT_EQ(TEST_DATA_DIR "/root.zone",
ztconf.getZoneConfig().begin()->second);
cache_conf.getZoneConfig().begin()->second);
// With multiple zones. There shouldn't be anything special, so we
// only check the size of getZoneConfig. Note that the constructor
......@@ -73,43 +73,41 @@ TEST_F(ZoneTableConfigTest, constructMasterFiles) {
" \"example.org\": \"file2\","
" \"example.info\": \"file3\"}"
"}"));
EXPECT_EQ(3, ZoneTableConfig("MasterFiles", 0, *config_elem_multi).
EXPECT_EQ(3, CacheConfig("MasterFiles", 0, *config_elem_multi).
getZoneConfig().size());
// A bit unusual, but acceptable case: empty parameters, so no zones.
EXPECT_TRUE(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")).
EXPECT_TRUE(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")).
getZoneConfig().empty());
}
TEST_F(ZoneTableConfigTest, badConstructMasterFiles) {
TEST_F(CacheConfigTest, badConstructMasterFiles) {
// no "params"
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": "
"true}")),
EXPECT_THROW(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true}")),
isc::data::TypeError);
// no "cache-enable"
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"params\": {}}")),
ZoneTableConfigError);
EXPECT_THROW(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"params\": {}}")),
CacheConfigError);
// cache disabled for MasterFiles
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": "
" false,"
" \"params\": {}}")),
ZoneTableConfigError);
EXPECT_THROW(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": false,"
" \"params\": {}}")),
CacheConfigError);
// type error for cache-enable
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": 1,"
" \"params\": {}}")),
EXPECT_THROW(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": 1,"
" \"params\": {}}")),
isc::data::TypeError);
// "params" is not a map
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": []}")),
EXPECT_THROW(CacheConfig("MasterFiles", 0,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": []}")),
isc::data::TypeError);
// bogus zone name
......@@ -117,32 +115,32 @@ TEST_F(ZoneTableConfigTest, badConstructMasterFiles) {
"{\"cache-enable\": true,"
" \"params\": "
"{\"bad..name\": \"file1\"}}"));
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0, *bad_config),
EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config),
isc::dns::EmptyLabel);
// file name is not a string
const ConstElementPtr bad_config2(Element::fromJSON(
"{\"cache-enable\": true,"
" \"params\": {\".\": 1}}"));
EXPECT_THROW(ZoneTableConfig("MasterFiles", 0, *bad_config2),
EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config2),
isc::data::TypeError);
// Specify data source client (must be null for MasterFiles)
EXPECT_THROW(ZoneTableConfig("MasterFiles", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")),
EXPECT_THROW(CacheConfig("MasterFiles", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"params\": {}}")),
isc::InvalidParameter);
}
TEST_F(ZoneTableConfigTest, constructWithMock) {
TEST_F(CacheConfigTest, constructWithMock) {
// Performing equivalent set of tests as constructMasterFiles
// Configure with a single zone.
const ZoneTableConfig ztconf("mock", &mock_client_, *mock_config_);
EXPECT_EQ(1, ztconf.getZoneConfig().size());
EXPECT_EQ(Name::ROOT_NAME(), ztconf.getZoneConfig().begin()->first);
EXPECT_EQ("", ztconf.getZoneConfig().begin()->second);
EXPECT_TRUE(ztconf.isEnabled());
const CacheConfig cache_conf("mock", &mock_client_, *mock_config_);
EXPECT_EQ(1, cache_conf.getZoneConfig().size());
EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first);
EXPECT_EQ("", cache_conf.getZoneConfig().begin()->second);
EXPECT_TRUE(cache_conf.isEnabled());
// Configure with multiple zones.
const ConstElementPtr config_elem_multi(
......@@ -150,47 +148,46 @@ TEST_F(ZoneTableConfigTest, constructWithMock) {
" \"cache-zones\": "
"[\"example.com\", \"example.org\",\"example.info\"]"
"}"));
EXPECT_EQ(3, ZoneTableConfig("mock", &mock_client_, *config_elem_multi).
EXPECT_EQ(3, CacheConfig("mock", &mock_client_, *config_elem_multi).
getZoneConfig().size());
// Empty
EXPECT_TRUE(ZoneTableConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": []}")).
EXPECT_TRUE(CacheConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": []}")).
getZoneConfig().empty());
// disabled. value of cache-zones are ignored.
const ConstElementPtr config_elem_disabled(
Element::fromJSON("{\"cache-enable\": false,"
" \"cache-zones\": [\"example.com\"]}"));
EXPECT_TRUE(ZoneTableConfig("mock", &mock_client_, *config_elem_disabled).
EXPECT_TRUE(CacheConfig("mock", &mock_client_, *config_elem_disabled).
getZoneConfig().empty());
}
TEST_F(ZoneTableConfigTest, badConstructWithMock) {
TEST_F(CacheConfigTest, badConstructWithMock) {
// no "cache-zones" (may become valid in future, but for now "notimp")
EXPECT_THROW(ZoneTableConfig("mock", &mock_client_,
*Element::fromJSON(
"{\"cache-enable\": true}")),
EXPECT_THROW(CacheConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true}")),
isc::NotImplemented);
// "cache-zones" is not a list
EXPECT_THROW(ZoneTableConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": {}}")),
EXPECT_THROW(CacheConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": {}}")),
isc::data::TypeError);
// "cache-zone" entry is not a string
EXPECT_THROW(ZoneTableConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": [1]}")),
EXPECT_THROW(CacheConfig("mock", &mock_client_,
*Element::fromJSON("{\"cache-enable\": true,"
" \"cache-zones\": [1]}")),
isc::data::TypeError);