mgmt: add face/list support and general purpose data segementer

refs: #1245

Change-Id: I3769941022b7ed6e2a8d39622032e4e16909f645
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