mgmt: add face/list support and general purpose data segementer
refs: #1245
Change-Id: I3769941022b7ed6e2a8d39622032e4e16909f645
diff --git a/tests/mgmt/face-manager.cpp b/tests/mgmt/face-manager.cpp
index 191de04..80e14d7 100644
--- a/tests/mgmt/face-manager.cpp
+++ b/tests/mgmt/face-manager.cpp
@@ -6,6 +6,7 @@
#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"
@@ -14,24 +15,27 @@
#include "common.hpp"
#include "tests/test-common.hpp"
#include "validation-common.hpp"
+#include "face-status-publisher-common.hpp"
+
+#include <ndn-cpp-dev/encoding/tlv.hpp>
namespace nfd {
namespace tests {
NFD_LOG_INIT("FaceManagerTest");
-class TestDummyFace : public DummyFace
+class FaceManagerTestFace : public DummyFace
{
public:
- TestDummyFace()
+ FaceManagerTestFace()
: m_closeFired(false)
{
}
virtual
- ~TestDummyFace()
+ ~FaceManagerTestFace()
{
}
@@ -60,7 +64,7 @@
m_addFired(false),
m_removeFired(false),
m_getFired(false),
- m_dummy(make_shared<TestDummyFace>())
+ m_dummy(make_shared<FaceManagerTestFace>())
{
}
@@ -116,7 +120,7 @@
m_getFired = false;
}
- shared_ptr<TestDummyFace>&
+ shared_ptr<FaceManagerTestFace>&
getDummyFace()
{
return m_dummy;
@@ -126,7 +130,7 @@
bool m_addFired;
bool m_removeFired;
mutable bool m_getFired;
- shared_ptr<TestDummyFace> m_dummy;
+ shared_ptr<FaceManagerTestFace> m_dummy;
};
@@ -257,18 +261,18 @@
m_manager.setConfigFile(m_config);
}
- void
- parseConfig(const std::string configuration, bool isDryRun)
- {
- m_config.parse(configuration, isDryRun, "dummy-config");
- }
-
virtual
~FaceManagerFixture()
{
}
+ void
+ parseConfig(const std::string configuration, bool isDryRun)
+ {
+ m_config.parse(configuration, isDryRun, "dummy-config");
+ }
+
FaceManager&
getManager()
{
@@ -1022,8 +1026,72 @@
BOOST_CHECK(TestFaceTableFixture::m_faceTable.getDummyFace()->didCloseFire());
}
+class FaceListFixture : public FaceStatusPublisherFixture
+{
+public:
+ FaceListFixture()
+ : m_manager(m_table, m_face)
+ {
+
+ }
+
+ virtual
+ ~FaceListFixture()
+ {
+
+ }
+
+protected:
+ FaceManager m_manager;
+};
+
+BOOST_FIXTURE_TEST_CASE(TestFaceList, FaceListFixture)
+
+{
+ Name commandName("/localhost/nfd/faces/list");
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+
+ // MAX_SEGMENT_SIZE == 4400, FaceStatus size with filler counters is 55
+ // 55 divides 4400 (== 80), so only use 79 FaceStatuses and then two smaller ones
+ // to force a FaceStatus to span Data packets
+ for (int i = 0; i < 79; i++)
+ {
+ shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>());
+
+ uint64_t filler = std::numeric_limits<uint64_t>::max() - 1;
+ dummy->setCounters(filler, filler, filler, filler);
+
+ m_referenceFaces.push_front(dummy);
+
+ add(dummy);
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>());
+ uint64_t filler = std::numeric_limits<uint32_t>::max() - 1;
+ dummy->setCounters(filler, filler, filler, filler);
+
+ m_referenceFaces.push_front(dummy);
+
+ add(dummy);
+ }
+
+ ndn::EncodingBuffer buffer;
+
+ m_face->onReceiveData +=
+ bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1);
+
+ m_manager.listFaces(*command);
+ BOOST_REQUIRE(m_finished);
+}
+
+
+
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace tests
} // namespace nfd
+
diff --git a/tests/mgmt/face-status-publisher-common.hpp b/tests/mgmt/face-status-publisher-common.hpp
new file mode 100644
index 0000000..e6ff706
--- /dev/null
+++ b/tests/mgmt/face-status-publisher-common.hpp
@@ -0,0 +1,219 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TESTS_MGMT_FACE_STATUS_PUBLISHER_COMMON_HPP
+#define NFD_TESTS_MGMT_FACE_STATUS_PUBLISHER_COMMON_HPP
+
+#include "mgmt/face-status-publisher.hpp"
+#include "mgmt/app-face.hpp"
+#include "mgmt/internal-face.hpp"
+#include "fw/forwarder.hpp"
+#include "../face/dummy-face.hpp"
+
+#include "tests/test-common.hpp"
+
+#include <ndn-cpp-dev/encoding/tlv.hpp>
+
+namespace nfd {
+namespace tests {
+
+class TestCountersFace : public DummyFace
+{
+public:
+
+ TestCountersFace()
+ {
+ }
+
+ virtual
+ ~TestCountersFace()
+ {
+ }
+
+ void
+ setCounters(FaceCounter inInterest,
+ FaceCounter inData,
+ FaceCounter outInterest,
+ FaceCounter outData)
+ {
+ FaceCounters& counters = getMutableCounters();
+ counters.getInInterest() = inInterest;
+ counters.getInData() = inData;
+ counters.getOutInterest() = outInterest;
+ counters.getOutData() = outData;
+ }
+
+
+};
+
+static inline uint64_t
+readNonNegativeIntegerType(const Block& block,
+ uint32_t type)
+{
+ if (block.type() == type)
+ {
+ return readNonNegativeInteger(block);
+ }
+ std::stringstream error;
+ error << "expected type " << type << " got " << block.type();
+ throw ndn::Tlv::Error(error.str());
+}
+
+static inline uint64_t
+checkedReadNonNegativeIntegerType(Block::element_const_iterator& i,
+ Block::element_const_iterator end,
+ uint32_t type)
+{
+ if (i != end)
+ {
+ const Block& block = *i;
+ ++i;
+ return readNonNegativeIntegerType(block, type);
+ }
+ throw ndn::Tlv::Error("Unexpected end of FaceStatus");
+}
+
+class FaceStatusPublisherFixture : public BaseFixture
+{
+public:
+
+ FaceStatusPublisherFixture()
+ : m_table(m_forwarder)
+ , m_face(make_shared<InternalFace>())
+ , m_publisher(m_table, m_face, "/localhost/nfd/FaceStatusPublisherFixture")
+ , m_finished(false)
+ {
+
+ }
+
+ virtual
+ ~FaceStatusPublisherFixture()
+ {
+
+ }
+
+ void
+ add(shared_ptr<Face> face)
+ {
+ m_table.add(face);
+ }
+
+ void
+ validateFaceStatus(const Block& status, const shared_ptr<Face>& reference)
+ {
+ const FaceCounters& counters = reference->getCounters();
+
+ FaceId faceId = INVALID_FACEID;
+ std::string uri;
+ FaceCounter inInterest = 0;
+ FaceCounter inData = 0;
+ FaceCounter outInterest = 0;
+ FaceCounter outData = 0;
+
+ status.parse();
+
+ for (Block::element_const_iterator i = status.elements_begin();
+ i != status.elements_end();
+ ++i)
+ {
+ // parse a full set of FaceStatus sub-blocks
+ faceId =
+ checkedReadNonNegativeIntegerType(i,
+ status.elements_end(),
+ ndn::tlv::nfd::FaceId);
+
+ BOOST_REQUIRE_EQUAL(faceId, reference->getId());
+
+ BOOST_REQUIRE(i->type() == ndn::tlv::nfd::Uri);
+
+ uri.append(reinterpret_cast<const char*>(i->value()), i->value_size());
+ ++i;
+
+ BOOST_REQUIRE(i != status.elements_end());
+
+ BOOST_REQUIRE_EQUAL(uri, reference->getUri().toString());
+
+ inInterest =
+ checkedReadNonNegativeIntegerType(i,
+ status.elements_end(),
+ ndn::tlv::nfd::TotalIncomingInterestCounter);
+
+ BOOST_REQUIRE_EQUAL(inInterest, counters.getInInterest());
+
+ inData =
+ checkedReadNonNegativeIntegerType(i,
+ status.elements_end(),
+ ndn::tlv::nfd::TotalIncomingDataCounter);
+
+ BOOST_REQUIRE_EQUAL(inData, counters.getInData());
+
+ outInterest =
+ checkedReadNonNegativeIntegerType(i,
+ status.elements_end(),
+ ndn::tlv::nfd::TotalOutgoingInterestCounter);
+ BOOST_REQUIRE_EQUAL(outInterest, counters.getOutInterest());
+
+ outData =
+ readNonNegativeIntegerType(*i,
+ ndn::tlv::nfd::TotalOutgoingDataCounter);
+
+ BOOST_REQUIRE_EQUAL(outData, counters.getOutData());
+ }
+ }
+
+ void
+ decodeFaceStatusBlock(const Data& data)
+ {
+ Block payload = data.getContent();
+
+ m_buffer.appendByteArray(payload.value(), payload.value_size());
+
+ uint64_t segmentNo = data.getName()[-1].toSegment();
+ if (data.getFinalBlockId() != data.getName()[-1])
+ {
+ return;
+ }
+
+ // wrap the Face Statuses in a single Content TLV for easy parsing
+ m_buffer.prependVarNumber(m_buffer.size());
+ m_buffer.prependVarNumber(ndn::Tlv::Content);
+
+ ndn::Block parser(m_buffer.buf(), m_buffer.size());
+ parser.parse();
+
+ BOOST_REQUIRE_EQUAL(parser.elements_size(), m_referenceFaces.size());
+
+ std::list<shared_ptr<Face> >::const_iterator iReference = m_referenceFaces.begin();
+ for (Block::element_const_iterator i = parser.elements_begin();
+ i != parser.elements_end();
+ ++i)
+ {
+ if (i->type() != ndn::tlv::nfd::FaceStatus)
+ {
+ BOOST_FAIL("expected face status, got type #" << i->type());
+ }
+ validateFaceStatus(*i, *iReference);
+ ++iReference;
+ }
+ m_finished = true;
+ }
+
+protected:
+ Forwarder m_forwarder;
+ FaceTable m_table;
+ shared_ptr<InternalFace> m_face;
+ FaceStatusPublisher m_publisher;
+ ndn::EncodingBuffer m_buffer;
+ std::list<shared_ptr<Face> > m_referenceFaces;
+
+protected:
+ bool m_finished;
+};
+
+} // namespace tests
+} // namespace nfd
+
+#endif // NFD_TESTS_MGMT_FACE_STATUS_PUBLISHER_COMMON_HPP
diff --git a/tests/mgmt/face-status-publisher.cpp b/tests/mgmt/face-status-publisher.cpp
new file mode 100644
index 0000000..eb9946c
--- /dev/null
+++ b/tests/mgmt/face-status-publisher.cpp
@@ -0,0 +1,59 @@
+/* -*- 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 "face-status-publisher-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+NFD_LOG_INIT("FaceStatusPublisherTest");
+
+BOOST_FIXTURE_TEST_SUITE(MgmtFaceManager, FaceStatusPublisherFixture)
+
+BOOST_AUTO_TEST_CASE(TestFaceStatusPublisher)
+{
+ Name commandName("/localhost/nfd/faces/list");
+ shared_ptr<Interest> command(make_shared<Interest>(commandName));
+
+ // MAX_SEGMENT_SIZE == 4400, FaceStatus size with filler counters is 55
+ // 55 divides 4400 (== 80), so only use 79 FaceStatuses and then two smaller ones
+ // to force a FaceStatus to span Data packets
+ for (int i = 0; i < 79; i++)
+ {
+ shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>());
+
+ uint64_t filler = std::numeric_limits<uint64_t>::max() - 1;
+ dummy->setCounters(filler, filler, filler, filler);
+
+ m_referenceFaces.push_front(dummy);
+
+ add(dummy);
+ }
+
+ for (int i = 0; i < 2; i++)
+ {
+ shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>());
+ uint64_t filler = std::numeric_limits<uint32_t>::max() - 1;
+ dummy->setCounters(filler, filler, filler, filler);
+
+ m_referenceFaces.push_front(dummy);
+
+ add(dummy);
+ }
+
+ ndn::EncodingBuffer buffer;
+
+ m_face->onReceiveData +=
+ bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1);
+
+ m_publisher.publish();
+ BOOST_REQUIRE(m_finished);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/mgmt/segment-publisher.cpp b/tests/mgmt/segment-publisher.cpp
new file mode 100644
index 0000000..0d65ee6
--- /dev/null
+++ b/tests/mgmt/segment-publisher.cpp
@@ -0,0 +1,133 @@
+/* -*- 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/segment-publisher.hpp"
+#include "mgmt/internal-face.hpp"
+#include "mgmt/app-face.hpp"
+
+#include "tests/test-common.hpp"
+#include <ndn-cpp-dev/encoding/tlv.hpp>
+
+namespace nfd {
+namespace tests {
+
+NFD_LOG_INIT("SegmentPublisherTest");
+
+class TestSegmentPublisher : public SegmentPublisher
+{
+public:
+ TestSegmentPublisher(shared_ptr<AppFace> face,
+ const Name& prefix,
+ const uint64_t limit=10000)
+ : SegmentPublisher(face, prefix)
+ , m_limit((limit == 0)?(1):(limit))
+ {
+
+ }
+
+ virtual
+ ~TestSegmentPublisher()
+ {
+
+ }
+
+ uint16_t
+ getLimit() const
+ {
+ return m_limit;
+ }
+
+protected:
+
+ virtual size_t
+ generate(ndn::EncodingBuffer& outBuffer)
+ {
+ size_t totalLength = 0;
+ for (uint64_t i = 0; i < m_limit; i++)
+ {
+ totalLength += prependNonNegativeIntegerBlock(outBuffer, ndn::Tlv::Content, i);
+ }
+ return totalLength;
+ }
+
+protected:
+ const uint64_t m_limit;
+};
+
+class SegmentPublisherFixture : public BaseFixture
+{
+public:
+ SegmentPublisherFixture()
+ : m_face(make_shared<InternalFace>())
+ , m_publisher(m_face, "/localhost/nfd/SegmentPublisherFixture")
+ , m_finished(false)
+ {
+
+ }
+
+ void
+ validate(const Data& data)
+ {
+ Block payload = data.getContent();
+ NFD_LOG_DEBUG("payload size (w/o Content TLV): " << payload.value_size());
+
+ m_buffer.appendByteArray(payload.value(), payload.value_size());
+
+ uint64_t segmentNo = data.getName()[-1].toSegment();
+ if (data.getFinalBlockId() != data.getName()[-1])
+ {
+ return;
+ }
+
+ NFD_LOG_DEBUG("got final block: #" << segmentNo);
+
+ // wrap data in a single Content TLV for easy parsing
+ m_buffer.prependVarNumber(m_buffer.size());
+ m_buffer.prependVarNumber(ndn::Tlv::Content);
+
+ BOOST_TEST_CHECKPOINT("creating parser");
+ ndn::Block parser(m_buffer.buf(), m_buffer.size());
+ BOOST_TEST_CHECKPOINT("parsing aggregated response");
+ parser.parse();
+
+ BOOST_REQUIRE_EQUAL(parser.elements_size(), m_publisher.getLimit());
+
+ uint64_t expectedNo = m_publisher.getLimit() - 1;
+ for (Block::element_const_iterator i = parser.elements_begin();
+ i != parser.elements_end();
+ ++i)
+ {
+ uint64_t number = readNonNegativeInteger(*i);
+ BOOST_REQUIRE_EQUAL(number, expectedNo);
+ --expectedNo;
+ }
+ m_finished = true;
+ }
+
+protected:
+ shared_ptr<InternalFace> m_face;
+ TestSegmentPublisher m_publisher;
+ ndn::EncodingBuffer m_buffer;
+
+protected:
+ bool m_finished;
+};
+
+BOOST_FIXTURE_TEST_SUITE(MgmtSegmentPublisher, SegmentPublisherFixture)
+
+BOOST_AUTO_TEST_CASE(Generate)
+{
+ m_face->onReceiveData +=
+ bind(&SegmentPublisherFixture::validate, this, _1);
+
+ m_publisher.publish();
+ BOOST_REQUIRE(m_finished);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nfd