Browse Source

[1975] Merge branch 'trac1975' from upstream with fixing conflicts.

JINMEI Tatuya 13 years ago
parent
commit
82d8a2a272

+ 1 - 1
src/lib/datasrc/Makefile.am

@@ -30,7 +30,7 @@ libdatasrc_la_SOURCES += logger.h logger.cc
 libdatasrc_la_SOURCES += client.h iterator.h
 libdatasrc_la_SOURCES += database.h database.cc
 libdatasrc_la_SOURCES += factory.h factory.cc
-libdatasrc_la_SOURCES += container.h container.cc
+libdatasrc_la_SOURCES += list.h list.cc
 nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 libdatasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
 

+ 40 - 26
src/lib/datasrc/container.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "container.h"
+#include "list.h"
 #include "client.h"
 #include "factory.h"
 
@@ -26,15 +26,15 @@ namespace isc {
 namespace datasrc {
 
 void
-ConfigurableContainer::configure(const ConstElementPtr& config, bool) {
+ConfigurableClientList::configure(const Element& config, bool) {
     // TODO: Implement the cache
-    // TODO: Implement recyclation from the old configuration.
+    // 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 {
         vector<DataSourceInfo> new_data_sources;
-        for (; i < config->size(); ++i) {
+        for (; i < config.size(); ++i) {
             // Extract the parameters
-            const ConstElementPtr dconf(config->get(i));
+            const ConstElementPtr dconf(config.get(i));
             const ConstElementPtr typeElem(dconf->get("type"));
             if (typeElem == ConstElementPtr()) {
                 isc_throw(ConfigurationError, "Missing the type option in "
@@ -47,12 +47,10 @@ ConfigurableContainer::configure(const ConstElementPtr& config, bool) {
             }
             // TODO: Special-case the master files type.
             // Ask the factory to create the data source for us
-            const DataSourcePair ds(this->getDataSource(type, paramConf));
+            const DataSourcePair ds(this->getDataSourceClient(type,
+                                                              paramConf));
             // And put it into the vector
-            DataSourceInfo info;
-            info.data_src_ = ds.first;
-            info.container_ = ds.second;
-            new_data_sources.push_back(info);
+            new_data_sources.push_back(DataSourceInfo(ds.first, ds.second));
         }
         // 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
@@ -64,13 +62,28 @@ ConfigurableContainer::configure(const ConstElementPtr& config, bool) {
     }
 }
 
-Container::SearchResult
-ConfigurableContainer::search(const dns::Name& name, bool want_exact_match,
-                              bool) const
+ClientList::FindResult
+ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
+                            bool) const
 {
     // Nothing found yet.
-    // Pointer is used as the SearchResult can't be assigned.
-    auto_ptr<SearchResult> candidate(new SearchResult());
+    //
+    // We have this class as a temporary storage, as the FindResult can't be
+    // assigned.
+    struct MutableResult {
+        MutableResult() :
+            datasrc_client(NULL),
+            matched_labels(0)
+        { }
+        DataSourceClient *datasrc_client;
+        ZoneFinderPtr finder;
+        uint8_t matched_labels;
+        operator FindResult() {
+            // Conversion to the right result. If we return this, there was
+            // a partial match at best.
+            return FindResult(datasrc_client, finder, matched_labels, false);
+        }
+    } candidate;
 
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
         // TODO: Once we have support for the caches, consider them too here
@@ -80,7 +93,7 @@ ConfigurableContainer::search(const dns::Name& name, bool want_exact_match,
         // 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_->findZone(name));
+            info.data_src_client_->findZone(name));
         switch (result.code) {
             case result::SUCCESS: {
                 // If we found an exact match, we have no hope to getting
@@ -88,8 +101,8 @@ ConfigurableContainer::search(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 (SearchResult(info.data_src_, result.zone_finder,
-                                     name.getLabelCount(), true));
+                return (FindResult(info.data_src_client_, result.zone_finder,
+                                   name.getLabelCount(), true));
             }
             case result::PARTIALMATCH: {
                 if (!want_exact_match) {
@@ -97,11 +110,11 @@ ConfigurableContainer::search(const dns::Name& name, bool want_exact_match,
                     // than what we have. If so, replace it.
                     const uint8_t labels(
                         result.zone_finder->getOrigin().getLabelCount());
-                    if (labels > candidate->matched_labels_) {
+                    if (labels > candidate.matched_labels) {
                         // This one is strictly better. Replace it.
-                        candidate.reset(new SearchResult(info.data_src_,
-                                                         result.zone_finder,
-                                                         labels, false));
+                    candidate.datasrc_client = info.data_src_client_;
+                        candidate.finder = result.zone_finder;
+                        candidate.matched_labels = labels;
                     }
                 }
                 break;
@@ -118,15 +131,16 @@ ConfigurableContainer::search(const dns::Name& name, bool want_exact_match,
 
     // Return the partial match we have. In case we didn't want a partial
     // match, this surely contains the original empty result.
-    return (*candidate);
+    return (candidate);
 }
 
 // NOTE: This function is not tested, it would be complicated. However, the
 // purpose of the function is to provide a very thin wrapper to be able to
 // replace the call to DataSourceClientContainer constructor in tests.
-ConfigurableContainer::DataSourcePair
-ConfigurableContainer::getDataSource(const string& type,
-                                     const ::ConstElementPtr& configuration)
+ConfigurableClientList::DataSourcePair
+ConfigurableClientList::getDataSourceClient(const string& type,
+                                            const ConstElementPtr&
+                                            configuration)
 {
     DataSourceClientContainerPtr
         container(new DataSourceClientContainer(type, configuration));

+ 99 - 73
src/lib/datasrc/container.h

@@ -34,38 +34,41 @@ class DataSourceClientContainer;
 typedef boost::shared_ptr<DataSourceClientContainer>
     DataSourceClientContainerPtr;
 
-/// \brief The container of data sources.
+/// \brief The list of data source clients.
 ///
-/// The purpose of this class is to hold several data sources and search
+/// The purpose of this class is to hold several data source clients and search
 /// through them to find one containing a zone best matching a request.
 ///
+/// All the data source clients should be for the same class. If you need
+/// to handle multiple classes, you need to create multiple separate lists.
+///
 /// This is an abstract base class. It is not expected we would use multiple
 /// implementation inside the servers (but it is not forbidden either), we
 /// have it to allow easy testing. It is possible to create a mock-up class
 /// instead of creating a full-blown configuration. The real implementation
-/// is the ConfigurableContainer.
-class Container : public boost::noncopyable {
+/// is the ConfigurableClientList.
+class ClientList : public boost::noncopyable {
 protected:
     /// \brief Constructor.
     ///
     /// It is protected to prevent accidental creation of the abstract base
     /// class.
-    Container() {}
+    ClientList() {}
 public:
-    /// \brief Structure holding the (compound) result of search.
+    /// \brief Structure holding the (compound) result of find.
     ///
     /// As this is read-only structure, we don't bother to create accessors.
     /// Instead, all the member variables are defined as const and can be
     /// accessed directly.
-    struct SearchResult {
+    struct FindResult {
         /// \brief Constructor.
         ///
         /// It simply fills in the member variables according to the
         /// parameters. See the member descriptions for their meaning.
-        SearchResult(DataSourceClient* datasrc,
-                     const ZoneFinderPtr& finder,
-                     uint8_t matched_labels, bool exact_match) :
-            datasrc_(datasrc),
+        FindResult(DataSourceClient* dsrc_client,
+                   const ZoneFinderPtr& finder,
+                   uint8_t matched_labels, bool exact_match) :
+            dsrc_client_(dsrc_client),
             finder_(finder),
             matched_labels_(matched_labels),
             exact_match_(exact_match)
@@ -75,8 +78,8 @@ public:
         ///
         /// This conscructs a result for negative answer. Both pointers are
         /// NULL, matched_labels_ is 0 and exact_match_ is false.
-        SearchResult() :
-            datasrc_(NULL),
+        FindResult() :
+            dsrc_client_(NULL),
             matched_labels_(0),
             exact_match_(false)
         { }
@@ -85,26 +88,30 @@ public:
         ///
         /// It is needed for tests and it might be of some use elsewhere
         /// too.
-        bool operator ==(const SearchResult& other) const {
-            return (datasrc_ == other.datasrc_ &&
+        bool operator ==(const FindResult& other) const {
+        return (dsrc_client_ == other.dsrc_client_ &&
                     finder_ == other.finder_ &&
                     matched_labels_ == other.matched_labels_ &&
                     exact_match_ == other.exact_match_);
         }
 
-        /// \brief The found data source.
+        /// \brief The found data source client.
+        ///
+        /// The client of the data source containing the best matching zone.
+        /// If no such data source exists, this is NULL pointer.
         ///
-        /// The data source containing the best matching zone. If no such
-        /// data source exists, this is NULL pointer.
-        DataSourceClient* const datasrc_;
+        /// Note that the pointer is valid only as long the ClientList which
+        /// returned is alive and was not reconfigured. The ownership is
+        /// preserved within the ClientList.
+        DataSourceClient* const dsrc_client_;
 
         /// \brief The finder for the requested zone.
         ///
         /// This is the finder corresponding to the best matching zone.
         /// This may be NULL even in case the datasrc_ is something
-        /// else, depending on the search options.
+        /// else, depending on the find options.
         ///
-        /// \see search
+        /// \see find
         const ZoneFinderPtr finder_;
 
         /// \brief Number of matching labels.
@@ -119,18 +126,19 @@ public:
 
     /// \brief Search for a zone through the data sources.
     ///
-    /// This searches the contained data sources for a one that best matches
-    /// the zone name.
+    /// This searches the contained data source clients for a one that best
+    /// matches the zone name.
     ///
     /// There are two expected usage scenarios. One is answering queries. In
     /// this case, the zone finder is needed and the best matching superzone
     /// of the searched name is needed. Therefore, the call would look like:
     ///
-    /// \code SearchResult result(container->search(queried_name));
-    /// if (result.datasrc_ != NULL) {
-    ///     createTheAnswer(result.finder_);
-    /// } else {
-    ///     createNotAuthAnswer();
+    /// \code FindResult result(list->find(queried_name));
+    ///   FindResult result(list->find(queried_name));
+    ///   if (result.datasrc_) {
+    ///       createTheAnswer(result.finder_);
+    ///   } else {
+    ///       createNotAuthAnswer();
     /// } \endcode
     ///
     /// The other scenario is manipulating zone data (XfrOut, XfrIn, DDNS,
@@ -138,20 +146,21 @@ public:
     /// we need an exact match (if we want to manipulate zone data, we must
     /// know exactly, which zone we are about to manipulate). Then the call
     ///
-    /// \code SearchResult result(container->search(zone_name, true, false));
-    /// if (result.datasrc_ != NULL) {
-    ///     ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
-    ///     ...
+    /// \code FindResult result(list->find(zone_name, true, false));
+    ///   FindResult result(list->find(zone_name, true, false));
+    ///   if (result.datasrc_) {
+    ///       ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
+    ///       ...
     /// } \endcode
     ///
-    /// \param zone The name of the zone to search.
+    /// \param zone The name of the zone to look for.
     /// \param want_exact_match If it is true, it returns only exact matches.
     ///     If the best possible match is partial, a negative result is
     ///     returned instead. It is possible the caller could check it and
     ///     act accordingly if the result would be partial match, but with this
-    ///     set to true, the search might be actually faster under some
+    ///     set to true, the find might be actually faster under some
     ///     circumstances.
-    /// \param want_finder If this is false, the finder_ member of SearchResult
+    /// \param want_finder If this is false, the finder_ member of FindResult
     ///     might be NULL even if the corresponding data source is found. This
     ///     is because of performance, in some cases the finder is a side
     ///     result of the searching algorithm (therefore asking for it again
@@ -161,25 +170,28 @@ public:
     ///     Other things are never the side effect of searching, therefore the
     ///     caller can get them explicitly (the updater, journal reader and
     ///     iterator).
-    /// \return A SearchResult describing the data source and zone with the
+    /// \return A FindResult describing the data source and zone with the
     ///     longest match against the zone parameter.
-    virtual SearchResult search(const dns::Name& zone,
-                                bool want_exact_match = false,
-                                bool want_finder = true) const = 0;
+    virtual FindResult find(const dns::Name& zone,
+                            bool want_exact_match = false,
+                            bool want_finder = true) const = 0;
 };
 
-/// \brief Shared pointer to the container.
-typedef boost::shared_ptr<Container> ContainerPtr;
-/// \brief Shared const pointer to the container.
-typedef boost::shared_ptr<const Container> ConstContainerPtr;
+/// \brief Shared pointer to the list.
+typedef boost::shared_ptr<ClientList> ClientListPtr;
+/// \brief Shared const pointer to the list.
+typedef boost::shared_ptr<const ClientList> ConstClientListPtr;
 
-/// \Concrete implementation of the Container, which is constructed based on
+/// \Concrete implementation of the ClientList, which is constructed based on
 ///     configuration.
 ///
 /// This is the implementation which is expected to be used in the servers.
-/// However, it is expected most of the code will use it as the Container,
+/// However, it is expected most of the code will use it as the ClientList,
 /// only the creation is expected to be direct.
-class ConfigurableContainer : public Container {
+///
+/// While it is possible to inherit this class, it is not expected to be
+/// inherited except for tests.
+class ConfigurableClientList : public ClientList {
 public:
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
@@ -191,9 +203,9 @@ public:
 
     /// \brief Sets the configuration.
     ///
-    /// This fills the Container with data sources corresponding to the
-    /// configuration. The data sources are newly created or recycled from
-    /// previous configuration.
+    /// This fills the ClientList with data source clients corresponding to the
+    /// configuration. The data source clients are newly created or recycled
+    /// from previous configuration.
     ///
     /// If any error is detected, an exception is thrown and the current
     /// configuration is preserved.
@@ -204,22 +216,34 @@ public:
     ///     configuration is used and some zones are cached into an In-Memory
     ///     data source according to it. If it is false, it is ignored and
     ///     no In-Memory data sources are created.
-    /// \throw DataSourceError if there's a problem creating a data source.
+    /// \throw DataSourceError if there's a problem creating a data source
+    ///     client.
     /// \throw ConfigurationError if the configuration is invalid in some
     ///     sense.
-    void configure(const data::ConstElementPtr& configuration,
-                   bool allow_cache);
+    void configure(const data::Element& configuration, bool allow_cache);
 
-    /// \brief Implementation of the Container::search.
-    virtual SearchResult search(const dns::Name& zone,
-                                bool want_exact_match = false,
-                                bool want_finder = true) const;
+    /// \brief Implementation of the ClientList::find.
+    virtual FindResult find(const dns::Name& zone,
+                              bool want_exact_match = false,
+                              bool want_finder = true) const;
 
-    /// \brief This holds one data source and corresponding information.
+    /// \brief This holds one data source client and corresponding information.
     ///
     /// \todo The content yet to be defined.
     struct DataSourceInfo {
-        DataSourceClient* data_src_;
+        /// \brief Default constructor.
+        ///
+        /// Don't use directly. It is here so the structure can live in
+        /// a vector.
+        DataSourceInfo() :
+            data_src_client_(NULL)
+        {}
+        DataSourceInfo(DataSourceClient* data_src_client,
+                       const DataSourceClientContainerPtr& container) :
+            data_src_client_(data_src_client),
+            container_(container)
+        { }
+        DataSourceClient* data_src_client_;
         DataSourceClientContainerPtr container_;
     };
 
@@ -229,7 +253,8 @@ protected:
     /// \brief The data sources held here.
     ///
     /// All our data sources are stored here. It is protected to let the
-    /// tests in.
+    /// tests in. You should consider it private if you ever want to
+    /// derive this class (which is not really recommended anyway).
     DataSources data_sources_;
 
     /// \brief Convenience type alias.
@@ -238,31 +263,32 @@ protected:
     typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
         DataSourcePair;
 
-    /// \brief Create a data source of given type and configuration.
+    /// \brief Create a data source client of given type and configuration.
     ///
     /// This is a thin wrapper around the DataSourceClientContainer
     /// constructor. The function is here to make it possible for tests
     /// to replace the DataSourceClientContainer with something else.
-    /// Also, derived classes might want to create the data sources
-    /// in a different way.
+    /// Also, derived classes could want to create the data source clients
+    /// in a different way, though inheriting this class is not recommended.
     ///
     /// The parameters are the same as of the constructor.
-    /// \return Pair containing both the data source and the container.
+    /// \return Pair containing both the data source client and the container.
     ///     The container might be NULL in the derived class, it is
-    ///     only stored so the data source is properly destroyed when
+    ///     only stored so the data source client is properly destroyed when
     ///     not needed. However, in such case, it is the caller's
-    ///     responsibility to ensure the data source is deleted when
+    ///     responsibility to ensure the data source client is deleted when
     ///     needed.
-    virtual DataSourcePair getDataSource(const std::string& type,
-                                         const data::ConstElementPtr&
-                                         configuration);
+    virtual DataSourcePair getDataSourceClient(const std::string& type,
+                                               const data::ConstElementPtr&
+                                               configuration);
 public:
-    /// \brief Access to the data sources.
+    /// \brief Access to the data source clients.
     ///
-    /// It can be used to examine the loaded list of data sources directly.
-    /// It is not known if it is of any use other than testing, but it might
-    /// be, so it is just made public.
-    const DataSources& dataSources() const { return (data_sources_); }
+    /// It can be used to examine the loaded list of data sources clients
+    /// directly. It is not known if it is of any use other than testing, but
+    /// it might be, so it is just made public (there's no real reason to
+    /// hide it).
+    const DataSources& getDataSources() const { return (data_sources_); }
 };
 
 } // namespace datasrc

+ 1 - 1
src/lib/datasrc/tests/Makefile.am

@@ -59,7 +59,7 @@ run_unittests_SOURCES += memory_datasrc_unittest.cc
 run_unittests_SOURCES += rbnode_rrset_unittest.cc
 run_unittests_SOURCES += zone_finder_context_unittest.cc
 run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
-run_unittests_SOURCES += container_unittest.cc
+run_unittests_SOURCES += list_unittest.cc
 
 # We need the actual module implementation in the tests (they are not part
 # of libdatasrc)

+ 138 - 130
src/lib/datasrc/tests/container_unittest.cc

@@ -12,7 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <datasrc/container.h>
+#include <datasrc/list.h>
 #include <datasrc/client.h>
 #include <datasrc/data_source.h>
 
@@ -31,7 +31,7 @@ using namespace std;
 namespace {
 
 // A test data source. It pretends it has some zones.
-class TestDS : public DataSourceClient {
+class MockDataSourceClient : public DataSourceClient {
 public:
     class Finder : public ZoneFinder {
     public:
@@ -64,14 +64,15 @@ public:
         Name origin_;
     };
     // Constructor from a list of zones.
-    TestDS(const char* zone_names[]) {
-        for (const char** zone(zone_names); *zone != NULL; ++zone) {
+    MockDataSourceClient(const char* zone_names[]) {
+        for (const char** zone(zone_names); *zone; ++zone) {
             zones.insert(Name(*zone));
         }
     }
     // Constructor from configuration. The list of zones will be empty, but
     // it will keep the configuration inside for further inspection.
-    TestDS(const string& type, const ConstElementPtr& configuration) :
+    MockDataSourceClient(const string& type,
+                         const ConstElementPtr& configuration) :
         type_(type),
         configuration_(configuration)
     { }
@@ -80,8 +81,11 @@ public:
             return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
         }
         set<Name>::const_iterator it(zones.upper_bound(name));
+        if (it == zones.begin()) {
+            return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+        }
         --it;
-        const NameComparisonResult compar(it->compare(name));
+        NameComparisonResult compar(it->compare(name));
         const ZoneFinderPtr finder(new Finder(*it));
         switch (compar.getRelation()) {
             case NameComparisonResult::EQUAL:
@@ -111,31 +115,32 @@ private:
 
 // The test version is the same as the normal version. We, however, add
 // some methods to dig directly in the internals, for the tests.
-class TestedContainer : public ConfigurableContainer {
+class TestedList : public ConfigurableClientList {
 public:
-    DataSources& dataSources() { return (data_sources_); }
-    // Overwrite the containers method to get a data source with given type
+    DataSources& getDataSources() { return (data_sources_); }
+    // Overwrite the list's method to get a data source with given type
     // and configuration. We mock the data source and don't create the
     // container. This is just to avoid some complexity in the tests.
-    virtual DataSourcePair getDataSource(const string& type,
-                                         const ConstElementPtr& configuration)
+    virtual DataSourcePair getDataSourceClient(const string& type,
+                                               const ConstElementPtr&
+                                               configuration)
     {
         if (type == "error") {
             isc_throw(DataSourceError, "The error data source type");
         }
-        shared_ptr<TestDS> ds(new TestDS(type, configuration));
-        // Make sure it is deleted when the test container is deleted.
+        shared_ptr<MockDataSourceClient>
+            ds(new MockDataSourceClient(type, configuration));
+        // Make sure it is deleted when the test list is deleted.
         to_delete_.push_back(ds);
         return (DataSourcePair(ds.get(), DataSourceClientContainerPtr()));
     }
 private:
     // Hold list of data sources created internally, so they are preserved
     // until the end of the test and then deleted.
-    vector<shared_ptr<TestDS> > to_delete_;
+    vector<shared_ptr<MockDataSourceClient> > to_delete_;
 };
-const size_t ds_count = 4;
 
-const char* ds_zones[ds_count][3] = {
+const char* ds_zones[][3] = {
     {
         "example.org.",
         "example.com.",
@@ -154,11 +159,13 @@ const char* ds_zones[ds_count][3] = {
     }
 };
 
-class ContainerTest : public ::testing::Test {
+const size_t ds_count = (sizeof (ds_zones) / sizeof (*ds_zones));
+
+class ListTest : public ::testing::Test {
 public:
-    ContainerTest() :
-        // The empty list corresponds to a container with no elements inside
-        container_(new TestedContainer()),
+    ListTest() :
+        // The empty list corresponds to a list with no elements inside
+        list_(new TestedList()),
         config_elem_(Element::fromJSON("["
             "{"
             "   \"type\": \"test_type\","
@@ -167,51 +174,51 @@ public:
             "}]"))
     {
         for (size_t i(0); i < ds_count; ++ i) {
-            shared_ptr<TestDS> ds(new TestDS(ds_zones[i]));
-            ConfigurableContainer::DataSourceInfo info;
-            info.data_src_ = ds.get();
+            shared_ptr<MockDataSourceClient>
+                ds(new MockDataSourceClient(ds_zones[i]));
             ds_.push_back(ds);
-            ds_info_.push_back(info);
+            ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
+                DataSourceClientContainerPtr()));
         }
     }
     // Check the positive result is as we expect it.
-    void positiveResult(const Container::SearchResult& result,
-                        const shared_ptr<TestDS>& dsrc,
+    void positiveResult(const ClientList::FindResult& result,
+                        const shared_ptr<MockDataSourceClient>& dsrc,
                         const Name& name, bool exact,
                         const char* test)
     {
         SCOPED_TRACE(test);
-        EXPECT_EQ(dsrc.get(), result.datasrc_);
+        EXPECT_EQ(dsrc.get(), result.dsrc_client_);
         ASSERT_NE(ZoneFinderPtr(), result.finder_);
         EXPECT_EQ(name, result.finder_->getOrigin());
         EXPECT_EQ(name.getLabelCount(), result.matched_labels_);
         EXPECT_EQ(exact, result.exact_match_);
     }
-    // Configure the container with multiple data sources, according to
+    // Configure the list with multiple data sources, according to
     // some configuration. It uses the index as parameter, to be able to
     // loop through the configurations.
     void multiConfiguration(size_t index) {
-        container_->dataSources().clear();
+        list_->getDataSources().clear();
         switch (index) {
             case 2:
-                container_->dataSources().push_back(ds_info_[2]);
-                // The ds3 is empty. We just check that it doesn't confuse
+                list_->getDataSources().push_back(ds_info_[2]);
+                // The ds_[2] is empty. We just check that it doesn't confuse
                 // us. Fall through to the case 0.
             case 0:
-                container_->dataSources().push_back(ds_info_[0]);
-                container_->dataSources().push_back(ds_info_[1]);
+                list_->getDataSources().push_back(ds_info_[0]);
+                list_->getDataSources().push_back(ds_info_[1]);
                 break;
             case 1:
                 // The other order
-                container_->dataSources().push_back(ds_info_[1]);
-                container_->dataSources().push_back(ds_info_[0]);
+                list_->getDataSources().push_back(ds_info_[1]);
+                list_->getDataSources().push_back(ds_info_[0]);
                 break;
             case 3:
-                container_->dataSources().push_back(ds_info_[1]);
-                container_->dataSources().push_back(ds_info_[0]);
-                // It is the same as 2, but we take from the first one.
+                list_->getDataSources().push_back(ds_info_[1]);
+                list_->getDataSources().push_back(ds_info_[0]);
+                // It is the same as ds_[1], but we take from the first one.
                 // The first one to match is the correct one.
-                container_->dataSources().push_back(ds_info_[3]);
+                list_->getDataSources().push_back(ds_info_[3]);
                 break;
             default:
                 FAIL() << "Unknown configuration index " << index;
@@ -219,80 +226,83 @@ public:
     }
     void checkDS(size_t index, const string& type, const string& params) const
     {
-        ASSERT_GT(container_->dataSources().size(), index);
-        const TestDS* ds(dynamic_cast<TestDS*>(
-            container_->dataSources()[index].data_src_));
+        ASSERT_GT(list_->getDataSources().size(), index);
+        MockDataSourceClient* ds(dynamic_cast<MockDataSourceClient*>(
+            list_->getDataSources()[index].data_src_client_));
+
         // Comparing with NULL does not work
-        ASSERT_TRUE(ds);
+        ASSERT_NE(ds, static_cast<const MockDataSourceClient*>(NULL));
         EXPECT_EQ(type, ds->type_);
         EXPECT_TRUE(Element::fromJSON(params)->equals(*ds->configuration_));
     }
-    shared_ptr<TestedContainer> container_;
-    const Container::SearchResult negativeResult_;
-    vector<shared_ptr<TestDS> > ds_;
-    vector<ConfigurableContainer::DataSourceInfo> ds_info_;
+    shared_ptr<TestedList> list_;
+    const ClientList::FindResult negativeResult_;
+    vector<shared_ptr<MockDataSourceClient> > ds_;
+    vector<ConfigurableClientList::DataSourceInfo> ds_info_;
     const ConstElementPtr config_elem_;
 };
 
 // Test the test itself
-TEST_F(ContainerTest, selfTest) {
+TEST_F(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);
     EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("org")).code);
     EXPECT_EQ(result::NOTFOUND, ds_[1]->findZone(Name("example.org")).code);
+    EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("aaa")).code);
+    EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("zzz")).code);
 }
 
-// Test the container we create with empty configuration is, in fact, empty
-TEST_F(ContainerTest, emptyContainer) {
-    EXPECT_TRUE(container_->dataSources().empty());
+// Test the list we create with empty configuration is, in fact, empty
+TEST_F(ListTest, emptyList) {
+    EXPECT_TRUE(list_->getDataSources().empty());
 }
 
-// Check the values returned by a search on an empty container. It should be
+// 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(ContainerTest, emptySearch) {
+TEST_F(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
     // EXPECT_EQ.  Same for other similar cases.
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("example.org"),
-                                                      false, false));
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("example.org"),
-                                                      false, true));
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("example.org"), true,
-                                                      false));
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("example.org"), true,
-                                                      true));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("example.org"), false,
+                                               false));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("example.org"), false,
+                                               true));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("example.org"), true,
+                                               false));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("example.org"), true,
+                                               true));
 }
 
-// Put a single data source inside the container and check it can find an
+// Put a single data source inside the list and check it can find an
 // exact match if there's one.
-TEST_F(ContainerTest, singleDSExactMatch) {
-    container_->dataSources().push_back(ds_info_[0]);
+TEST_F(ListTest, singleDSExactMatch) {
+    list_->getDataSources().push_back(ds_info_[0]);
     // This zone is not there
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("org."), true));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
     // But this one is, so check it.
-    positiveResult(container_->search(Name("example.org"), true),
-                   ds_[0], Name("example.org"), true, "Exact match");
+    positiveResult(list_->find(Name("example.org"), true), ds_[0],
+                   Name("example.org"), true, "Exact match");
     // When asking for a sub zone of a zone there, we get nothing
     // (we want exact match, this would be partial one)
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("sub.example.org."),
-                                                      true));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("sub.example.org."),
+                                               true));
 }
 
 // When asking for a partial match, we get all that the exact one, but more.
