tools: refactor nfd-status
refs #3658
Change-Id: Ia347074bea802eba5f539208e276e849a60db8a4
diff --git a/tests/tools/nfd-status/channel-module.t.cpp b/tests/tools/nfd-status/channel-module.t.cpp
new file mode 100644
index 0000000..f524907
--- /dev/null
+++ b/tests/tools/nfd-status/channel-module.t.cpp
@@ -0,0 +1,75 @@
+/* -*- 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 "nfd-status/channel-module.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestChannelModule, ModuleFixture<ChannelModule>)
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <channels>
+ <channel>
+ <localUri>tcp4://192.0.2.1:6363</localUri>
+ </channel>
+ <channel>
+ <localUri>ws://[::]:9696/NFD</localUri>
+ </channel>
+ </channels>
+)XML");
+
+const std::string STATUS_TEXT = std::string(R"TEXT(
+Channels:
+ tcp4://192.0.2.1:6363
+ ws://[::]:9696/NFD
+)TEXT").substr(1);
+
+BOOST_AUTO_TEST_CASE(Status)
+{
+ this->fetchStatus();
+ ChannelStatus payload1;
+ payload1.setLocalUri("tcp4://192.0.2.1:6363");
+ ChannelStatus payload2;
+ payload2.setLocalUri("ws://[::]:9696/NFD");
+ this->sendDataset("/localhost/nfd/faces/channels", payload1, payload2);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestChannelModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/face-module.t.cpp b/tests/tools/nfd-status/face-module.t.cpp
new file mode 100644
index 0000000..292ccd8
--- /dev/null
+++ b/tests/tools/nfd-status/face-module.t.cpp
@@ -0,0 +1,146 @@
+/* -*- 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 "nfd-status/face-module.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestFaceModule, ModuleFixture<FaceModule>)
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <faces>
+ <face>
+ <faceId>134</faceId>
+ <remoteUri>udp4://233.252.0.4:6363</remoteUri>
+ <localUri>udp4://192.0.2.1:6363</localUri>
+ <faceScope>non-local</faceScope>
+ <facePersistency>permanent</facePersistency>
+ <linkType>multi-access</linkType>
+ <packetCounters>
+ <incomingPackets>
+ <nInterests>22562</nInterests>
+ <nDatas>22031</nDatas>
+ <nNacks>63</nNacks>
+ </incomingPackets>
+ <outgoingPackets>
+ <nInterests>30121</nInterests>
+ <nDatas>20940</nDatas>
+ <nNacks>1218</nNacks>
+ </outgoingPackets>
+ </packetCounters>
+ <byteCounters>
+ <incomingBytes>2522915</incomingBytes>
+ <outgoingBytes>1353592</outgoingBytes>
+ </byteCounters>
+ </face>
+ <face>
+ <faceId>745</faceId>
+ <remoteUri>fd://75</remoteUri>
+ <localUri>unix:///var/run/nfd.sock</localUri>
+ <faceScope>local</faceScope>
+ <facePersistency>on-demand</facePersistency>
+ <linkType>point-to-point</linkType>
+ <packetCounters>
+ <incomingPackets>
+ <nInterests>18998</nInterests>
+ <nDatas>26701</nDatas>
+ <nNacks>147</nNacks>
+ </incomingPackets>
+ <outgoingPackets>
+ <nInterests>34779</nInterests>
+ <nDatas>17028</nDatas>
+ <nNacks>1176</nNacks>
+ </outgoingPackets>
+ </packetCounters>
+ <byteCounters>
+ <incomingBytes>4672308</incomingBytes>
+ <outgoingBytes>8957187</outgoingBytes>
+ </byteCounters>
+ </face>
+ </faces>
+)XML");
+
+const std::string STATUS_TEXT =
+ "Faces:\n"
+ " faceid=134 remote=udp4://233.252.0.4:6363 local=udp4://192.0.2.1:6363"
+ " counters={in={22562i 22031d 63n 2522915B} out={30121i 20940d 1218n 1353592B}}"
+ " non-local permanent multi-access\n"
+ " faceid=745 remote=fd://75 local=unix:///var/run/nfd.sock"
+ " counters={in={18998i 26701d 147n 4672308B} out={34779i 17028d 1176n 8957187B}}"
+ " local on-demand point-to-point\n";
+
+BOOST_AUTO_TEST_CASE(Status)
+{
+ this->fetchStatus();
+ FaceStatus payload1;
+ payload1.setFaceId(134)
+ .setRemoteUri("udp4://233.252.0.4:6363")
+ .setLocalUri("udp4://192.0.2.1:6363")
+ .setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL)
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT)
+ .setLinkType(ndn::nfd::LINK_TYPE_MULTI_ACCESS)
+ .setNInInterests(22562)
+ .setNInDatas(22031)
+ .setNInNacks(63)
+ .setNOutInterests(30121)
+ .setNOutDatas(20940)
+ .setNOutNacks(1218)
+ .setNInBytes(2522915)
+ .setNOutBytes(1353592);
+ FaceStatus payload2;
+ payload2.setFaceId(745)
+ .setRemoteUri("fd://75")
+ .setLocalUri("unix:///var/run/nfd.sock")
+ .setFaceScope(ndn::nfd::FACE_SCOPE_LOCAL)
+ .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND)
+ .setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT)
+ .setNInInterests(18998)
+ .setNInDatas(26701)
+ .setNInNacks(147)
+ .setNOutInterests(34779)
+ .setNOutDatas(17028)
+ .setNOutNacks(1176)
+ .setNInBytes(4672308)
+ .setNOutBytes(8957187);
+ this->sendDataset("/localhost/nfd/faces/list", payload1, payload2);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestFaceModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/fib-module.t.cpp b/tests/tools/nfd-status/fib-module.t.cpp
new file mode 100644
index 0000000..f509461
--- /dev/null
+++ b/tests/tools/nfd-status/fib-module.t.cpp
@@ -0,0 +1,104 @@
+/* -*- 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 "nfd-status/fib-module.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestFibModule, ModuleFixture<FibModule>)
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <fib>
+ <fibEntry>
+ <prefix>/</prefix>
+ <nextHops>
+ <nextHop>
+ <faceId>262</faceId>
+ <cost>9</cost>
+ </nextHop>
+ <nextHop>
+ <faceId>272</faceId>
+ <cost>50</cost>
+ </nextHop>
+ <nextHop>
+ <faceId>274</faceId>
+ <cost>78</cost>
+ </nextHop>
+ </nextHops>
+ </fibEntry>
+ <fibEntry>
+ <prefix>/localhost/nfd</prefix>
+ <nextHops>
+ <nextHop>
+ <faceId>1</faceId>
+ <cost>0</cost>
+ </nextHop>
+ <nextHop>
+ <faceId>274</faceId>
+ <cost>0</cost>
+ </nextHop>
+ </nextHops>
+ </fibEntry>
+ </fib>
+)XML");
+
+const std::string STATUS_TEXT = std::string(R"TEXT(
+FIB:
+ / nexthops={faceid=262 (cost=9), faceid=272 (cost=50), faceid=274 (cost=78)}
+ /localhost/nfd nexthops={faceid=1 (cost=0), faceid=274 (cost=0)}
+)TEXT").substr(1);
+
+BOOST_AUTO_TEST_CASE(Status)
+{
+ this->fetchStatus();
+ FibEntry payload1;
+ payload1.setPrefix("/")
+ .addNextHopRecord(NextHopRecord().setFaceId(262).setCost(9))
+ .addNextHopRecord(NextHopRecord().setFaceId(272).setCost(50))
+ .addNextHopRecord(NextHopRecord().setFaceId(274).setCost(78));
+ FibEntry payload2;
+ payload2.setPrefix("/localhost/nfd")
+ .addNextHopRecord(NextHopRecord().setFaceId(1).setCost(0))
+ .addNextHopRecord(NextHopRecord().setFaceId(274).setCost(0));
+ this->sendDataset("/localhost/nfd/fib/list", payload1, payload2);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestFibModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/format-helpers.t.cpp b/tests/tools/nfd-status/format-helpers.t.cpp
new file mode 100644
index 0000000..01d7f47
--- /dev/null
+++ b/tests/tools/nfd-status/format-helpers.t.cpp
@@ -0,0 +1,74 @@
+/* -*- 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 "nfd-status/format-helpers.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+using boost::test_tools::output_test_stream;
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_AUTO_TEST_SUITE(TestFormatHelpers)
+
+BOOST_AUTO_TEST_SUITE(Xml)
+
+BOOST_AUTO_TEST_CASE(TextEscaping)
+{
+ output_test_stream os;
+ os << xml::Text{"\"less than\" & 'greater than' surround XML <element> tag name"};
+
+ BOOST_CHECK(os.is_equal(""less than" & 'greater than'"
+ " surround XML <element> tag name"));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Xml
+
+BOOST_AUTO_TEST_SUITE(Text)
+
+BOOST_AUTO_TEST_CASE(Sep)
+{
+ output_test_stream os;
+ text::Separator sep(",");
+ for (int i = 1; i <= 3; ++i) {
+ os << sep << i;
+ }
+
+ BOOST_CHECK(os.is_equal("1,2,3"));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Text
+
+BOOST_AUTO_TEST_SUITE_END() // TestFormatHelpers
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/forwarder-general-module.t.cpp b/tests/tools/nfd-status/forwarder-general-module.t.cpp
new file mode 100644
index 0000000..e9c881b
--- /dev/null
+++ b/tests/tools/nfd-status/forwarder-general-module.t.cpp
@@ -0,0 +1,156 @@
+/* -*- 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 "nfd-status/forwarder-general-module.hpp"
+#include <ndn-cxx/security/signing-helpers.hpp>
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestForwarderGeneralModule, ModuleFixture<ForwarderGeneralModule>)
+
+class MakeNfdIdCollector
+{
+public:
+ unique_ptr<NfdIdCollector>
+ operator()(Face&, KeyChain&) const
+ {
+ return make_unique<NfdIdCollector>(make_unique<ValidatorNull>());
+ };
+};
+
+class ForwarderGeneralStatusFixture : public ModuleFixture<ForwarderGeneralModule,
+ MakeNfdIdCollector>
+{
+protected:
+ ForwarderGeneralStatusFixture()
+ {
+ module.setNfdIdCollector(*validator);
+
+ this->systemClock->setNow(time::seconds(1468784936));
+ BOOST_REQUIRE(this->addIdentity("/nfd-status/test-nfdid"));
+ }
+
+private:
+ virtual void
+ signDatasetReply(Data& data) override
+ {
+ m_keyChain.sign(data, ndn::security::signingByIdentity("/nfd-status/test-nfdid"));
+ }
+};
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <generalStatus>
+ <nfdId>/nfd-status/test-nfdid/KEY/ksk-1468784936000/ID-CERT</nfdId>
+ <version>0.4.1-1-g704430c</version>
+ <startTime>2016-06-24T15:13:46.856000</startTime>
+ <currentTime>2016-07-17T17:55:54.109000</currentTime>
+ <uptime>PT1996927S</uptime>
+ <nNameTreeEntries>668</nNameTreeEntries>
+ <nFibEntries>70</nFibEntries>
+ <nPitEntries>7</nPitEntries>
+ <nMeasurementsEntries>1</nMeasurementsEntries>
+ <nCsEntries>65536</nCsEntries>
+ <packetCounters>
+ <incomingPackets>
+ <nInterests>20699052</nInterests>
+ <nDatas>5598070</nDatas>
+ <nNacks>7230</nNacks>
+ </incomingPackets>
+ <outgoingPackets>
+ <nInterests>36501092</nInterests>
+ <nDatas>5671942</nDatas>
+ <nNacks>26762</nNacks>
+ </outgoingPackets>
+ </packetCounters>
+ </generalStatus>
+)XML");
+
+const std::string STATUS_TEXT = std::string(R"TEXT(
+General NFD status:
+ nfdId=/nfd-status/test-nfdid/KEY/ksk-1468784936000/ID-CERT
+ version=0.4.1-1-g704430c
+ startTime=20160624T151346.856000
+ currentTime=20160717T175554.109000
+ uptime=1996927 seconds
+ nNameTreeEntries=668
+ nFibEntries=70
+ nPitEntries=7
+ nMeasurementsEntries=1
+ nCsEntries=65536
+ nInInterests=20699052
+ nOutInterests=36501092
+ nInDatas=5598070
+ nOutDatas=5671942
+ nInNacks=7230
+ nOutNacks=26762
+)TEXT").substr(1);
+
+BOOST_FIXTURE_TEST_CASE(Status, ForwarderGeneralStatusFixture)
+{
+ this->fetchStatus();
+ ForwarderStatus payload;
+ payload.setNfdVersion("0.4.1-1-g704430c")
+ .setStartTimestamp(time::fromUnixTimestamp(time::milliseconds(1466781226856)))
+ .setCurrentTimestamp(time::fromUnixTimestamp(time::milliseconds(1468778154109)))
+ .setNNameTreeEntries(668)
+ .setNFibEntries(70)
+ .setNPitEntries(7)
+ .setNMeasurementsEntries(1)
+ .setNCsEntries(65536)
+ .setNInInterests(20699052)
+ .setNInDatas(5598070)
+ .setNInNacks(7230)
+ .setNOutInterests(36501092)
+ .setNOutDatas(5671942)
+ .setNOutNacks(26762);
+ this->sendDataset("/localhost/nfd/status/general", payload);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_CASE(StatusNoNfdId)
+{
+ this->fetchStatus();
+ ForwarderStatus payload;
+ payload.setNfdVersion("0.4.1-1-g704430c");
+ this->sendDataset("/localhost/nfd/status/general", payload);
+ BOOST_CHECK_NO_THROW(this->prepareStatusOutput());
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestForwarderGeneralModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/module-fixture.hpp b/tests/tools/nfd-status/module-fixture.hpp
new file mode 100644
index 0000000..38d0d64
--- /dev/null
+++ b/tests/tools/nfd-status/module-fixture.hpp
@@ -0,0 +1,236 @@
+/* -*- 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/>.
+ */
+
+#ifndef NFD_TESTS_TOOLS_NFD_STATUS_MODULE_FIXTURE_HPP
+#define NFD_TESTS_TOOLS_NFD_STATUS_MODULE_FIXTURE_HPP
+
+#include "nfd-status/module.hpp"
+#include <ndn-cxx/security/validator-null.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+#include "tests/test-common.hpp"
+#include "tests/identity-management-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+using namespace nfd::tests;
+using ndn::Face;
+using ndn::KeyChain;
+using ndn::Validator;
+using ndn::ValidatorNull;
+using ndn::util::DummyClientFace;
+using boost::test_tools::output_test_stream;
+
+class MakeValidatorNull
+{
+public:
+ unique_ptr<ValidatorNull>
+ operator()(Face&, KeyChain&) const
+ {
+ return make_unique<ValidatorNull>();
+ };
+};
+
+/** \brief fixture to test a \p Module
+ * \tparam MODULE a subclass of \p Module
+ * \tparam MakeValidator a callable to make a Validator for use in \p controller;
+ * MakeValidator()(Face&, KeyChain&) should return a unique_ptr
+ * to Validator or its subclass
+ */
+template<typename MODULE, typename MakeValidator = MakeValidatorNull>
+class ModuleFixture : public UnitTestTimeFixture
+ , public IdentityManagementFixture
+{
+protected:
+ typedef typename std::result_of<MakeValidator(Face&, KeyChain&)>::type ValidatorUniquePtr;
+
+ ModuleFixture()
+ : face(g_io, m_keyChain)
+ , validator(MakeValidator()(face, m_keyChain))
+ , controller(face, m_keyChain, *validator)
+ , nFetchStatusSuccess(0)
+ {
+ }
+
+protected: // status fetching
+ /** \brief start fetching status
+ *
+ * A test case should call \p fetchStatus, \p sendDataset, and \p prepareStatusOutput
+ * in this order, and then check \p statusXml and \p statusText contain the correct outputs.
+ * No advanceClocks is needed in between, as they are handled by the fixture.
+ */
+ void
+ fetchStatus()
+ {
+ nFetchStatusSuccess = 0;
+ module.fetchStatus(controller, [this] { ++nFetchStatusSuccess; },
+ [this] (uint32_t code, const std::string& reason) {
+ BOOST_FAIL("fetchStatus failure " << code << " " << reason);
+ },
+ CommandOptions());
+ this->advanceClocks(time::milliseconds(1));
+ }
+
+ /** \brief send one WireEncodable in reply to StatusDataset request
+ * \param prefix dataset prefix without version and segment
+ * \param payload payload block
+ * \note payload must fit in one Data
+ * \pre fetchStatus has been invoked, sendDataset has not been invoked
+ */
+ template<typename T>
+ void
+ sendDataset(const Name& prefix, const T& payload)
+ {
+ BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
+
+ this->sendDatasetReply(prefix, payload.wireEncode());
+ }
+
+ /** \brief send two WireEncodables in reply to StatusDataset request
+ * \param prefix dataset prefix without version and segment
+ * \param payload1 first vector item
+ * \param payload2 second vector item
+ * \note all payloads must fit in one Data
+ * \pre fetchStatus has been invoked, sendDataset has not been invoked
+ */
+ template<typename T1, typename T2>
+ void
+ sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
+ {
+ BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
+ BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
+
+ ndn::encoding::EncodingBuffer buffer;
+ payload2.wireEncode(buffer);
+ payload1.wireEncode(buffer);
+
+ this->sendDatasetReply(prefix, buffer.buf(), buffer.size());
+ }
+
+ /** \brief prepare status output as XML and text
+ * \pre sendDataset has been invoked
+ */
+ void
+ prepareStatusOutput()
+ {
+ this->advanceClocks(time::milliseconds(1));
+ BOOST_REQUIRE_EQUAL(nFetchStatusSuccess, 1);
+
+ statusXml.str("");
+ module.formatStatusXml(statusXml);
+ statusText.str("");
+ module.formatStatusText(statusText);
+ }
+
+private:
+ /** \brief send a payload in reply to StatusDataset request
+ * \param prefix dataset prefix without version and segment
+ * \param contentArgs passed to Data::setContent
+ */
+ template<typename ...ContentArgs>
+ void
+ sendDatasetReply(const Name& prefix, ContentArgs&&...contentArgs)
+ {
+ Name name = prefix;
+ name.appendVersion().appendSegment(0);
+
+ // These warnings assist in debugging a `nFetchStatusSuccess != 1` check failure.
+ // They usually indicate a misspelled prefix or incorrect timing in the test case.
+ if (face.sentInterests.size() < 1) {
+ BOOST_WARN_MESSAGE(false, "no Interest expressed");
+ }
+ else {
+ BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
+ "last Interest " << face.sentInterests.back().getName() <<
+ " cannot be satisfied by this Data " << name);
+ }
+
+ auto data = make_shared<Data>(name);
+ data->setFinalBlockId(name[-1]);
+ data->setContent(std::forward<ContentArgs>(contentArgs)...);
+ this->signDatasetReply(*data);
+ face.receive(*data);
+ }
+
+ virtual void
+ signDatasetReply(Data& data)
+ {
+ signData(data);
+ }
+
+protected:
+ DummyClientFace face;
+ ValidatorUniquePtr validator;
+ Controller controller;
+
+ MODULE module;
+
+ int nFetchStatusSuccess;
+ output_test_stream statusXml;
+ output_test_stream statusText;
+};
+
+/** \brief strips leading spaces on every line in expected XML
+ *
+ * This allows expected XML to be written as:
+ * \code
+ * const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ * <rootElement>
+ * <element>value</element>
+ * </rootElement>
+ * )XML");
+ * \endcode
+ * And \p STATUS_XML would be assigned:
+ * \code
+ * "<rootElement><element>value</element></rootElement>"
+ * \endcode
+ */
+inline std::string
+stripXmlSpaces(const std::string& xml)
+{
+ std::string s;
+ bool isSkipping = true;
+ std::copy_if(xml.begin(), xml.end(), std::back_inserter(s),
+ [&isSkipping] (char ch) {
+ if (ch == '\n') {
+ isSkipping = true;
+ }
+ else if (ch != ' ') {
+ isSkipping = false;
+ }
+ return !isSkipping;
+ });
+ return s;
+}
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
+
+#endif // NFD_TESTS_TOOLS_NFD_STATUS_MODULE_FIXTURE_HPP
diff --git a/tests/tools/nfd-status/rib-module.t.cpp b/tests/tools/nfd-status/rib-module.t.cpp
new file mode 100644
index 0000000..bfd663c
--- /dev/null
+++ b/tests/tools/nfd-status/rib-module.t.cpp
@@ -0,0 +1,141 @@
+/* -*- 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 "nfd-status/rib-module.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestRibModule, ModuleFixture<RibModule>)
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <rib>
+ <ribEntry>
+ <prefix>/</prefix>
+ <routes>
+ <route>
+ <faceId>262</faceId>
+ <origin>255</origin>
+ <cost>9</cost>
+ <flags>
+ <ribCapture/>
+ </flags>
+ </route>
+ <route>
+ <faceId>272</faceId>
+ <origin>255</origin>
+ <cost>50</cost>
+ <flags/>
+ </route>
+ <route>
+ <faceId>274</faceId>
+ <origin>255</origin>
+ <cost>78</cost>
+ <flags>
+ <childInherit/>
+ <ribCapture/>
+ </flags>
+ </route>
+ <route>
+ <faceId>276</faceId>
+ <origin>255</origin>
+ <cost>79</cost>
+ <flags>
+ <childInherit/>
+ </flags>
+ <expirationPeriod>PT47S</expirationPeriod>
+ </route>
+ </routes>
+ </ribEntry>
+ <ribEntry>
+ <prefix>/localhost/nfd</prefix>
+ <routes>
+ <route>
+ <faceId>258</faceId>
+ <origin>0</origin>
+ <cost>0</cost>
+ <flags>
+ <childInherit/>
+ </flags>
+ </route>
+ </routes>
+ </ribEntry>
+ </rib>
+)XML");
+
+const std::string STATUS_TEXT =
+ "RIB:\n"
+ " / route={faceid=262 (origin=255 cost=9 RibCapture), faceid=272 (origin=255 cost=50), "
+ "faceid=274 (origin=255 cost=78 ChildInherit RibCapture), "
+ "faceid=276 (origin=255 cost=79 expires=47s ChildInherit)}\n"
+ " /localhost/nfd route={faceid=258 (origin=0 cost=0 ChildInherit)}\n";
+
+BOOST_AUTO_TEST_CASE(Status)
+{
+ this->fetchStatus();
+ RibEntry payload1;
+ payload1.setName("/")
+ .addRoute(Route().setFaceId(262)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_STATIC)
+ .setCost(9)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CAPTURE))
+ .addRoute(Route().setFaceId(272)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_STATIC)
+ .setCost(50)
+ .setFlags(ndn::nfd::ROUTE_FLAGS_NONE))
+ .addRoute(Route().setFaceId(274)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_STATIC)
+ .setCost(78)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT | ndn::nfd::ROUTE_FLAG_CAPTURE))
+ .addRoute(Route().setFaceId(276)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_STATIC)
+ .setCost(79)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT)
+ .setExpirationPeriod(time::milliseconds(47292)));
+ RibEntry payload2;
+ payload2.setName("/localhost/nfd")
+ .addRoute(Route().setFaceId(258)
+ .setOrigin(ndn::nfd::ROUTE_ORIGIN_APP)
+ .setCost(0)
+ .setFlags(ndn::nfd::ROUTE_FLAG_CHILD_INHERIT));
+ this->sendDataset("/localhost/nfd/rib/list", payload1, payload2);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestRibModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/status-report.t.cpp b/tests/tools/nfd-status/status-report.t.cpp
new file mode 100644
index 0000000..309c83a
--- /dev/null
+++ b/tests/tools/nfd-status/status-report.t.cpp
@@ -0,0 +1,220 @@
+/* -*- 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 "nfd-status/status-report.hpp"
+#include "core/scheduler.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <?xml version="1.0"?>
+ <nfdStatus xmlns="ndn:/localhost/nfd/status/1">
+ <module1/>
+ <module2/>
+ </nfdStatus>
+)XML");
+
+const std::string STATUS_TEXT = std::string(R"TEXT(
+module1
+module2
+)TEXT").substr(1);
+
+class DummyModule : public Module
+{
+public:
+ explicit
+ DummyModule(const std::string& moduleName)
+ : m_moduleName(moduleName)
+ , m_res(0)
+ , m_delay(time::milliseconds(1))
+ {
+ }
+
+ /** \brief cause fetchStatus to succeed or fail
+ * \param res zero to succeed, non-zero to fail with specific code
+ * \param delay duration from fetchStatus invocation to succeed or fail; must be positive
+ */
+ void
+ setResult(uint32_t res, time::nanoseconds delay)
+ {
+ BOOST_ASSERT(delay > time::nanoseconds::zero());
+ m_res = res;
+ m_delay = delay;
+ }
+
+ virtual void
+ fetchStatus(Controller& controller,
+ const function<void()>& onSuccess,
+ const Controller::CommandFailCallback& onFailure,
+ const CommandOptions& options) override
+ {
+ ++nFetchStatusCalls;
+ scheduler::schedule(m_delay, [=] {
+ if (m_res == 0) {
+ onSuccess();
+ }
+ else {
+ onFailure(m_res, m_moduleName + " fails with code " + to_string(m_res));
+ }
+ });
+ }
+
+ virtual void
+ formatStatusXml(std::ostream& os) const override
+ {
+ os << '<' << m_moduleName << "/>";
+ }
+
+ virtual void
+ formatStatusText(std::ostream& os) const override
+ {
+ os << m_moduleName << '\n';
+ }
+
+public:
+ int nFetchStatusCalls = 0;
+
+private:
+ std::string m_moduleName;
+ uint32_t m_res;
+ time::nanoseconds m_delay;
+};
+
+class StatusReportTester : public StatusReport
+{
+private:
+ virtual void
+ processEvents(Face&) override
+ {
+ processEventsFunc();
+ }
+
+public:
+ std::function<void()> processEventsFunc;
+};
+
+class StatusReportModulesFixture : public IdentityManagementTimeFixture
+{
+protected:
+ StatusReportModulesFixture()
+ : face(g_io, m_keyChain)
+ , controller(face, m_keyChain, validator)
+ , res(0)
+ {
+ }
+
+ DummyModule&
+ addModule(const std::string& moduleName)
+ {
+ report.sections.push_back(make_unique<DummyModule>(moduleName));
+ return static_cast<DummyModule&>(*report.sections.back());
+ }
+
+ void
+ collect(time::nanoseconds tick, size_t nTicks)
+ {
+ report.processEventsFunc = [=] {
+ this->advanceClocks(tick, nTicks);
+ };
+ res = report.collect(face, m_keyChain, validator, CommandOptions());
+
+ if (res == 0) {
+ statusXml.str("");
+ report.formatXml(statusXml);
+ statusText.str("");
+ report.formatText(statusText);
+ }
+ }
+
+protected:
+ DummyClientFace face;
+ ValidatorNull validator;
+ Controller controller;
+ StatusReportTester report;
+
+ uint32_t res;
+ output_test_stream statusXml;
+ output_test_stream statusText;
+};
+
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestStatusReport, StatusReportModulesFixture)
+
+BOOST_AUTO_TEST_CASE(Normal)
+{
+ DummyModule& m1 = addModule("module1");
+ m1.setResult(0, time::milliseconds(10));
+ DummyModule& m2 = addModule("module2");
+ m2.setResult(0, time::milliseconds(20));
+
+ this->collect(time::milliseconds(5), 6);
+
+ BOOST_CHECK_EQUAL(m1.nFetchStatusCalls, 1);
+ BOOST_CHECK_EQUAL(m2.nFetchStatusCalls, 1);
+
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_CASE(Reorder)
+{
+ DummyModule& m1 = addModule("module1");
+ m1.setResult(0, time::milliseconds(20));
+ DummyModule& m2 = addModule("module2");
+ m2.setResult(0, time::milliseconds(10)); // module2 completes earlier than module1
+
+ this->collect(time::milliseconds(5), 6);
+
+ BOOST_CHECK_EQUAL(res, 0);
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML)); // output is still in order
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_CASE(Error)
+{
+ DummyModule& m1 = addModule("module1");
+ m1.setResult(0, time::milliseconds(20));
+ DummyModule& m2 = addModule("module2");
+ m2.setResult(500, time::milliseconds(10));
+
+ this->collect(time::milliseconds(5), 6);
+
+ BOOST_CHECK_EQUAL(res, 1000500);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestRibModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd
diff --git a/tests/tools/nfd-status/strategy-choice-module.t.cpp b/tests/tools/nfd-status/strategy-choice-module.t.cpp
new file mode 100644
index 0000000..a41ba1f
--- /dev/null
+++ b/tests/tools/nfd-status/strategy-choice-module.t.cpp
@@ -0,0 +1,83 @@
+/* -*- 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 "nfd-status/strategy-choice-module.hpp"
+
+#include "module-fixture.hpp"
+
+namespace nfd {
+namespace tools {
+namespace nfd_status {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(NfdStatus)
+BOOST_FIXTURE_TEST_SUITE(TestStrategyChoiceModule, ModuleFixture<StrategyChoiceModule>)
+
+const std::string STATUS_XML = stripXmlSpaces(R"XML(
+ <strategyChoices>
+ <strategyChoice>
+ <namespace>/</namespace>
+ <strategy>
+ <name>/localhost/nfd/strategy/best-route/%FD%04</name>
+ </strategy>
+ </strategyChoice>
+ <strategyChoice>
+ <namespace>/localhost</namespace>
+ <strategy>
+ <name>/localhost/nfd/strategy/multicast/%FD%01</name>
+ </strategy>
+ </strategyChoice>
+ </strategyChoices>
+)XML");
+
+const std::string STATUS_TEXT = std::string(R"TEXT(
+Strategy choices:
+ / strategy=/localhost/nfd/strategy/best-route/%FD%04
+ /localhost strategy=/localhost/nfd/strategy/multicast/%FD%01
+)TEXT").substr(1);
+
+BOOST_AUTO_TEST_CASE(Status)
+{
+ this->fetchStatus();
+ StrategyChoice payload1;
+ payload1.setName("/")
+ .setStrategy("/localhost/nfd/strategy/best-route/%FD%04");
+ StrategyChoice payload2;
+ payload2.setName("/localhost")
+ .setStrategy("/localhost/nfd/strategy/multicast/%FD%01");
+ this->sendDataset("/localhost/nfd/strategy-choice/list", payload1, payload2);
+ this->prepareStatusOutput();
+
+ BOOST_CHECK(statusXml.is_equal(STATUS_XML));
+ BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestStrategyChoiceModule
+BOOST_AUTO_TEST_SUITE_END() // NfdStatus
+
+} // namespace tests
+} // namespace nfd_status
+} // namespace tools
+} // namespace nfd