mgmt: added FIB manager support for insert, delete, and remove-nexthop verbs
Refactor option decoding, verb authorization (placeholder),
and response sending into single location.
Added unit tests for ManagerBase.
refs: #1223
Change-Id: I731be586ee8f06defb00fcadc6010409560891a1
diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp
index b07d11b..25c38b3 100644
--- a/tests/mgmt/fib-manager.cpp
+++ b/tests/mgmt/fib-manager.cpp
@@ -5,7 +5,6 @@
*/
#include "mgmt/fib-manager.hpp"
-#include "fw/forwarder.hpp"
#include "table/fib.hpp"
#include "table/fib-nexthop.hpp"
#include "face/face.hpp"
@@ -52,6 +51,7 @@
void
validateControlResponse(const Data& response,
+ const Name& expectedName,
uint32_t expectedCode,
const std::string& expectedText)
{
@@ -66,8 +66,9 @@
<< " code: " << control.getCode()
<< " text: " << control.getText());
- BOOST_REQUIRE(control.getCode() == expectedCode);
- BOOST_REQUIRE(control.getText() == expectedText);
+ BOOST_CHECK_EQUAL(response.getName(), expectedName);
+ BOOST_CHECK_EQUAL(control.getCode(), expectedCode);
+ BOOST_CHECK_EQUAL(control.getText(), expectedText);
}
bool
@@ -101,7 +102,7 @@
bool
addedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint32_t cost)
{
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch(prefix);
+ shared_ptr<fib::Entry> entry = fib.findExactMatch(prefix);
if (static_cast<bool>(entry))
{
@@ -112,42 +113,44 @@
return false;
}
-BOOST_AUTO_TEST_CASE(TestFireInterestFilter)
+BOOST_FIXTURE_TEST_CASE(TestFireInterestFilter, FibManagerFixture)
{
- FibManagerFixture fixture;
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- &fixture, _1),
- face);
-
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, &fixture, _1, 400, "Malformed command");
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
Interest command("/localhost/nfd/fib");
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ command.getName(), 400, "Malformed command");
+
face->sendInterest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
}
-BOOST_AUTO_TEST_CASE(MalformedCommmand)
+BOOST_FIXTURE_TEST_CASE(MalformedCommmand, FibManagerFixture)
{
- FibManagerFixture fixture;
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- &fixture, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- BOOST_REQUIRE(fixture.didCallbackFire() == false);
-
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, &fixture, _1, 400, "Malformed command");
+ BOOST_REQUIRE(didCallbackFire() == false);
Interest command("/localhost/nfd/fib");
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ command.getName(), 400, "Malformed command");
+
manager.onFibRequest(command);
- BOOST_REQUIRE(fixture.didCallbackFire());
+ BOOST_REQUIRE(didCallbackFire());
}
BOOST_FIXTURE_TEST_CASE(UnsupportedVerb, FibManagerFixture)
@@ -155,13 +158,9 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 501, "Unsupported command");
-
ndn::FibManagementOptions options;
options.setName("/hello");
options.setFaceId(1);
@@ -173,6 +172,10 @@
commandName.append("unsupported");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 501, "Unsupported command");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -186,13 +189,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- /// \todo enable once sig checking implement
- // bind(&FibManagerFixture::validateControlResponse, this, _1, 401, "SIGREG");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -205,11 +203,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+ /// \todo enable once sig checking implemented
+ // bind(&FibManagerFixture::validateControlResponse, this, _1, 401, "Signature required");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101));
+ BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101));
}
BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, FibManagerFixture)
@@ -219,13 +223,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- /// \todo enable once sig checking implement
- // bind(&FibManagerFixture::validateControlResponse, this, _1, 403, "Unauthorized command");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -238,11 +237,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+ /// \todo enable once sig checking implemented
+ // bind(&FibManagerFixture::validateControlResponse, this, _1, 403, "Unauthorized command");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101));
+ BOOST_REQUIRE(!addedNextHopWithCost(fib, "/hello", 0, 101));
}
BOOST_FIXTURE_TEST_CASE(BadOptionParse, FibManagerFixture)
@@ -252,17 +257,17 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 400, "Malformed command");
-
Name commandName("/localhost/nfd/fib");
commandName.append("add-nexthop");
commandName.append("NotReallyOptions");
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 400, "Malformed command");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -276,13 +281,9 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 400, "Malformed command");
-
ndn::FibManagementOptions options;
options.setName("/hello");
options.setFaceId(1000);
@@ -294,6 +295,10 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Face not found");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -308,11 +313,8 @@
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -325,6 +327,12 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ fib.insert("/hello");
+
Interest command(commandName);
manager.onFibRequest(command);
@@ -335,26 +343,21 @@
BOOST_FIXTURE_TEST_CASE(AddNextHopVerbAddToExisting, FibManagerFixture)
{
addFace(make_shared<DummyFace>());
- addFace(make_shared<DummyFace>());
shared_ptr<InternalFace> face(make_shared<InternalFace>());
Fib fib;
FibManager manager(fib,
- bind(&FibManagerFixture::getFace,
- this, _1),
+ bind(&FibManagerFixture::getFace, this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
- // Add faces with cost == FaceID for the name /hello
- // This test assumes:
- // FaceIDs are -1 because we don't add them to a forwarder
+ fib.insert("/hello");
for (int i = 1; i <= 2; i++)
{
+
ndn::FibManagementOptions options;
options.setName("/hello");
- options.setFaceId(i);
+ options.setFaceId(1);
options.setCost(100 + i);
Block encodedOptions(options.wireEncode());
@@ -363,25 +366,31 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
BOOST_REQUIRE(didCallbackFire());
resetCallbackFired();
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
if (static_cast<bool>(entry))
{
const fib::NextHopList& hops = entry->getNextHops();
- for (int j = 1; j <= i; j++)
- {
- BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", i - 1, 100 + j));
- }
+ BOOST_REQUIRE(hops.size() == 1);
+ BOOST_REQUIRE(std::find_if(hops.begin(), hops.end(),
+ bind(&foundNextHop, -1, 100 + i, _1)) != hops.end());
+
}
else
{
BOOST_FAIL("Failed to find expected fib entry");
}
+
+ face->onReceiveData.clear();
}
}
@@ -396,8 +405,8 @@
bind(&FibManagerFixture::getFace,
this, _1),
face);
- face->onReceiveData +=
- bind(&FibManagerFixture::validateControlResponse, this, _1, 200, "OK");
+
+ fib.insert("/hello");
ndn::FibManagementOptions options;
options.setName("/hello");
@@ -412,12 +421,19 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
+
BOOST_REQUIRE(didCallbackFire());
- resetCallbackFired();
}
+ resetCallbackFired();
+ face->onReceiveData.clear();
+
{
options.setCost(102);
@@ -427,12 +443,17 @@
commandName.append("add-nexthop");
commandName.append(encodedOptions);
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
Interest command(commandName);
manager.onFibRequest(command);
+
BOOST_REQUIRE(didCallbackFire());
}
- shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
// Add faces with cost == FaceID for the name /hello
// This test assumes:
@@ -451,6 +472,286 @@
}
}
+BOOST_FIXTURE_TEST_CASE(Insert, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ {
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("insert");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+ }
+
+ BOOST_REQUIRE(didCallbackFire());
+
+ shared_ptr<fib::Entry> entry = fib.findExactMatch("/hello");
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ BOOST_CHECK_EQUAL(hops.size(), 0);
+ }
+
+ resetCallbackFired();
+
+ {
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("insert");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+ }
+
+ BOOST_REQUIRE(didCallbackFire());
+
+ entry = fib.findExactMatch("/hello");
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ BOOST_CHECK_EQUAL(hops.size(), 0);
+ }
+
+}
+
+void
+testRemove(FibManagerFixture* fixture,
+ FibManager& manager,
+ Fib& fib,
+ shared_ptr<Face> face,
+ const Name& target)
+{
+ ndn::FibManagementOptions options;
+ options.setName(target);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("delete");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, fixture, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(fixture->didCallbackFire());
+
+ if (static_cast<bool>(fib.findExactMatch(target)))
+ {
+ BOOST_FAIL("Found \"removed\" prefix");
+ }
+ face->onReceiveData.clear();
+}
+
+BOOST_FIXTURE_TEST_CASE(Delete, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ fib.insert("/a");
+ fib.insert("/a/b");
+ fib.insert("/a/b/c");
+
+ testRemove(this, manager, fib, face, "/");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a/b");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")) ||
+ !static_cast<bool>(fib.findExactMatch("/a/b/c")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a/b/c");
+
+ if (!static_cast<bool>(fib.findExactMatch("/a")))
+ {
+ BOOST_FAIL("Removed incorrect entry");
+ }
+
+ testRemove(this, manager, fib, face, "/a");
+
+ testRemove(this, manager, fib, face, "/does/not/exist");
+}
+
+bool
+removedNextHopWithCost(const Fib& fib, const Name& prefix, size_t oldSize, uint32_t cost)
+{
+ shared_ptr<fib::Entry> entry = fib.findExactMatch(prefix);
+
+ if (static_cast<bool>(entry))
+ {
+ const fib::NextHopList& hops = entry->getNextHops();
+ return hops.size() == oldSize - 1 &&
+ std::find_if(hops.begin(), hops.end(), bind(&foundNextHop, -1, cost, _1)) == hops.end();
+ }
+ return false;
+}
+
+void
+testRemoveNextHop(FibManagerFixture* fixture,
+ FibManager& manager,
+ Fib& fib,
+ shared_ptr<Face> face,
+ const Name& targetName,
+ FaceId targetFace)
+{
+ ndn::FibManagementOptions options;
+ options.setName(targetName);
+ options.setFaceId(targetFace);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, fixture, _1,
+ commandName, 200, "OK");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(fixture->didCallbackFire());
+
+ fixture->resetCallbackFired();
+ face->onReceiveData.clear();
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNextHop, FibManagerFixture)
+{
+ shared_ptr<Face> face1 = make_shared<DummyFace>();
+ shared_ptr<Face> face2 = make_shared<DummyFace>();
+ shared_ptr<Face> face3 = make_shared<DummyFace>();
+
+ addFace(face1);
+ addFace(face2);
+ addFace(face3);
+
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ shared_ptr<fib::Entry> entry = fib.insert("/hello").first;
+
+ entry->addNextHop(face1, 101);
+ entry->addNextHop(face2, 202);
+ entry->addNextHop(face3, 303);
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 2);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 3, 202));
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 3);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 2, 303));
+
+ testRemoveNextHop(this, manager, fib, face, "/hello", 1);
+ BOOST_REQUIRE(removedNextHopWithCost(fib, "/hello", 1, 101));
+
+ if (!static_cast<bool>(fib.findExactMatch("/hello")))
+ {
+ BOOST_FAIL("removed entry after removing all next hops");
+ }
+
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNoFace, FibManagerFixture)
+{
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+ options.setFaceId(1);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Face not found");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveNoPrefix, FibManagerFixture)
+{
+ addFace(make_shared<DummyFace>());
+
+ shared_ptr<InternalFace> face(make_shared<InternalFace>());
+ Fib fib;
+ FibManager manager(fib,
+ bind(&FibManagerFixture::getFace, this, _1),
+ face);
+
+ ndn::FibManagementOptions options;
+ options.setName("/hello");
+ options.setFaceId(1);
+
+ Block encodedOptions(options.wireEncode());
+
+ Name commandName("/localhost/nfd/fib");
+ commandName.append("remove-nexthop");
+ commandName.append(encodedOptions);
+
+ face->onReceiveData +=
+ bind(&FibManagerFixture::validateControlResponse, this, _1,
+ commandName, 404, "Prefix not found");
+
+ Interest command(commandName);
+ manager.onFibRequest(command);
+
+ BOOST_REQUIRE(didCallbackFire());
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace nfd