mgmt: add faces/update command
refs #3731
Change-Id: I79777a10feecb2de83276371100cc86a43d0e76d
diff --git a/tests/daemon/mgmt/face-manager-update-face.t.cpp b/tests/daemon/mgmt/face-manager-update-face.t.cpp
new file mode 100644
index 0000000..68ac36a
--- /dev/null
+++ b/tests/daemon/mgmt/face-manager-update-face.t.cpp
@@ -0,0 +1,523 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016, 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 "face-manager-command-fixture.hpp"
+#include "nfd-manager-common-fixture.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Mgmt)
+BOOST_AUTO_TEST_SUITE(TestFaceManager)
+
+class FaceManagerUpdateFixture : public FaceManagerCommandFixture
+{
+public:
+ FaceManagerUpdateFixture()
+ : faceId(0)
+ {
+ }
+
+ ~FaceManagerUpdateFixture()
+ {
+ destroyFace();
+ }
+
+ void
+ createFace(const std::string& uri = "tcp4://127.0.0.1:26363",
+ ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+ bool enableLocalFields = false)
+ {
+ ControlParameters params;
+ params.setUri(uri);
+ params.setFacePersistency(persistency);
+ params.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, enableLocalFields);
+
+ Name commandName("/localhost/nfd/faces/create");
+ commandName.append(params.wireEncode());
+ auto command = makeInterest(commandName);
+ m_keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ signal::ScopedConnection connection = this->node1.face.onSendData.connect(
+ [this, command, &hasCallbackFired] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse create(response.getContent().blockFromValue());
+ BOOST_REQUIRE_EQUAL(create.getCode(), 200);
+
+ if (create.getBody().hasWire()) {
+ ControlParameters faceParams(create.getBody());
+ BOOST_REQUIRE(faceParams.hasFaceId());
+ this->faceId = faceParams.getFaceId();
+ }
+ else {
+ BOOST_FAIL("Face creation failed");
+ }
+
+ hasCallbackFired = true;
+ });
+
+ this->node1.face.receive(*command);
+ this->advanceClocks(time::milliseconds(1), 5);
+
+ BOOST_REQUIRE(hasCallbackFired);
+ }
+
+ void
+ updateFace(const ControlParameters& requestParams,
+ bool isSelfUpdating,
+ const function<void(const ControlResponse& resp)>& checkResp)
+ {
+ Name commandName("/localhost/nfd/faces/update");
+ commandName.append(requestParams.wireEncode());
+ auto command = makeInterest(commandName);
+ if (isSelfUpdating) {
+ // Attach IncomingFaceIdTag to interest
+ command->setTag(make_shared<lp::IncomingFaceIdTag>(faceId));
+ }
+ m_keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ signal::ScopedConnection connection = this->node1.face.onSendData.connect(
+ [this, command, &hasCallbackFired, &checkResp] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse actual(response.getContent().blockFromValue());
+ checkResp(actual);
+
+ hasCallbackFired = true;
+ });
+
+ this->node1.face.receive(*command);
+ this->advanceClocks(time::milliseconds(1), 5);
+
+ BOOST_CHECK(hasCallbackFired);
+ }
+
+private:
+ void
+ destroyFace()
+ {
+ if (faceId == 0) {
+ return;
+ }
+
+ ControlParameters params;
+ params.setFaceId(faceId);
+
+ Name commandName("/localhost/nfd/faces/destroy");
+ commandName.append(params.wireEncode());
+ auto command = makeInterest(commandName);
+ m_keyChain.sign(*command);
+
+ bool hasCallbackFired = false;
+ signal::ScopedConnection connection = this->node1.face.onSendData.connect(
+ [this, command, &hasCallbackFired] (const Data& response) {
+ if (!command->getName().isPrefixOf(response.getName())) {
+ return;
+ }
+
+ ControlResponse destroy(response.getContent().blockFromValue());
+ BOOST_CHECK_EQUAL(destroy.getCode(), 200);
+
+ faceId = 0;
+ hasCallbackFired = true;
+ });
+
+ this->node1.face.receive(*command);
+ this->advanceClocks(time::milliseconds(1), 5);
+
+ BOOST_CHECK(hasCallbackFired);
+ }
+
+public:
+ FaceId faceId;
+};
+
+BOOST_FIXTURE_TEST_SUITE(UpdateFace, FaceManagerUpdateFixture)
+
+BOOST_AUTO_TEST_CASE(FaceDoesNotExist)
+{
+ ControlParameters requestParams;
+ requestParams.setFaceId(65535);
+
+ updateFace(requestParams, false, [] (const ControlResponse& actual) {
+ ControlResponse expected(404, "Specified face does not exist");
+ BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+ });
+}
+
+// TODO #3232: Expected failure until FacePersistency updating implemented
+BOOST_AUTO_TEST_CASE(UpdatePersistency)
+{
+ createFace();
+
+ ControlParameters requestParams;
+ requestParams.setFaceId(faceId);
+ requestParams.setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+
+ updateFace(requestParams, false, [] (const ControlResponse& actual) {
+ ControlResponse expected(409, "Invalid fields specified");
+ BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+
+ if (actual.getBody().hasWire()) {
+ ControlParameters actualParams(actual.getBody());
+
+ BOOST_REQUIRE(actualParams.hasFacePersistency());
+ BOOST_CHECK_EQUAL(actualParams.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+ }
+ else {
+ BOOST_ERROR("Response does not contain ControlParameters");
+ }
+ });
+}
+
+class TcpLocalFieldsEnable
+{
+public:
+ std::string
+ getUri()
+ {
+ return "tcp4://127.0.0.1:26363";
+ }
+
+ boost::asio::ip::address_v4
+ getIpAddress()
+ {
+ return boost::asio::ip::address_v4::from_string("127.0.0.1");
+ }
+
+ ndn::nfd::FacePersistency
+ getPersistency()
+ {
+ return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
+ }
+
+ bool
+ getInitLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabled()
+ {
+ return true;
+ }
+
+ bool
+ getLocalFieldsEnabledMask()
+ {
+ return true;
+ }
+
+ bool
+ shouldHaveWire()
+ {
+ return false;
+ }
+};
+
+class TcpLocalFieldsDisable
+{
+public:
+ std::string
+ getUri()
+ {
+ return "tcp4://127.0.0.1:26363";
+ }
+
+ ndn::nfd::FacePersistency
+ getPersistency()
+ {
+ return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
+ }
+
+ bool
+ getInitLocalFieldsEnabled()
+ {
+ return true;
+ }
+
+ bool
+ getLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabledMask()
+ {
+ return true;
+ }
+
+ bool
+ shouldHaveWire()
+ {
+ return false;
+ }
+};
+
+// UDP faces are non-local by definition
+class UdpLocalFieldsEnable
+{
+public:
+ std::string
+ getUri()
+ {
+ return "udp4://127.0.0.1:26363";
+ }
+
+ ndn::nfd::FacePersistency
+ getPersistency()
+ {
+ return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
+ }
+
+ bool
+ getInitLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabled()
+ {
+ return true;
+ }
+
+ bool
+ getLocalFieldsEnabledMask()
+ {
+ return true;
+ }
+
+ bool
+ shouldHaveWire()
+ {
+ return true;
+ }
+};
+
+// UDP faces are non-local by definition
+// In this test case, attempt to disable local fields on face with local fields already disabled
+class UdpLocalFieldsDisable
+{
+public:
+ std::string
+ getUri()
+ {
+ return "udp4://127.0.0.1:26363";
+ }
+
+ ndn::nfd::FacePersistency
+ getPersistency()
+ {
+ return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
+ }
+
+ bool
+ getInitLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabledMask()
+ {
+ return true;
+ }
+
+ bool
+ shouldHaveWire()
+ {
+ return false;
+ }
+};
+
+// In this test case, set Flags to enable local fields on non-local face, but exclude local fields
+// from Mask. This test case will pass as no action is taken due to the missing Mask bit.
+class UdpLocalFieldsEnableNoMaskBit
+{
+public:
+ std::string
+ getUri()
+ {
+ return "udp4://127.0.0.1:26363";
+ }
+
+ ndn::nfd::FacePersistency
+ getPersistency()
+ {
+ return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
+ }
+
+ bool
+ getInitLocalFieldsEnabled()
+ {
+ return false;
+ }
+
+ bool
+ getLocalFieldsEnabled()
+ {
+ return true;
+ }
+
+ bool
+ getLocalFieldsEnabledMask()
+ {
+ return false;
+ }
+
+ bool
+ shouldHaveWire()
+ {
+ return false;
+ }
+};
+
+namespace mpl = boost::mpl;
+
+typedef mpl::vector<mpl::pair<TcpLocalFieldsEnable, CommandSuccess>,
+ mpl::pair<TcpLocalFieldsDisable, CommandSuccess>,
+ mpl::pair<UdpLocalFieldsEnable, CommandFailure<409>>,
+ mpl::pair<UdpLocalFieldsDisable, CommandSuccess>,
+ mpl::pair<UdpLocalFieldsEnableNoMaskBit, CommandSuccess>> LocalFieldFaces;
+
+BOOST_AUTO_TEST_CASE_TEMPLATE(UpdateLocalFields, T, LocalFieldFaces)
+{
+ typedef typename T::first TestType;
+ typedef typename T::second ResultType;
+
+ createFace(TestType().getUri(), TestType().getPersistency(), TestType().getInitLocalFieldsEnabled());
+
+ ControlParameters requestParams;
+ requestParams.setFaceId(faceId);
+ requestParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, TestType().getLocalFieldsEnabled());
+ if (!TestType().getLocalFieldsEnabledMask()) {
+ requestParams.unsetFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
+ }
+
+ updateFace(requestParams, false, [] (const ControlResponse& actual) {
+ ControlResponse expected(ResultType().getExpected().getCode(), "");
+ BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+
+ if (TestType().shouldHaveWire() && actual.getBody().hasWire()) {
+ ControlParameters actualParams(actual.getBody());
+
+ BOOST_CHECK(!actualParams.hasFacePersistency());
+ BOOST_CHECK(actualParams.hasFlags());
+ BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+ BOOST_CHECK(actualParams.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+ }
+ });
+}
+
+BOOST_AUTO_TEST_CASE(UpdateLocalFieldsEnableDisable)
+{
+ createFace();
+
+ ControlParameters enableParams;
+ enableParams.setFaceId(faceId);
+ enableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
+
+ ControlParameters disableParams;
+ disableParams.setFaceId(faceId);
+ disableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
+
+ updateFace(enableParams, false, [] (const ControlResponse& actual) {
+ ControlResponse expected(200, "OK");
+ BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+
+ if (actual.getBody().hasWire()) {
+ ControlParameters actualParams(actual.getBody());
+
+ BOOST_CHECK(actualParams.hasFaceId());
+ BOOST_CHECK(actualParams.hasFacePersistency());
+ BOOST_REQUIRE(actualParams.hasFlags());
+ // Check if flags indicate local fields enabled
+ BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+ }
+ else {
+ BOOST_ERROR("Enable: Response does not contain ControlParameters");
+ }
+ });
+
+ updateFace(disableParams, false, [] (const ControlResponse& actual) {
+ ControlResponse expected(200, "OK");
+ BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+
+ if (actual.getBody().hasWire()) {
+ ControlParameters actualParams(actual.getBody());
+
+ BOOST_CHECK(actualParams.hasFaceId());
+ BOOST_CHECK(actualParams.hasFacePersistency());
+ BOOST_REQUIRE(actualParams.hasFlags());
+ // Check if flags indicate local fields disabled
+ BOOST_CHECK(!actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+ }
+ else {
+ BOOST_ERROR("Disable: Response does not contain ControlParameters");
+ }
+ });
+}
+
+BOOST_AUTO_TEST_CASE(SelfUpdating)
+{
+ createFace();
+
+ // Send a command that does nothing (will return 200) and does not contain a FaceId
+ ControlParameters sentParams;
+
+ updateFace(sentParams, true, [] (const ControlResponse& actual) {
+ ControlResponse expected(200, "OK");
+ BOOST_REQUIRE_EQUAL(actual.getCode(), expected.getCode());
+ BOOST_TEST_MESSAGE(actual.getText());
+ });
+}
+
+BOOST_AUTO_TEST_SUITE_END() // UpdateFace
+BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
+BOOST_AUTO_TEST_SUITE_END() // Mgmt
+
+} // namespace tests
+} // namespace nfd