-TEST_F(ContainerTest, singleDSBestMatch) {
-    container_->dataSources().push_back(ds_info_[0]);
+TEST_F(ListTest, singleDSBestMatch) {
+    list_->getDataSources().push_back(ds_info_[0]);
     // This zone is not there
-    EXPECT_TRUE(negativeResult_ == container_->search(Name("org.")));
+    EXPECT_TRUE(negativeResult_ == list_->find(Name("org.")));
     // But this one is, so check it.
-    positiveResult(container_->search(Name("example.org")),
-                   ds_[0], Name("example.org"), true, "Exact match");
-    // When asking for a sub zone of a zone there, we get nothing
-    // (we want exact match, this would be partial one)
-    positiveResult(container_->search(Name("sub.example.org.")),
-                   ds_[0], Name("example.org"), false, "Subdomain match");
+    positiveResult(list_->find(Name("example.org")), ds_[0],
+                   Name("example.org"), true, "Exact match");
+    // When asking for a sub zone of a zone there, we get the parent
+    // one.
+    positiveResult(list_->find(Name("sub.example.org.")), ds_[0],
+                   Name("example.org"), false, "Subdomain match");
 }
 
 const char* const test_names[] = {
@@ -302,57 +312,54 @@ const char* const test_names[] = {
     "With a duplicity"
 };
 
-TEST_F(ContainerTest, multiExactMatch) {
+TEST_F(ListTest, multiExactMatch) {
     // Run through all the multi-configurations
-    for (size_t i(0); i < 4; ++i) {
+    for (size_t i(0); i < sizeof(test_names) / sizeof(*test_names); ++i) {
         SCOPED_TRACE(test_names[i]);
         multiConfiguration(i);
         // Something that is nowhere there
-        EXPECT_TRUE(negativeResult_ == container_->search(Name("org."), true));
+        EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
         // This one is there exactly.
-        positiveResult(container_->search(Name("example.org"), true),
-                       ds_[0], Name("example.org"), true, "Exact match");
+        positiveResult(list_->find(Name("example.org"), true), ds_[0],
+                       Name("example.org"), true, "Exact match");
         // This one too, but in a different data source.
-        positiveResult(container_->search(Name("sub.example.org."), true),
-                       ds_[1], Name("sub.example.org"), true,
-                       "Subdomain match");
+        positiveResult(list_->find(Name("sub.example.org."), true), ds_[1],
+                       Name("sub.example.org"), true, "Subdomain match");
         // But this one is in neither data source.
         EXPECT_TRUE(negativeResult_ ==
-                    container_->search(Name("sub.example.com."), true));
+                    list_->find(Name("sub.example.com."), true));
     }
 }
 
-TEST_F(ContainerTest, multiBestMatch) {
+TEST_F(ListTest, multiBestMatch) {
     // Run through all the multi-configurations
     for (size_t i(0); i < 4; ++ i) {
         SCOPED_TRACE(test_names[i]);
         multiConfiguration(i);
         // Something that is nowhere there
-        EXPECT_TRUE(negativeResult_ == container_->search(Name("org.")));
+        EXPECT_TRUE(negativeResult_ == list_->find(Name("org.")));
         // This one is there exactly.
-        positiveResult(container_->search(Name("example.org")),
-                       ds_[0], Name("example.org"), true, "Exact match");
+        positiveResult(list_->find(Name("example.org")), ds_[0],
+                       Name("example.org"), true, "Exact match");
         // This one too, but in a different data source.
-        positiveResult(container_->search(Name("sub.example.org.")),
-                       ds_[1], Name("sub.example.org"), true,
-                       "Subdomain match");
+        positiveResult(list_->find(Name("sub.example.org.")), ds_[1],
+                       Name("sub.example.org"), true, "Subdomain match");
         // But this one is in neither data source. But it is a subdomain
         // of one of the zones in the first data source.
-        positiveResult(container_->search(Name("sub.example.com.")),
-                       ds_[0], Name("example.com."), false,
-                       "Subdomain in com");
+        positiveResult(list_->find(Name("sub.example.com.")), ds_[0],
+                       Name("example.com."), false, "Subdomain in com");
     }
 }
 
 // Check the configuration is empty when the list is empty
-TEST_F(ContainerTest, configureEmpty) {
+TEST_F(ListTest, configureEmpty) {
     ConstElementPtr elem(new ListElement);
-    container_->configure(elem, true);
-    EXPECT_TRUE(container_->dataSources().empty());
+    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(ContainerTest, configureMulti) {
+TEST_F(ListTest, configureMulti) {
     ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"type1\","
@@ -365,14 +372,14 @@ TEST_F(ContainerTest, configureMulti) {
         "   \"params\": {}"
         "}]"
     ));
-    container_->configure(elem, true);
-    EXPECT_EQ(2, container_->dataSources().size());
+    list_->configure(*elem, true);
+    EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}");
     checkDS(1, "type2", "{}");
 }
 
 // Check we can pass whatever we want to the params
-TEST_F(ContainerTest, configureParams) {
+TEST_F(ListTest, configureParams) {
     const char* params[] = {
         "true",
         "false",
@@ -391,77 +398,78 @@ TEST_F(ContainerTest, configureParams) {
             "   \"cache\": \"off\","
             "   \"params\": ") + *param +
             "}]"));
-        container_->configure(elem, true);
-        EXPECT_EQ(1, container_->dataSources().size());
+        list_->configure(*elem, true);
+        EXPECT_EQ(1, list_->getDataSources().size());
         checkDS(0, "t", *param);
     }
 }
 
-TEST_F(ContainerTest, wrongConfig) {
+TEST_F(ListTest, wrongConfig) {
     const char* configs[] = {
         // A lot of stuff missing from there
-        "[{}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, {}]",
         // Some bad types completely
         "{}",
         "true",
         "42",
         "null",
-        "[true]",
-        "[[]]",
-        "[42]",
+        "[{\"type\": \"test_type\", \"params\": 13}, true]",
+        "[{\"type\": \"test_type\", \"params\": 13}, []]",
+        "[{\"type\": \"test_type\", \"params\": 13}, 42]",
         // Bad type of type
-        "[{\"type\": 42}]",
-        "[{\"type\": true}]",
-        "[{\"type\": null}]",
-        "[{\"type\": []}]",
-        "[{\"type\": {}}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": 42}]",
+        "[{\"type\": \"test_type\", \"params\": 13}, {\"type\": true}]",
+        "[{\"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
         NULL
     };
     // Put something inside to see it survives the exception
-    container_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}");
     for (const char** config(configs); *config; ++config) {
         SCOPED_TRACE(*config);
         ConstElementPtr elem(Element::fromJSON(*config));
-        EXPECT_THROW(container_->configure(elem, true),
-                     ConfigurableContainer::ConfigurationError);
+        EXPECT_THROW(list_->configure(*elem, true),
+                     ConfigurableClientList::ConfigurationError);
         // Still untouched
         checkDS(0, "test_type", "{}");
+        EXPECT_EQ(1, list_->getDataSources().size());
     }
 }
 
 // The param thing defaults to null. Cache is not used yet.
-TEST_F(ContainerTest, defaults) {
+TEST_F(ListTest, defaults) {
     ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"type1\""
         "}]"));
-    container_->configure(elem, true);
-    EXPECT_EQ(1, container_->dataSources().size());
+    list_->configure(*elem, true);
+    EXPECT_EQ(1, list_->getDataSources().size());
     checkDS(0, "type1", "null");
 }
 
 // Check we can call the configure multiple times, to change the configuration
-TEST_F(ContainerTest, reconfigure) {
+TEST_F(ListTest, reconfigure) {
     ConstElementPtr empty(new ListElement);
-    container_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}");
-    container_->configure(empty, true);
-    EXPECT_TRUE(container_->dataSources().empty());
-    container_->configure(config_elem_, true);
+    list_->configure(*empty, true);
+    EXPECT_TRUE(list_->getDataSources().empty());
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}");
 }
 
 // Make sure the data source error exception from the factory is propagated
-TEST_F(ContainerTest, dataSrcError) {
+TEST_F(ListTest, dataSrcError) {
     ConstElementPtr elem(Element::fromJSON("["
         "{"
         "   \"type\": \"error\""
         "}]"));
-    container_->configure(config_elem_, true);
+    list_->configure(*config_elem_, true);
     checkDS(0, "test_type", "{}");
-    EXPECT_THROW(container_->configure(elem, true), DataSourceError);
+    EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
     checkDS(0, "test_type", "{}");
 }