mgmt: Process FacePersistency in FaceManager
Change-Id:I3a93bd658d40f3d77f7790b72e8873646ecc7990
Refs: #2991
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 692acf9..db3b92f 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -931,6 +931,7 @@
addCreatedFaceToForwarder(newFace);
parameters.setFaceId(newFace->getId());
parameters.setUri(newFace->getRemoteUri().toString());
+ parameters.setFacePersistency(newFace->getPersistency());
sendResponse(requestName, 200, "Success", parameters.wireEncode());
}
@@ -981,7 +982,7 @@
try
{
factory->second->createFace(uri,
- ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+ parameters.getFacePersistency(),
bind(&FaceManager::onCreated,
this, requestName, parameters, _1),
bind(&FaceManager::onConnectFailed,
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index f9a2771..36e9e8a 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -1626,6 +1626,7 @@
ControlParameters resultParameters;
resultParameters.setUri("dummy://");
resultParameters.setFaceId(FACEID_RESERVED_MAX + 1);
+ resultParameters.setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
shared_ptr<DummyFace> dummy(make_shared<DummyFace>());
diff --git a/tests/daemon/mgmt/face-manager/create-face.t.cpp b/tests/daemon/mgmt/face-manager/create-face.t.cpp
new file mode 100644
index 0000000..3a70619
--- /dev/null
+++ b/tests/daemon/mgmt/face-manager/create-face.t.cpp
@@ -0,0 +1,449 @@
+/* -*- 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/face-manager.hpp"
+#include "mgmt/internal-face.hpp"
+#include "fw/forwarder.hpp"
+
+#include "tests/test-common.hpp"
+
+#include <boost/property_tree/info_parser.hpp>
+
+namespace nfd {
+namespace tests {
+
+BOOST_FIXTURE_TEST_SUITE(MgmtFaceManager, BaseFixture)
+
+BOOST_AUTO_TEST_SUITE(CreateFace)
+
+class FaceManagerNode
+{
+public:
+ FaceManagerNode(ndn::KeyChain& keyChain, const std::string& port = "6363")
+ : face(make_shared<InternalFace>())
+ , manager(forwarder.getFaceTable(), face, keyChain)
+ {
+ std::string basicConfig =
+ "face_system\n"
+ "{\n"
+ " tcp\n"
+ " {\n"
+ " port " + port + "\n"
+ " }\n"
+ " udp\n"
+ " {\n"
+ " port " + port + "\n"
+ " }\n"
+ "}\n"
+ "authorizations\n"
+ "{\n"
+ " authorize\n"
+ " {\n"
+ " certfile any\n"
+ " privileges\n"
+ " {\n"
+ " faces\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "\n";
+ std::istringstream input(basicConfig);
+ nfd::ConfigSection configSection;
+ boost::property_tree::read_info(input, configSection);
+
+ ConfigFile config;
+ manager.setConfigFile(config);
+ face->getValidator().setConfigFile(config);
+ config.parse(configSection, false, "dummy-config");
+ }
+
+ void
+ closeFaces()
+ {
+ std::vector<shared_ptr<Face>> facesToClose;
+ std::copy(forwarder.getFaceTable().begin(), forwarder.getFaceTable().end(),
+ std::back_inserter(facesToClose));
+ for (auto face : facesToClose) {
+ face->close();
+ }
+ }
+
+public:
+ Forwarder forwarder;
+ shared_ptr<InternalFace> face;
+ FaceManager manager;
+};
+
+class FaceManagerFixture : public UnitTestTimeFixture
+{
+public:
+ FaceManagerFixture()
+ : node1(keyChain, "16363")
+ , node2(keyChain, "26363")
+ {
+ }
+
+ ~FaceManagerFixture()
+ {
+ node1.closeFaces();
+ node2.closeFaces();
+ advanceClocks(time::milliseconds(1), 100);
+ }
+
+public:
+ ndn::KeyChain keyChain;
+ FaceManagerNode node1; // used to test FaceManager
+ FaceManagerNode node2; // acts as a remote endpoint
+};
+
+class TcpFaceOnDemand
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("tcp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+ }
+};
+
+class TcpFacePersistent
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("tcp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+ }
+};
+
+class TcpFacePermanent
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("tcp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+ }
+};
+
+class UdpFaceOnDemand
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("udp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+ }
+};
+
+class UdpFacePersistent
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("udp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+ }
+};
+
+class UdpFacePermanent
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("udp4://127.0.0.1:26363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+ }
+};
+
+class Success
+{
+public:
+ ControlResponse
+ getExpected()
+ {
+ return ControlResponse()
+ .setCode(200)
+ .setText("Success");
+ }
+};
+
+template<int CODE>
+class Failure
+{
+public:
+ ControlResponse
+ getExpected()
+ {
+ return ControlResponse()
+ .setCode(CODE)
+ .setText("Error"); // error description should not be checked
+ }
+};
+
+namespace mpl = boost::mpl;
+
+// pairs of CreateCommand and Success status
+typedef mpl::vector<mpl::pair<TcpFaceOnDemand, Failure<500>>,
+ mpl::pair<TcpFacePersistent, Success>,
+ mpl::pair<TcpFacePermanent, Failure<500>>,
+ mpl::pair<UdpFaceOnDemand, Failure<500>>,
+ mpl::pair<UdpFacePersistent, Success>,
+ mpl::pair<UdpFacePermanent, Success>> Faces;
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerFixture)
+{
+ typedef typename T::first FaceType;
+ typedef typename T::second CreateResult;
+
+ Name commandName("/localhost/nfd/faces");
+ commandName.append("create");
+ commandName.append(FaceType().getParameters().wireEncode());
+
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+ this->keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse actual(response.getContent().blockFromValue());
+ ControlResponse expected(CreateResult().getExpected());
+ BOOST_CHECK_EQUAL(expected.getCode(), actual.getCode());
+ BOOST_MESSAGE(actual.getText());
+
+ if (actual.getBody().hasWire()) {
+ ControlParameters expectedParams(FaceType().getParameters());
+ ControlParameters actualParams(actual.getBody());
+
+ BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
+ BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
+ }
+ hasCallbackFired = true;
+ });
+
+ this->node1.face->sendInterest(*command);
+ this->advanceClocks(time::milliseconds(1), 10);
+
+ BOOST_CHECK(hasCallbackFired);
+}
+
+
+typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
+ // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
+ mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
+ mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;
+
+
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFace, T, FaceTransitions, FaceManagerFixture)
+{
+ typedef typename T::first::first FaceType1;
+ typedef typename T::first::second FaceType2;
+ typedef typename T::second FinalFaceType;
+
+ {
+ // create face
+
+ Name commandName("/localhost/nfd/faces");
+ commandName.append("create");
+ commandName.append(FaceType1().getParameters().wireEncode());
+
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+ this->keyChain.sign(*command);
+
+ this->node1.face->sendInterest(*command);
+ this->advanceClocks(time::milliseconds(1), 10);
+ }
+
+ //
+ {
+ // re-create face (= change face persistency)
+
+ Name commandName("/localhost/nfd/faces");
+ commandName.append("create");
+ commandName.append(FaceType2().getParameters().wireEncode());
+
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+ this->keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse actual(response.getContent().blockFromValue());
+ BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
+
+ ControlParameters expectedParams(FinalFaceType().getParameters());
+ ControlParameters actualParams(actual.getBody());
+ BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
+
+ hasCallbackFired = true;
+ });
+
+ this->node1.face->sendInterest(*command);
+ this->advanceClocks(time::milliseconds(1), 10);
+
+ BOOST_CHECK(hasCallbackFired);
+ }
+}
+
+
+// class TcpFace
+// {
+// public:
+// ControlParameters
+// getParameters()
+// {
+// return ControlParameters()
+// .setUri("tcp4://127.0.0.1:16363")
+// .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+// }
+// };
+
+class UdpFace
+{
+public:
+ ControlParameters
+ getParameters()
+ {
+ return ControlParameters()
+ .setUri("udp4://127.0.0.1:16363")
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+ }
+};
+
+
+// Note that the transitions from on-demand TcpFace are intentionally not tested.
+// On-demand TcpFace has a remote endpoint with a randomized port number. Normal face
+// creation operations will not need to create a face toward a remote port not listened by
+// a channel.
+
+typedef mpl::vector<mpl::pair<UdpFace, UdpFacePersistent>,
+ mpl::pair<UdpFace, UdpFacePermanent>> OnDemandFaceTransitions;
+
+// need a slightly different logic to test transitions from OnDemand state
+BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFaceOnDemand, T, OnDemandFaceTransitions, FaceManagerFixture)
+{
+ typedef typename T::first OtherNodeFace;
+ typedef typename T::second FaceType;
+
+ {
+ // create on-demand face
+
+ Name commandName("/localhost/nfd/faces");
+ commandName.append("create");
+ commandName.append(OtherNodeFace().getParameters().wireEncode());
+
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+ this->keyChain.sign(*command);
+
+ ndn::util::signal::ScopedConnection connection =
+ this->node2.face->onReceiveData.connect([this, command] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse controlResponse(response.getContent().blockFromValue());
+ BOOST_REQUIRE_EQUAL(controlResponse.getText(), "Success");
+ BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 200);
+ uint64_t faceId = ControlParameters(controlResponse.getBody()).getFaceId();
+ auto face = this->node2.forwarder.getFace(static_cast<FaceId>(faceId));
+
+ // to force creation of on-demand face
+ auto dummyInterest = make_shared<Interest>("/hello/world");
+ face->sendInterest(*dummyInterest);
+ });
+
+ this->node2.face->sendInterest(*command);
+ this->advanceClocks(time::milliseconds(1), 10);
+ }
+
+ // make sure there is on-demand face
+ bool onDemandFaceFound = false;
+ FaceUri onDemandFaceUri(FaceType().getParameters().getUri());
+ for (auto face : this->node1.forwarder.getFaceTable()) {
+ if (face->getRemoteUri() == onDemandFaceUri) {
+ onDemandFaceFound = true;
+ break;
+ }
+ }
+ BOOST_REQUIRE(onDemandFaceFound);
+
+ //
+ {
+ // re-create face (= change face persistency)
+
+ Name commandName("/localhost/nfd/faces");
+ commandName.append("create");
+ commandName.append(FaceType().getParameters().wireEncode());
+
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+ this->keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ this->node1.face->onReceiveData.connect([this, command, &hasCallbackFired] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse actual(response.getContent().blockFromValue());
+ BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
+
+ ControlParameters expectedParams(FaceType().getParameters());
+ ControlParameters actualParams(actual.getBody());
+ BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
+
+ hasCallbackFired = true;
+ });
+
+ this->node1.face->sendInterest(*command);
+ this->advanceClocks(time::milliseconds(1), 10);
+
+ BOOST_CHECK(hasCallbackFired);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END() // CreateFace
+
+BOOST_AUTO_TEST_SUITE_END() // MgmtFaceManager
+
+} // tests
+} // nfd