mgmt: add faces/update command
refs #3731
Change-Id: I79777a10feecb2de83276371100cc86a43d0e76d
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index 9cd0e07..f41f4de 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -59,6 +59,9 @@
registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
bind(&FaceManager::createFace, this, _2, _3, _4, _5));
+ registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
+ bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
+
registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
@@ -143,6 +146,8 @@
m_faceTable.add(newFace);
+ // TODO: #3731: Verify and add Flags
+
// Set ControlResponse parameters
response.setFaceId(newFace->getId());
response.setFacePersistency(newFace->getPersistency());
@@ -161,6 +166,69 @@
}
void
+FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
+ const ControlParameters& parameters,
+ const ndn::mgmt::CommandContinuation& done)
+{
+ FaceId faceId = parameters.getFaceId();
+ if (faceId == 0) {
+ // Self-updating
+ shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
+ if (incomingFaceIdTag == nullptr) {
+ NFD_LOG_TRACE("unable to determine face for self-update");
+ done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
+ return;
+ }
+ faceId = *incomingFaceIdTag;
+ }
+
+ Face* face = m_faceTable.get(faceId);
+
+ if (face == nullptr) {
+ NFD_LOG_TRACE("invalid face specified");
+ done(ControlResponse(404, "Specified face does not exist"));
+ return;
+ }
+
+ // Verify validity of requested changes
+ ControlParameters response;
+ bool areParamsValid = true;
+
+ if (parameters.hasFacePersistency()) {
+ // TODO #3232: Add FacePersistency updating
+ NFD_LOG_TRACE("received unsupported face persistency change");
+ areParamsValid = false;
+ response.setFacePersistency(parameters.getFacePersistency());
+ }
+
+ if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+ parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+ face->getScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
+ NFD_LOG_TRACE("received request to enable local fields on non-local face");
+ areParamsValid = false;
+ response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED,
+ parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
+ }
+
+ if (!areParamsValid) {
+ done(ControlResponse(409, "Invalid properties specified").setBody(response.wireEncode()));
+ return;
+ }
+
+ // All specified properties are valid, so make changes
+
+ // TODO #3232: Add FacePersistency updating
+
+ setLinkServiceOptions(*face, parameters, response);
+
+ // Set remaining ControlResponse fields
+ response.setFaceId(faceId);
+ response.setFacePersistency(face->getPersistency());
+
+ done(ControlResponse(200, "OK").setBody(response.wireEncode()));
+}
+
+void
FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
const ControlParameters& parameters,
const ndn::mgmt::CommandContinuation& done)
@@ -183,8 +251,7 @@
return;
}
- // TODO#3226 redesign enable-local-control
- // For now, enable-local-control will enable all local fields in GenericLinkService.
+ // enable-local-control will enable all local fields in GenericLinkService
auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
if (service == nullptr) {
return done(ControlResponse(503, "LinkService type not supported"));
@@ -208,8 +275,7 @@
return;
}
- // TODO#3226 redesign disable-local-control
- // For now, disable-local-control will disable all local fields in GenericLinkService.
+ // disable-local-control will disable all local fields in GenericLinkService
auto service = dynamic_cast<face::GenericLinkService*>(face->getLinkService());
if (service == nullptr) {
return done(ControlResponse(503, "LinkService type not supported"));
@@ -251,6 +317,25 @@
}
void
+FaceManager::setLinkServiceOptions(Face& face,
+ const ControlParameters& parameters,
+ ControlParameters& response)
+{
+ auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+ BOOST_ASSERT(linkService != nullptr);
+
+ auto options = linkService->getOptions();
+ if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+ face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
+ options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
+ }
+ linkService->setOptions(options);
+
+ // Set Flags for ControlResponse
+ response.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false);
+}
+
+void
FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
ndn::mgmt::StatusDatasetContext& context)
{
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index 094f288..b168da4 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -61,15 +61,26 @@
const ndn::mgmt::CommandContinuation& done);
void
+ updateFace(const Name& topPrefix, const Interest& interest,
+ const ControlParameters& parameters,
+ const ndn::mgmt::CommandContinuation& done);
+
+ void
destroyFace(const Name& topPrefix, const Interest& interest,
const ControlParameters& parameters,
const ndn::mgmt::CommandContinuation& done);
+ /**
+ * \deprecated use Flags+Mask in faces/update instead
+ */
void
enableLocalControl(const Name& topPrefix, const Interest& interest,
const ControlParameters& parameters,
const ndn::mgmt::CommandContinuation& done);
+ /**
+ * \deprecated use Flags+Mask in faces/update instead
+ */
void
disableLocalControl(const Name& topPrefix, const Interest& interest,
const ControlParameters& parameters,
@@ -91,6 +102,11 @@
const ControlParameters& parameters,
const ndn::mgmt::CommandContinuation& done);
+ static void
+ setLinkServiceOptions(Face& face,
+ const ControlParameters& parameters,
+ ControlParameters& response);
+
PUBLIC_WITH_TESTS_ELSE_PRIVATE: // StatusDataset
void
listFaces(const Name& topPrefix, const Interest& interest,
@@ -151,9 +167,9 @@
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
std::map<std::string /*protocol*/, shared_ptr<ProtocolFactory>> m_factories;
+ FaceTable& m_faceTable;
private:
- FaceTable& m_faceTable;
ndn::mgmt::PostNotification m_postNotification;
signal::ScopedConnection m_faceAddConn;
signal::ScopedConnection m_faceRemoveConn;
diff --git a/tests/daemon/mgmt/face-manager-create-face.t.cpp b/tests/daemon/mgmt/face-manager-create-face.t.cpp
index 052b89c..c691491 100644
--- a/tests/daemon/mgmt/face-manager-create-face.t.cpp
+++ b/tests/daemon/mgmt/face-manager-create-face.t.cpp
@@ -84,19 +84,6 @@
}
};
-class UdpFaceConnectToSelf // face that will cause afterCreateFaceFailure to be invoked
- // fails because remote endpoint is prohibited
-{
-public:
- ControlParameters
- getParameters()
- {
- return ControlParameters()
- .setUri("udp4://0.0.0.0:16363"); // cannot connect to self
- }
-};
-
-
class UdpFacePersistent
{
public:
@@ -121,41 +108,28 @@
}
};
-class Success
+class UdpFaceConnectToSelf // face that will cause afterCreateFaceFailure to be invoked
+ // fails because remote endpoint is prohibited
{
public:
- ControlResponse
- getExpected()
+ ControlParameters
+ getParameters()
{
- return ControlResponse()
- .setCode(200)
- .setText("OK");
- }
-};
-
-template<int CODE>
-class Failure
-{
-public:
- ControlResponse
- getExpected()
- {
- return ControlResponse()
- .setCode(CODE)
- .setText("Error"); // error description should not be checked
+ return ControlParameters()
+ .setUri("udp4://0.0.0.0:16363"); // cannot connect to self
}
};
namespace mpl = boost::mpl;
// pairs of CreateCommand and Success/Failure status
-typedef mpl::vector<mpl::pair<TcpFaceOnDemand, Failure<406>>,
- mpl::pair<TcpFacePersistent, Success>,
- mpl::pair<TcpFacePermanent, Failure<406>>,
- mpl::pair<UdpFaceOnDemand, Failure<406>>,
- mpl::pair<UdpFacePersistent, Success>,
- mpl::pair<UdpFacePermanent, Success>,
- mpl::pair<UdpFaceConnectToSelf, Failure<406>>> Faces;
+typedef mpl::vector<mpl::pair<TcpFaceOnDemand, CommandFailure<406>>,
+ mpl::pair<TcpFacePersistent, CommandSuccess>,
+ mpl::pair<TcpFacePermanent, CommandFailure<406>>,
+ mpl::pair<UdpFaceOnDemand, CommandFailure<406>>,
+ mpl::pair<UdpFacePersistent, CommandSuccess>,
+ mpl::pair<UdpFacePermanent, CommandSuccess>,
+ mpl::pair<UdpFaceConnectToSelf, CommandFailure<406>>> Faces;
BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerCommandFixture)
{
@@ -186,10 +160,28 @@
BOOST_CHECK(actualParams.hasFaceId());
BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
- if (actual.getCode() != 200) {
+ if (actual.getCode() == 200) {
+ if (expectedParams.hasFlags()) {
+ // TODO: #3731 check if Flags match
+ }
+ else {
+ // TODO: #3731 check if Flags at defaults
+ }
+ }
+ else {
BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
}
}
+
+ if (actual.getCode() != 200) {
+ // ensure face not created
+ FaceUri uri(FaceType().getParameters().getUri());
+ auto& faceTable = this->node1.manager.m_faceTable;
+ BOOST_CHECK(std::none_of(faceTable.begin(), faceTable.end(), [uri] (Face& face) {
+ return face.getRemoteUri() == uri;
+ }));
+ }
+
hasCallbackFired = true;
});
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
diff --git a/tests/daemon/mgmt/nfd-manager-common-fixture.hpp b/tests/daemon/mgmt/nfd-manager-common-fixture.hpp
index 32650ce..65c5dcc 100644
--- a/tests/daemon/mgmt/nfd-manager-common-fixture.hpp
+++ b/tests/daemon/mgmt/nfd-manager-common-fixture.hpp
@@ -55,6 +55,31 @@
shared_ptr<CommandAuthenticator> m_authenticator;
};
+class CommandSuccess
+{
+public:
+ ControlResponse
+ getExpected()
+ {
+ return ControlResponse()
+ .setCode(200)
+ .setText("OK");
+ }
+};
+
+template<int CODE>
+class CommandFailure
+{
+public:
+ ControlResponse
+ getExpected()
+ {
+ return ControlResponse()
+ .setCode(CODE);
+ // error description should not be checked
+ }
+};
+
} // namespace tests
} // namespace nfd