mgmt: echo FibManagementOptions as response body on command success

Add support for commands with FaceId == zero

refs: #1236

Change-Id: If67e955668d5a3622893582111601d358df9137e
diff --git a/daemon/mgmt/fib-manager.cpp b/daemon/mgmt/fib-manager.cpp
index 01e2cc8..0b20c02 100644
--- a/daemon/mgmt/fib-manager.cpp
+++ b/daemon/mgmt/fib-manager.cpp
@@ -80,6 +80,8 @@
   const Name& command = request.getName();
   const size_t commandNComps = command.size();
 
+
+
   if (FIB_MANAGER_COMMAND_UNSIGNED_NCOMPS <= commandNComps &&
       commandNComps < FIB_MANAGER_COMMAND_SIGNED_NCOMPS)
     {
@@ -117,7 +119,6 @@
         }
 
       NFD_LOG_INFO("command result: processing verb: " << verb);
-
       ControlResponse response;
       (verbProcessor->second)(this, options, response);
 
@@ -149,6 +150,12 @@
       NFD_LOG_INFO("Bad command option parse: " << command);
       return false;
     }
+
+  if (extractedOptions.getFaceId() == 0)
+    {
+      extractedOptions.setFaceId(request.getIncomingFaceId());
+    }
+
   NFD_LOG_DEBUG("Options parsed OK");
   return true;
 }
@@ -161,7 +168,7 @@
   NFD_LOG_INFO("insert result: OK"
                << " prefix: " << options.getName());
   std::pair<shared_ptr<fib::Entry>, bool> insertResult = m_managedFib.insert(options.getName());
-  setResponse(response, 200, "OK");
+  setResponse(response, 200, "Success", options.wireEncode());
 }
 
 void
@@ -173,7 +180,7 @@
                << " prefix: " << options.getName());
 
   m_managedFib.remove(options.getName());
-  setResponse(response, 200, "OK");
+  setResponse(response, 200, "Success", options.wireEncode());
 }
 
 static inline bool
@@ -202,7 +209,7 @@
                        << " prefix:" << options.getName()
                        << " faceid: " << options.getFaceId()
                        << " cost: " << options.getCost());
-          setResponse(response, 200, "OK");
+          setResponse(response, 200, "Success", options.wireEncode());
         }
       else
         {
@@ -234,7 +241,7 @@
           NFD_LOG_INFO("remove-nexthop result: OK prefix: " << options.getName()
                        << " faceid: " << options.getFaceId());
 
-          setResponse(response, 200, "OK");
+          setResponse(response, 200, "Success", options.wireEncode());
         }
       else
         {
diff --git a/daemon/mgmt/manager-base.hpp b/daemon/mgmt/manager-base.hpp
index e8d63cf..8fb8cd3 100644
--- a/daemon/mgmt/manager-base.hpp
+++ b/daemon/mgmt/manager-base.hpp
@@ -30,6 +30,11 @@
   setResponse(ControlResponse& response,
               uint32_t code,
               const std::string& text);
+  void
+  setResponse(ControlResponse& response,
+              uint32_t code,
+              const std::string& text,
+              const Block& body);
 
   void
   sendResponse(const Name& name,
@@ -53,6 +58,16 @@
   response.setText(text);
 }
 
+inline void
+ManagerBase::setResponse(ControlResponse& response,
+                         uint32_t code,
+                         const std::string& text,
+                         const Block& body)
+{
+  setResponse(response, code, text);
+  response.setBody(body);
+}
+
 
 } // namespace nfd
 
diff --git a/tests/mgmt/fib-manager.cpp b/tests/mgmt/fib-manager.cpp
index 1c1cf9f..2352f53 100644
--- a/tests/mgmt/fib-manager.cpp
+++ b/tests/mgmt/fib-manager.cpp
@@ -47,15 +47,15 @@
   }
 
   void
