mgmt refactoring: ManagerBase
Change-Id: I0710297f352723874d05092d091128b02b3747a2
Refs: #2107
diff --git a/common.hpp b/common.hpp
index bd8f10b..9e44569 100644
--- a/common.hpp
+++ b/common.hpp
@@ -97,6 +97,7 @@
using ndn::Interest;
using ndn::Data;
using ndn::Name;
+using ndn::PartialName;
using ndn::Exclude;
using ndn::Link;
using ndn::Block;
diff --git a/core/config-file.cpp b/core/config-file.cpp
index 9724168..d989455 100644
--- a/core/config-file.cpp
+++ b/core/config-file.cpp
@@ -52,6 +52,25 @@
// do nothing
}
+bool
+ConfigFile::parseYesNo(const ConfigSection::const_iterator& i,
+ const std::string& optionName,
+ const std::string& sectionName)
+{
+ const std::string value = i->second.get_value<std::string>();
+ if (value == "yes") {
+ return true;
+ }
+
+ if (value == "no") {
+ return false;
+ }
+
+ BOOST_THROW_EXCEPTION(ConfigFile::Error("Invalid value for option \"" +
+ optionName + "\" in \"" +
+ sectionName + "\" section"));
+}
+
ConfigFile::ConfigFile(UnknownConfigSectionHandler unknownSectionCallback)
: m_unknownSectionCallback(unknownSectionCallback)
{
diff --git a/core/config-file.hpp b/core/config-file.hpp
index 9991484..ae9102e 100644
--- a/core/config-file.hpp
+++ b/core/config-file.hpp
@@ -73,6 +73,16 @@
const ConfigSection& section,
bool isDryRun);
+ /** @brief parse a config option that can be either "yes" or "no"
+ *
+ * @throw ConfigFile::Error value is neither "yes" nor "no"
+ * @return true if "yes", false if "no"
+ */
+ static bool
+ parseYesNo(const ConfigSection::const_iterator& i,
+ const std::string& optionName,
+ const std::string& sectionName);
+
/// \brief setup notification of configuration file sections
void
addSectionHandler(const std::string& sectionName,
diff --git a/daemon/mgmt/manager-base.cpp b/daemon/mgmt/manager-base.cpp
new file mode 100644
index 0000000..418c3d6
--- /dev/null
+++ b/daemon/mgmt/manager-base.cpp
@@ -0,0 +1,120 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "manager-base.hpp"
+
+namespace nfd {
+
+using ndn::mgmt::ValidateParameters;
+using ndn::mgmt::Authorization;
+
+ManagerBase::ManagerBase(Dispatcher& dispatcher,
+ CommandValidator& validator,
+ const std::string& module)
+ : m_dispatcher(dispatcher)
+ , m_validator(validator)
+ , m_mgmtModuleName(module)
+{
+ m_validator.addSupportedPrivilege(module);
+}
+
+void
+ManagerBase::registerStatusDatasetHandler(const std::string& verb,
+ const ndn::mgmt::StatusDatasetHandler& handler)
+{
+ m_dispatcher.addStatusDataset(makeRelPrefix(verb),
+ ndn::mgmt::makeAcceptAllAuthorization(),
+ handler);
+}
+
+ndn::mgmt::PostNotification
+ManagerBase::registerNotificationStream(const std::string& verb)
+{
+ return m_dispatcher.addNotificationStream(makeRelPrefix(verb));
+}
+
+void
+ManagerBase::authorize(const Name& prefix, const Interest& interest,
+ const ndn::mgmt::ControlParameters* params,
+ ndn::mgmt::AcceptContinuation accept,
+ ndn::mgmt::RejectContinuation reject)
+{
+ BOOST_ASSERT(params != nullptr);
+ BOOST_ASSERT(typeid(*params) == typeid(ndn::nfd::ControlParameters));
+
+ m_validator.validate(interest,
+ bind(&ManagerBase::extractRequester, this, interest, accept),
+ bind([&] { reject(ndn::mgmt::RejectReply::STATUS403); }));
+}
+
+void
+ManagerBase::extractRequester(const Interest& interest,
+ ndn::mgmt::AcceptContinuation accept)
+{
+ const Name& interestName = interest.getName();
+
+ try {
+ ndn::SignatureInfo sigInfo(interestName.at(ndn::signed_interest::POS_SIG_INFO).blockFromValue());
+ if (!sigInfo.hasKeyLocator() ||
+ sigInfo.getKeyLocator().getType() != ndn::KeyLocator::KeyLocator_Name) {
+ return accept("");
+ }
+
+ accept(sigInfo.getKeyLocator().getName().toUri());
+ }
+ catch (const tlv::Error&) {
+ accept("");
+ }
+}
+
+bool
+ManagerBase::validateParameters(const nfd::ControlCommand& command, const ndn::mgmt::ControlParameters& parameters)
+{
+ BOOST_ASSERT(dynamic_cast<const ControlParameters*>(¶meters) != nullptr);
+
+ try {
+ command.validateRequest(static_cast<const ControlParameters&>(parameters));
+ }
+ catch (const ControlCommand::ArgumentError&) {
+ return false;
+ }
+ return true;
+}
+
+void
+ManagerBase::handleCommand(shared_ptr<nfd::ControlCommand> command,
+ const ControlCommandHandler& handler,
+ const Name& prefix, const Interest& interest,
+ const ndn::mgmt::ControlParameters& params,
+ ndn::mgmt::CommandContinuation done)
+{
+ BOOST_ASSERT(dynamic_cast<const ControlParameters*>(¶ms) != nullptr);
+ ControlParameters parameters = static_cast<const ControlParameters&>(params);
+ command->applyDefaultsToRequest(parameters);
+ handler(*command, prefix, interest, parameters, done);
+}
+
+
+} // namespace nfd
diff --git a/daemon/mgmt/manager-base.hpp b/daemon/mgmt/manager-base.hpp
new file mode 100644
index 0000000..988fff1
--- /dev/null
+++ b/daemon/mgmt/manager-base.hpp
@@ -0,0 +1,180 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_DAEMON_MGMT_MANAGER_BASE_HPP
+#define NFD_DAEMON_MGMT_MANAGER_BASE_HPP
+
+#include "common.hpp"
+#include "mgmt/command-validator.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
+#include <ndn-cxx/management/nfd-control-command.hpp>
+#include <ndn-cxx/management/nfd-control-response.hpp>
+#include <ndn-cxx/management/nfd-control-parameters.hpp>
+
+namespace nfd {
+
+using ndn::mgmt::Dispatcher;
+
+using ndn::nfd::ControlCommand;
+using ndn::nfd::ControlResponse;
+using ndn::nfd::ControlParameters;
+
+/**
+ * @brief a collection of common functions shared by all NFD managers,
+ * such as communicating with the dispatcher and command validator.
+ */
+class ManagerBase : public noncopyable
+{
+public:
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+ }
+ };
+
+public:
+ ManagerBase(Dispatcher& dispatcher,
+ CommandValidator& validator,
+ const std::string& module);
+
+PUBLIC_WITH_TESTS_ELSE_PROTECTED: // registrations to the dispatcher
+
+ // difference from mgmt::ControlCommand: accepts nfd::ControlParameters
+ typedef function<void(const ControlCommand& command,
+ const Name& prefix, const Interest& interest,
+ const ControlParameters& parameters,
+ const ndn::mgmt::CommandContinuation done)> ControlCommandHandler;
+
+ template<typename Command>
+ void
+ registerCommandHandler(const std::string& verb,
+ const ControlCommandHandler& handler);
+
+ void
+ registerStatusDatasetHandler(const std::string& verb,
+ const ndn::mgmt::StatusDatasetHandler& handler);
+
+ ndn::mgmt::PostNotification
+ registerNotificationStream(const std::string& verb);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE: // command validation
+ /**
+ * @brief validate a request for ControlCommand.
+ *
+ * This is called by the dispatcher.
+ *
+ * @pre params != null
+ * @pre typeid(*params) == typeid(ndn::nfd::ControlParameters)
+ *
+ * @param prefix the top prefix
+ * @param interest a request for ControlCommand
+ * @param params the parameters for ControlCommand
+ * @param accept callback of successful validation, take the requester string as a argument
+ * @param reject callback of failure in validation, take the action code as a argument
+ */
+ void
+ authorize(const Name& prefix, const Interest& interest,
+ const ndn::mgmt::ControlParameters* params,
+ ndn::mgmt::AcceptContinuation accept,
+ ndn::mgmt::RejectContinuation reject);
+
+ /**
+ * @brief extract a requester from a ControlCommand request
+ *
+ * This is called after the signature is validated.
+ *
+ * @param interest a request for ControlCommand
+ * @param accept callback of successful validation, take the requester string as a argument
+ */
+ void
+ extractRequester(const Interest& interest,
+ ndn::mgmt::AcceptContinuation accept);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers
+ /**
+ * @brief validate the @p parameters for a given @p command
+ *
+ * @param parameters the original ControlParameters
+ *
+ * @return whether the original ControlParameters can be validated
+ */
+ static bool
+ validateParameters(const nfd::ControlCommand& command,
+ const ndn::mgmt::ControlParameters& parameters);
+
+ /** @brief Handle control command
+ */
+ static void
+ handleCommand(shared_ptr<nfd::ControlCommand> command,
+ const ControlCommandHandler& handler,
+ const Name& prefix, const Interest& interest,
+ const ndn::mgmt::ControlParameters& params,
+ ndn::mgmt::CommandContinuation done);
+
+ /**
+ * @brief generate the relative prefix for a handler,
+ * by appending the verb name to the module name.
+ *
+ * @param verb the verb name
+ *
+ * @return the generated relative prefix
+ */
+ PartialName
+ makeRelPrefix(const std::string& verb);
+
+private:
+ Dispatcher& m_dispatcher;
+ CommandValidator& m_validator;
+ std::string m_mgmtModuleName;
+};
+
+inline PartialName
+ManagerBase::makeRelPrefix(const std::string& verb)
+{
+ return PartialName(m_mgmtModuleName).append(verb);
+}
+
+template<typename Command>
+inline void
+ManagerBase::registerCommandHandler(const std::string& verb,
+ const ControlCommandHandler& handler)
+{
+ auto command = make_shared<Command>();
+
+ m_dispatcher.addControlCommand<ControlParameters>(
+ makeRelPrefix(verb),
+ bind(&ManagerBase::authorize, this, _1, _2, _3, _4, _5),
+ bind(&ManagerBase::validateParameters, cref(*command), _1),
+ bind(&ManagerBase::handleCommand, command, handler, _1, _2, _3, _4));
+}
+
+} // namespace nfd
+
+#endif // NFD_DAEMON_MGMT_MANAGER_BASE_HPP
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
index 66ab514..741e495 100644
--- a/daemon/nfd.cpp
+++ b/daemon/nfd.cpp
@@ -39,6 +39,9 @@
// #include "mgmt/status-server.hpp"
#include "mgmt/general-config-section.hpp"
#include "mgmt/tables-config-section.hpp"
+#include "mgmt/command-validator.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
namespace nfd {
@@ -131,6 +134,9 @@
m_internalFace = make_shared<InternalFace>();
m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
m_internalClientFace = makeInternalClientFace(m_internalFace, m_keyChain);
+ m_dispatcher.reset(new ndn::mgmt::Dispatcher(*m_internalClientFace, m_keyChain));
+
+ m_validator.reset(new CommandValidator());
// m_fibManager.reset(new FibManager(m_forwarder->getFib(),
// bind(&Forwarder::getFace, m_forwarder.get(), _1),
@@ -153,9 +159,7 @@
m_forwarder->getMeasurements());
tablesConfig.setConfigFile(config);
- // m_internalFace->getValidator().setConfigFile(config);
-
- m_forwarder->getFaceTable().addReserved(m_internalFace, FACEID_INTERNAL_FACE);
+ m_validator->setConfigFile(config);
// m_faceManager->setConfigFile(config);
@@ -172,8 +176,10 @@
tablesConfig.ensureTablesAreConfigured();
// add FIB entry for NFD Management Protocol
- shared_ptr<fib::Entry> entry = m_forwarder->getFib().insert("/localhost/nfd").first;
+ Name topPrefix("/localhost/nfd");
+ auto entry = m_forwarder->getFib().insert(topPrefix).first;
entry->addNextHop(m_internalFace, 0);
+ m_dispatcher->addTopPrefix(topPrefix, false);
}
void
@@ -196,8 +202,8 @@
tablesConfig.setConfigFile(config);
- // m_internalFace->getValidator().setConfigFile(config);
// m_faceManager->setConfigFile(config);
+ m_validator->setConfigFile(config);
if (!m_configFile.empty()) {
config.parse(m_configFile, false);
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
index 1240835..7dc7148 100644
--- a/daemon/nfd.hpp
+++ b/daemon/nfd.hpp
@@ -33,6 +33,14 @@
#include <ndn-cxx/security/key-chain.hpp>
#include <ndn-cxx/util/network-monitor.hpp>
+namespace ndn {
+namespace mgmt {
+
+class Dispatcher;
+
+}
+}
+
namespace nfd {
class Forwarder;
@@ -42,6 +50,7 @@
class StrategyChoiceManager;
class StatusServer;
class InternalClientFace;
+class CommandValidator;
/**
* \brief Class representing NFD instance
@@ -101,6 +110,9 @@
ndn::KeyChain& m_keyChain;
shared_ptr<InternalFace> m_internalFace;
shared_ptr<InternalClientFace> m_internalClientFace;
+ unique_ptr<CommandValidator> m_validator;
+
+ unique_ptr<ndn::mgmt::Dispatcher> m_dispatcher;
// unique_ptr<FibManager> m_fibManager;
// unique_ptr<FaceManager> m_faceManager;
// unique_ptr<StrategyChoiceManager> m_strategyChoiceManager;
diff --git a/tests/daemon/mgmt/manager-base.t.cpp b/tests/daemon/mgmt/manager-base.t.cpp
new file mode 100644
index 0000000..f3ea152
--- /dev/null
+++ b/tests/daemon/mgmt/manager-base.t.cpp
@@ -0,0 +1,190 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mgmt/manager-base.hpp"
+#include "manager-common-fixture.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/management/nfd-control-command.hpp>
+
+namespace nfd {
+namespace tests {
+
+NFD_LOG_INIT("ManagerBaseTest");
+
+class TestCommandVoidParameters : public ndn::nfd::ControlCommand
+{
+public:
+ TestCommandVoidParameters()
+ : ndn::nfd::ControlCommand("test-module", "test-void-parameters")
+ {
+ }
+};
+
+class TestCommandRequireName : public ndn::nfd::ControlCommand
+{
+public:
+ TestCommandRequireName()
+ : ndn::nfd::ControlCommand("test-module", "test-require-name")
+ {
+ m_requestValidator.required(ndn::nfd::CONTROL_PARAMETER_NAME);
+ }
+};
+
+class ManagerBaseFixture : public ManagerCommonFixture
+{
+public:
+ ManagerBaseFixture()
+ : m_manager(m_dispatcher, m_validator, "test-module")
+ {
+ }
+
+protected:
+ ManagerBase m_manager;
+};
+
+BOOST_FIXTURE_TEST_SUITE(MgmtManagerBase, ManagerBaseFixture)
+
+BOOST_AUTO_TEST_CASE(AddSupportedPrivilegeInConstructor)
+{
+ BOOST_CHECK_NO_THROW(m_validator.addSupportedPrivilege("other-module"));
+ // test-module has already been added by the constructor of ManagerBase
+ BOOST_CHECK_THROW(m_validator.addSupportedPrivilege("test-module"), CommandValidator::Error);
+}
+
+BOOST_AUTO_TEST_CASE(RegisterCommandHandler)
+{
+ bool wasCommandHandlerCalled = false;
+ auto handler = bind([&] { wasCommandHandlerCalled = true; });
+
+ m_manager.registerCommandHandler<TestCommandVoidParameters>("test-void", handler);
+ m_manager.registerCommandHandler<TestCommandRequireName>("test-require-name", handler);
+ setTopPrefixAndPrivilege("/localhost/nfd", "test-module");
+
+ auto testRegisterCommandHandler = [&wasCommandHandlerCalled, this] (const Name& commandName) {
+ wasCommandHandlerCalled = false;
+ receiveInterest(makeControlCommandRequest(commandName, ControlParameters()));
+ };
+
+ testRegisterCommandHandler("/localhost/nfd/test-module/test-void");
+ BOOST_CHECK(wasCommandHandlerCalled);
+
+ testRegisterCommandHandler("/localhost/nfd/test-module/test-require-name");
+ BOOST_CHECK(!wasCommandHandlerCalled);
+}
+
+BOOST_AUTO_TEST_CASE(RegisterStatusDataset)
+{
+ bool isStatusDatasetCalled = false;
+ auto handler = bind([&] { isStatusDatasetCalled = true; });
+
+ m_manager.registerStatusDatasetHandler("test-status", handler);
+ m_dispatcher.addTopPrefix("/localhost/nfd");
+ advanceClocks(time::milliseconds(1));
+
+ receiveInterest(makeInterest("/localhost/nfd/test-module/test-status"));
+ BOOST_CHECK(isStatusDatasetCalled);
+}
+
+BOOST_AUTO_TEST_CASE(RegisterNotificationStream)
+{
+ auto post = m_manager.registerNotificationStream("test-notification");
+ m_dispatcher.addTopPrefix("/localhost/nfd");
+ advanceClocks(time::milliseconds(1));
+
+ post(Block("\x82\x01\x02", 3));
+ advanceClocks(time::milliseconds(1));
+
+ BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
+ BOOST_CHECK_EQUAL(m_responses[0].getName(),
+ Name("/localhost/nfd/test-module/test-notification/%FE%00"));
+}
+
+BOOST_AUTO_TEST_CASE(CommandAuthorization)
+{
+ bool didAcceptCallbackFire = false;
+ bool didRejectCallbackFire = false;
+ auto testAuthorization = [&] {
+ didAcceptCallbackFire = false;
+ didRejectCallbackFire = false;
+
+ auto command = makeControlCommandRequest("/localhost/nfd/test-module/test-verb",
+ ControlParameters());
+ ndn::nfd::ControlParameters params;
+ m_manager.authorize("/top/prefix", *command, ¶ms,
+ bind([&] { didAcceptCallbackFire = true; }),
+ bind([&] { didRejectCallbackFire = true; }));
+ };
+
+ testAuthorization();
+ BOOST_CHECK(!didAcceptCallbackFire);
+ BOOST_CHECK(didRejectCallbackFire);
+
+ m_validator.addInterestRule("^<localhost><nfd><test-module>", *m_certificate);
+ testAuthorization();
+ BOOST_CHECK(didAcceptCallbackFire);
+ BOOST_CHECK(!didRejectCallbackFire);
+}
+
+BOOST_AUTO_TEST_CASE(ExtractRequester)
+{
+ std::string requesterName;
+ auto testAccept = [&] (const std::string& requester) { requesterName = requester; };
+
+ auto unsignedCommand = makeInterest("/test/interest/unsigned");
+ auto signedCommand = makeControlCommandRequest("/test/interest/signed", ControlParameters());
+
+ m_manager.extractRequester(*unsignedCommand, testAccept);
+ BOOST_CHECK(requesterName.empty());
+
+ requesterName = "";
+ m_manager.extractRequester(*signedCommand, testAccept);
+ auto keyLocator = m_keyChain.getDefaultCertificateNameForIdentity(m_identityName).getPrefix(-1);
+ BOOST_CHECK_EQUAL(requesterName, keyLocator.toUri());
+}
+
+BOOST_AUTO_TEST_CASE(ValidateParameters)
+{
+ ControlParameters params;
+ TestCommandVoidParameters commandVoidParams;
+ TestCommandRequireName commandRequireName;
+
+ BOOST_CHECK_EQUAL(ManagerBase::validateParameters(commandVoidParams, params), true); // succeeds
+ BOOST_CHECK_EQUAL(ManagerBase::validateParameters(commandRequireName, params), false); // fails
+
+ params.setName("test-name");
+ BOOST_CHECK_EQUAL(ManagerBase::validateParameters(commandRequireName, params), true); // succeeds
+}
+
+BOOST_AUTO_TEST_CASE(MakeRelPrefix)
+{
+ auto generatedRelPrefix = m_manager.makeRelPrefix("test-verb");
+ BOOST_CHECK_EQUAL(generatedRelPrefix, PartialName("/test-module/test-verb"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/mgmt/manager-common-fixture.cpp b/tests/daemon/mgmt/manager-common-fixture.cpp
new file mode 100644
index 0000000..b03449e
--- /dev/null
+++ b/tests/daemon/mgmt/manager-common-fixture.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "manager-common-fixture.hpp"
+
+namespace nfd {
+namespace tests {
+
+ManagerCommonFixture::ManagerCommonFixture()
+ : m_face(ndn::util::makeDummyClientFace(UnitTestTimeFixture::g_io, {true, true}))
+ , m_dispatcher(*m_face, m_keyChain, ndn::security::SigningInfo())
+ , m_responses(m_face->sentDatas)
+ , m_identityName("/unit-test/ManagerCommonFixture/identity")
+ , m_certificate(m_keyChain.getCertificate(m_keyChain.createIdentity(m_identityName)))
+{
+}
+
+void
+ManagerCommonFixture::setTopPrefixAndPrivilege(const Name& topPrefix,
+ const std::string& privilege)
+{
+ m_dispatcher.addTopPrefix(topPrefix); // such that all filters are added
+ advanceClocks(time::milliseconds(1));
+
+ std::string regex("^");
+ for (auto component : topPrefix) {
+ regex += "<" + component.toUri() + ">";
+ }
+ m_validator.addInterestRule(regex + "<" + privilege + ">", *m_certificate);
+}
+
+shared_ptr<Interest>
+ManagerCommonFixture::makeControlCommandRequest(Name commandName,
+ const ControlParameters& parameters,
+ const InterestHandler& beforeSigning)
+{
+ shared_ptr<Interest> command = makeInterest(commandName.append(parameters.wireEncode()));
+
+ if (beforeSigning != nullptr) {
+ beforeSigning(command);
+ }
+
+ m_keyChain.sign(*command, ndn::security::SigningInfo(ndn::security::SigningInfo::SIGNER_TYPE_ID,
+ m_identityName));
+ return command;
+}
+
+void
+ManagerCommonFixture::receiveInterest(shared_ptr<Interest> interest)
+{
+ m_face->receive<Interest>(*interest);
+ advanceClocks(time::milliseconds(1));
+}
+
+ControlResponse
+ManagerCommonFixture::makeResponse(uint32_t code, const std::string& text,
+ const ControlParameters& parameters)
+{
+ return ControlResponse(code, text).setBody(parameters.wireEncode());
+}
+
+ManagerCommonFixture::CheckResponseResult
+ManagerCommonFixture::checkResponse(size_t idx,
+ const Name& expectedName,
+ const ControlResponse& expectedResponse,
+ int expectedContentType /*= -1*/)
+{
+ Data data;
+ try {
+ data = m_responses.at(idx);
+ }
+ catch (const std::out_of_range&) {
+ return CheckResponseResult::OUT_OF_BOUNDARY;
+ }
+
+ if (data.getName() != expectedName) {
+ return CheckResponseResult::WRONG_NAME;
+ }
+
+ if (expectedContentType != -1 &&
+ data.getContentType() != static_cast<uint32_t>(expectedContentType)) {
+ return CheckResponseResult::WRONG_CONTENT_TYPE;
+ }
+
+ ControlResponse response;
+ try {
+ response.wireDecode(data.getContent().blockFromValue());
+ }
+ catch (const tlv::Error&) {
+ return CheckResponseResult::INVALID_RESPONSE;
+ }
+
+ if (response.getCode() != expectedResponse.getCode()) {
+ return CheckResponseResult::WRONG_CODE;
+ }
+
+ if (response.getText() != expectedResponse.getText()) {
+ return CheckResponseResult::WRONG_TEXT;
+ }
+
+ const Block& body = response.getBody();
+ const Block& expectedBody = expectedResponse.getBody();
+ if (body.value_size() != expectedBody.value_size()) {
+ return CheckResponseResult::WRONG_BODY_SIZE;
+ }
+ if (body.value_size() > 0 && memcmp(body.value(), expectedBody.value(), body.value_size()) != 0) {
+ return CheckResponseResult::WRONG_BODY_VALUE;
+ }
+
+ return CheckResponseResult::OK;
+}
+
+Block
+ManagerCommonFixture::concatenateResponses(size_t startIndex, size_t nResponses)
+{
+ size_t endIndex = startIndex + nResponses; // not included
+ if (nResponses == startIndex || endIndex > m_responses.size()) {
+ endIndex = m_responses.size();
+ }
+
+ ndn::EncodingBuffer encoder;
+ size_t valueLength = 0;
+ for (size_t i = startIndex; i < endIndex ; i ++) {
+ valueLength += encoder.appendByteArray(m_responses[i].getContent().value(),
+ m_responses[i].getContent().value_size());
+ }
+ encoder.prependVarNumber(valueLength);
+ encoder.prependVarNumber(tlv::Content);
+ return encoder.block();
+}
+
+std::ostream&
+operator<<(std::ostream &os, const ManagerCommonFixture::CheckResponseResult& result)
+{
+ switch (result) {
+ case ManagerCommonFixture::CheckResponseResult::OK:
+ os << "OK";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::OUT_OF_BOUNDARY:
+ os << "OUT_OF_BOUNDARY";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_NAME:
+ os << "WRONG_NAME";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_CONTENT_TYPE:
+ os << "WRONG_CONTENT_TYPE";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::INVALID_RESPONSE:
+ os << "INVALID_RESPONSE";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_CODE:
+ os << "WRONG_CODE";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_TEXT:
+ os << "WRONG_TEXT";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_BODY_SIZE:
+ os << "WRONG_BODY_SIZE";
+ break;
+ case ManagerCommonFixture::CheckResponseResult::WRONG_BODY_VALUE:
+ os << "WRONG_BODY_VALUE";
+ break;
+ default:
+ break;
+ };
+
+ return os;
+}
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/mgmt/manager-common-fixture.hpp b/tests/daemon/mgmt/manager-common-fixture.hpp
new file mode 100644
index 0000000..ffdb579
--- /dev/null
+++ b/tests/daemon/mgmt/manager-common-fixture.hpp
@@ -0,0 +1,163 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015, Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology,
+ * The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_TESTS_NFD_MGMT_MANAGER_COMMON_HPP
+#define NFD_TESTS_NFD_MGMT_MANAGER_COMMON_HPP
+
+#include "tests/test-common.hpp"
+#include "tests/identity-management-fixture.hpp"
+#include "mgmt/manager-base.hpp"
+#include "fw/forwarder.hpp"
+
+#include <ndn-cxx/mgmt/dispatcher.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace nfd {
+namespace tests {
+
+/**
+ * @brief a collection of common functions shared by all manager's testing fixtures.
+ */
+class ManagerCommonFixture : public UnitTestTimeFixture
+ , public IdentityManagementFixture
+{
+public: // initialize
+ ManagerCommonFixture();
+
+ /**
+ * @brief set topPrefix to the dispatcher and configure an interest rule for the module.
+ *
+ * after setting @param topPrefix, call advanceClocks to ensure all added filters take effects.
+ *
+ * @param topPrefix top prefix for the dispatcher
+ * @param privilege the module name
+ */
+ void
+ setTopPrefixAndPrivilege(const Name& topPrefix, const std::string& privilege);
+
+public: // test
+ typedef std::function<void(shared_ptr<Interest> interest)> InterestHandler;
+
+ /**
+ * @brief create a ControlCommand request
+ *
+ * step1: append the @param parameters to the @param commandName and make an Interest.
+ * step2: call @param beforeSinging to do something with the Interest.
+ * step3: sign the generated command
+ *
+ * @param commandName the command name
+ * @param parameters the ControlParameters
+ * @param beforeSigning a callback that can modify the Interest before it's signed
+ *
+ * @return the signed ControlCommand request
+ */
+ shared_ptr<Interest>
+ makeControlCommandRequest(Name commandName,
+ const ControlParameters& parameters,
+ const InterestHandler& beforeSigning = nullptr);
+
+ /**
+ * @brief cause management to receive an Interest
+ *
+ * call DummyClientFace::receive to receive Interest and then call advanceClocks to ensure
+ * the Interest dispatched
+ *
+ * @param interest the Interest to receive
+ */
+ void
+ receiveInterest(shared_ptr<Interest> interest);
+
+public: // verify
+ ControlResponse
+ makeResponse(uint32_t code, const std::string& text,
+ const ControlParameters& parameters);
+
+ enum class CheckResponseResult
+ {
+ OK,
+ OUT_OF_BOUNDARY,
+ WRONG_NAME,
+ WRONG_CONTENT_TYPE,
+ INVALID_RESPONSE,
+ WRONG_CODE,
+ WRONG_TEXT,
+ WRONG_BODY_SIZE,
+ WRONG_BODY_VALUE
+ };
+
+ /**
+ * @brief check a specified response data with the expected ControlResponse
+ *
+ * @param idx the index of the specified Data in m_responses
+ * @param expectedDataName the expected name of this Data
+ * @param expectedResponse the expected ControlResponse
+ * @param expectedContentType the expected content type of this Data, use -1 to skip this check
+ *
+ * @retval OK the response at the specified index can be decoded from the response data,
+ * and its code, text and response body are all matched with the expected response
+ * @retval OUT_OF_BOUNDARY the specified index out of boundary
+ * @retval WRONG_NAME the name of the specified response data does not match
+ * @retval WRONG_CONTENT_TYPE the content type of the specified response data does not match
+ * @retval INVALID_RESPONSE the data name matches but it fails in decoding a ControlResponse from
+ * the content of the specified response data
+ * @retval WRONG_CODE a valid ControlResponse can be decoded but has a wrong code
+ * @retval WRONG_TEXT a valid ControlResponse can be decoded but has a wrong text
+ * @retval WRONG_BODY_SIZE the body size of decoded ControlResponse does not match
+ * @retval WRONT_BODY_VALUE the body value of decoded ControlResponse does not match
+ */
+ CheckResponseResult
+ checkResponse(size_t idx,
+ const Name& expectedName,
+ const ControlResponse& expectedResponse,
+ int expectedContentType = -1);
+
+ /**
+ * @brief concatenate specified response Data into a single block
+ *
+ * @param startIndex the start index in m_responses
+ * @param nResponses the number of response to concatenate
+ *
+ * @return the generated block
+ */
+ Block
+ concatenateResponses(size_t startIndex = 0, size_t nResponses = 0);
+
+protected:
+ shared_ptr<ndn::util::DummyClientFace> m_face;
+ ndn::mgmt::Dispatcher m_dispatcher;
+ CommandValidator m_validator;
+ Forwarder m_forwarder;
+ std::vector<Data>& m_responses; // a reference of m_face->sentDatas
+ Name m_identityName; // the identity used to sign request
+ shared_ptr<ndn::IdentityCertificate> m_certificate; // the certificate used to sign request
+};
+
+std::ostream&
+operator<<(std::ostream &os, const ManagerCommonFixture::CheckResponseResult& result);
+
+} // namespace tests
+} // namespace nfd
+
+#endif // NFD_TESTS_NFD_MGMT_MANAGER_COMMON_HPP
diff --git a/tests/daemon/mgmt/validation-common.cpp b/tests/daemon/mgmt/validation-common.cpp
deleted file mode 100644
index 6065c27..0000000
--- a/tests/daemon/mgmt/validation-common.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014 Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#include "validation-common.hpp"
-
-#include <boost/test/unit_test.hpp>
-
-namespace nfd {
-namespace tests {
-
-const Name CommandIdentityGlobalFixture::s_identityName("/unit-test/CommandFixture/id");
-shared_ptr<ndn::IdentityCertificate> CommandIdentityGlobalFixture::s_certificate;
-
-CommandIdentityGlobalFixture::CommandIdentityGlobalFixture()
-{
- BOOST_ASSERT(!static_cast<bool>(s_certificate));
- s_certificate = m_keys.getCertificate(m_keys.createIdentity(s_identityName));
-}
-
-CommandIdentityGlobalFixture::~CommandIdentityGlobalFixture()
-{
- s_certificate.reset();
- m_keys.deleteIdentity(s_identityName);
-}
-
-BOOST_GLOBAL_FIXTURE(CommandIdentityGlobalFixture)
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/mgmt/validation-common.hpp b/tests/daemon/mgmt/validation-common.hpp
deleted file mode 100644
index f8b1367..0000000
--- a/tests/daemon/mgmt/validation-common.hpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014 Regents of the University of California,
- * Arizona Board of Regents,
- * Colorado State University,
- * University Pierre & Marie Curie, Sorbonne University,
- * Washington University in St. Louis,
- * Beijing Institute of Technology
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-#ifndef NFD_TESTS_NFD_MGMT_VALIDATION_COMMON_HPP
-#define NFD_TESTS_NFD_MGMT_VALIDATION_COMMON_HPP
-
-#include "common.hpp"
-#include <ndn-cxx/util/command-interest-generator.hpp>
-
-namespace nfd {
-namespace tests {
-
-// class ValidatedManagementFixture
-// {
-// public:
-// ValidatedManagementFixture()
-// : m_validator(make_shared<ndn::CommandInterestValidator>())
-// {
-// }
-
-// virtual
-// ~ValidatedManagementFixture()
-// {
-// }
-
-// protected:
-// shared_ptr<ndn::CommandInterestValidator> m_validator;
-// };
-
-/// a global fixture that holds the identity for CommandFixture
-class CommandIdentityGlobalFixture
-{
-public:
- CommandIdentityGlobalFixture();
-
- ~CommandIdentityGlobalFixture();
-
- static const Name& getIdentityName()
- {
- return s_identityName;
- }
-
- static shared_ptr<ndn::IdentityCertificate> getCertificate()
- {
- BOOST_ASSERT(static_cast<bool>(s_certificate));
- return s_certificate;
- }
-
-private:
- ndn::KeyChain m_keys;
- static const Name s_identityName;
- static shared_ptr<ndn::IdentityCertificate> s_certificate;
-};
-
-template<typename T>
-class CommandFixture : public T
-{
-public:
- virtual
- ~CommandFixture()
- {
- }
-
- void
- generateCommand(Interest& interest)
- {
- m_generator.generateWithIdentity(interest, getIdentityName());
- }
-
- const Name&
- getIdentityName() const
- {
- return CommandIdentityGlobalFixture::getIdentityName();
- }
-
-protected:
- CommandFixture()
- : m_certificate(CommandIdentityGlobalFixture::getCertificate())
- {
- }
-
-protected:
- shared_ptr<ndn::IdentityCertificate> m_certificate;
- ndn::CommandInterestGenerator m_generator;
-};
-
-template <typename T>
-class UnauthorizedCommandFixture : public CommandFixture<T>
-{
-public:
- UnauthorizedCommandFixture()
- {
- }
-
- virtual
- ~UnauthorizedCommandFixture()
- {
- }
-};
-
-} // namespace tests
-} // namespace nfd
-
-#endif // NFD_TESTS_NFD_MGMT_VALIDATION_COMMON_HPP