BIND 10 master, updated. 7197d4f537cf2e2931ad17370eeaf34154479dea Merge #2044

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Jul 5 08:08:28 UTC 2012


The branch, master has been updated
       via  7197d4f537cf2e2931ad17370eeaf34154479dea (commit)
       via  afddf8828805e696c391be55105f620ae4840b4c (commit)
       via  cd6b6e00ddc1fec370ccc55c3c84e082850fb29d (commit)
       via  db1cb6a8bb11f390e7a56bddcf3b8042d60f3191 (commit)
       via  42b565e0690fc72752047c9aa73f249fae1162a4 (commit)
       via  6d84b65cd4206e960b441fa47dff7c6b1b3ced6d (commit)
       via  98d893ecdff8ee42d270a9548f91fe3dffdf6c43 (commit)
       via  4d67ce9015c75a7b8d7fa986037f9e2f428cf657 (commit)
      from  1fc2b06b57a008ec602daa2dac79939b3cc6b65d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 7197d4f537cf2e2931ad17370eeaf34154479dea
Merge: 1fc2b06 afddf88
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Thu Jul 5 09:43:18 2012 +0200

    Merge #2044

-----------------------------------------------------------------------

Summary of changes:
 src/lib/datasrc/Makefile.am                   |    7 +-
 src/lib/datasrc/client_list.cc                |   76 ++++++--
 src/lib/datasrc/client_list.h                 |   13 +-
 src/lib/datasrc/tests/Makefile.am             |    1 -
 src/lib/datasrc/tests/client_list_unittest.cc |  247 ++++++++++++++++++++++---
 5 files changed, 299 insertions(+), 45 deletions(-)

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index 9a4d733..5359c09 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -36,6 +36,7 @@ libdatasrc_la_SOURCES += client.h iterator.h
 libdatasrc_la_SOURCES += database.h database.cc
 libdatasrc_la_SOURCES += factory.h factory.cc
 libdatasrc_la_SOURCES += client_list.h client_list.cc
+libdatasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
 nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 libdatasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
 
@@ -49,14 +50,12 @@ sqlite3_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 sqlite3_ds_la_LIBADD += libdatasrc.la
 sqlite3_ds_la_LIBADD += $(SQLITE_LIBS)
 
-memory_ds_la_SOURCES = memory_datasrc.h memory_datasrc.cc
-memory_ds_la_SOURCES += memory_datasrc_link.cc
+memory_ds_la_SOURCES = memory_datasrc_link.cc
 memory_ds_la_LDFLAGS = -module -avoid-version
 memory_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 memory_ds_la_LIBADD += libdatasrc.la
 
-static_ds_la_SOURCES = memory_datasrc.h memory_datasrc.cc
-static_ds_la_SOURCES += static_datasrc_link.cc
+static_ds_la_SOURCES = static_datasrc_link.cc
 static_ds_la_LDFLAGS = -module -avoid-version
 static_ds_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 static_ds_la_LIBADD += libdatasrc.la
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index 549b216..fab534d 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -15,19 +15,32 @@
 #include "client_list.h"
 #include "client.h"
 #include "factory.h"
+#include "memory_datasrc.h"
 
 #include <memory>
 #include <boost/foreach.hpp>
 
 using namespace isc::data;
+using namespace isc::dns;
 using namespace std;
