mgmt: improved interest filter matching and bug fixes

tests/mgmt: added test fixtures to simplify unit testing

Added control response Data signing
Fixed control response payload parsing
Simplified fib-manager unit test assumptions
Expanded internal-face unit tests

refs: #1138

Change-Id: Ibe5d95ab9c42f890c0691c9040e4ae792e598974
diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp
index 6ac4a7f..4e4f587 100644
--- a/tests/mgmt/fib-manager.cpp
+++ b/tests/mgmt/fib-manager.cpp
@@ -7,214 +7,284 @@
 #include "mgmt/fib-manager.hpp"
 #include "fw/forwarder.hpp"
 #include "table/fib.hpp"
+#include "table/fib-nexthop.hpp"
 #include "face/face.hpp"
 #include "mgmt/internal-face.hpp"
 #include "../face/dummy-face.hpp"
 
+#include <algorithm>
+
 #include <ndn-cpp-dev/management/fib-management-options.hpp>
+#include <ndn-cpp-dev/management/control-response.hpp>
 
 #include <boost/test/unit_test.hpp>
 
-static nfd::FaceId g_faceCount = 1;
-static std::vector<nfd::shared_ptr<nfd::Face> > g_faces;
+namespace nfd {
 
-static nfd::shared_ptr<nfd::Face>
-getFace(nfd::FaceId id)
+NFD_LOG_INIT("FibManagerTest");
+
+class FibManagerFixture
 {
-  if (g_faces.size() < id)
-    {
-      BOOST_FAIL("Attempted to access invalid FaceId: " << id);
-    }
-  return g_faces[id-1];
+public:
+
+  shared_ptr<Face>
+  getFace(FaceId id)
+  {
+    if (m_faces.size() < id)
+      {
+        BOOST_FAIL("Attempted to access invalid FaceId: " << id);
+      }
+    return m_faces[id-1];
+  }
+
+  void
+  addFace(shared_ptr<Face> face)
+  {
+    m_faces.push_back(face);
+  }
+
+private:
+  std::vector<shared_ptr<Face> > m_faces;
+};
+
+
+BOOST_AUTO_TEST_SUITE(MgmtFibManager)
+
+void
+validateControlResponse(const Data& response,
+                        uint32_t expectedCode,
+                        const std::string& expectedText)
+{
+  Block controlRaw = response.getContent().blockFromValue();
+
+  ndn::ControlResponse control;
+  control.wireDecode(controlRaw);
+
+  NFD_LOG_DEBUG("received control response"
+                << " Name: " << response.getName()
+                << " code: " << control.getCode()
+                << " text: " << control.getText());
+
+  BOOST_REQUIRE(control.getCode() == expectedCode);
+  BOOST_REQUIRE(control.getText() == expectedText);
 }
 
-// namespace nfd {
+BOOST_AUTO_TEST_CASE(MalformedCommmand)
+{
+  FibManagerFixture fixture;
+  shared_ptr<InternalFace> face(new InternalFace);
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace,
+                          &fixture, _1),
+                          face);
 
-// NFD_LOG_INIT("FibManagerTest");
+  face->onReceiveData +=
+    bind(&validateControlResponse, _1, 404, "MALFORMED");
 
-// BOOST_AUTO_TEST_SUITE(MgmtFibManager)
+  Interest command("/localhost/nfd/fib");
+  manager.onFibRequest(command);
+}
 
-// BOOST_AUTO_TEST_CASE(MalformedCommmand)
-// {
-//   shared_ptr<InternalFace> face(new InternalFace);
-//   Fib fib;
-//   FibManager manager(fib, &getFace, face);
+BOOST_AUTO_TEST_CASE(UnsupportedVerb)
+{
+  FibManagerFixture fixture;
+  shared_ptr<InternalFace> face(new InternalFace);
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace,
+                          &fixture, _1),
+                          face);
+  face->onReceiveData +=
+    bind(&validateControlResponse, _1, 404, "UNSUPPORTED");
 
-//   Interest command(manager.getRequestPrefix());
-//   manager.onFibRequest(command);
-// }
+  ndn::FibManagementOptions options;
+  options.setName("/hello");
+  options.setFaceId(1);
+  options.setCost(1);
 
-// BOOST_AUTO_TEST_CASE(UnsupportedVerb)
-// {
-//   shared_ptr<InternalFace> face(new InternalFace);
-//   Fib fib;
-//   FibManager manager(fib, &getFace, face);
+  Block encodedOptions(options.wireEncode());
 
-//   ndn::FibManagementOptions options;
-//   options.setName("/hello");
-//   options.setFaceId(1);
-//   options.setCost(1);
+  Name commandName("/localhost/nfd/fib");
+  commandName.append("unsupported");
+  commandName.append(encodedOptions);
 
-//   Block encodedOptions(options.wireEncode());
+  Interest command(commandName);
+  manager.onFibRequest(command);
+}
 
