util: allow customizing FaceId in DummyClientFace

refs #5011

Change-Id: I0551ec55816f11bf3c05972c9a8bd6a3c4133310
diff --git a/ndn-cxx/util/dummy-client-face.cpp b/ndn-cxx/util/dummy-client-face.cpp
index 8079353..69e6dc5 100644
--- a/ndn-cxx/util/dummy-client-face.cpp
+++ b/ndn-cxx/util/dummy-client-face.cpp
@@ -149,7 +149,7 @@
     this->enablePacketLogging();
 
   if (options.enableRegistrationReply)
-    this->enableRegistrationReply();
+    this->enableRegistrationReply(options.registrationReplyFaceId);
 
   m_processEventsOverride = options.processEventsOverride;
 
@@ -203,17 +203,23 @@
 }
 
 void
-DummyClientFace::enableRegistrationReply()
+DummyClientFace::enableRegistrationReply(uint64_t faceId)
 {
-  onSendInterest.connect([this] (const Interest& interest) {
-    static const Name localhostRegistration("/localhost/nfd/rib");
-    if (!localhostRegistration.isPrefixOf(interest.getName()))
+  onSendInterest.connect([=] (const Interest& interest) {
+    static const Name localhostRibPrefix("/localhost/nfd/rib");
+    static const name::Component registerVerb("register");
+    const auto& name = interest.getName();
+    if (name.size() <= 4 || !localhostRibPrefix.isPrefixOf(name))
       return;
 
-    nfd::ControlParameters params(interest.getName().get(-5).blockFromValue());
-    params.setFaceId(1);
-    params.setOrigin(nfd::ROUTE_ORIGIN_APP);
-    if (interest.getName().get(3) == name::Component("register")) {
+    nfd::ControlParameters params(name[4].blockFromValue());
+    if (!params.hasFaceId()) {
+      params.setFaceId(faceId);
+    }
+    if (!params.hasOrigin()) {
+      params.setOrigin(nfd::ROUTE_ORIGIN_APP);
+    }
+    if (!params.hasCost() && name[3] == registerVerb) {
       params.setCost(0);
     }
 
@@ -221,11 +227,9 @@
     resp.setCode(200);
     resp.setBody(params.wireEncode());
 
-    shared_ptr<Data> data = make_shared<Data>(interest.getName());
+    shared_ptr<Data> data = make_shared<Data>(name);
     data->setContent(resp.wireEncode());
-
     m_keyChain.sign(*data, security::SigningInfo(security::SigningInfo::SIGNER_TYPE_SHA256));
-
     this->getIoService().post([this, data] { this->receive(*data); });
   });
 }
diff --git a/ndn-cxx/util/dummy-client-face.hpp b/ndn-cxx/util/dummy-client-face.hpp
index 599d934..4b86222 100644
--- a/ndn-cxx/util/dummy-client-face.hpp
+++ b/ndn-cxx/util/dummy-client-face.hpp
@@ -67,6 +67,10 @@
      */
     bool enableRegistrationReply;
 
+    /** \brief FaceId used in prefix registration replies.
+     */
+    uint64_t registrationReplyFaceId = 1;
+
     /** \brief if not empty, face.processEvents() will be overridden by this function
      */
     std::function<void(time::milliseconds)> processEventsOverride;
@@ -138,7 +142,7 @@
   enablePacketLogging();
 
   void
-  enableRegistrationReply();
+  enableRegistrationReply(uint64_t faceId);
 
   void
   doProcessEvents(time::milliseconds timeout, bool keepThread) override;
diff --git a/tests/unit/util/dummy-client-face.t.cpp b/tests/unit/util/dummy-client-face.t.cpp
index b823be2..ad0c3bf 100644
--- a/tests/unit/util/dummy-client-face.t.cpp
+++ b/tests/unit/util/dummy-client-face.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2020 Regents of the University of California.
+ * Copyright (c) 2013-2022 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,6 +20,7 @@
  */
 
 #include "ndn-cxx/util/dummy-client-face.hpp"
+#include "ndn-cxx/mgmt/nfd/controller.hpp"
 
 #include "tests/test-common.hpp"
 #include "tests/unit/io-key-chain-fixture.hpp"
@@ -46,6 +47,54 @@
   BOOST_CHECK(isOverrideInvoked);
 }
 
+BOOST_AUTO_TEST_CASE(RegistrationReply)
+{
+  DummyClientFace::Options opts;
+  opts.enableRegistrationReply = true;
+  opts.registrationReplyFaceId = 3001;
+  DummyClientFace face(m_io, m_keyChain, opts);
+
+  ndn::nfd::Controller controller(face, m_keyChain);
+  ndn::nfd::ControlParameters params;
+  bool didRibRegisterSucceed = false;
+  controller.start<ndn::nfd::RibRegisterCommand>(
+    ndn::nfd::ControlParameters()
+      .setName("/Q")
+      .setOrigin(ndn::nfd::ROUTE_ORIGIN_NLSR)
+      .setCost(2400)
+      .setFlags(0),
+    [&] (const ndn::nfd::ControlParameters& p) {
+      BOOST_CHECK_EQUAL(p.getName(), "/Q");
+      BOOST_CHECK_EQUAL(p.getFaceId(), 3001);
+      BOOST_CHECK_EQUAL(p.getOrigin(), ndn::nfd::ROUTE_ORIGIN_NLSR);
+      BOOST_CHECK_EQUAL(p.getCost(), 2400);
+      BOOST_CHECK_EQUAL(p.getFlags(), 0);
+      didRibRegisterSucceed = true;
+    },
+    [] (const ndn::nfd::ControlResponse& r) {
+      BOOST_TEST_FAIL("RibRegisterCommand failed " << r);
+    });
+  advanceClocks(1_ms, 2);
+  BOOST_CHECK(didRibRegisterSucceed);
+
+  bool didRibUnregisterSucceed = false;
+  controller.start<ndn::nfd::RibUnregisterCommand>(
+    ndn::nfd::ControlParameters()
+      .setName("/Q")
+      .setOrigin(ndn::nfd::ROUTE_ORIGIN_NLSR),
+    [&] (const ndn::nfd::ControlParameters& p) {
+      BOOST_CHECK_EQUAL(p.getName(), "/Q");
+      BOOST_CHECK_EQUAL(p.getFaceId(), 3001);
+      BOOST_CHECK_EQUAL(p.getOrigin(), ndn::nfd::ROUTE_ORIGIN_NLSR);
+      didRibUnregisterSucceed = true;
+    },
+    [] (const ndn::nfd::ControlResponse& r) {
+      BOOST_TEST_FAIL("RibUnregisterCommand failed " << r);
+    });
+  advanceClocks(1_ms, 2);
+  BOOST_CHECK(didRibUnregisterSucceed);
+}
+
 BOOST_AUTO_TEST_CASE(BroadcastLink)
 {
   DummyClientFace face1(m_io, m_keyChain, DummyClientFace::Options{true, true});
@@ -56,13 +105,13 @@
   int nFace2Interest = 0;
   face1.setInterestFilter("/face1",
                           [&] (const InterestFilter&, const Interest& interest) {
-                            BOOST_CHECK_EQUAL(interest.getName().toUri(), "/face1/data");
+                            BOOST_CHECK_EQUAL(interest.getName(), "/face1/data");
                             nFace1Interest++;
                             face1.put(ndn::tests::makeNack(interest, lp::NackReason::NO_ROUTE));
                           }, nullptr, nullptr);
   face2.setInterestFilter("/face2",
                           [&] (const InterestFilter&, const Interest& interest) {
-                            BOOST_CHECK_EQUAL(interest.getName().toUri(), "/face2/data");
+                            BOOST_CHECK_EQUAL(interest.getName(), "/face2/data");
                             nFace2Interest++;
                             face2.put(*ndn::tests::makeData("/face2/data"));
                             return;
@@ -74,7 +123,7 @@
   int nFace2Nack = 0;
   face1.expressInterest(*makeInterest("/face2/data"),
                         [&] (const Interest& i, const Data& d) {
-                          BOOST_CHECK_EQUAL(d.getName().toUri(), "/face2/data");
+                          BOOST_CHECK_EQUAL(d.getName(), "/face2/data");
                           nFace1Data++;
                         }, nullptr, nullptr);
   face2.expressInterest(*makeInterest("/face1/data"),
@@ -82,7 +131,7 @@
                           BOOST_CHECK(false);
                         },
                         [&] (const Interest& i, const lp::Nack& n) {
-                          BOOST_CHECK_EQUAL(n.getInterest().getName().toUri(), "/face1/data");
+                          BOOST_CHECK_EQUAL(n.getInterest().getName(), "/face1/data");
                           nFace2Nack++;
                         }, nullptr);