+using namespace boost;
 
 namespace isc {
 namespace datasrc {
 
+ConfigurableClientList::DataSourceInfo::DataSourceInfo(
+    DataSourceClient* data_src_client,
+    const DataSourceClientContainerPtr& container, bool hasCache) :
+    data_src_client_(data_src_client),
+    container_(container)
+{
+    if (hasCache) {
+        cache_.reset(new InMemoryClient);
+    }
+}
+
 void
-ConfigurableClientList::configure(const Element& config, bool) {
-    // TODO: Implement the cache
+ConfigurableClientList::configure(const Element& config, bool allow_cache) {
     // TODO: Implement recycling from the old configuration.
     size_t i(0); // Outside of the try to be able to access it in the catch
     try {
@@ -49,8 +62,48 @@ ConfigurableClientList::configure(const Element& config, bool) {
             // Ask the factory to create the data source for us
             const DataSourcePair ds(this->getDataSourceClient(type,
                                                               paramConf));
+            const bool want_cache(allow_cache &&
+                                  dconf->contains("cache-enable") &&
+                                  dconf->get("cache-enable")->boolValue());
             // And put it into the vector
-            new_data_sources.push_back(DataSourceInfo(ds.first, ds.second));
+            new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
+                                                      want_cache));
+            if (want_cache) {
+                if (!dconf->contains("cache-zones")) {
+                    isc_throw(isc::NotImplemented, "Auto-detection of zones "
+                              "to cache is not yet implemented, supply "
+                              "cache-zones parameter");
+                    // TODO: Auto-detect list of all zones in the
+                    // data source.
+                }
+                const ConstElementPtr zones(dconf->get("cache-zones"));
+                const shared_ptr<InMemoryClient>
+                    cache(new_data_sources.back().cache_);
+                const DataSourceClient* const
+                    client(new_data_sources.back().data_src_client_);
+                for (size_t i(0); i < zones->size(); ++i) {
+                    const Name origin(zones->get(i)->stringValue());
+                    const DataSourceClient::FindResult
+                        zone(client->findZone(origin));
+                    if (zone.code != result::SUCCESS) {
+                        // The data source does not contain the zone, it can't
+                        // be cached.
+                        isc_throw(ConfigurationError, "Unable to cache "
+                                  "non-existent zone " << origin);
+                    }
+                    shared_ptr<InMemoryZoneFinder>
+                        finder(new
+                            InMemoryZoneFinder(zone.zone_finder->getClass(),
+                                               origin));
+                    ZoneIteratorPtr iterator(client->getIterator(origin));
+                    if (!iterator) {
+                        isc_throw(isc::Unexpected, "Got NULL iterator for "
+                                  "zone " << origin);
+                    }
+                    finder->load(*iterator);
+                    cache->addZone(finder);
+                }
+            }
         }
         // If everything is OK up until now, we have the new configuration
         // ready. So just put it there and let the old one die when we exit
@@ -88,14 +141,11 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
     } candidate;
 
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
-        // TODO: Once we have support for the caches, consider them too here
-        // somehow. This would probably get replaced by a function, that
-        // checks if there's a cache available, if it is, checks the loaded
-        // zones and zones expected to be in the real data source. If it is
-        // the cached one, provide the cached one. If it is in the external
-        // data source, use the datasource and don't provide the finder yet.
-        const DataSourceClient::FindResult result(
-            info.data_src_client_->findZone(name));
+        DataSourceClient* client(info.cache_ ? info.cache_.get() :
+                                 info.data_src_client_);
+        const DataSourceClient::FindResult result(client->findZone(name));
+        // TODO: Once we mark the zones that are not loaded, but are present
+        // in the data source somehow, check them too.
         switch (result.code) {
             case result::SUCCESS:
                 // If we found an exact match, we have no hope to getting
@@ -103,7 +153,7 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
 
                 // TODO: In case we have only the datasource and not the finder
                 // and the need_updater parameter is true, get the zone there.
-                return (FindResult(info.data_src_client_, result.zone_finder,
+                return (FindResult(client, result.zone_finder,
                                    true));
             case result::PARTIALMATCH:
                 if (!want_exact_match) {
@@ -124,7 +174,7 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
                     if (labels > candidate.matched_labels ||
                         !candidate.matched) {
                         // This one is strictly better. Replace it.
-                        candidate.datasrc_client = info.data_src_client_;
+                        candidate.datasrc_client = client;
                         candidate.finder = result.zone_finder;
                         candidate.matched_labels = labels;
                         candidate.matched = true;
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index 599dca8..5105d08 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -33,6 +33,7 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
 class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
+class InMemoryClient;
 
 /// \brief The list of data source clients.
 ///
@@ -212,6 +213,11 @@ public:
     ///     client.
     /// \throw ConfigurationError if the configuration is invalid in some
     ///     sense.
+    /// \throw Unexpected if something misbehaves (like the data source
+    ///     returning NULL iterator).
+    /// \throw NotImplemented if the auto-detection of list of zones is
+    ///     needed.
+    /// \throw Whatever is propagated from within the data source.
     void configure(const data::Element& configuration, bool allow_cache);
 
     /// \brief Implementation of the ClientList::find.
@@ -231,12 +237,11 @@ public:
             data_src_client_(NULL)
         {}
         DataSourceInfo(DataSourceClient* data_src_client,
-                       const DataSourceClientContainerPtr& container) :
-            data_src_client_(data_src_client),
-            container_(container)
-        {}
+                       const DataSourceClientContainerPtr& container,
+                       bool hasCache);
         DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
+        boost::shared_ptr<InMemoryClient> cache_;
     };
 
     /// \brief The collection of data sources.
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 44b20ca..0d3ce1a 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -67,7 +67,6 @@ run_unittests_SOURCES += client_list_unittest.cc
 # We need the actual module implementation in the tests (they are not part
 # of libdatasrc)
 run_unittests_SOURCES += $(top_srcdir)/src/lib/datasrc/sqlite3_accessor.cc
-run_unittests_SOURCES += $(top_srcdir)/src/lib/datasrc/memory_datasrc.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index ae22470..7498d23 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -14,9 +14,13 @@
 
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
+#include <datasrc/iterator.h>
 #include <datasrc/data_source.h>
+#include <datasrc/memory_datasrc.h>
 
 #include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/rdataclass.h>
 
 #include <gtest/gtest.h>
 
@@ -41,7 +45,7 @@ public:
         Name getOrigin() const { return (origin_); }
         // The rest is not to be called, so just have them
         RRClass getClass() const {
-            isc_throw(isc::NotImplemented, "Not implemented");
+            return (RRClass::IN());
         }
         shared_ptr<Context> find(const Name&, const RRType&,
                                  const FindOptions)
@@ -60,6 +64,35 @@ public:
     private:
         Name origin_;
     };
+    class Iterator : public ZoneIterator {
+    public:
+        Iterator(const Name& origin) :
+            origin_(origin),
+            finished_(false),
+            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));
+        }
+        virtual isc::dns::ConstRRsetPtr getNextRRset() {
+            if (finished_) {
+                return (ConstRRsetPtr());
+            } else {
+                finished_ = true;
+                return (soa_);
+            }
+        }
+        virtual isc::dns::ConstRRsetPtr getSOA() const {
+            return (soa_);
+        }
+    private:
+        const Name origin_;
+        bool finished_;
+        const isc::dns::RRsetPtr soa_;
+    };
     // Constructor from a list of zones.
     MockDataSourceClient(const char* zone_names[]) {
         for (const char** zone(zone_names); *zone; ++zone) {
@@ -72,7 +105,13 @@ public:
                          const ConstElementPtr& configuration) :
         type_(type),
         configuration_(configuration)
-    {}
+    {
+        if (configuration_->getType() == Element::list) {
+            for (size_t i(0); i < configuration_->size(); ++i) {
+                zones.insert(Name(configuration_->get(i)->stringValue()));
+            }
+        }
+    }
     virtual FindResult findZone(const Name& name) const {
         if (zones.empty()) {
             return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
@@ -103,6 +142,15 @@ public:
     {
         isc_throw(isc::NotImplemented, "Not implemented");
     }
+    virtual ZoneIteratorPtr getIterator(const Name& name, bool) const {
+        if (name == Name("noiter.org")) {
+            isc_throw(isc::NotImplemented, "Asked not to be implemented");
+        } else if (name == Name("null.org")) {
+            return (ZoneIteratorPtr());
+        } else {
+            return (ZoneIteratorPtr(new Iterator(name)));
+        }
+    }
     const string type_;
     const ConstElementPtr configuration_;
 private:
@@ -166,7 +214,6 @@ public:
         config_elem_(Element::fromJSON("["
             "{"
             "   \"type\": \"test_type\","
-            "   \"cache\": \"off\","
             "   \"params\": {}"
             "}]"))
     {
@@ -175,20 +222,28 @@ public:
                 ds(new MockDataSourceClient(ds_zones[i]));
             ds_.push_back(ds);
             ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
-                DataSourceClientContainerPtr()));
+                DataSourceClientContainerPtr(), false));
         }
     }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
                         const shared_ptr<MockDataSourceClient>& dsrc,
                         const Name& name, bool exact,
