tools: nfdc route remove command
refs #3866
Change-Id: Iffbcf3face8758a52d35a854408f9910f4ba6c0b
diff --git a/tests/tools/nfdc/mock-nfd-mgmt-fixture.hpp b/tests/tools/nfdc/mock-nfd-mgmt-fixture.hpp
index d1b8274..319a9f1 100644
--- a/tests/tools/nfdc/mock-nfd-mgmt-fixture.hpp
+++ b/tests/tools/nfdc/mock-nfd-mgmt-fixture.hpp
@@ -59,45 +59,73 @@
}
protected: // ControlCommand
- /** \brief check the last Interest is a command with specified prefix
+ /** \brief check the Interest is a command with specified prefix
* \retval nullopt last Interest is not the expected command
* \return command parameters
*/
- ndn::optional<ControlParameters>
- getCommand(const Name& expectedPrefix) const
+ static ndn::optional<ControlParameters>
+ parseCommand(const Interest& interest, const Name& expectedPrefix)
{
- if (face.sentInterests.empty() ||
- !expectedPrefix.isPrefixOf(face.sentInterests.back().getName())) {
+ if (!expectedPrefix.isPrefixOf(interest.getName())) {
return ndn::nullopt;
}
- return ControlParameters(face.sentInterests.back().getName()
- .at(expectedPrefix.size()).blockFromValue());
+ return ControlParameters(interest.getName().at(expectedPrefix.size()).blockFromValue());
+ }
+
+ DEPRECATED(
+ ndn::optional<ControlParameters>
+ getCommand(const Name& expectedPrefix) const)
+ {
+ if (face.sentInterests.empty()) {
+ return ndn::nullopt;
+ }
+ return parseCommand(face.sentInterests.back(), expectedPrefix);
}
/** \brief respond to the last command
- * \pre last Interest is a command
*/
void
- succeedCommand(const ControlParameters& parameters)
+ succeedCommand(const Interest& interest, const ControlParameters& parameters)
{
ndn::nfd::ControlResponse resp(200, "OK");
resp.setBody(parameters.wireEncode());
- this->sendCommandReply(resp);
+ this->sendCommandReply(interest, resp);
+ }
+
+ DEPRECATED(
+ void
+ succeedCommand(const ControlParameters& parameters))
+ {
+ this->succeedCommand(face.sentInterests.back(), parameters);
}
/** \brief respond to the last command
* \pre last Interest is a command
*/
void
- failCommand(uint32_t code, const std::string& text)
+ failCommand(const Interest& interest, uint32_t code, const std::string& text)
{
- this->sendCommandReply({code, text});
+ this->sendCommandReply(interest, {code, text});
+ }
+
+ DEPRECATED(
+ void
+ failCommand(uint32_t code, const std::string& text))
+ {
+ this->sendCommandReply(face.sentInterests.back(), {code, text});
}
void
- failCommand(uint32_t code, const std::string& text, const ControlParameters& resp)
+ failCommand(const Interest& interest, uint32_t code, const std::string& text, const ControlParameters& body)
{
- this->sendCommandReply(ndn::nfd::ControlResponse(code, text).setBody(resp.wireEncode()));
+ this->sendCommandReply(interest, code, text, body.wireEncode());
+ }
+
+ DEPRECATED(
+ void
+ failCommand(uint32_t code, const std::string& text, const ControlParameters& body))
+ {
+ this->failCommand(face.sentInterests.back(), code, text, body);
}
protected: // StatusDataset
@@ -218,13 +246,21 @@
}
void
- sendCommandReply(const ndn::nfd::ControlResponse& resp)
+ sendCommandReply(const Interest& interest, const ndn::nfd::ControlResponse& resp)
{
- auto data = makeData(face.sentInterests.back().getName());
+ auto data = makeData(interest.getName());
data->setContent(resp.wireEncode());
face.receive(*data);
}
+ void
+ sendCommandReply(const Interest& interest, uint32_t code, const std::string& text,
+ const Block& body)
+ {
+ this->sendCommandReply(interest,
+ ndn::nfd::ControlResponse(code, text).setBody(body));
+ }
+
/** \brief send a payload in reply to StatusDataset request
* \param name dataset prefix without version and segment
* \param contentArgs passed to Data::setContent
@@ -269,13 +305,23 @@
} // namespace tools
} // namespace nfd
+/** \brief require the command in \p interest has expected prefix
+ * \note This must be used in processInterest lambda, and the Interest must be named 'interest'.
+ */
+#define MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix) \
+ [interest] { \
+ auto params = parseCommand(interest, (expectedPrefix)); \
+ BOOST_REQUIRE_MESSAGE(params, "Interest " << interest.getName() << \
+ " does not match command prefix " << (expectedPrefix)); \
+ return *params; \
+ } ()
+
+///\deprecated use MOCK_NFD_MGMT_REQUIRE_COMMAND_IS
#define MOCK_NFD_MGMT_REQUIRE_LAST_COMMAND_IS(expectedPrefix) \
[this] { \
BOOST_REQUIRE_MESSAGE(!face.sentInterests.empty(), "no Interest expressed"); \
- auto params = this->getCommand(expectedPrefix); \
- BOOST_REQUIRE_MESSAGE(params, "last Interest " << face.sentInterests.back().getName() << \
- " does not match command prefix " << expectedPrefix); \
- return *params; \
+ const Interest& interest = face.sentInterests.back(); \
+ return MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix); \
} ()
#endif // NFD_TESTS_TOOLS_NFDC_MOCK_NFD_MGMT_FIXTURE_HPP
diff --git a/tests/tools/nfdc/rib-module.t.cpp b/tests/tools/nfdc/rib-module.t.cpp
index 04c2b5f..df0a696 100644
--- a/tests/tools/nfdc/rib-module.t.cpp
+++ b/tests/tools/nfdc/rib-module.t.cpp
@@ -164,6 +164,124 @@
BOOST_AUTO_TEST_SUITE_END() // AddCommand
+BOOST_FIXTURE_TEST_SUITE(RemoveCommand, ExecuteCommandFixture)
+
+BOOST_AUTO_TEST_CASE(NormalByFaceId)
+{
+ this->processInterest = [this] (const Interest& interest) {
+ if (this->respondFaceQuery(interest)) {
+ return;
+ }
+
+ ControlParameters req = MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/rib/unregister");
+ ndn::nfd::RibUnregisterCommand cmd;
+ cmd.validateRequest(req);
+ cmd.applyDefaultsToRequest(req);
+ BOOST_CHECK_EQUAL(req.getName(), "/2B5NUGjpt");
+ BOOST_CHECK_EQUAL(req.getFaceId(), 10156);
+ BOOST_CHECK_EQUAL(req.getOrigin(), ndn::nfd::ROUTE_ORIGIN_STATIC);
+
+ this->succeedCommand(interest, req);
+ };
+
+ this->execute("route remove /2B5NUGjpt 10156");
+ BOOST_CHECK_EQUAL(exitCode, 0);
+ BOOST_CHECK(out.is_equal("route-removed prefix=/2B5NUGjpt nexthop=10156 origin=255\n"));
+ BOOST_CHECK(err.is_empty());
+}
+
+BOOST_AUTO_TEST_CASE(NormalByFaceUri)
+{
+ this->processInterest = [this] (const Interest& interest) {
+ if (this->respondFaceQuery(interest)) {
+ return;
+ }
+
+ ControlParameters req = MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/rib/unregister");
+ ndn::nfd::RibUnregisterCommand cmd;
+ cmd.validateRequest(req);
+ cmd.applyDefaultsToRequest(req);
+ BOOST_CHECK_EQUAL(req.getName(), "/wHdNn0BtUF");
+ BOOST_CHECK_EQUAL(req.getFaceId(), 2249);
+ BOOST_CHECK_EQUAL(req.getOrigin(), 15246);
+
+ this->succeedCommand(interest, req);
+ };
+
+ this->execute("route remove /wHdNn0BtUF tcp4://32.121.182.82:6363 origin 15246");
+ BOOST_CHECK_EQUAL(exitCode, 0);
+ BOOST_CHECK(out.is_equal("route-removed prefix=/wHdNn0BtUF nexthop=2249 origin=15246\n"));
+ BOOST_CHECK(err.is_empty());
+}
+
+BOOST_AUTO_TEST_CASE(MultipleFaces)
+{
+ std::set<uint64_t> faceIds{6720, 31066};
+ this->processInterest = [this, &faceIds] (const Interest& interest) {
+ if (this->respondFaceQuery(interest)) {
+ return;
+ }
+
+ ControlParameters req = MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/rib/unregister");
+ ndn::nfd::RibUnregisterCommand cmd;
+ cmd.validateRequest(req);
+ cmd.applyDefaultsToRequest(req);
+ BOOST_CHECK_EQUAL(req.getName(), "/nm5y8X8b2");
+ BOOST_CHECK_MESSAGE(faceIds.erase(req.getFaceId()), "expected face " + std::to_string(req.getFaceId()));
+ BOOST_CHECK_EQUAL(req.getOrigin(), ndn::nfd::ROUTE_ORIGIN_STATIC);
+
+ this->succeedCommand(interest, req);
+ };
+
+ this->execute("route remove /nm5y8X8b2 udp4://225.131.75.231:56363");
+ BOOST_CHECK(faceIds.empty());
+ BOOST_CHECK_EQUAL(exitCode, 0);
+ BOOST_CHECK(out.is_equal("route-removed prefix=/nm5y8X8b2 nexthop=6720 origin=255\n"
+ "route-removed prefix=/nm5y8X8b2 nexthop=31066 origin=255\n"));
+ BOOST_CHECK(err.is_empty());
+}
+
+BOOST_AUTO_TEST_CASE(FaceNotExist)
+{
+ this->processInterest = [this] (const Interest& interest) {
+ BOOST_CHECK(this->respondFaceQuery(interest));
+ };
+
+ this->execute("route remove /HeGRjzwFM 23728");
+ BOOST_CHECK_EQUAL(exitCode, 3);
+ BOOST_CHECK(out.is_empty());
+ BOOST_CHECK(err.is_equal("Face not found\n"));
+}
+
+BOOST_AUTO_TEST_CASE(ErrorDataset)
+{
+ this->processInterest = nullptr; // no response to dataset or command
+
+ this->execute("route remove /YX4xQQN3v5 udp://26.97.248.3");
+ BOOST_CHECK_EQUAL(exitCode, 1);
+ BOOST_CHECK(out.is_empty());
+ BOOST_CHECK(err.is_equal("Error 10060 when querying face: Timeout\n"));
+}
+
+BOOST_AUTO_TEST_CASE(ErrorCommand)
+{
+ this->processInterest = [this] (const Interest& interest) {
+ if (this->respondFaceQuery(interest)) {
+ return;
+ }
+
+ MOCK_NFD_MGMT_REQUIRE_COMMAND_IS("/localhost/nfd/rib/unregister");
+ // no response to command
+ };
+
+ this->execute("route remove /mvGRoxD2 10156");
+ BOOST_CHECK_EQUAL(exitCode, 1);
+ BOOST_CHECK(out.is_empty());
+ BOOST_CHECK(err.is_equal("Error 10060 when removing route: request timed out\n"));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // RemoveCommand
+
const std::string STATUS_XML = stripXmlSpaces(R"XML(
<rib>
<ribEntry>