From fbb40a8d2920b1e949b1117199e98be2bc545fcf Mon Sep 17 00:00:00 2001 From: Steve DiBenedetto Date: Tue, 11 Mar 2014 19:40:15 -0600 Subject: [PATCH] mgmt: add face event notification and notification stream refs: #1244 Change-Id: I14bd327be53bcb607b457d6cb4bd66bd28a2feaa --- daemon/mgmt/face-manager.cpp | 37 +++++- daemon/mgmt/face-manager.hpp | 19 ++++ daemon/mgmt/notification-stream.hpp | 60 ++++++++++ tests/mgmt/face-manager.cpp | 168 +++++++++++++++++++++------- tests/mgmt/notification-stream.cpp | 123 ++++++++++++++++++++ wscript | 2 +- 6 files changed, 362 insertions(+), 47 deletions(-) create mode 100644 daemon/mgmt/notification-stream.hpp create mode 100644 tests/mgmt/notification-stream.cpp diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp index 237a9145..e4769ff4 100644 --- a/daemon/mgmt/face-manager.cpp +++ b/daemon/mgmt/face-manager.cpp @@ -12,6 +12,8 @@ #include "face/tcp-factory.hpp" #include "face/udp-factory.hpp" +#include + #ifdef HAVE_UNIX_SOCKETS #include "face/unix-stream-factory.hpp" #endif // HAVE_UNIX_SOCKETS @@ -54,18 +56,24 @@ const FaceManager::UnsignedVerbAndProcessor FaceManager::UNSIGNED_COMMAND_VERBS[ Name::Component("list"), &FaceManager::listFaces ), + + UnsignedVerbAndProcessor( + Name::Component("events"), + &FaceManager::ignoreUnsignedVerb + ), }; const Name FaceManager::LIST_COMMAND_PREFIX("/localhost/nfd/faces/list"); const size_t FaceManager::LIST_COMMAND_NCOMPS = LIST_COMMAND_PREFIX.size(); - +const Name FaceManager::EVENTS_COMMAND_PREFIX("/localhost/nfd/faces/events"); FaceManager::FaceManager(FaceTable& faceTable, shared_ptr face) : ManagerBase(face, FACE_MANAGER_PRIVILEGE) , m_faceTable(faceTable) , m_statusPublisher(m_faceTable, m_face, LIST_COMMAND_PREFIX) + , m_notificationStream(m_face, EVENTS_COMMAND_PREFIX) , m_signedVerbDispatch(SIGNED_COMMAND_VERBS, SIGNED_COMMAND_VERBS + (sizeof(SIGNED_COMMAND_VERBS) / sizeof(SignedVerbAndProcessor))) @@ -76,6 +84,9 @@ FaceManager::FaceManager(FaceTable& faceTable, { face->setInterestFilter("/localhost/nfd/faces", bind(&FaceManager::onFaceRequest, this, _2)); + + m_faceTable.onAdd += bind(&FaceManager::onAddFace, this, _1); + m_faceTable.onRemove += bind(&FaceManager::onRemoveFace, this, _1); } FaceManager::~FaceManager() @@ -632,14 +643,34 @@ FaceManager::destroyFace(const Name& requestName, ndn::nfd::FaceManagementOptions& options) { shared_ptr target = m_faceTable.get(options.getFaceId()); - if (target) + if (static_cast(target)) { - // don't call m_faceTable.remove(target): it's called by target->close() via onFail target->close(); } sendResponse(requestName, 200, "Success"); } +void +FaceManager::onAddFace(shared_ptr face) +{ + ndn::nfd::FaceEventNotification faceCreated(ndn::nfd::FACE_EVENT_CREATED, + face->getId(), + face->getUri().toString()); + + m_notificationStream.postNotification(faceCreated); +} + +void +FaceManager::onRemoveFace(shared_ptr face) +{ + ndn::nfd::FaceEventNotification faceDestroyed(ndn::nfd::FACE_EVENT_DESTROYED, + face->getId(), + face->getUri().toString()); + + m_notificationStream.postNotification(faceDestroyed); +} + + void FaceManager::listFaces(const Interest& request) { diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp index 8efb5099..6787084d 100644 --- a/daemon/mgmt/face-manager.hpp +++ b/daemon/mgmt/face-manager.hpp @@ -13,6 +13,7 @@ #include "mgmt/manager-base.hpp" #include "mgmt/config-file.hpp" #include "mgmt/face-status-publisher.hpp" +#include "mgmt/notification-stream.hpp" #include "fw/face-table.hpp" #include @@ -69,6 +70,9 @@ PROTECTED_WITH_TESTS_ELSE_PRIVATE: destroyFace(const Name& requestName, ndn::nfd::FaceManagementOptions& options); + void + ignoreUnsignedVerb(const Interest& request); + bool extractOptions(const Interest& request, ndn::nfd::FaceManagementOptions& extractedOptions); @@ -81,6 +85,12 @@ PROTECTED_WITH_TESTS_ELSE_PRIVATE: void onConnectFailed(const Name& requestName, const std::string& reason); + void + onAddFace(shared_ptr face); + + void + onRemoveFace(shared_ptr face); + private: void onConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename); @@ -115,6 +125,7 @@ private: FactoryMap m_factories; FaceTable& m_faceTable; FaceStatusPublisher m_statusPublisher; + NotificationStream m_notificationStream; typedef function face, const Name& prefix); + + ~NotificationStream(); + + template void + postNotification(const T& notification); + +private: + shared_ptr m_face; + const Name m_prefix; + uint64_t m_sequenceNo; +}; + +inline +NotificationStream::NotificationStream(shared_ptr face, const Name& prefix) + : m_face(face) + , m_prefix(prefix) + , m_sequenceNo(0) +{ +} + +template +inline void +NotificationStream::postNotification(const T& notification) +{ + Name dataName(m_prefix); + dataName.appendSegment(m_sequenceNo); + shared_ptr data(make_shared(dataName)); + data->setContent(notification.wireEncode()); + + m_face->sign(*data); + m_face->put(*data); + + ++m_sequenceNo; +} + +inline +NotificationStream::~NotificationStream() +{ +} + +} // namespace nfd + + +#endif // NFD_MGMT_NOTIFICATION_STREAM_HPP diff --git a/tests/mgmt/face-manager.cpp b/tests/mgmt/face-manager.cpp index 310a4254..cca36718 100644 --- a/tests/mgmt/face-manager.cpp +++ b/tests/mgmt/face-manager.cpp @@ -1,12 +1,13 @@ -// /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -// /** -// * Copyright (C) 2014 Named Data Networking Project -// * See COPYING for copyright and distribution information. -// */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ #include "mgmt/face-manager.hpp" #include "mgmt/internal-face.hpp" #include "mgmt/face-status-publisher.hpp" + #include "face/face.hpp" #include "../face/dummy-face.hpp" #include "fw/face-table.hpp" @@ -18,6 +19,7 @@ #include "face-status-publisher-common.hpp" #include +#include namespace nfd { namespace tests { @@ -62,7 +64,6 @@ public: TestFaceTable(Forwarder& forwarder) : FaceTable(forwarder), m_addFired(false), - m_removeFired(false), m_getFired(false), m_dummy(make_shared()) { @@ -81,12 +82,6 @@ public: m_addFired = true; } -// virtual void -// remove(shared_ptr face) -// { -// m_removeFired = true; -// } - virtual shared_ptr get(FaceId id) const { @@ -100,12 +95,6 @@ public: return m_addFired; } -// bool -// didRemoveFire() const -// { -// return m_removeFired; -// } - bool didGetFire() const { @@ -116,7 +105,6 @@ public: reset() { m_addFired = false; - m_removeFired = false; m_getFired = false; } @@ -128,7 +116,6 @@ public: private: bool m_addFired; - bool m_removeFired; mutable bool m_getFired; shared_ptr m_dummy; }; @@ -292,12 +279,6 @@ public: return m_faceTable.didAddFire(); } -// bool -// didFaceTableRemoveFire() const -// { -// return m_faceTable.didRemoveFire(); -// } - bool didFaceTableGetFire() const { @@ -880,13 +861,33 @@ BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestDestroyFace, BOOST_CHECK(didDestroyFaceFire()); } -class FaceFixture : public TestFaceTableFixture, - public TestFaceManagerCommon, - public FaceManager +class FaceTableFixture +{ +public: + FaceTableFixture() + : m_faceTable(m_forwarder) + { + } + + virtual + ~FaceTableFixture() + { + } + +protected: + Forwarder m_forwarder; + FaceTable m_faceTable; +}; + +class FaceFixture : public FaceTableFixture, + public TestFaceManagerCommon, + public FaceManager { public: FaceFixture() - : FaceManager(TestFaceTableFixture::m_faceTable, TestFaceManagerCommon::m_face) + : FaceManager(FaceTableFixture::m_faceTable, + TestFaceManagerCommon::m_face) + , m_receivedNotification(false) { } @@ -896,6 +897,76 @@ public: { } + + void + callbackDispatch(const Data& response, + const Name& expectedName, + uint32_t expectedCode, + const std::string& expectedText, + const Block& expectedBody, + const ndn::nfd::FaceEventNotification& expectedFaceEvent) + { + Block payload = response.getContent().blockFromValue(); + if (payload.type() == ndn::tlv::nfd::ControlResponse) + { + validateControlResponse(response, expectedName, expectedCode, + expectedText, expectedBody); + } + else if (payload.type() == ndn::tlv::nfd::FaceEventNotification) + { + validateFaceEvent(payload, expectedFaceEvent); + } + else + { + BOOST_FAIL("Received unknown message type: #" << payload.type()); + } + } + + void + callbackDispatch(const Data& response, + const Name& expectedName, + uint32_t expectedCode, + const std::string& expectedText, + const ndn::nfd::FaceEventNotification& expectedFaceEvent) + { + Block payload = response.getContent().blockFromValue(); + if (payload.type() == ndn::tlv::nfd::ControlResponse) + { + validateControlResponse(response, expectedName, + expectedCode, expectedText); + } + else if (payload.type() == ndn::tlv::nfd::FaceEventNotification) + { + validateFaceEvent(payload, expectedFaceEvent); + } + else + { + BOOST_FAIL("Received unknown message type: #" << payload.type()); + } + } + + void + validateFaceEvent(const Block& wire, + const ndn::nfd::FaceEventNotification& expectedFaceEvent) + { + + m_receivedNotification = true; + + ndn::nfd::FaceEventNotification notification(wire); + + BOOST_CHECK_EQUAL(notification.getFaceId(), expectedFaceEvent.getFaceId()); + BOOST_CHECK_EQUAL(notification.getUri(), expectedFaceEvent.getUri()); + BOOST_CHECK_EQUAL(notification.getEventKind(), expectedFaceEvent.getEventKind()); + } + + bool + didReceiveNotication() const + { + return m_receivedNotification; + } + +protected: + bool m_receivedNotification; }; BOOST_FIXTURE_TEST_CASE(CreateFaceBadUri, AuthorizedCommandFixture) @@ -962,18 +1033,25 @@ BOOST_FIXTURE_TEST_CASE(OnCreated, AuthorizedCommandFixture) ndn::nfd::FaceManagementOptions resultOptions; resultOptions.setUri("tcp://127.0.0.1"); - resultOptions.setFaceId(-1); + resultOptions.setFaceId(1); + + shared_ptr dummy(make_shared()); + + ndn::nfd::FaceEventNotification expectedFaceEvent(ndn::nfd::FACE_EVENT_CREATED, + 1, + dummy->getUri().toString()); Block encodedResultOptions(resultOptions.wireEncode()); getFace()->onReceiveData += - bind(&FaceFixture::validateControlResponse, this, _1, - command->getName(), 200, "Success", encodedResultOptions); + bind(&FaceFixture::callbackDispatch, this, _1, + command->getName(), 200, "Success", + encodedResultOptions, expectedFaceEvent); - onCreated(command->getName(), options, make_shared()); + onCreated(command->getName(), options, dummy); BOOST_REQUIRE(didCallbackFire()); - BOOST_CHECK(TestFaceTableFixture::m_faceTable.didAddFire()); + BOOST_REQUIRE(didReceiveNotication()); } BOOST_FIXTURE_TEST_CASE(OnConnectFailed, AuthorizedCommandFixture) @@ -997,14 +1075,18 @@ BOOST_FIXTURE_TEST_CASE(OnConnectFailed, AuthorizedCommandFixture) onConnectFailed(command->getName(), "unit-test-reason"); BOOST_REQUIRE(didCallbackFire()); - BOOST_CHECK_EQUAL(TestFaceTableFixture::m_faceTable.didAddFire(), false); + BOOST_CHECK_EQUAL(didReceiveNotication(), false); } BOOST_FIXTURE_TEST_CASE(DestroyFace, AuthorizedCommandFixture) { + shared_ptr dummy(make_shared()); + FaceTableFixture::m_faceTable.add(dummy); + ndn::nfd::FaceManagementOptions options; options.setUri("tcp://127.0.0.1"); + options.setFaceId(dummy->getId()); Block encodedOptions(options.wireEncode()); @@ -1015,15 +1097,18 @@ BOOST_FIXTURE_TEST_CASE(DestroyFace, AuthorizedCommandFixture) shared_ptr command(make_shared(commandName)); generateCommand(*command); + ndn::nfd::FaceEventNotification expectedFaceEvent(ndn::nfd::FACE_EVENT_DESTROYED, + dummy->getId(), + dummy->getUri().toString()); + getFace()->onReceiveData += - bind(&FaceFixture::validateControlResponse, this, _1, - command->getName(), 200, "Success"); + bind(&FaceFixture::callbackDispatch, this, _1, + command->getName(), 200, "Success", expectedFaceEvent); destroyFace(command->getName(), options); BOOST_REQUIRE(didCallbackFire()); -// BOOST_CHECK(TestFaceTableFixture::m_faceTable.didRemoveFire()); - BOOST_CHECK(TestFaceTableFixture::m_faceTable.getDummyFace()->didCloseFire()); + BOOST_REQUIRE(didReceiveNotication()); } class FaceListFixture : public FaceStatusPublisherFixture @@ -1086,9 +1171,6 @@ BOOST_FIXTURE_TEST_CASE(TestFaceList, FaceListFixture) BOOST_REQUIRE(m_finished); } - - - BOOST_AUTO_TEST_SUITE_END() } // namespace tests diff --git a/tests/mgmt/notification-stream.cpp b/tests/mgmt/notification-stream.cpp new file mode 100644 index 00000000..1883a8e2 --- /dev/null +++ b/tests/mgmt/notification-stream.cpp @@ -0,0 +1,123 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/** + * Copyright (C) 2014 Named Data Networking Project + * See COPYING for copyright and distribution information. + */ + +#include "mgmt/notification-stream.hpp" +#include "mgmt/internal-face.hpp" + +#include "tests/test-common.hpp" + + +namespace nfd { +namespace tests { + +NFD_LOG_INIT("NotificationStreamTest"); + + + +class NotificationStreamFixture : public BaseFixture +{ +public: + NotificationStreamFixture() + : m_callbackFired(false) + , m_prefix("/localhost/nfd/NotificationStreamTest") + , m_message("TestNotificationMessage") + , m_sequenceNo(0) + { + } + + virtual + ~NotificationStreamFixture() + { + } + + void + validateCallback(const Data& data) + { + Name expectedName(m_prefix); + expectedName.appendSegment(m_sequenceNo); + BOOST_REQUIRE_EQUAL(data.getName(), expectedName); + + ndn::Block payload = data.getContent(); + std::string message; + + message.append(reinterpret_cast(payload.value()), payload.value_size()); + + BOOST_REQUIRE_EQUAL(message, m_message); + + m_callbackFired = true; + ++m_sequenceNo; + } + + void + resetCallbackFired() + { + m_callbackFired = false; + } + +protected: + bool m_callbackFired; + const std::string m_prefix; + const std::string m_message; + uint64_t m_sequenceNo; +}; + +BOOST_FIXTURE_TEST_SUITE(MgmtNotificationStream, NotificationStreamFixture) + +class TestNotification +{ +public: + TestNotification(const std::string& message) + : m_message(message) + { + } + + ~TestNotification() + { + } + + Block + wireEncode() const + { + ndn::EncodingBuffer buffer; + + prependByteArrayBlock(buffer, + ndn::Tlv::Content, + reinterpret_cast(m_message.c_str()), + m_message.size()); + return buffer.block(); + } + +private: + const std::string m_message; +}; + +BOOST_AUTO_TEST_CASE(TestPostEvent) +{ + shared_ptr face(make_shared()); + NotificationStream notificationStream(face, "/localhost/nfd/NotificationStreamTest"); + + face->onReceiveData += bind(&NotificationStreamFixture::validateCallback, this, _1); + + TestNotification event1(m_message); + notificationStream.postNotification(event1); + + BOOST_REQUIRE(m_callbackFired); + + resetCallbackFired(); + + TestNotification event2(m_message); + notificationStream.postNotification(event2); + + BOOST_REQUIRE(m_callbackFired); +} + + +BOOST_AUTO_TEST_SUITE_END() + + +} // namespace tests +} // namespace nfd + diff --git a/wscript b/wscript index af6d67ae..c728fa85 100644 --- a/wscript +++ b/wscript @@ -69,7 +69,7 @@ def configure(conf): conf.load('coverage') - conf.define('DEFAULT_CONFIG_FILE', '%s/nfd/nfd.conf' % conf.env['SYSCONFDIR']) + conf.define('DEFAULT_CONFIG_FILE', '%s/ndn/nfd.conf' % conf.env['SYSCONFDIR']) conf.write_config_header('daemon/config.hpp')