-                        const char* test)
+                        const char* test, bool from_cache = false)
     {
         SCOPED_TRACE(test);
-        EXPECT_EQ(dsrc.get(), result.dsrc_client_);
         ASSERT_NE(ZoneFinderPtr(), result.finder_);
         EXPECT_EQ(name, result.finder_->getOrigin());
         EXPECT_EQ(exact, result.exact_match_);
+        if (from_cache) {
+            EXPECT_NE(shared_ptr<InMemoryZoneFinder>(),
+                      dynamic_pointer_cast<InMemoryZoneFinder>(
+                          result.finder_)) << "Finder is not from cache";
+            EXPECT_TRUE(NULL !=
+                        dynamic_cast<InMemoryClient*>(result.dsrc_client_));
+        } else {
+            EXPECT_EQ(dsrc.get(), result.dsrc_client_);
+        }
     }
     // Configure the list with multiple data sources, according to
     // some configuration. It uses the index as parameter, to be able to
@@ -220,7 +275,8 @@ public:
                 FAIL() << "Unknown configuration index " << index;
         }
     }
-    void checkDS(size_t index, const string& type, const string& params) const
+    void checkDS(size_t index, const string& type, const string& params,
+                 bool cache) const
     {
         ASSERT_GT(list_->getDataSources().size(), index);
         MockDataSourceClient* ds(dynamic_cast<MockDataSourceClient*>(
@@ -230,6 +286,8 @@ public:
         ASSERT_NE(ds, static_cast<const MockDataSourceClient*>(NULL));
         EXPECT_EQ(type, ds->type_);
         EXPECT_TRUE(Element::fromJSON(params)->equals(*ds->configuration_));
+        EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
+                  shared_ptr<InMemoryClient>());
     }
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negativeResult_;
@@ -349,14 +407,14 @@ TEST_F(ListTest, multiBestMatch) {
 
 // Check the configuration is empty when the list is empty
 TEST_F(ListTest, configureEmpty) {
-    ConstElementPtr elem(new ListElement);
+    const ConstElementPtr elem(new ListElement);
     list_->configure(*elem, true);
     EXPECT_TRUE(list_->getDataSources().empty());
 }
 
 // Check we can get multiple data sources and they are in the right order.
 TEST_F(ListTest, configureMulti) {
-    ConstElementPtr elem(Element::fromJSON("["
+    const ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"type1\","
         "   \"cache\": \"off\","
@@ -370,8 +428,8 @@ TEST_F(ListTest, configureMulti) {
     ));
     list_->configure(*elem, true);
     EXPECT_EQ(2, list_->getDataSources().size());
-    checkDS(0, "type1", "{}");
-    checkDS(1, "type2", "{}");
+    checkDS(0, "type1", "{}", false);
+    checkDS(1, "type2", "{}", false);
 }
 
 // Check we can pass whatever we want to the params
@@ -396,7 +454,7 @@ TEST_F(ListTest, configureParams) {
             "}]"));
         list_->configure(*elem, true);
         EXPECT_EQ(1, list_->getDataSources().size());
-        checkDS(0, "t", *param);
+        checkDS(0, "t", *param, false);
     }
 }
 
