BIND 10 master, updated. a251c4f239e7b42856314412142cd9777f91dbf1 Merge remote-tracking branch 'origin/trac925'
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue May 17 11:28:03 UTC 2011
The branch, master has been updated
via a251c4f239e7b42856314412142cd9777f91dbf1 (commit)
via 2360fc72c24eb39d32b0afd6a389cfe8f10cb2f9 (commit)
via bc0688b0e7846ec9bb38e4e014ed23be84876948 (commit)
via b8a7bf58c974c9ba4518fd894963cd66a19baf7e (commit)
via 3a54f64afc94e9394a527872b957609d14002ff1 (commit)
via 62168918aceee04418765089cdc5fdfb34bf66a3 (commit)
via 929a9cae2b351e67ac1953514a63b0c54095361c (commit)
via 04ea273e2988cc405ae3ee7555a0f028258c17a5 (commit)
via 5b495e880e559c413a80d0dcc741a5076f3f7eb4 (commit)
via 94d43a69237b5d2bf671e384ff8b2b9a5ce445b4 (commit)
via c3e1e45419104bdb01dd385b22eae85bb8799611 (commit)
via 946b527467c19236814cae6e35191ce19db3284a (commit)
via 02e2f3a3c2ae669824d595bc9b42f37d9624b22c (commit)
via 54210ba456b4e0822c5e333fd1f996bb35c6bee9 (commit)
from fc9c42d22de8c2c5555573a1a3e29b2d30146a29 (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 a251c4f239e7b42856314412142cd9777f91dbf1
Merge: 2360fc72c24eb39d32b0afd6a389cfe8f10cb2f9 62168918aceee04418765089cdc5fdfb34bf66a3
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue May 17 12:53:51 2011 +0200
Merge remote-tracking branch 'origin/trac925'
Conflicts:
configure.ac
commit 2360fc72c24eb39d32b0afd6a389cfe8f10cb2f9
Merge: fc9c42d22de8c2c5555573a1a3e29b2d30146a29 bc0688b0e7846ec9bb38e4e014ed23be84876948
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Tue May 17 12:41:13 2011 +0200
Merge remote-tracking branch 'origin/trac922'
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 1 +
src/lib/config/ccsession.cc | 51 +++++++-
src/lib/config/ccsession.h | 41 +++++--
src/lib/config/tests/ccsession_unittests.cc | 97 ++++++++++++++
src/lib/server_common/Makefile.am | 3 +
src/lib/server_common/keyring.cc | 61 +++++++++
src/lib/server_common/keyring.h | 96 ++++++++++++++
src/lib/server_common/tests/Makefile.am | 4 +
.../tests/data_path.h.in} | 13 +--
src/lib/server_common/tests/keyring_test.cc | 132 ++++++++++++++++++++
src/lib/server_common/tests/testdata/spec.spec | 6 +
11 files changed, 481 insertions(+), 24 deletions(-)
create mode 100644 src/lib/server_common/keyring.cc
create mode 100644 src/lib/server_common/keyring.h
copy src/lib/{datasrc/logger.cc => server_common/tests/data_path.h.in} (87%)
create mode 100644 src/lib/server_common/tests/keyring_test.cc
create mode 100644 src/lib/server_common/tests/testdata/spec.spec
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index c95396a..d478924 100644
--- a/configure.ac
+++ b/configure.ac
@@ -843,6 +843,7 @@ AC_OUTPUT([doc/version.ent
src/lib/cc/tests/session_unittests_config.h
src/lib/log/tests/run_time_init_test.sh
src/lib/util/python/mkpywrapper.py
+ src/lib/server_common/tests/data_path.h
tests/system/conf.sh
tests/system/glue/setup.sh
tests/system/glue/nsx1/b10-config.db
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index 1b5e47d..45710e3 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -356,11 +356,40 @@ ModuleCCSession::checkCommand() {
}
std::string
-ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
- ModuleSpec rmod_spec = readModuleSpecification(spec_file_name);
- std::string module_name = rmod_spec.getFullSpec()->get("module_name")->stringValue();
+ModuleCCSession::addRemoteConfig(const std::string& spec_name,
+ void (*handler)(const std::string& module,
+ ConstElementPtr),
+ bool spec_is_filename)
+{
+ std::string module_name;
+ ModuleSpec rmod_spec;
+ if (spec_is_filename) {
+ // It's a file name, so load it
+ rmod_spec = readModuleSpecification(spec_name);
+ module_name =
+ rmod_spec.getFullSpec()->get("module_name")->stringValue();
+ } else {
+ // It's module name, request it from config manager
+ ConstElementPtr cmd = Element::fromJSON("{ \"command\": ["
+ "\"get_module_spec\","
+ "{\"module_name\": \"" +
+ module_name + "\"} ] }");
+ unsigned int seq = session_.group_sendmsg(cmd, "ConfigManager");
+ ConstElementPtr env, answer;
+ session_.group_recvmsg(env, answer, false, seq);
+ int rcode;
+ ConstElementPtr spec_data = parseAnswer(rcode, answer);
+ if (rcode == 0 && spec_data) {
+ rmod_spec = ModuleSpec(spec_data);
+ module_name = spec_name;
+ if (module_name != rmod_spec.getModuleName()) {
+ isc_throw(CCSessionError, "Module name mismatch");
+ }
+ } else {
+ isc_throw(CCSessionError, "Error getting config for " + module_name + ": " + answer->str());
+ }
+ }
ConfigData rmod_config = ConfigData(rmod_spec);
- session_.subscribe(module_name);
// Get the current configuration values for that module
ConstElementPtr cmd = Element::fromJSON("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name + "\"} ] }");
@@ -370,8 +399,9 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
session_.group_recvmsg(env, answer, false, seq);
int rcode;
ConstElementPtr new_config = parseAnswer(rcode, answer);
+ ElementPtr local_config;
if (rcode == 0 && new_config) {
- ElementPtr local_config = rmod_config.getLocalConfig();
+ local_config = rmod_config.getLocalConfig();
isc::data::merge(local_config, new_config);
rmod_config.setLocalConfig(local_config);
} else {
@@ -380,6 +410,11 @@ ModuleCCSession::addRemoteConfig(const std::string& spec_file_name) {
// all ok, add it
remote_module_configs_[module_name] = rmod_config;
+ if (handler) {
+ remote_module_handlers_[module_name] = handler;
+ handler(module_name, local_config);
+ }
+ session_.subscribe(module_name);
return (module_name);
}
@@ -390,6 +425,7 @@ ModuleCCSession::removeRemoteConfig(const std::string& module_name) {
it = remote_module_configs_.find(module_name);
if (it != remote_module_configs_.end()) {
remote_module_configs_.erase(it);
+ remote_module_handlers_.erase(module_name);
session_.unsubscribe(module_name);
}
}
@@ -419,6 +455,11 @@ ModuleCCSession::updateRemoteConfig(const std::string& module_name,
if (it != remote_module_configs_.end()) {
ElementPtr rconf = (*it).second.getLocalConfig();
isc::data::merge(rconf, new_config);
+ std::map<std::string, RemoteHandler>::iterator hit =
+ remote_module_handlers_.find(module_name);
+ if (hit != remote_module_handlers_.end()) {
+ hit->second(module_name, new_config);
+ }
}
}
diff --git a/src/lib/config/ccsession.h b/src/lib/config/ccsession.h
index 7364876..c845b8f 100644
--- a/src/lib/config/ccsession.h
+++ b/src/lib/config/ccsession.h
@@ -234,24 +234,43 @@ public:
/**
* Gives access to the configuration values of a different module
* Once this function has been called with the name of the specification
- * file of the module you want the configuration of, you can use
+ * file or the module you want the configuration of, you can use
* \c getRemoteConfigValue() to get a specific setting.
- * Changes are automatically updated, but you cannot specify handlers
- * for those changes, must use \c getRemoteConfigValue() to get a value
- * This function will subscribe to the relevant module channel.
+ * Changes are automatically updated, and you can specify handlers
+ * for those changes. This function will subscribe to the relevant module
+ * channel.
*
- * \param spec_file_name The path to the specification file of
- * the module we want to have configuration
- * values from
+ * \param spec_name This specifies the module to add. It is either a
+ * filename of the spec file to use or a name of module
+ * (in case it's a module name, the spec data is
+ * downloaded from the configuration manager, therefore
+ * the configuration manager must know it). If
+ * spec_is_filenabe is true (the default), then a
+ * filename is assumed, otherwise a module name.
+ * \param handler The handler function called whenever there's a change.
+ * Called once initally from this function. May be NULL
+ * if you don't want any handler to be called and you're
+ * fine with requesting the data through
+ * getRemoteConfigValue() each time.
+ *
+ * The handler should not throw, or it'll fall trough and
+ * the exception will get into strange places, probably
+ * aborting the application.
+ * \param spec_is_filename Says if spec_name is filename or module name.
* \return The name of the module specified in the given specification
* file
*/
- std::string addRemoteConfig(const std::string& spec_file_name);
+ std::string addRemoteConfig(const std::string& spec_name,
+ void (*handler)(const std::string& module_name,
+ isc::data::ConstElementPtr
+ update) = NULL,
+ bool spec_is_filename = true);
/**
* Removes the module with the given name from the remote config
* settings. If the module was not added with \c addRemoteConfig(),
- * nothing happens.
+ * nothing happens. If there was a handler for this config, it is
+ * removed as well.
*/
void removeRemoteConfig(const std::string& module_name);
@@ -296,7 +315,11 @@ private:
const std::string& command,
isc::data::ConstElementPtr args);
+ typedef void (*RemoteHandler)(const std::string&,
+ isc::data::ConstElementPtr);
std::map<std::string, ConfigData> remote_module_configs_;
+ std::map<std::string, RemoteHandler> remote_module_handlers_;
+
void updateRemoteConfig(const std::string& module_name,
isc::data::ConstElementPtr new_config);
};
diff --git a/src/lib/config/tests/ccsession_unittests.cc b/src/lib/config/tests/ccsession_unittests.cc
index f566949..3564d4b 100644
--- a/src/lib/config/tests/ccsession_unittests.cc
+++ b/src/lib/config/tests/ccsession_unittests.cc
@@ -346,6 +346,18 @@ TEST_F(CCSessionTest, checkCommand2) {
EXPECT_EQ(2, mccs.getValue("item1")->intValue());
}
+std::string remote_module_name;
+int remote_item1(0);
+ConstElementPtr remote_config;
+ModuleCCSession *remote_mccs(NULL);
+
+void remoteHandler(const std::string& module_name, ConstElementPtr config) {
+ remote_module_name = module_name;
+ remote_item1 = remote_mccs->getRemoteConfigValue("Spec2", "item1")->
+ intValue();
+ remote_config = config;
+}
+
TEST_F(CCSessionTest, remoteConfig) {
std::string module_name;
int item1;
@@ -392,6 +404,91 @@ TEST_F(CCSessionTest, remoteConfig) {
session.getMessages()->add(createAnswer());
EXPECT_THROW(mccs.addRemoteConfig(ccspecfile("spec2.spec")), CCSessionError);
+
+ {
+ SCOPED_TRACE("With module name");
+ // Try adding it with downloading the spec from config manager
+ ModuleSpec spec(moduleSpecFromFile(ccspecfile("spec2.spec")));
+ session.getMessages()->add(createAnswer(0, spec.getFullSpec()));
+ session.getMessages()->add(createAnswer(0, el("{}")));
+
+ EXPECT_NO_THROW(module_name = mccs.addRemoteConfig("Spec2", NULL,
+ false));
+
+ EXPECT_EQ("Spec2", module_name);
+ EXPECT_NO_THROW(item1 =
+ mccs.getRemoteConfigValue(module_name,
+ "item1")->intValue());
+ EXPECT_EQ(1, item1);
+
+ mccs.removeRemoteConfig(module_name);
+ }
+
+ {
+ // Try adding it with a handler.
+ // Pass non-default value to see the handler is called after
+ // downloading the configuration, not too soon.
+ SCOPED_TRACE("With handler");
+ session.getMessages()->add(createAnswer(0, el("{ \"item1\": 2 }")));
+ remote_mccs = &mccs;
+ module_name = mccs.addRemoteConfig(ccspecfile("spec2.spec"),
+ remoteHandler);
+ {
+ SCOPED_TRACE("Before update");
+ EXPECT_EQ("Spec2", module_name);
+ EXPECT_TRUE(session.haveSubscription("Spec2", "*"));
+ // Now check the parameters the remote handler stored
+ // This also checks it was called
+ EXPECT_EQ("Spec2", remote_module_name);
+ remote_module_name = "";
+ EXPECT_EQ(2, remote_item1);
+ remote_item1 = 0;
+ if (remote_config) {
+ EXPECT_EQ(2, remote_config->get("item1")->intValue());
+ } else {
+ ADD_FAILURE() << "Remote config not set";
+ }
+ remote_config.reset();
+ // Make sure normal way still works
+ item1 = mccs.getRemoteConfigValue(module_name,
+ "item1")->intValue();
+ EXPECT_EQ(2, item1);
+ }
+
+ {
+ SCOPED_TRACE("After update");
+ session.addMessage(el("{ \"command\": [ \"config_update\", "
+ "{ \"item1\": 3 } ] }"), module_name, "*");
+ mccs.checkCommand();
+ EXPECT_EQ("Spec2", remote_module_name);
+ remote_module_name = "";
+ EXPECT_EQ(3, remote_item1);
+ remote_item1 = 0;
+ if (remote_config) {
+ EXPECT_EQ(3, remote_config->get("item1")->intValue());
+ } else {
+ ADD_FAILURE() << "Remote config not set";
+ }
+ remote_config.reset();
+ // Make sure normal way still works
+ item1 = mccs.getRemoteConfigValue(module_name,
+ "item1")->intValue();
+ EXPECT_EQ(3, item1);
+ }
+
+ remote_mccs = NULL;
+ mccs.removeRemoteConfig(module_name);
+
+ {
+ SCOPED_TRACE("When removed");
+ // Make sure nothing is called any more
+ session.addMessage(el("{ \"command\": [ \"config_update\", "
+ "{ \"item1\": 4 } ] }"), module_name, "*");
+ EXPECT_EQ("", remote_module_name);
+ EXPECT_EQ(0, remote_item1);
+ EXPECT_FALSE(remote_config);
+ }
+ }
}
TEST_F(CCSessionTest, ignoreRemoteConfigCommands) {
diff --git a/src/lib/server_common/Makefile.am b/src/lib/server_common/Makefile.am
index dfb3014..a3063ba 100644
--- a/src/lib/server_common/Makefile.am
+++ b/src/lib/server_common/Makefile.am
@@ -18,9 +18,12 @@ endif
lib_LTLIBRARIES = libserver_common.la
libserver_common_la_SOURCES = portconfig.h portconfig.cc
+libserver_common_la_SOURCES += keyring.h keyring.cc
libserver_common_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
libserver_common_la_LIBADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
libserver_common_la_LIBADD += $(top_builddir)/src/lib/cc/libcc.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/config/libcfgclient.la
libserver_common_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
+libserver_common_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/server_common/keyring.cc b/src/lib/server_common/keyring.cc
new file mode 100644
index 0000000..f68db70
--- /dev/null
+++ b/src/lib/server_common/keyring.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2011 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 <server_common/keyring.h>
+
+using namespace isc::dns;
+using namespace isc::data;
+
+namespace isc {
+namespace server_common {
+
+typedef boost::shared_ptr<TSIGKeyRing> KeyringPtr;
+
+KeyringPtr keyring;
+
+namespace {
+
+void
+updateKeyring(const std::string&, ConstElementPtr data) {
+ ConstElementPtr list(data->get("keys"));
+ KeyringPtr load(new TSIGKeyRing);
+ for (size_t i(0); i < list->size(); ++ i) {
+ load->add(TSIGKey(list->get(i)->stringValue()));
+ }
+ keyring.swap(load);
+}
+
+}
+
+void
+initKeyring(config::ModuleCCSession& session) {
+ if (keyring) {
+ // We are already initialized
+ return;
+ }
+ session.addRemoteConfig("tsig_keys", updateKeyring, false);
+}
+
+void
+deinitKeyring(config::ModuleCCSession& session) {
+ if (!keyring) {
+ // Not initialized, ignore it
+ return;
+ }
+ keyring.reset();
+ session.removeRemoteConfig("tsig_keys");
+}
+
+}
+}
diff --git a/src/lib/server_common/keyring.h b/src/lib/server_common/keyring.h
new file mode 100644
index 0000000..8832095
--- /dev/null
+++ b/src/lib/server_common/keyring.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2011 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 ISC_SERVER_COMMON_KEYRING_H
+#define ISC_SERVER_COMMON_KEYRING_H
+
+#include <boost/shared_ptr.hpp>
+#include <dns/tsigkey.h>
+#include <config/ccsession.h>
+
+/**
+ * \file keyring.h
+ * \brief TSIG keyring loaded from configuration.
+ *
+ * This file contains routines for loading a TSIG key ring from
+ * the tsig_keys configuration section and keeping them up to date
+ * on updates.
+ *
+ * You simply initialize/load the keyring with isc::server_common::initKeyring
+ * and then just use the key ring in in isc::server_common::keyring. It is
+ * automatically reloaded, when the configuration updates, so you no longer
+ * needs to care about it.
+ *
+ * If you want to keep a key (or session) for longer time or your application
+ * is multithreaded, you might want to have a copy of the shared pointer.
+ * Otherwise an update might replace the keyring and delete the keys in the
+ * old one.
+ */
+
+namespace isc {
+
+namespace server_common {
+
+/**
+ * \brief The key ring itself
+ *
+ * This is where the key ring is stored. You can directly use it to your needs,
+ * but you need to call initKeyring first, otherwise you'll find a NULL pointer
+ * here only.
+ */
+extern boost::shared_ptr<dns::TSIGKeyRing> keyring;
+
+/**
+ * \brief Load the key ring for the first time
+ *
+ * This loads the key ring from configuration to keyring. It also registers for
+ * config updates, so from now on, it'll be kept up to date.
+ *
+ * You can unload the key ring with deinitKeyring.
+ *
+ * If it is already loaded, this function does nothing. So, if more than one
+ * part of an application needs to use the key ring, they all can just call
+ * this independently to ensure the keyring is loaded.
+ *
+ * \param session The configuration session used to talk to the config manager.
+ */
+void
+initKeyring(config::ModuleCCSession& session);
+
+/**
+ * \brief Unload the key ring
+ *
+ * This can be used to unload the key ring. It will reset the keyring to NULL
+ * and stop receiving updates of the configuration.
+ *
+ * The need for this function should be quite rare, as it isn't required to be
+ * called before application shutdown. And not calling it has only small
+ * performance penalty -- the keyring will be kept in memory and updated when
+ * the user changes configuration.
+ *
+ * This does nothing if the key ring is not loaded currently.
+ *
+ * \param session The configuration session used to talk to the config manager.
+ *
+ * \todo What do we do when the data that come are invalid? Should we ignore it,
+ * as walidity should have been checked already in the config manager, or
+ * throw? What about when we get an update and it's invalid?
+ */
+void
+deinitKeyring(config::ModuleCCSession& session);
+
+}
+}
+
+#endif
diff --git a/src/lib/server_common/tests/Makefile.am b/src/lib/server_common/tests/Makefile.am
index a04a884..e711002 100644
--- a/src/lib/server_common/tests/Makefile.am
+++ b/src/lib/server_common/tests/Makefile.am
@@ -27,6 +27,8 @@ if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = run_unittests.cc
run_unittests_SOURCES += portconfig_unittest.cc
+run_unittests_SOURCES += keyring_test.cc
+run_unittests_SOURCES += data_path.h
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
@@ -38,6 +40,8 @@ run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.la
run_unittests_LDADD += $(top_builddir)/src/lib/asiodns/libasiodns.la
run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.la
run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/libcfgclient.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
endif
noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/server_common/tests/data_path.h.in b/src/lib/server_common/tests/data_path.h.in
new file mode 100644
index 0000000..8ac0380
--- /dev/null
+++ b/src/lib/server_common/tests/data_path.h.in
@@ -0,0 +1,16 @@
+// Copyright (C) 2011 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.
+
+#define TEST_DATA_PATH "@abs_srcdir@/testdata"
+#define PLUGIN_DATA_PATH "@top_srcdir@/src/bin/cfgmgr/plugins"
diff --git a/src/lib/server_common/tests/keyring_test.cc b/src/lib/server_common/tests/keyring_test.cc
new file mode 100644
index 0000000..6d2f226
--- /dev/null
+++ b/src/lib/server_common/tests/keyring_test.cc
@@ -0,0 +1,132 @@
+// Copyright (C) 2011 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 <server_common/keyring.h>
+#include <server_common/tests/data_path.h>
+
+#include <config/tests/fake_session.h>
+#include <config/ccsession.h>
+#include <dns/name.h>
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <string>
+
+using namespace isc::data;
+using namespace isc::config;
+using namespace isc::server_common;
+using namespace isc::dns;
+
+namespace {
+
+class KeyringTest : public ::testing::Test {
+public:
+ KeyringTest() :
+ session(ElementPtr(new ListElement), ElementPtr(new ListElement),
+ ElementPtr(new ListElement)),
+ specfile(std::string(TEST_DATA_PATH) + "/spec.spec")
+ {
+ session.getMessages()->add(createAnswer());
+ mccs.reset(new ModuleCCSession(specfile, session, NULL, NULL));
+ }
+ isc::cc::FakeSession session;
+ std::auto_ptr<ModuleCCSession> mccs;
+ std::string specfile;
+ void doInit() {
+ // Prepare the module specification for it and the config
+ session.getMessages()->
+ add(createAnswer(0,
+ moduleSpecFromFile(std::string(PLUGIN_DATA_PATH) +
+ "/tsig_keys.spec").
+ getFullSpec()));
+ session.getMessages()->add(createAnswer(0, Element::fromJSON(
+ "{\"keys\": [\"key:MTIzNAo=:hmac-sha1\"]}")));
+ // Now load it
+ EXPECT_NO_THROW(initKeyring(*mccs));
+ EXPECT_NE(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+ "No keyring even after init";
+ }
+};
+
+// Test usual use - init, using the keyring, update, deinit
+TEST_F(KeyringTest, keyring) {
+ // First, initialize it
+ {
+ SCOPED_TRACE("Init");
+ doInit();
+
+ // Make sure it contains the correct key
+ TSIGKeyRing::FindResult result(keyring->find(Name("key"),
+ TSIGKey::HMACSHA1_NAME()));
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result.code);
+ }
+
+ {
+ SCOPED_TRACE("Update");
+ session.addMessage(createCommand("config_update", Element::fromJSON(
+ "{\"keys\": [\"another:MTIzNAo=:hmac-sha256\"]}")),
+ "tsig_keys", "*");
+ mccs->checkCommand();
+
+ // Make sure it no longer contains the original key
+ TSIGKeyRing::FindResult result(keyring->find(Name("key"),
+ TSIGKey::HMACSHA1_NAME()));
+ EXPECT_EQ(TSIGKeyRing::NOTFOUND, result.code);
+ // but it does contain the new one
+ TSIGKeyRing::FindResult result2 = keyring->find(Name("another"),
+ TSIGKey::HMACSHA256_NAME());
+ EXPECT_EQ(TSIGKeyRing::SUCCESS, result2.code);
+ }
+
+ {
+ SCOPED_TRACE("Deinit");
+ deinitKeyring(*mccs);
+ EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+ "The keyring didn't disappear";
+ }
+}
+
+// Init twice
+TEST_F(KeyringTest, initTwice) {
+ // It is NULL before
+ EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+ "Someone forgot to deinit it before";
+ {
+ SCOPED_TRACE("First init");
+ doInit();
+ }
+ boost::shared_ptr<TSIGKeyRing> backup(keyring);
+ {
+ SCOPED_TRACE("Second init");
+ EXPECT_NO_THROW(initKeyring(*mccs)) <<
+ "It not only does something when it is already initialized, "
+ "it even throws at it";
+ }
+ EXPECT_EQ(backup, keyring) << "The second init replaced the data";
+ deinitKeyring(*mccs);
+}
+
+// deinit when not initialized
+TEST_F(KeyringTest, extraDeinit) {
+ // It is NULL before
+ EXPECT_EQ(boost::shared_ptr<TSIGKeyRing>(), keyring) <<
+ "Someone forgot to deinit it before";
+ // Check that it doesn't get confused when we do not have it initialized
+ EXPECT_NO_THROW(deinitKeyring(*mccs));
+ // It is still NULL
+ EXPECT_EQ(keyring, boost::shared_ptr<TSIGKeyRing>()) <<
+ "Where did it get something after deinit?";
+}
+
+}
diff --git a/src/lib/server_common/tests/testdata/spec.spec b/src/lib/server_common/tests/testdata/spec.spec
new file mode 100644
index 0000000..3e0a822
--- /dev/null
+++ b/src/lib/server_common/tests/testdata/spec.spec
@@ -0,0 +1,6 @@
+{
+ "module_spec": {
+ "module_name": "test"
+ }
+}
+
More information about the bind10-changes
mailing list