-//   Name commandName(manager.getRequestPrefix());
-//   commandName.append("unsupported");
-//   commandName.append(encodedOptions);
+bool
+foundNextHop(FaceId id, uint32_t cost, const fib::NextHop& next)
+{
+  return id == next.getFace()->getId() && next.getCost() == cost;
+}
 
-//   Interest command(commandName);
-//   manager.onFibRequest(command);
-// }
+BOOST_AUTO_TEST_CASE(AddNextHopVerbInitialAdd)
+{
+  FibManagerFixture fixture;
+  fixture.addFace(make_shared<DummyFace>());
 
-// BOOST_AUTO_TEST_CASE(AddNextHopVerbInitialAdd)
-// {
-//   g_faceCount = 1;
-//   g_faces.clear();
-//   g_faces.push_back(make_shared<DummyFace>());
+  shared_ptr<InternalFace> face(new InternalFace);
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace,
+                          &fixture, _1),
+                          face);
+  face->onReceiveData +=
+    bind(&validateControlResponse, _1, 200, "OK");
 
-//   shared_ptr<InternalFace> face(new InternalFace);
-//   Fib fib;
-//   FibManager manager(fib, &getFace, face);
 
-//   ndn::FibManagementOptions options;
-//   options.setName("/hello");
-//   options.setFaceId(1);
-//   options.setCost(1);
 
-//   Block encodedOptions(options.wireEncode());
+  ndn::FibManagementOptions options;
+  options.setName("/hello");
+  options.setFaceId(1);
+  options.setCost(101);
 
-//   Name commandName(manager.getRequestPrefix());
-//   commandName.append("add-nexthop");
-//   commandName.append(encodedOptions);
+  Block encodedOptions(options.wireEncode());
 
-//   Interest command(commandName);
-//   manager.onFibRequest(command);
+  Name commandName("/localhost/nfd/fib");
+  commandName.append("add-nexthop");
+  commandName.append(encodedOptions);
 
-//   shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+  Interest command(commandName);
+  manager.onFibRequest(command);
 
-//   if (entry)
-//     {
-//       const fib::NextHopList& hops = entry->getNextHops();
-//       BOOST_REQUIRE(hops.size() == 1);
-//       //      BOOST_CHECK(hops[0].getFace()->getFaceId() == 1);
-//       BOOST_CHECK(hops[0].getCost() == 1);
-//     }
-//   else
-//     {
-//       BOOST_FAIL("Failed to find expected fib entry");
-//     }
-// }
+  shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
 
-// BOOST_AUTO_TEST_CASE(AddNextHopVerbAddToExisting)
-// {
-//   g_faceCount = 1;
-//   g_faces.clear();
-//   g_faces.push_back(make_shared<DummyFace>());
-//   g_faces.push_back(make_shared<DummyFace>());
+  if (entry)
+    {
+      const fib::NextHopList& hops = entry->getNextHops();
+      NFD_LOG_DEBUG("FaceId: " << hops[0].getFace()->getId());
+      BOOST_REQUIRE(hops.size() == 1);
+      BOOST_REQUIRE(std::find_if(hops.begin(),
+                                 hops.end(),
+                                 bind(&foundNextHop, -1, 101, _1)) != hops.end());
+    }
+  else
+    {
+      BOOST_FAIL("Failed to find expected fib entry");
+    }
+}
 
-//   shared_ptr<InternalFace> face(new InternalFace);
-//   Fib fib;
-//   FibManager manager(fib, &getFace, face);
+BOOST_AUTO_TEST_CASE(AddNextHopVerbAddToExisting)
+{
+  FibManagerFixture fixture;
+  fixture.addFace(make_shared<DummyFace>());
+  fixture.addFace(make_shared<DummyFace>());
 
-//   // Add faces with cost == FaceID for the name /hello
-//   // This test assumes:
-//   //   FaceIDs are assigned from 1 to N
-//   //   Faces are store sequentially in the NextHopList
-//   //   NextHopList supports random access
+  shared_ptr<InternalFace> face(new InternalFace);
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace,
+                          &fixture, _1),
+                          face);
+  face->onReceiveData +=
+    bind(&validateControlResponse, _1, 200, "OK");
 
-//   for (int i = 1; i <= 2; i++)
-//     {
-//       ndn::FibManagementOptions options;
-//       options.setName("/hello");
-//       options.setFaceId(i);
-//       options.setCost(i);
+  // Add faces with cost == FaceID for the name /hello
+  // This test assumes:
+  //   FaceIDs are -1 because we don't add them to a forwarder
 