@@ -418,55 +476,198 @@ TEST_F(ListTest, wrongConfig) {
         "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": null}]",
         "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": []}]",
         "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": {}}]",
-        // TODO: Once cache is supported, add some invalid cache values
+        // Bad type of cache-enable
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": 13, \"cache-zones\": []}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": \"xx\", \"cache-zones\": []}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": [], \"cache-zones\": []}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": {}, \"cache-zones\": []}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": null, \"cache-zones\": []}]",
+        // Bad type of cache-zones
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": \"x\"}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": true}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": null}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": 13}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, "
+         "{\"type\": \"x\", \"cache-enable\": true, \"cache-zones\": {}}]",
         NULL
     };
     // Put something inside to see it survives the exception
     list_->configure(*config_elem_, true);
-    checkDS(0, "test_type", "{}");
+    checkDS(0, "test_type", "{}", false);
     for (const char** config(configs); *config; ++config) {
         SCOPED_TRACE(*config);
         ConstElementPtr elem(Element::fromJSON(*config));
         EXPECT_THROW(list_->configure(*elem, true),
                      ConfigurableClientList::ConfigurationError);
         // Still untouched
-        checkDS(0, "test_type", "{}");
+        checkDS(0, "test_type", "{}", false);
         EXPECT_EQ(1, list_->getDataSources().size());
     }
 }
 
 // The param thing defaults to null. Cache is not used yet.
 TEST_F(ListTest, defaults) {
-    ConstElementPtr elem(Element::fromJSON("["
+    const ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"type1\""
         "}]"));
     list_->configure(*elem, true);
     EXPECT_EQ(1, list_->getDataSources().size());
-    checkDS(0, "type1", "null");
+    checkDS(0, "type1", "null", false);
 }
 
 // Check we can call the configure multiple times, to change the configuration
 TEST_F(ListTest, reconfigure) {
-    ConstElementPtr empty(new ListElement);
+    const ConstElementPtr empty(new ListElement);
     list_->configure(*config_elem_, true);
-    checkDS(0, "test_type", "{}");
+    checkDS(0, "test_type", "{}", false);
     list_->configure(*empty, true);
     EXPECT_TRUE(list_->getDataSources().empty());
     list_->configure(*config_elem_, true);
-    checkDS(0, "test_type", "{}");
+    checkDS(0, "test_type", "{}", false);
 }
 
 // Make sure the data source error exception from the factory is propagated
 TEST_F(ListTest, dataSrcError) {
-    ConstElementPtr elem(Element::fromJSON("["
+    const ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"error\""
         "}]"));
     list_->configure(*config_elem_, true);
-    checkDS(0, "test_type", "{}");
+    checkDS(0, "test_type", "{}", false);
     EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
-    checkDS(0, "test_type", "{}");
+    checkDS(0, "test_type", "{}", false);
+}
+
+// Check we can get the cache
+TEST_F(ListTest, configureCacheEmpty) {
+    const ConstElementPtr elem(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [],"
+        "   \"params\": {}"
+        "},"
+        "{"
+        "   \"type\": \"type2\","
+        "   \"cache-enable\": false,"
+        "   \"cache-zones\": [],"
+        "   \"params\": {}"
+        "}]"
+    ));
+    list_->configure(*elem, true);
+    EXPECT_EQ(2, list_->getDataSources().size());
+    checkDS(0, "type1", "{}", true);
+    checkDS(1, "type2", "{}", false);
+}
+
+// But no cache if we disallow it globally
+TEST_F(ListTest, configureCacheDisabled) {
+    const ConstElementPtr elem(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [],"
+        "   \"params\": {}"
+        "},"
+        "{"
+        "   \"type\": \"type2\","
+        "   \"cache-enable\": false,"
+        "   \"cache-zones\": [],"
+        "   \"params\": {}"
+        "}]"
+    ));
+    list_->configure(*elem, false);
+    EXPECT_EQ(2, list_->getDataSources().size());
+    checkDS(0, "type1", "{}", false);
+    checkDS(1, "type2", "{}", false);
+}
+
+// Put some zones into the cache
+TEST_F(ListTest, cacheZones) {
+    const ConstElementPtr elem(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [\"example.org\", \"example.com\"],"
+        "   \"params\": [\"example.org\", \"example.com\", \"exmaple.cz\"]"
+        "}]"));
+    list_->configure(*elem, true);
+    checkDS(0, "type1", "[\"example.org\", \"example.com\", \"exmaple.cz\"]",
+            true);
+
+    const shared_ptr<InMemoryClient> cache(list_->getDataSources()[0].cache_);
+    EXPECT_EQ(2, cache->getZoneCount());
+
+    EXPECT_EQ(result::SUCCESS, cache->findZone(Name("example.org")).code);
+    EXPECT_EQ(result::SUCCESS, cache->findZone(Name("example.com")).code);
+    EXPECT_EQ(result::NOTFOUND, cache->findZone(Name("example.cz")).code);
+
+    // These are cached and answered from the cache
+    positiveResult(list_->find(Name("example.com.")), ds_[0],
+                   Name("example.com."), true, "com", true);
+    positiveResult(list_->find(Name("example.org.")), ds_[0],
+                   Name("example.org."), true, "org", true);
+    positiveResult(list_->find(Name("sub.example.com.")), ds_[0],
+                   Name("example.com."), false, "Subdomain of com", true);
+    // For now, the ones not cached are ignored.
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("example.cz.")));
+}
+
+// Check the caching handles misbehaviour from the data source and
+// misconfiguration gracefully
+TEST_F(ListTest, badCache) {
+    list_->configure(*config_elem_, true);
+    checkDS(0, "test_type", "{}", false);
+    // First, the zone is not in the data source
+    const ConstElementPtr elem1(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [\"example.org\"],"
+        "   \"params\": []"
+        "}]"));
+    EXPECT_THROW(list_->configure(*elem1, true),
+                 ConfigurableClientList::ConfigurationError);
+    checkDS(0, "test_type", "{}", false);
+    // Now, the zone doesn't give an iterator
+    const ConstElementPtr elem2(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [\"noiter.org\"],"
+        "   \"params\": [\"noiter.org\"]"
+        "}]"));
+    EXPECT_THROW(list_->configure(*elem2, true), isc::NotImplemented);
+    checkDS(0, "test_type", "{}", false);
+    // Now, the zone returns NULL iterator
+    const ConstElementPtr elem3(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"cache-zones\": [\"null.org\"],"
+        "   \"params\": [\"null.org\"]"
+        "}]"));
+    EXPECT_THROW(list_->configure(*elem3, true), isc::Unexpected);
+    checkDS(0, "test_type", "{}", false);
+    // The autodetection of zones is not enabled
+    const ConstElementPtr elem4(Element::fromJSON("["
+        "{"
+        "   \"type\": \"type1\","
+        "   \"cache-enable\": true,"
+        "   \"params\": [\"example.org\"]"
+        "}]"));
+    EXPECT_THROW(list_->configure(*elem4, true), isc::NotImplemented);
+    checkDS(0, "test_type", "{}", false);
 }
 
 }



More information about the bind10-changes mailing list