-  validateControlResponse(const Data& response,
-                          const Name& expectedName,
-                          uint32_t expectedCode,
-                          const std::string& expectedText)
+  validateControlResponseCommon(const Data& response,
+                                const Name& expectedName,
+                                uint32_t expectedCode,
+                                const std::string& expectedText,
+                                ControlResponse& control)
   {
     m_callbackFired = true;
     Block controlRaw = response.getContent().blockFromValue();
 
-    ControlResponse control;
     control.wireDecode(controlRaw);
 
     NFD_LOG_DEBUG("received control response"
@@ -68,6 +68,41 @@
     BOOST_CHECK_EQUAL(control.getText(), expectedText);
   }
 
+  void
+  validateControlResponse(const Data& response,
+                          const Name& expectedName,
+                          uint32_t expectedCode,
+                          const std::string& expectedText)
+  {
+    ControlResponse control;
+    validateControlResponseCommon(response, expectedName,
+                                  expectedCode, expectedText, control);
+
+    if (!control.getBody().empty())
+      {
+        BOOST_FAIL("found unexpected control response body");
+      }
+  }
+
+  void
+  validateControlResponse(const Data& response,
+                          const Name& expectedName,
+                          uint32_t expectedCode,
+                          const std::string& expectedText,
+                          const Block& expectedBody)
+  {
+    ControlResponse control;
+    validateControlResponseCommon(response, expectedName,
+                                  expectedCode, expectedText, control);
+
+    BOOST_REQUIRE(!control.getBody().empty());
+    BOOST_REQUIRE(control.getBody().value_size() == expectedBody.value_size());
+
+    BOOST_CHECK(memcmp(control.getBody().value(), expectedBody.value(),
+                       expectedBody.value_size()) == 0);
+
+  }
+
   bool
   didCallbackFire()
   {
@@ -110,6 +145,28 @@
   return false;
 }
 
+bool
+foundNextHopWithFace(FaceId id, uint32_t cost,
+                     shared_ptr<Face> face, const fib::NextHop& next)
+{
+  return id == next.getFace()->getId() && next.getCost() == cost && face == next.getFace();
+}
+
+bool
+addedNextHopWithFace(const Fib& fib, const Name& prefix, size_t oldSize,
+                     uint32_t cost, shared_ptr<Face> face)
+{
+  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;
+}
+
 BOOST_FIXTURE_TEST_CASE(TestFireInterestFilter, FibManagerFixture)
 {
   shared_ptr<InternalFace> face(make_shared<InternalFace>());
@@ -303,6 +360,48 @@
   BOOST_REQUIRE(addedNextHopWithCost(fib, "/hello", 0, 101) == false);
 }
 
+BOOST_FIXTURE_TEST_CASE(TestImplicitFaceId, FibManagerFixture)
+{
+  addFace(make_shared<DummyFace>());
+
+  shared_ptr<InternalFace> face(make_shared<InternalFace>());
+  Fib fib;
+  FibManager manager(fib,
+                     bind(&FibManagerFixture::getFace, this, _1),
+                          face);
+
+  FibManagementOptions options;
+  options.setName("/hello");
+  options.setFaceId(0);
+  options.setCost(101);
+
+  Block encodedOptions(options.wireEncode());
+
+  Name commandName("/localhost/nfd/fib");
+  commandName.append("add-nexthop");
+  commandName.append(encodedOptions);
+
+  FibManagementOptions expectedOptions;
+  expectedOptions.setName("/hello");
+  expectedOptions.setFaceId(1);
+  expectedOptions.setCost(101);
+
+  Block encodedExpectedOptions(expectedOptions.wireEncode());
+
+  face->onReceiveData +=
+    bind(&FibManagerFixture::validateControlResponse, this, _1,
+         commandName, 200, "Success", encodedExpectedOptions);
+
+  fib.insert("/hello");
+
+  Interest command(commandName);
+  command.setIncomingFaceId(1);
+  manager.onFibRequest(command);
+
+  BOOST_REQUIRE(didCallbackFire());
+  BOOST_REQUIRE(addedNextHopWithFace(fib, "/hello", 0, 101, getFace(1)));
+}
+
 BOOST_FIXTURE_TEST_CASE(AddNextHopVerbInitialAdd, FibManagerFixture)
 {
   addFace(make_shared<DummyFace>());
@@ -326,7 +425,7 @@
 
   face->onReceiveData +=
     bind(&FibManagerFixture::validateControlResponse, this, _1,
-         commandName, 200, "OK");
+         commandName, 200, "Success", encodedOptions);
 
   fib.insert("/hello");
 
@@ -365,7 +464,7 @@
 
       face->onReceiveData +=
         bind(&FibManagerFixture::validateControlResponse, this, _1,
-             commandName, 200, "OK");
+             commandName, 200, "Success", encodedOptions);
 
       Interest command(commandName);
       manager.onFibRequest(command);
@@ -420,7 +519,7 @@
 
     face->onReceiveData +=
       bind(&FibManagerFixture::validateControlResponse, this, _1,
-           commandName, 200, "OK");
+           commandName, 200, "Success", encodedOptions);
 
     Interest command(commandName);
     manager.onFibRequest(command);
@@ -442,7 +541,7 @@
 
     face->onReceiveData +=
       bind(&FibManagerFixture::validateControlResponse, this, _1,
-           commandName, 200, "OK");
+           commandName, 200, "Success", encodedOptions);
 
     Interest command(commandName);
     manager.onFibRequest(command);
@@ -489,7 +588,7 @@
 
     face->onReceiveData +=
       bind(&FibManagerFixture::validateControlResponse, this, _1,
-           commandName, 200, "OK");
+           commandName, 200, "Success", encodedOptions);
 
     Interest command(commandName);
     manager.onFibRequest(command);
@@ -518,7 +617,7 @@
 
     face->onReceiveData +=
       bind(&FibManagerFixture::validateControlResponse, this, _1,
-           commandName, 200, "OK");
+           commandName, 200, "Success", encodedOptions);
 
     Interest command(commandName);
     manager.onFibRequest(command);
@@ -553,7 +652,7 @@
 
   face->onReceiveData +=
     bind(&FibManagerFixture::validateControlResponse, fixture, _1,
-         commandName, 200, "OK");
+         commandName, 200, "Success", encodedOptions);
 
   Interest command(commandName);
   manager.onFibRequest(command);
@@ -642,7 +741,7 @@
 
   face->onReceiveData +=
     bind(&FibManagerFixture::validateControlResponse, fixture, _1,
-         commandName, 200, "OK");
+         commandName, 200, "Success", encodedOptions);
 
   Interest command(commandName);
   manager.onFibRequest(command);