BIND 10 trac1975, updated. 7dcf7f71a999d1e20185fef0e55d4c1447aea24b [1975] Minor: braces, comments
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Jun 14 13:04:49 UTC 2012
The branch, trac1975 has been updated
via 7dcf7f71a999d1e20185fef0e55d4c1447aea24b (commit)
via bf59ff6ae4f426559e3fec86fcc4fe15ae98f485 (commit)
via da15f58fb83ca24cc09812dec9c02b272d730caa (commit)
via b66ca2c6cc969be893e40184de90e12a33602b67 (commit)
from 52a26b21697e8986400ab4af46429e3d00c895c5 (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 7dcf7f71a999d1e20185fef0e55d4c1447aea24b
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jun 14 15:00:12 2012 +0200
[1975] Minor: braces, comments
commit bf59ff6ae4f426559e3fec86fcc4fe15ae98f485
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jun 14 14:48:54 2012 +0200
[1975] Rename the files
The list.{h,cc} is too generic.
commit da15f58fb83ca24cc09812dec9c02b272d730caa
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jun 14 14:45:58 2012 +0200
[1975] Small optimisation
Don't compute the number of matched labels at the first match, there's
nothing to compare against anyway. We hope that there'll be only one one
partial match in practice.
commit b66ca2c6cc969be893e40184de90e12a33602b67
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jun 14 14:35:20 2012 +0200
[1975] Remove matched_labels from the result
They are likely not to be useful anyway and this allows a small
optimisation.
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/Makefile.am | 2 +-
src/lib/datasrc/{list.cc => client_list.cc} | 41 +++++++++++++-------
src/lib/datasrc/{list.h => client_list.h} | 28 +++++--------
src/lib/datasrc/tests/Makefile.am | 2 +-
.../{list_unittest.cc => client_list_unittest.cc} | 7 ++--
5 files changed, 40 insertions(+), 40 deletions(-)
rename src/lib/datasrc/{list.cc => client_list.cc} (83%)
rename src/lib/datasrc/{list.h => client_list.h} (94%)
rename src/lib/datasrc/tests/{list_unittest.cc => client_list_unittest.cc} (99%)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index 52f2165..bb014a1 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/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 += list.h list.cc
+libdatasrc_la_SOURCES += client_list.h client_list.cc
nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
libdatasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
new file mode 100644
index 0000000..549b216
--- /dev/null
+++ b/src/lib/datasrc/client_list.cc
@@ -0,0 +1,162 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "client_list.h"
+#include "client.h"
+#include "factory.h"
+
+#include <memory>
+#include <boost/foreach.hpp>
+
+using namespace isc::data;
+using namespace std;
+
+namespace isc {
+namespace datasrc {
+
+void
+ConfigurableClientList::configure(const Element& config, bool) {
+ // TODO: Implement the 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 {
+ vector<DataSourceInfo> new_data_sources;
+ for (; i < config.size(); ++i) {
+ // Extract the parameters
+ const ConstElementPtr dconf(config.get(i));
+ const ConstElementPtr typeElem(dconf->get("type"));
+ if (typeElem == ConstElementPtr()) {
+ isc_throw(ConfigurationError, "Missing the type option in "
+ "data source no " << i);
+ }
+ const string type(typeElem->stringValue());
+ ConstElementPtr paramConf(dconf->get("params"));
+ if (paramConf == ConstElementPtr()) {
+ paramConf.reset(new NullElement());
+ }
+ // TODO: Special-case the master files type.
+ // Ask the factory to create the data source for us
+ const DataSourcePair ds(this->getDataSourceClient(type,
+ paramConf));
+ // And put it into the vector
+ 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
+ // the scope.
+ data_sources_.swap(new_data_sources);
+ } catch (const TypeError& te) {
+ isc_throw(ConfigurationError, "Malformed configuration at data source "
+ "no. " << i << ": " << te.what());
+ }
+}
+
+ClientList::FindResult
+ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
+ bool) const
+{
+ // Nothing found yet.
+ //
+ // We have this class as a temporary storage, as the FindResult can't be
+ // assigned.
+ struct MutableResult {
+ MutableResult() :
+ datasrc_client(NULL),
+ matched_labels(0),
+ matched(false)
+ {}
+ DataSourceClient* datasrc_client;
+ ZoneFinderPtr finder;
+ uint8_t matched_labels;
+ bool matched;
+ operator FindResult() const {
+ // Conversion to the right result. If we return this, there was
+ // a partial match at best.
+ return (FindResult(datasrc_client, finder, false));
+ }
+ } 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));
+ switch (result.code) {
+ case result::SUCCESS:
+ // If we found an exact match, we have no hope to getting
+ // a better one. Stop right here.
+
+ // 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,
+ true));
+ case result::PARTIALMATCH:
+ if (!want_exact_match) {
+ // In case we have a partial match, check if it is better
+ // than what we have. If so, replace it.
+ //
+ // We don't need the labels at the first partial match,
+ // we have nothing to compare with. So we don't get it
+ // (as a performance) and hope we will not need it at all.
+ const uint8_t labels(candidate.matched ?
+ result.zone_finder->getOrigin().getLabelCount() : 0);
+ if (candidate.matched && candidate.matched_labels == 0) {
+ // But if the hope turns out to be false, we need to
+ // compute it for the first match anyway.
+ candidate.matched_labels = candidate.finder->
+ getOrigin().getLabelCount();
+ }
+ if (labels > candidate.matched_labels ||
+ !candidate.matched) {
+ // This one is strictly better. Replace it.
+ candidate.datasrc_client = info.data_src_client_;
+ candidate.finder = result.zone_finder;
+ candidate.matched_labels = labels;
+ candidate.matched = true;
+ }
+ }
+ break;
+ default:
+ // Nothing found, nothing to do.
+ break;
+ }
+ }
+
+ // TODO: In case we have only the datasource and not the finder
+ // and the need_updater parameter is true, get the zone there.
+
+ // Return the partial match we have. In case we didn't want a partial
+ // match, this surely contains the original empty result.
+ 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.
+ConfigurableClientList::DataSourcePair
+ConfigurableClientList::getDataSourceClient(const string& type,
+ const ConstElementPtr&
+ configuration)
+{
+ DataSourceClientContainerPtr
+ container(new DataSourceClientContainer(type, configuration));
+ return (DataSourcePair(&container->getInstance(), container));
+}
+
+}
+}
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
new file mode 100644
index 0000000..5b3102e
--- /dev/null
+++ b/src/lib/datasrc/client_list.h
@@ -0,0 +1,287 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_CONTAINER_H
+#define DATASRC_CONTAINER_H
+
+#include <dns/name.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
+
+#include <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace datasrc {
+
+class ZoneFinder;
+typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
+class DataSourceClient;
+typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
+class DataSourceClientContainer;
+typedef boost::shared_ptr<DataSourceClientContainer>
+ DataSourceClientContainerPtr;
+
+/// \brief The list of data source clients.
+///
+/// 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 ConfigurableClientList.
+class ClientList : public boost::noncopyable {
+protected:
+ /// \brief Constructor.
+ ///
+ /// It is protected to prevent accidental creation of the abstract base
+ /// class.
+ ClientList() {}
+public:
+ /// \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 FindResult {
+ /// \brief Constructor.
+ ///
+ /// It simply fills in the member variables according to the
+ /// parameters. See the member descriptions for their meaning.
+ FindResult(DataSourceClient* dsrc_client, const ZoneFinderPtr& finder,
+ bool exact_match) :
+ dsrc_client_(dsrc_client),
+ finder_(finder),
+ exact_match_(exact_match)
+ {}
+
+ /// \brief Negative answer constructor.
+ ///
+ /// This conscructs a result for negative answer. Both pointers are
+ /// NULL, and exact_match_ is false.
+ FindResult() :
+ dsrc_client_(NULL),
+ exact_match_(false)
+ {}
+
+ /// \brief Comparison operator.
+ ///
+ /// It is needed for tests and it might be of some use elsewhere
+ /// too.
+ bool operator ==(const FindResult& other) const {
+ return (dsrc_client_ == other.dsrc_client_ &&
+ finder_ == other.finder_ &&
+ exact_match_ == other.exact_match_);
+ }
+
+ /// \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.
+ ///
+ /// Note that the pointer is valid only as long the ClientList which
+ /// returned the pointer 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 find options.
+ ///
+ /// \see find
+ const ZoneFinderPtr finder_;
+
+ /// \brief If the result is an exact match.
+ const bool exact_match_;
+ };
+
+ /// \brief Search for a zone through the data sources.
+ ///
+ /// 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 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,
+ /// ...). In this case, the finder itself is not so important. However,
+ /// 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 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 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 find might be actually faster under some
+ /// circumstances.
+ /// \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
+ /// would be a waste), but under other circumstances it is not, so
+ /// providing it when it is not needed would also be wasteful.
+ ///
+ /// Other things are never the side effect of searching, therefore the
+ /// caller can get them explicitly (the updater, journal reader and
+ /// iterator).
+ /// \return A FindResult describing the data source and zone with the
+ /// longest match against the zone parameter.
+ virtual FindResult find(const dns::Name& zone,
+ bool want_exact_match = false,
+ bool want_finder = true) const = 0;
+};
+
+/// \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 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 ClientList,
+/// only the creation is expected to be direct.
+///
+/// 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 {
+ public:
+ ConfigurationError(const char* file, size_t line, const char* what) :
+ Exception(file, line, what)
+ {}
+ };
+
+ /// \brief Sets the 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.
+ ///
+ /// \param configuration The JSON element describing the configuration to
+ /// use.
+ /// \param allow_cache If it is true, the 'cache' option of the
+ /// 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
+ /// client.
+ /// \throw ConfigurationError if the configuration is invalid in some
+ /// sense.
+ void configure(const data::Element& configuration, bool allow_cache);
+
+ /// \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 client and corresponding information.
+ ///
+ /// \todo The content yet to be defined.
+ struct DataSourceInfo {
+ /// \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_;
+ };
+
+ /// \brief The collection of data sources.
+ typedef std::vector<DataSourceInfo> DataSources;
+protected:
+ /// \brief The data sources held here.
+ ///
+ /// All our data sources are stored here. It is protected to let the
+ /// 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.
+ ///
+ /// \see getDataSource
+ typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
+ DataSourcePair;
+
+ /// \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 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 client and the container.
+ /// The container might be NULL in the derived class, it is
+ /// 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 client is deleted when
+ /// needed.
+ virtual DataSourcePair getDataSourceClient(const std::string& type,
+ const data::ConstElementPtr&
+ configuration);
+public:
+ /// \brief Access to the data source clients.
+ ///
+ /// 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
+} // namespace isc
+
+#endif // DATASRC_CONTAINER_H
diff --git a/src/lib/datasrc/list.cc b/src/lib/datasrc/list.cc
deleted file mode 100644
index acfaf96..0000000
--- a/src/lib/datasrc/list.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include "list.h"
-#include "client.h"
-#include "factory.h"
-
-#include <memory>
-#include <boost/foreach.hpp>
-
-using namespace isc::data;
-using namespace std;
-
-namespace isc {
-namespace datasrc {
-
-void
-ConfigurableClientList::configure(const Element& config, bool) {
- // TODO: Implement the 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 {
- vector<DataSourceInfo> new_data_sources;
- for (; i < config.size(); ++i) {
- // Extract the parameters
- const ConstElementPtr dconf(config.get(i));
- const ConstElementPtr typeElem(dconf->get("type"));
- if (typeElem == ConstElementPtr()) {
- isc_throw(ConfigurationError, "Missing the type option in "
- "data source no " << i);
- }
- const string type(typeElem->stringValue());
- ConstElementPtr paramConf(dconf->get("params"));
- if (paramConf == ConstElementPtr()) {
- paramConf.reset(new NullElement());
- }
- // TODO: Special-case the master files type.
- // Ask the factory to create the data source for us
- const DataSourcePair ds(this->getDataSourceClient(type,
- paramConf));
- // And put it into the vector
- 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
- // the scope.
- data_sources_.swap(new_data_sources);
- } catch (const TypeError& te) {
- isc_throw(ConfigurationError, "Malformed configuration at data source "
- "no. " << i << ": " << te.what());
- }
-}
-
-ClientList::FindResult
-ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
- bool) const
-{
- // Nothing found yet.
- //
- // 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() const {
- // 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
- // 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));
- switch (result.code) {
- case result::SUCCESS: {
- // If we found an exact match, we have no hope to getting
- // a better one. Stop right here.
-
- // 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,
- name.getLabelCount(), true));
- }
- case result::PARTIALMATCH: {
- if (!want_exact_match) {
- // In case we have a partial match, check if it is better
- // than what we have. If so, replace it.
- const uint8_t labels(
- result.zone_finder->getOrigin().getLabelCount());
- if (labels > candidate.matched_labels) {
- // This one is strictly better. Replace it.
- candidate.datasrc_client = info.data_src_client_;
- candidate.finder = result.zone_finder;
- candidate.matched_labels = labels;
- }
- }
- break;
- }
- default: {
- // Nothing found, nothing to do.
- ;
- }
- }
- }
-
- // TODO: In case we have only the datasource and not the finder
- // and the need_updater parameter is true, get the zone there.
-
- // Return the partial match we have. In case we didn't want a partial
- // match, this surely contains the original empty result.
- 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.
-ConfigurableClientList::DataSourcePair
-ConfigurableClientList::getDataSourceClient(const string& type,
- const ConstElementPtr&
- configuration)
-{
- DataSourceClientContainerPtr
- container(new DataSourceClientContainer(type, configuration));
- return (DataSourcePair(&container->getInstance(), container));
-}
-
-}
-}
diff --git a/src/lib/datasrc/list.h b/src/lib/datasrc/list.h
deleted file mode 100644
index 0033d71..0000000
--- a/src/lib/datasrc/list.h
+++ /dev/null
@@ -1,297 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#ifndef DATASRC_CONTAINER_H
-#define DATASRC_CONTAINER_H
-
-#include <dns/name.h>
-#include <cc/data.h>
-#include <exceptions/exceptions.h>
-
-#include <vector>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-
-namespace isc {
-namespace datasrc {
-
-class ZoneFinder;
-typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
-class DataSourceClient;
-typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
-class DataSourceClientContainer;
-typedef boost::shared_ptr<DataSourceClientContainer>
- DataSourceClientContainerPtr;
-
-/// \brief The list of data source clients.
-///
-/// 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 ConfigurableClientList.
-class ClientList : public boost::noncopyable {
-protected:
- /// \brief Constructor.
- ///
- /// It is protected to prevent accidental creation of the abstract base
- /// class.
- ClientList() {}
-public:
- /// \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 FindResult {
- /// \brief Constructor.
- ///
- /// It simply fills in the member variables according to the
- /// parameters. See the member descriptions for their meaning.
- 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)
- { }
-
- /// \brief Negative answer constructor.
- ///
- /// This conscructs a result for negative answer. Both pointers are
- /// NULL, matched_labels_ is 0 and exact_match_ is false.
- FindResult() :
- dsrc_client_(NULL),
- matched_labels_(0),
- exact_match_(false)
- { }
-
- /// \brief Comparison operator.
- ///
- /// It is needed for tests and it might be of some use elsewhere
- /// too.
- 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 client.
- ///
- /// The client of the data source containing the best matching zone.
- /// If no such data source exists, this is NULL pointer.
- ///
- /// 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 find options.
- ///
- /// \see find
- const ZoneFinderPtr finder_;
-
- /// \brief Number of matching labels.
- ///
- /// The number of labels the result have in common with the queried
- /// name of zone.
- const uint8_t matched_labels_;
-
- /// \brief If the result is an exact match.
- const bool exact_match_;
- };
-
- /// \brief Search for a zone through the data sources.
- ///
- /// 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 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,
- /// ...). In this case, the finder itself is not so important. However,
- /// 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 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 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 find might be actually faster under some
- /// circumstances.
- /// \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
- /// would be a waste), but under other circumstances it is not, so
- /// providing it when it is not needed would also be wasteful.
- ///
- /// Other things are never the side effect of searching, therefore the
- /// caller can get them explicitly (the updater, journal reader and
- /// iterator).
- /// \return A FindResult describing the data source and zone with the
- /// longest match against the zone parameter.
- virtual FindResult find(const dns::Name& zone,
- bool want_exact_match = false,
- bool want_finder = true) const = 0;
-};
-
-/// \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 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 ClientList,
-/// only the creation is expected to be direct.
-///
-/// 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 {
- public:
- ConfigurationError(const char* file, size_t line, const char* what) :
- Exception(file, line, what)
- { }
- };
-
- /// \brief Sets the 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.
- ///
- /// \param configuration The JSON element describing the configuration to
- /// use.
- /// \param allow_cache If it is true, the 'cache' option of the
- /// 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
- /// client.
- /// \throw ConfigurationError if the configuration is invalid in some
- /// sense.
- void configure(const data::Element& configuration, bool allow_cache);
-
- /// \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 client and corresponding information.
- ///
- /// \todo The content yet to be defined.
- struct DataSourceInfo {
- /// \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_;
- };
-
- /// \brief The collection of data sources.
- typedef std::vector<DataSourceInfo> DataSources;
-protected:
- /// \brief The data sources held here.
- ///
- /// All our data sources are stored here. It is protected to let the
- /// 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.
- ///
- /// \see getDataSource
- typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
- DataSourcePair;
-
- /// \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 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 client and the container.
- /// The container might be NULL in the derived class, it is
- /// 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 client is deleted when
- /// needed.
- virtual DataSourcePair getDataSourceClient(const std::string& type,
- const data::ConstElementPtr&
- configuration);
-public:
- /// \brief Access to the data source clients.
- ///
- /// 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
-} // namespace isc
-
-#endif // DATASRC_CONTAINER_H
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index ce38714..01a6045 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/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 += list_unittest.cc
+run_unittests_SOURCES += client_list_unittest.cc
# We need the actual module implementation in the tests (they are not part
# of libdatasrc)
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
new file mode 100644
index 0000000..4fed961
--- /dev/null
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -0,0 +1,475 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/client_list.h>
+#include <datasrc/client.h>
+#include <datasrc/data_source.h>
+
+#include <dns/rrclass.h>
+
+#include <gtest/gtest.h>
+
+#include <set>
+
+using namespace isc::datasrc;
+using namespace isc::data;
+using namespace isc::dns;
+using namespace boost;
+using namespace std;
+
+namespace {
+
+// A test data source. It pretends it has some zones.
+class MockDataSourceClient : public DataSourceClient {
+public:
+ class Finder : public ZoneFinder {
+ public:
+ Finder(const Name& origin) :
+ origin_(origin)
+ {}
+ 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");
+ }
+ shared_ptr<Context> find(const Name&, const RRType&,
+ const FindOptions)
+ {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ shared_ptr<Context> findAll(const Name&,
+ vector<ConstRRsetPtr>&,
+ const FindOptions)
+ {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ FindNSEC3Result findNSEC3(const Name&, bool) {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ Name findPreviousName(const Name&) const {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ private:
+ Name origin_;
+ };
+ // Constructor from a list of zones.
+ 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.
+ MockDataSourceClient(const string& type,
+ const ConstElementPtr& configuration) :
+ type_(type),
+ configuration_(configuration)
+ {}
+ virtual FindResult findZone(const Name& name) const {
+ if (zones.empty()) {
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+ }
+ set<Name>::const_iterator it(zones.upper_bound(name));
+ if (it == zones.begin()) {
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+ }
+ --it;
+ NameComparisonResult compar(it->compare(name));
+ const ZoneFinderPtr finder(new Finder(*it));
+ switch (compar.getRelation()) {
+ case NameComparisonResult::EQUAL:
+ return (FindResult(result::SUCCESS, finder));
+ case NameComparisonResult::SUPERDOMAIN:
+ return (FindResult(result::PARTIALMATCH, finder));
+ default:
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+ }
+ }
+ // These methods are not used. They just need to be there to have
+ // complete vtable.
+ virtual ZoneUpdaterPtr getUpdater(const Name&, bool, bool) const {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ virtual pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
+ getJournalReader(const Name&, uint32_t, uint32_t) const
+ {
+ isc_throw(isc::NotImplemented, "Not implemented");
+ }
+ const string type_;
+ const ConstElementPtr configuration_;
+private:
+ set<Name> zones;
+};
+
+
+// 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 TestedList : public ConfigurableClientList {
+public:
+ 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 getDataSourceClient(const string& type,
+ const ConstElementPtr&
+ configuration)
+ {
+ if (type == "error") {
+ isc_throw(DataSourceError, "The error data source type");
+ }
+ 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<MockDataSourceClient> > to_delete_;
+};
+
+const char* ds_zones[][3] = {
+ {
+ "example.org.",
+ "example.com.",
+ NULL
+ },
+ {
+ "sub.example.org.",
+ NULL, NULL
+ },
+ {
+ NULL, NULL, NULL
+ },
+ {
+ "sub.example.org.",
+ NULL, NULL
+ }
+};
+
+const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
+
+class ListTest : public ::testing::Test {
+public:
+ ListTest() :
+ // The empty list corresponds to a list with no elements inside
+ list_(new TestedList()),
+ config_elem_(Element::fromJSON("["
+ "{"
+ " \"type\": \"test_type\","
+ " \"cache\": \"off\","
+ " \"params\": {}"
+ "}]"))
+ {
+ for (size_t i(0); i < ds_count; ++ i) {
+ shared_ptr<MockDataSourceClient>
+ ds(new MockDataSourceClient(ds_zones[i]));
+ ds_.push_back(ds);
+ ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
+ DataSourceClientContainerPtr()));
+ }
+ }
+ // 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)
+ {
+ 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_);
+ }
+ // 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) {
+ list_->getDataSources().clear();
+ switch (index) {
+ case 2:
+ 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:
+ list_->getDataSources().push_back(ds_info_[0]);
+ list_->getDataSources().push_back(ds_info_[1]);
+ break;
+ case 1:
+ // The other order
+ list_->getDataSources().push_back(ds_info_[1]);
+ list_->getDataSources().push_back(ds_info_[0]);
+ break;
+ case 3:
+ 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.
+ list_->getDataSources().push_back(ds_info_[3]);
+ break;
+ default:
+ FAIL() << "Unknown configuration index " << index;
+ }
+ }
+ void checkDS(size_t index, const string& type, const string& params) const
+ {
+ ASSERT_GT(list_->getDataSources().size(), index);
+ MockDataSourceClient* ds(dynamic_cast<MockDataSourceClient*>(
+ list_->getDataSources()[index].data_src_client_));
+
+ // Comparing with NULL does not work
+ ASSERT_NE(ds, static_cast<const MockDataSourceClient*>(NULL));
+ EXPECT_EQ(type, ds->type_);
+ EXPECT_TRUE(Element::fromJSON(params)->equals(*ds->configuration_));
+ }
+ 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(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 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 find on an empty list. It should be
+// a negative answer (nothing found) no matter if we want an exact or inexact
+// match.
+TEST_F(ListTest, emptySearch) {
+ // 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_ == 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 list and check it can find an
+// exact match if there's one.
+TEST_F(ListTest, singleDSExactMatch) {
+ list_->getDataSources().push_back(ds_info_[0]);
+ // This zone is not there
+ EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
+ // But this one is, so check it.
+ 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_ == list_->find(Name("sub.example.org."),
+ true));
+}
+
+// When asking for a partial match, we get all that the exact one, but more.
+TEST_F(ListTest, singleDSBestMatch) {
+ list_->getDataSources().push_back(ds_info_[0]);
+ // This zone is not there
+ EXPECT_TRUE(negativeResult_ == list_->find(Name("org.")));
+ // But this one is, so check it.
+ 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[] = {
+ "Sub second",
+ "Sub first",
+ "With empty",
+ "With a duplicity"
+};
+
+TEST_F(ListTest, multiExactMatch) {
+ // Run through all the multi-configurations
+ for (size_t i(0); i < sizeof(test_names) / sizeof(*test_names); ++i) {
+ SCOPED_TRACE(test_names[i]);
+ multiConfiguration(i);
+ // Something that is nowhere there
+ EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
+ // This one is there exactly.
+ 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(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_ ==
+ list_->find(Name("sub.example.com."), true));
+ }
+}
+
+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_ == list_->find(Name("org.")));
+ // This one is there exactly.
+ positiveResult(list_->find(Name("example.org")), ds_[0],
+ Name("example.org"), true, "Exact match");
+ // This one too, but in a different data source.
+ 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(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(ListTest, configureEmpty) {
+ 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("["
+ "{"
+ " \"type\": \"type1\","
+ " \"cache\": \"off\","
+ " \"params\": {}"
+ "},"
+ "{"
+ " \"type\": \"type2\","
+ " \"cache\": \"off\","
+ " \"params\": {}"
+ "}]"
+ ));
+ 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(ListTest, configureParams) {
+ const char* params[] = {
+ "true",
+ "false",
+ "null",
+ "\"hello\"",
+ "42",
+ "[]",
+ "{}",
+ NULL
+ };
+ for (const char** param(params); *param; ++param) {
+ SCOPED_TRACE(*param);
+ ConstElementPtr elem(Element::fromJSON(string("["
+ "{"
+ " \"type\": \"t\","
+ " \"cache\": \"off\","
+ " \"params\": ") + *param +
+ "}]"));
+ list_->configure(*elem, true);
+ EXPECT_EQ(1, list_->getDataSources().size());
+ checkDS(0, "t", *param);
+ }
+}
+
+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",
+ "[{\"type\": \"test_type\", \"params\": 13}, true]",
+ "[{\"type\": \"test_type\", \"params\": 13}, []]",
+ "[{\"type\": \"test_type\", \"params\": 13}, 42]",
+ // Bad type of 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
+ 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(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(ListTest, defaults) {
+ ConstElementPtr elem(Element::fromJSON("["
+ "{"
+ " \"type\": \"type1\""
+ "}]"));
+ 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(ListTest, reconfigure) {
+ ConstElementPtr empty(new ListElement);
+ list_->configure(*config_elem_, true);
+ checkDS(0, "test_type", "{}");
+ 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(ListTest, dataSrcError) {
+ ConstElementPtr elem(Element::fromJSON("["
+ "{"
+ " \"type\": \"error\""
+ "}]"));
+ list_->configure(*config_elem_, true);
+ checkDS(0, "test_type", "{}");
+ EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
+ checkDS(0, "test_type", "{}");
+}
+
+}
diff --git a/src/lib/datasrc/tests/list_unittest.cc b/src/lib/datasrc/tests/list_unittest.cc
deleted file mode 100644
index ca07d67..0000000
--- a/src/lib/datasrc/tests/list_unittest.cc
+++ /dev/null
@@ -1,476 +0,0 @@
-// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-#include <datasrc/list.h>
-#include <datasrc/client.h>
-#include <datasrc/data_source.h>
-
-#include <dns/rrclass.h>
-
-#include <gtest/gtest.h>
-
-#include <set>
-
-using namespace isc::datasrc;
-using namespace isc::data;
-using namespace isc::dns;
-using namespace boost;
-using namespace std;
-
-namespace {
-
-// A test data source. It pretends it has some zones.
-class MockDataSourceClient : public DataSourceClient {
-public:
- class Finder : public ZoneFinder {
- public:
- Finder(const Name& origin) :
- origin_(origin)
- { }
- 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");
- }
- shared_ptr<Context> find(const Name&, const RRType&,
- const FindOptions)
- {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- shared_ptr<Context> findAll(const Name&,
- vector<ConstRRsetPtr>&,
- const FindOptions)
- {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- FindNSEC3Result findNSEC3(const Name&, bool) {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- Name findPreviousName(const Name&) const {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- private:
- Name origin_;
- };
- // Constructor from a list of zones.
- 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.
- MockDataSourceClient(const string& type,
- const ConstElementPtr& configuration) :
- type_(type),
- configuration_(configuration)
- { }
- virtual FindResult findZone(const Name& name) const {
- if (zones.empty()) {
- return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
- }
- set<Name>::const_iterator it(zones.upper_bound(name));
- if (it == zones.begin()) {
- return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
- }
- --it;
- NameComparisonResult compar(it->compare(name));
- const ZoneFinderPtr finder(new Finder(*it));
- switch (compar.getRelation()) {
- case NameComparisonResult::EQUAL:
- return (FindResult(result::SUCCESS, finder));
- case NameComparisonResult::SUPERDOMAIN:
- return (FindResult(result::PARTIALMATCH, finder));
- default:
- return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
- }
- }
- // These methods are not used. They just need to be there to have
- // complete vtable.
- virtual ZoneUpdaterPtr getUpdater(const Name&, bool, bool) const {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- virtual pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
- getJournalReader(const Name&, uint32_t, uint32_t) const
- {
- isc_throw(isc::NotImplemented, "Not implemented");
- }
- const string type_;
- const ConstElementPtr configuration_;
-private:
- set<Name> zones;
-};
-
-
-// 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 TestedList : public ConfigurableClientList {
-public:
- 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 getDataSourceClient(const string& type,
- const ConstElementPtr&
- configuration)
- {
- if (type == "error") {
- isc_throw(DataSourceError, "The error data source type");
- }
- 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<MockDataSourceClient> > to_delete_;
-};
-
-const char* ds_zones[][3] = {
- {
- "example.org.",
- "example.com.",
- NULL
- },
- {
- "sub.example.org.",
- NULL, NULL
- },
- {
- NULL, NULL, NULL
- },
- {
- "sub.example.org.",
- NULL, NULL
- }
-};
-
-const size_t ds_count = (sizeof(ds_zones) / sizeof(*ds_zones));
-
-class ListTest : public ::testing::Test {
-public:
- ListTest() :
- // The empty list corresponds to a list with no elements inside
- list_(new TestedList()),
- config_elem_(Element::fromJSON("["
- "{"
- " \"type\": \"test_type\","
- " \"cache\": \"off\","
- " \"params\": {}"
- "}]"))
- {
- for (size_t i(0); i < ds_count; ++ i) {
- shared_ptr<MockDataSourceClient>
- ds(new MockDataSourceClient(ds_zones[i]));
- ds_.push_back(ds);
- ds_info_.push_back(ConfigurableClientList::DataSourceInfo(ds.get(),
- DataSourceClientContainerPtr()));
- }
- }
- // 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)
- {
- SCOPED_TRACE(test);
- 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 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) {
- list_->getDataSources().clear();
- switch (index) {
- case 2:
- 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:
- list_->getDataSources().push_back(ds_info_[0]);
- list_->getDataSources().push_back(ds_info_[1]);
- break;
- case 1:
- // The other order
- list_->getDataSources().push_back(ds_info_[1]);
- list_->getDataSources().push_back(ds_info_[0]);
- break;
- case 3:
- 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.
- list_->getDataSources().push_back(ds_info_[3]);
- break;
- default:
- FAIL() << "Unknown configuration index " << index;
- }
- }
- void checkDS(size_t index, const string& type, const string& params) const
- {
- ASSERT_GT(list_->getDataSources().size(), index);
- MockDataSourceClient* ds(dynamic_cast<MockDataSourceClient*>(
- list_->getDataSources()[index].data_src_client_));
-
- // Comparing with NULL does not work
- ASSERT_NE(ds, static_cast<const MockDataSourceClient*>(NULL));
- EXPECT_EQ(type, ds->type_);
- EXPECT_TRUE(Element::fromJSON(params)->equals(*ds->configuration_));
- }
- 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(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 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 find on an empty list. It should be
-// a negative answer (nothing found) no matter if we want an exact or inexact
-// match.
-TEST_F(ListTest, emptySearch) {
- // 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_ == 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 list and check it can find an
-// exact match if there's one.
-TEST_F(ListTest, singleDSExactMatch) {
- list_->getDataSources().push_back(ds_info_[0]);
- // This zone is not there
- EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
- // But this one is, so check it.
- 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_ == list_->find(Name("sub.example.org."),
- true));
-}
-
-// When asking for a partial match, we get all that the exact one, but more.
-TEST_F(ListTest, singleDSBestMatch) {
- list_->getDataSources().push_back(ds_info_[0]);
- // This zone is not there
- EXPECT_TRUE(negativeResult_ == list_->find(Name("org.")));
- // But this one is, so check it.
- 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[] = {
- "Sub second",
- "Sub first",
- "With empty",
- "With a duplicity"
-};
-
-TEST_F(ListTest, multiExactMatch) {
- // Run through all the multi-configurations
- for (size_t i(0); i < sizeof(test_names) / sizeof(*test_names); ++i) {
- SCOPED_TRACE(test_names[i]);
- multiConfiguration(i);
- // Something that is nowhere there
- EXPECT_TRUE(negativeResult_ == list_->find(Name("org."), true));
- // This one is there exactly.
- 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(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_ ==
- list_->find(Name("sub.example.com."), true));
- }
-}
-
-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_ == list_->find(Name("org.")));
- // This one is there exactly.
- positiveResult(list_->find(Name("example.org")), ds_[0],
- Name("example.org"), true, "Exact match");
- // This one too, but in a different data source.
- 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(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(ListTest, configureEmpty) {
- 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("["
- "{"
- " \"type\": \"type1\","
- " \"cache\": \"off\","
- " \"params\": {}"
- "},"
- "{"
- " \"type\": \"type2\","
- " \"cache\": \"off\","
- " \"params\": {}"
- "}]"
- ));
- 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(ListTest, configureParams) {
- const char* params[] = {
- "true",
- "false",
- "null",
- "\"hello\"",
- "42",
- "[]",
- "{}",
- NULL
- };
- for (const char** param(params); *param; ++param) {
- SCOPED_TRACE(*param);
- ConstElementPtr elem(Element::fromJSON(string("["
- "{"
- " \"type\": \"t\","
- " \"cache\": \"off\","
- " \"params\": ") + *param +
- "}]"));
- list_->configure(*elem, true);
- EXPECT_EQ(1, list_->getDataSources().size());
- checkDS(0, "t", *param);
- }
-}
-
-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",
- "[{\"type\": \"test_type\", \"params\": 13}, true]",
- "[{\"type\": \"test_type\", \"params\": 13}, []]",
- "[{\"type\": \"test_type\", \"params\": 13}, 42]",
- // Bad type of 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
- 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(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(ListTest, defaults) {
- ConstElementPtr elem(Element::fromJSON("["
- "{"
- " \"type\": \"type1\""
- "}]"));
- 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(ListTest, reconfigure) {
- ConstElementPtr empty(new ListElement);
- list_->configure(*config_elem_, true);
- checkDS(0, "test_type", "{}");
- 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(ListTest, dataSrcError) {
- ConstElementPtr elem(Element::fromJSON("["
- "{"
- " \"type\": \"error\""
- "}]"));
- list_->configure(*config_elem_, true);
- checkDS(0, "test_type", "{}");
- EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
- checkDS(0, "test_type", "{}");
-}
-
-}
More information about the bind10-changes
mailing list