-//       Block encodedOptions(options.wireEncode());
+  for (int i = 1; i <= 2; i++)
+    {
+      ndn::FibManagementOptions options;
+      options.setName("/hello");
+      options.setFaceId(i);
+      options.setCost(100 + i);
 
-//       Name commandName(manager.getRequestPrefix());
-//       commandName.append("add-nexthop");
-//       commandName.append(encodedOptions);
+      Block encodedOptions(options.wireEncode());
 
-//       Interest command(commandName);
-//       manager.onFibRequest(command);
+      Name commandName("/localhost/nfd/fib");
+      commandName.append("add-nexthop");
+      commandName.append(encodedOptions);
 
-//       shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+      Interest command(commandName);
+      manager.onFibRequest(command);
 
-//       if (entry)
-//         {
-//           const fib::NextHopList& hops = entry->getNextHops();
-//           for (int j = 1; j <= i; j++)
-//             {
-//               BOOST_REQUIRE(hops.size() == i);
-//               BOOST_CHECK(hops[j-1].getCost() == j);
-//             }
-//         }
-//       else
-//         {
-//           BOOST_FAIL("Failed to find expected fib entry");
-//         }
-//     }
-// }
+      shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
 
-// BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost)
-// {
-//   g_faceCount = 1;
-//   g_faces.clear();
-//   g_faces.push_back(make_shared<DummyFace>());
+      if (entry)
+        {
+          const fib::NextHopList& hops = entry->getNextHops();
+          for (int j = 1; j <= i; j++)
+            {
+              BOOST_REQUIRE(hops.size() == i);
+              // BOOST_REQUIRE(hops[j-1].getCost() == j);
+              BOOST_REQUIRE(std::find_if(hops.begin(),
+                                         hops.end(),
+                                         bind(&foundNextHop, -1, 100 + j, _1)) != hops.end());
+            }
+        }
+      else
+        {
+          BOOST_FAIL("Failed to find expected fib entry");
+        }
+    }
+}
 
-//   shared_ptr<InternalFace> face(new InternalFace);
-//   Fib fib;
-//   FibManager manager(fib, &getFace, face);
+BOOST_AUTO_TEST_CASE(AddNextHopVerbUpdateFaceCost)
+{
+  FibManagerFixture fixture;
+  fixture.addFace(make_shared<DummyFace>());
 
-//   ndn::FibManagementOptions options;
-//   options.setName("/hello");
-//   options.setFaceId(1);
+  shared_ptr<InternalFace> face(new InternalFace);
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace,
+                          &fixture, _1),
+                          face);
+  face->onReceiveData +=
+    bind(&validateControlResponse, _1, 200, "OK");
 
-//   {
-//     options.setCost(1);
+  ndn::FibManagementOptions options;
+  options.setName("/hello");
+  options.setFaceId(1);
 
-//     Block encodedOptions(options.wireEncode());
+  {
+    options.setCost(1);
 
-//     Name commandName(manager.getRequestPrefix());
-//     commandName.append("add-nexthop");
-//     commandName.append(encodedOptions);
+    Block encodedOptions(options.wireEncode());
 
-//     Interest command(commandName);
-//     manager.onFibRequest(command);
-//   }
+    Name commandName("/localhost/nfd/fib");
+    commandName.append("add-nexthop");
+    commandName.append(encodedOptions);
 
-//   {
-//     options.setCost(2);
+    Interest command(commandName);
+    manager.onFibRequest(command);
+  }
 
-//     Block encodedOptions(options.wireEncode());
+  {
+    options.setCost(102);
 
-//     Name commandName(manager.getRequestPrefix());
-//     commandName.append("add-nexthop");
-//     commandName.append(encodedOptions);
+    Block encodedOptions(options.wireEncode());
 
-//     Interest command(commandName);
-//     manager.onFibRequest(command);
-//   }
+    Name commandName("/localhost/nfd/fib");
+    commandName.append("add-nexthop");
+    commandName.append(encodedOptions);
 
-//   shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
+    Interest command(commandName);
+    manager.onFibRequest(command);
+  }
 
-//   // Add faces with cost == FaceID for the name /hello
-//   // This test assumes:
-//   //   FaceIDs are assigned from 1 to N
-//   //   Faces are store sequentially in the NextHopList
-//   //   NextHopList supports random access
-//   if (entry)
-//     {
-//       const fib::NextHopList& hops = entry->getNextHops();
-//       BOOST_REQUIRE(hops.size() == 1);
-//       // BOOST_CHECK(hops[0].getFace()->getFaceId() == 1);
-//       BOOST_CHECK(hops[0].getCost() == 2);
-//     }
-//   else
-//     {
-//       BOOST_FAIL("Failed to find expected fib entry");
-//     }
-// }
+  shared_ptr<fib::Entry> entry = fib.findLongestPrefixMatch("/hello");
 
-// BOOST_AUTO_TEST_SUITE_END()
+  // Add faces with cost == FaceID for the name /hello
+  // This test assumes:
+  //   FaceIDs are -1 because we don't add them to a forwarder
+  if (entry)
+    {
+      const fib::NextHopList& hops = entry->getNextHops();
+      BOOST_REQUIRE(hops.size() == 1);
+      BOOST_REQUIRE(std::find_if(hops.begin(),
+                                 hops.end(),
+                                 bind(&foundNextHop, -1, 102, _1)) != hops.end());
+    }
+  else
+    {
+      BOOST_FAIL("Failed to find expected fib entry");
+    }
+}
 
-// } // namespace nfd
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace nfd