fw: pull FaceTable construction out of Forwarder class

Refs: #4922, #4973
Change-Id: Ibbd4a8840cb0d01ebbd4cabf9c34fa78a1d23db1
diff --git a/daemon/face/face-system.cpp b/daemon/face/face-system.cpp
index 67738aa..5601057 100644
--- a/daemon/face/face-system.cpp
+++ b/daemon/face/face-system.cpp
@@ -34,15 +34,17 @@
 
 NFD_LOG_INIT(FaceSystem);
 
-static const std::string SECTION_GENERAL = "general";
-static const std::string SECTION_NETDEVBOUND = "netdev_bound";
+const std::string CFGSEC_FACESYSTEM = "face_system";
+const std::string CFGSEC_GENERAL = "general";
+const std::string CFGSEC_GENERAL_FQ = CFGSEC_FACESYSTEM + ".general";
+const std::string CFGSEC_NETDEVBOUND = "netdev_bound";
 
 FaceSystem::FaceSystem(FaceTable& faceTable, shared_ptr<ndn::net::NetworkMonitor> netmon)
   : m_faceTable(faceTable)
   , m_netmon(std::move(netmon))
 {
   auto pfCtorParams = this->makePFCtorParams();
-  for (const std::string& id : ProtocolFactory::listRegistered()) {
+  for (const auto& id : ProtocolFactory::listRegistered()) {
     NFD_LOG_TRACE("creating factory " << id);
     m_factories[id] = ProtocolFactory::create(id, pfCtorParams);
   }
@@ -53,7 +55,7 @@
 ProtocolFactoryCtorParams
 FaceSystem::makePFCtorParams()
 {
-  auto addFace = [&ft = m_faceTable] (auto face) { ft.add(std::move(face)); };
+  auto addFace = [this] (auto face) { m_faceTable.add(std::move(face)); };
   return {addFace, m_netmon};
 }
 
@@ -92,25 +94,25 @@
 void
 FaceSystem::setConfigFile(ConfigFile& configFile)
 {
-  configFile.addSectionHandler("face_system", bind(&FaceSystem::processConfig, this, _1, _2, _3));
+  configFile.addSectionHandler(CFGSEC_FACESYSTEM, bind(&FaceSystem::processConfig, this, _1, _2, _3));
 }
 
 void
-FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string& filename)
+FaceSystem::processConfig(const ConfigSection& configSection, bool isDryRun, const std::string&)
 {
   ConfigContext context;
   context.isDryRun = isDryRun;
 
   // process general protocol factory config section
-  auto generalSection = configSection.get_child_optional(SECTION_GENERAL);
+  auto generalSection = configSection.get_child_optional(CFGSEC_GENERAL);
   if (generalSection) {
     for (const auto& pair : *generalSection) {
       const std::string& key = pair.first;
       if (key == "enable_congestion_marking") {
-        context.generalConfig.wantCongestionMarking = ConfigFile::parseYesNo(pair, "face_system.general");
+        context.generalConfig.wantCongestionMarking = ConfigFile::parseYesNo(pair, CFGSEC_GENERAL_FQ);
       }
       else {
-        NDN_THROW(ConfigFile::Error("Unrecognized option face_system.general." + key));
+        NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_GENERAL_FQ + "." + key));
       }
     }
   }
@@ -140,7 +142,7 @@
   }
 
   // process netdev_bound section, after factories start providing *+dev schemes
-  auto netdevBoundSection = configSection.get_child_optional(SECTION_NETDEVBOUND);
+  auto netdevBoundSection = configSection.get_child_optional(CFGSEC_NETDEVBOUND);
   m_netdevBound->processConfig(netdevBoundSection, context);
 
   // process other sections
@@ -150,15 +152,15 @@
     // const ConfigSection& subSection = pair.second;
 
     if (!seenSections.insert(sectionName).second) {
-      NDN_THROW(ConfigFile::Error("Duplicate section face_system." + sectionName));
+      NDN_THROW(ConfigFile::Error("Duplicate section " + CFGSEC_FACESYSTEM + "." + sectionName));
     }
 
-    if (sectionName == SECTION_GENERAL || sectionName == SECTION_NETDEVBOUND ||
+    if (sectionName == CFGSEC_GENERAL || sectionName == CFGSEC_NETDEVBOUND ||
         m_factories.count(sectionName) > 0) {
       continue;
     }
 
-    NDN_THROW(ConfigFile::Error("Unrecognized option face_system." + sectionName));
+    NDN_THROW(ConfigFile::Error("Unrecognized option " + CFGSEC_FACESYSTEM + "." + sectionName));
   }
 }
 
diff --git a/daemon/fw/face-table.hpp b/daemon/fw/face-table.hpp
index f501813..d1c51c7 100644
--- a/daemon/fw/face-table.hpp
+++ b/daemon/fw/face-table.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2019,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -27,6 +27,7 @@
 #define NFD_DAEMON_FW_FACE_TABLE_HPP
 
 #include "face/face.hpp"
+
 #include <boost/range/adaptor/indirected.hpp>
 #include <boost/range/adaptor/map.hpp>
 
@@ -79,15 +80,15 @@
   end() const;
 
 public: // signals
-  /** \brief fires after a face is added
+  /** \brief Fires immediately after a face is added.
    */
-  signal::Signal<FaceTable, Face&> afterAdd;
+  signal::Signal<FaceTable, Face> afterAdd;
 
-  /** \brief fires before a face is removed
+  /** \brief Fires immediately before a face is removed.
    *
-   *  When this signal is emitted, face is still in FaceTable and has valid FaceId.
+   *  When this signal is emitted, the face is still in FaceTable and has a valid FaceId.
    */
-  signal::Signal<FaceTable, Face&> beforeRemove;
+  signal::Signal<FaceTable, Face> beforeRemove;
 
 private:
   void
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 4c91fb7..f59963e 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -44,14 +44,15 @@
   return fw::BestRouteStrategy2::getStrategyName();
 }
 
-Forwarder::Forwarder()
-  : m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
+Forwarder::Forwarder(FaceTable& faceTable)
+  : m_faceTable(faceTable)
+  , m_unsolicitedDataPolicy(make_unique<fw::DefaultUnsolicitedDataPolicy>())
   , m_fib(m_nameTree)
   , m_pit(m_nameTree)
   , m_measurements(m_nameTree)
   , m_strategyChoice(*this)
 {
-  m_faceTable.afterAdd.connect([this] (Face& face) {
+  m_faceTable.afterAdd.connect([this] (const Face& face) {
     face.afterReceiveInterest.connect(
       [this, &face] (const Interest& interest, const EndpointId& endpointId) {
         this->startProcessInterest(FaceEndpoint(face, endpointId), interest);
@@ -70,7 +71,7 @@
       });
   });
 
-  m_faceTable.beforeRemove.connect([this] (Face& face) {
+  m_faceTable.beforeRemove.connect([this] (const Face& face) {
     cleanupOnFaceRemoval(m_nameTree, m_fib, m_pit, face);
   });
 
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index cc1d048..3b14a61 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -44,14 +44,15 @@
 class Strategy;
 } // namespace fw
 
-/** \brief Main class of NFD forwarding engine.
+/** \brief Main class of NFD's forwarding engine.
  *
- *  Forwarder owns all faces and tables, and implements the forwarding pipelines.
+ *  Forwarder owns all tables and implements the forwarding pipelines.
  */
 class Forwarder
 {
 public:
-  Forwarder();
+  explicit
+  Forwarder(FaceTable& faceTable);
 
   VIRTUAL_WITH_TESTS
   ~Forwarder();
@@ -62,33 +63,6 @@
     return m_counters;
   }
 
-public: // faces and policies
-  FaceTable&
-  getFaceTable()
-  {
-    return m_faceTable;
-  }
-
-  /** \brief get existing Face
-   *
-   *  shortcut to .getFaceTable().get(face)
-   */
-  Face*
-  getFace(FaceId id) const
-  {
-    return m_faceTable.get(id);
-  }
-
-  /** \brief add new Face
-   *
-   *  shortcut to .getFaceTable().add(face)
-   */
-  void
-  addFace(shared_ptr<Face> face)
-  {
-    m_faceTable.add(face);
-  }
-
   fw::UnsolicitedDataPolicy&
   getUnsolicitedDataPolicy() const
   {
@@ -274,7 +248,7 @@
 private:
   ForwarderCounters m_counters;
 
-  FaceTable m_faceTable;
+  FaceTable& m_faceTable;
   unique_ptr<fw::UnsolicitedDataPolicy> m_unsolicitedDataPolicy;
 
   NameTree           m_nameTree;
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index b0b9362..f9f4106 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -141,8 +141,8 @@
 }
 
 Strategy::Strategy(Forwarder& forwarder)
-  : afterAddFace(forwarder.getFaceTable().afterAdd)
-  , beforeRemoveFace(forwarder.getFaceTable().beforeRemove)
+  : afterAddFace(forwarder.m_faceTable.afterAdd)
+  , beforeRemoveFace(forwarder.m_faceTable.beforeRemove)
   , m_forwarder(forwarder)
   , m_measurements(m_forwarder.getMeasurements(), m_forwarder.getStrategyChoice(), *this)
 {
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 8c62329..99e4826 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -322,13 +322,13 @@
   Face*
   getFace(FaceId id) const
   {
-    return m_forwarder.getFace(id);
+    return getFaceTable().get(id);
   }
 
   const FaceTable&
   getFaceTable() const
   {
-    return m_forwarder.getFaceTable();
+    return m_forwarder.m_faceTable;
   }
 
 protected: // instance name
@@ -379,8 +379,8 @@
   find(const Name& instanceName);
 
 protected: // accessors
-  signal::Signal<FaceTable, Face&>& afterAddFace;
-  signal::Signal<FaceTable, Face&>& beforeRemoveFace;
+  signal::Signal<FaceTable, Face>& afterAddFace;
+  signal::Signal<FaceTable, Face>& beforeRemoveFace;
 
 private: // instance fields
   Name m_name;
diff --git a/daemon/nfd.cpp b/daemon/nfd.cpp
index 63af6c7..e07b5d8 100644
--- a/daemon/nfd.cpp
+++ b/daemon/nfd.cpp
@@ -30,6 +30,7 @@
 #include "face/face-system.hpp"
 #include "face/internal-face.hpp"
 #include "face/null-face.hpp"
+#include "fw/face-table.hpp"
 #include "fw/forwarder.hpp"
 #include "mgmt/cs-manager.hpp"
 #include "mgmt/face-manager.hpp"
@@ -76,26 +77,25 @@
 {
   configureLogging();
 
-  m_forwarder = make_unique<Forwarder>();
+  m_faceTable = make_unique<FaceTable>();
+  m_faceTable->addReserved(face::makeNullFace(), face::FACEID_NULL);
+  m_faceTable->addReserved(face::makeNullFace(FaceUri("contentstore://")), face::FACEID_CONTENT_STORE);
 
-  FaceTable& faceTable = m_forwarder->getFaceTable();
-  faceTable.addReserved(face::makeNullFace(), face::FACEID_NULL);
-  faceTable.addReserved(face::makeNullFace(FaceUri("contentstore://")), face::FACEID_CONTENT_STORE);
-  m_faceSystem = make_unique<face::FaceSystem>(faceTable, m_netmon);
+  m_faceSystem = make_unique<face::FaceSystem>(*m_faceTable, m_netmon);
+  m_forwarder = make_unique<Forwarder>(*m_faceTable);
 
   initializeManagement();
 
   PrivilegeHelper::drop();
 
   m_netmon->onNetworkStateChanged.connect([this] {
-      // delay stages, so if multiple events are triggered in short sequence,
-      // only one auto-detection procedure is triggered
-      m_reloadConfigEvent = getScheduler().schedule(5_s,
-        [this] {
-          NFD_LOG_INFO("Network change detected, reloading face section of the config file...");
-          this->reloadConfigFileFaceSection();
-        });
+    // delay stages, so if multiple events are triggered in short sequence,
+    // only one auto-detection procedure is triggered
+    m_reloadConfigEvent = getScheduler().schedule(5_s, [this] {
+      NFD_LOG_INFO("Network change detected, reloading face section of the config file...");
+      reloadConfigFileFaceSection();
     });
+  });
 }
 
 void
@@ -133,14 +133,14 @@
 Nfd::initializeManagement()
 {
   std::tie(m_internalFace, m_internalClientFace) = face::makeInternalFace(m_keyChain);
-  m_forwarder->getFaceTable().addReserved(m_internalFace, face::FACEID_INTERNAL_FACE);
+  m_faceTable->addReserved(m_internalFace, face::FACEID_INTERNAL_FACE);
 
   m_dispatcher = make_unique<ndn::mgmt::Dispatcher>(*m_internalClientFace, m_keyChain);
   m_authenticator = CommandAuthenticator::create();
 
   m_forwarderStatusManager = make_unique<ForwarderStatusManager>(*m_forwarder, *m_dispatcher);
   m_faceManager = make_unique<FaceManager>(*m_faceSystem, *m_dispatcher, *m_authenticator);
-  m_fibManager = make_unique<FibManager>(m_forwarder->getFib(), m_forwarder->getFaceTable(),
+  m_fibManager = make_unique<FibManager>(m_forwarder->getFib(), *m_faceTable,
                                          *m_dispatcher, *m_authenticator);
   m_csManager = make_unique<CsManager>(m_forwarder->getCs(), m_forwarder->getCounters(),
                                        *m_dispatcher, *m_authenticator);
diff --git a/daemon/nfd.hpp b/daemon/nfd.hpp
index 508876c..787afb8 100644
--- a/daemon/nfd.hpp
+++ b/daemon/nfd.hpp
@@ -35,10 +35,10 @@
 
 namespace nfd {
 
+class FaceTable;
 class Forwarder;
-class CommandAuthenticator;
 
-// forward-declare management modules, in the order defined in management protocol
+class CommandAuthenticator;
 class ForwarderStatusManager;
 class FaceManager;
 class FibManager;
@@ -110,8 +110,9 @@
   std::string m_configFile;
   ConfigSection m_configSection;
 
-  unique_ptr<Forwarder> m_forwarder;
+  unique_ptr<FaceTable> m_faceTable;
   unique_ptr<face::FaceSystem> m_faceSystem;
+  unique_ptr<Forwarder> m_forwarder;
 
   ndn::KeyChain& m_keyChain;
   shared_ptr<face::Face> m_internalFace;
diff --git a/tests/daemon/fw/asf-strategy.t.cpp b/tests/daemon/fw/asf-strategy.t.cpp
index 77cb4b6..09013ee 100644
--- a/tests/daemon/fw/asf-strategy.t.cpp
+++ b/tests/daemon/fw/asf-strategy.t.cpp
@@ -469,7 +469,8 @@
   }
 
 protected:
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
 };
 
 BOOST_FIXTURE_TEST_CASE(InstantiationTest, ParametersFixture)
diff --git a/tests/daemon/fw/best-route-strategy2.t.cpp b/tests/daemon/fw/best-route-strategy2.t.cpp
index 3ab261e..fa9d883 100644
--- a/tests/daemon/fw/best-route-strategy2.t.cpp
+++ b/tests/daemon/fw/best-route-strategy2.t.cpp
@@ -43,27 +43,25 @@
 {
 protected:
   BestRouteStrategy2Fixture()
-    : strategy(forwarder)
-    , fib(forwarder.getFib())
-    , pit(forwarder.getPit())
-    , face1(make_shared<DummyFace>())
+    : face1(make_shared<DummyFace>())
     , face2(make_shared<DummyFace>())
     , face3(make_shared<DummyFace>())
     , face4(make_shared<DummyFace>())
     , face5(make_shared<DummyFace>())
   {
-    forwarder.addFace(face1);
-    forwarder.addFace(face2);
-    forwarder.addFace(face3);
-    forwarder.addFace(face4);
-    forwarder.addFace(face5);
+    faceTable.add(face1);
+    faceTable.add(face2);
+    faceTable.add(face3);
+    faceTable.add(face4);
+    faceTable.add(face5);
   }
 
-public:
-  Forwarder forwarder;
-  BestRouteStrategy2Tester strategy;
-  Fib& fib;
-  Pit& pit;
+protected:
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  BestRouteStrategy2Tester strategy{forwarder};
+  Fib& fib{forwarder.getFib()};
+  Pit& pit{forwarder.getPit()};
 
   shared_ptr<DummyFace> face1;
   shared_ptr<DummyFace> face2;
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index c2e646e..af362e1 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -37,17 +37,30 @@
 namespace nfd {
 namespace tests {
 
+class ForwarderFixture : public GlobalIoTimeFixture
+{
+protected:
+  template<typename ...Args>
+  shared_ptr<DummyFace>
+  addFace(Args&&... args)
+  {
+    auto face = make_shared<DummyFace>(std::forward<Args>(args)...);
+    faceTable.add(face);
+    return face;
+  }
+
+protected:
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+};
+
 BOOST_AUTO_TEST_SUITE(Fw)
-BOOST_FIXTURE_TEST_SUITE(TestForwarder, GlobalIoTimeFixture)
+BOOST_FIXTURE_TEST_SUITE(TestForwarder, ForwarderFixture)
 
 BOOST_AUTO_TEST_CASE(SimpleExchange)
 {
-  Forwarder forwarder;
-
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = addFace();
+  auto face2 = addFace();
 
   Fib& fib = forwarder.getFib();
   fib::Entry* entry = fib.insert("/A").first;
@@ -82,14 +95,9 @@
 
 BOOST_AUTO_TEST_CASE(CsMatched)
 {
-  Forwarder forwarder;
-
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace();
 
   Fib& fib = forwarder.getFib();
   fib::Entry* entry = fib.insert("/A").first;
@@ -124,11 +132,8 @@
 
 BOOST_AUTO_TEST_CASE(OutgoingInterest)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = addFace();
+  auto face2 = addFace();
 
   Pit& pit = forwarder.getPit();
   auto interestA1 = makeInterest("/A", false, nullopt, 8378);
@@ -148,14 +153,9 @@
 
 BOOST_AUTO_TEST_CASE(NextHopFaceId)
 {
-  Forwarder forwarder;
-
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace();
 
   Fib& fib = forwarder.getFib();
   fib::Entry* entry = fib.insert("/A").first;
@@ -174,6 +174,8 @@
 class ScopeLocalhostIncomingTestForwarder : public Forwarder
 {
 public:
+  using Forwarder::Forwarder;
+
   void
   onDataUnsolicited(const FaceEndpoint&, const Data&) final
   {
@@ -192,13 +194,15 @@
   int onDataUnsolicited_count = 0;
 };
 
-BOOST_AUTO_TEST_CASE(ScopeLocalhostIncoming)
+BOOST_FIXTURE_TEST_CASE(ScopeLocalhostIncoming, GlobalIoTimeFixture)
 {
-  ScopeLocalhostIncomingTestForwarder forwarder;
+  FaceTable faceTable;
+  ScopeLocalhostIncomingTestForwarder forwarder(faceTable);
+
   auto face1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
   auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   // local face, /localhost: OK
   forwarder.dispatchToStrategy_count = 0;
@@ -251,11 +255,8 @@
 
 BOOST_AUTO_TEST_CASE(IncomingInterestStrategyDispatch)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = addFace();
+  auto face2 = addFace();
 
   DummyStrategy& strategyA = choose<DummyStrategy>(forwarder, "/", DummyStrategy::getStrategyName());
   DummyStrategy& strategyB = choose<DummyStrategy>(forwarder, "/B", DummyStrategy::getStrategyName());
@@ -292,15 +293,10 @@
 
 BOOST_AUTO_TEST_CASE(IncomingData)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>();
-  auto face4 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
-  forwarder.addFace(face4);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace();
+  auto face4 = addFace();
 
   Pit& pit = forwarder.getPit();
   auto interestD = makeInterest("/A/B/C/D");
@@ -327,16 +323,12 @@
 
 BOOST_AUTO_TEST_CASE(IncomingNack)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
-                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
-                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace("dummy://", "dummy://",
+                       ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                       ndn::nfd::LINK_TYPE_MULTI_ACCESS);
 
   DummyStrategy& strategyA = choose<DummyStrategy>(forwarder, "/", DummyStrategy::getStrategyName());
   DummyStrategy& strategyB = choose<DummyStrategy>(forwarder, "/B", DummyStrategy::getStrategyName());
@@ -410,16 +402,12 @@
 
 BOOST_AUTO_TEST_CASE(OutgoingNack)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
-                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
-                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace("dummy://", "dummy://",
+                       ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                       ndn::nfd::LINK_TYPE_MULTI_ACCESS);
 
   Pit& pit = forwarder.getPit();
 
@@ -474,18 +462,13 @@
 
 BOOST_AUTO_TEST_CASE(InterestLoopNack)
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
-                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
-                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
-  auto face4 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
-  forwarder.addFace(face4);
+  auto face1 = addFace();
+  auto face2 = addFace();
+  auto face3 = addFace("dummy://", "dummy://",
+                       ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                       ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+  auto face4 = addFace();
 
   Fib& fib = forwarder.getFib();
   fib::Entry* entry = fib.insert("/zT4XwK0Hnx").first;
@@ -526,11 +509,8 @@
 
 BOOST_AUTO_TEST_CASE(InterestLoopWithShortLifetime) // Bug 1953
 {
-  Forwarder forwarder;
-  auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = addFace();
+  auto face2 = addFace();
 
   // cause an Interest sent out of face2 to loop back into face1 after a delay
   face2->afterSend.connect([face1, face2] (uint32_t pktType) {
@@ -563,9 +543,7 @@
 
 BOOST_AUTO_TEST_CASE(PitLeak) // Bug 3484
 {
-  Forwarder forwarder;
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
+  auto face1 = addFace();
 
   auto interest = makeInterest("/hcLSAsQ9A", false, 2_s, 61883075);
 
diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp
index 7db3abd..526d7b0 100644
--- a/tests/daemon/fw/multicast-strategy.t.cpp
+++ b/tests/daemon/fw/multicast-strategy.t.cpp
@@ -41,23 +41,22 @@
 {
 protected:
   MulticastStrategyFixture()
-    : strategy(forwarder)
-    , fib(forwarder.getFib())
-    , pit(forwarder.getPit())
-    , face1(make_shared<DummyFace>())
+    : face1(make_shared<DummyFace>())
     , face2(make_shared<DummyFace>())
     , face3(make_shared<DummyFace>())
   {
-    forwarder.addFace(face1);
-    forwarder.addFace(face2);
-    forwarder.addFace(face3);
+    faceTable.add(face1);
+    faceTable.add(face2);
+    faceTable.add(face3);
   }
 
 protected:
-  Forwarder forwarder;
-  MulticastStrategyTester strategy;
-  Fib& fib;
-  Pit& pit;
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  MulticastStrategyTester strategy{forwarder};
+  Fib& fib{forwarder.getFib()};
+  Pit& pit{forwarder.getPit()};
+
   shared_ptr<DummyFace> face1;
   shared_ptr<DummyFace> face2;
   shared_ptr<DummyFace> face3;
diff --git a/tests/daemon/fw/ncc-strategy.t.cpp b/tests/daemon/fw/ncc-strategy.t.cpp
index 7b03f4f..3c3f4d4 100644
--- a/tests/daemon/fw/ncc-strategy.t.cpp
+++ b/tests/daemon/fw/ncc-strategy.t.cpp
@@ -46,16 +46,17 @@
   // and favors this upstream in subsequent Interests.
 
   LimitedIo limitedIo(this);
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
@@ -106,15 +107,16 @@
 
 BOOST_AUTO_TEST_CASE(Bug1853)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
@@ -156,16 +158,17 @@
 BOOST_AUTO_TEST_CASE(Bug1961)
 {
   LimitedIo limitedIo(this);
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
@@ -211,14 +214,15 @@
 BOOST_AUTO_TEST_CASE(Bug1971)
 {
   LimitedIo limitedIo(this);
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
   strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
@@ -255,13 +259,14 @@
 
 BOOST_AUTO_TEST_CASE(Bug1998)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NccStrategyTester& strategy = choose<NccStrategyTester>(forwarder);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Fib& fib = forwarder.getFib();
   fib::Entry& fibEntry = *fib.insert(Name()).first;
diff --git a/tests/daemon/fw/pit-expiry.t.cpp b/tests/daemon/fw/pit-expiry.t.cpp
index d69448c..16956fc 100644
--- a/tests/daemon/fw/pit-expiry.t.cpp
+++ b/tests/daemon/fw/pit-expiry.t.cpp
@@ -121,12 +121,13 @@
 
 BOOST_AUTO_TEST_CASE(UnsatisfiedInterest)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Pit& pit = forwarder.getPit();
 
@@ -145,12 +146,13 @@
 
 BOOST_AUTO_TEST_CASE(SatisfiedInterest)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Pit& pit = forwarder.getPit();
 
@@ -169,12 +171,13 @@
 
 BOOST_AUTO_TEST_CASE(CsHit)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Name strategyA("/strategyA/%FD%01");
   PitExpiryTestStrategy::registerAs(strategyA);
@@ -206,14 +209,15 @@
 
 BOOST_AUTO_TEST_CASE(ReceiveNack)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
   auto face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Name strategyA("/strategyA/%FD%01");
   PitExpiryTestStrategy::registerAs(strategyA);
@@ -241,10 +245,11 @@
 
 BOOST_AUTO_TEST_CASE(ResetTimerAfterReceiveInterest)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face = make_shared<DummyFace>();
-  forwarder.addFace(face);
+  faceTable.add(face);
 
   Name strategyA("/strategyA/%FD%01");
   PitExpiryTestStrategy::registerAs(strategyA);
@@ -266,14 +271,15 @@
 
 BOOST_AUTO_TEST_CASE(ResetTimerBeforeSatisfyInterest)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
   auto face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Name strategyA("/strategyA/%FD%01");
   Name strategyB("/strategyB/%FD%01");
@@ -322,12 +328,13 @@
 
 BOOST_AUTO_TEST_CASE(ResetTimerAfterReceiveData)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   Name strategyA("/strategyA/%FD%01");
   PitExpiryTestStrategy::registerAs(strategyA);
@@ -368,14 +375,15 @@
 
 BOOST_AUTO_TEST_CASE(ReceiveNackAfterResetTimer)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
   auto face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   Name strategyA("/strategyA/%FD%01");
   PitExpiryTestStrategy::registerAs(strategyA);
diff --git a/tests/daemon/fw/random-strategy.t.cpp b/tests/daemon/fw/random-strategy.t.cpp
index 84347f5..4822e4c 100644
--- a/tests/daemon/fw/random-strategy.t.cpp
+++ b/tests/daemon/fw/random-strategy.t.cpp
@@ -43,25 +43,23 @@
 {
 protected:
   RandomStrategyFixture()
-    : strategy(forwarder)
-    , fib(forwarder.getFib())
-    , pit(forwarder.getPit())
-    , face1(make_shared<DummyFace>())
+    : face1(make_shared<DummyFace>())
     , face2(make_shared<DummyFace>())
     , face3(make_shared<DummyFace>())
     , face4(make_shared<DummyFace>())
   {
-    forwarder.addFace(face1);
-    forwarder.addFace(face2);
-    forwarder.addFace(face3);
-    forwarder.addFace(face4);
+    faceTable.add(face1);
+    faceTable.add(face2);
+    faceTable.add(face3);
+    faceTable.add(face4);
   }
 
-public:
-  Forwarder forwarder;
-  RandomStrategyTester strategy;
-  Fib& fib;
-  Pit& pit;
+protected:
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  RandomStrategyTester strategy{forwarder};
+  Fib& fib{forwarder.getFib()};
+  Pit& pit{forwarder.getPit()};
 
   shared_ptr<DummyFace> face1;
   shared_ptr<DummyFace> face2;
diff --git a/tests/daemon/fw/retx-suppression.t.cpp b/tests/daemon/fw/retx-suppression.t.cpp
index 07831ae..3522ace 100644
--- a/tests/daemon/fw/retx-suppression.t.cpp
+++ b/tests/daemon/fw/retx-suppression.t.cpp
@@ -42,7 +42,8 @@
 
 BOOST_AUTO_TEST_CASE(Fixed)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   Pit& pit = forwarder.getPit();
   static const time::milliseconds MIN_RETX_INTERVAL(200);
   RetxSuppressionFixed rs(MIN_RETX_INTERVAL);
@@ -50,9 +51,9 @@
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-  forwarder.addFace(face3);
+  faceTable.add(face1);
+  faceTable.add(face2);
+  faceTable.add(face3);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/0JiimvmxK8");
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
@@ -91,14 +92,15 @@
 
 BOOST_AUTO_TEST_CASE(Exponential)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   Pit& pit = forwarder.getPit();
   RetxSuppressionExponential rs(10_ms, 3.0, 100_ms);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/smuVeQSW6q");
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
@@ -159,14 +161,15 @@
 
 BOOST_AUTO_TEST_CASE(ExponentialPerUpstream)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   Pit& pit = forwarder.getPit();
   RetxSuppressionExponential rs(10_ms, 3.0, 100_ms);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   shared_ptr<Interest> interest = makeInterest("ndn:/covfefeW6q");
   shared_ptr<pit::Entry> pitEntry = pit.insert(*interest).first;
diff --git a/tests/daemon/fw/strategy-instantiation.t.cpp b/tests/daemon/fw/strategy-instantiation.t.cpp
index 705b3aa..312294c 100644
--- a/tests/daemon/fw/strategy-instantiation.t.cpp
+++ b/tests/daemon/fw/strategy-instantiation.t.cpp
@@ -96,7 +96,8 @@
   uint64_t maxVersion = T::Strategy::getStrategyName().at(-1).toVersion();
   BOOST_REQUIRE_LE(T::getMinVersion(), maxVersion);
 
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   for (uint64_t version = T::getMinVersion(); version <= maxVersion; ++version) {
     Name versionedName = T::getVersionedStrategyName(version);
     unique_ptr<typename T::Strategy> instance;
diff --git a/tests/daemon/fw/strategy-nack-return.t.cpp b/tests/daemon/fw/strategy-nack-return.t.cpp
index bfddf0c..870253b 100644
--- a/tests/daemon/fw/strategy-nack-return.t.cpp
+++ b/tests/daemon/fw/strategy-nack-return.t.cpp
@@ -51,6 +51,7 @@
 public:
   StrategyNackReturnFixture()
     : limitedIo(this)
+    , forwarder(faceTable)
     , strategy(choose<StrategyTester<S>>(forwarder))
     , fib(forwarder.getFib())
     , pit(forwarder.getPit())
@@ -60,16 +61,17 @@
     , face4(make_shared<DummyFace>())
     , face5(make_shared<DummyFace>())
   {
-    forwarder.addFace(face1);
-    forwarder.addFace(face2);
-    forwarder.addFace(face3);
-    forwarder.addFace(face4);
-    forwarder.addFace(face5);
+    faceTable.add(face1);
+    faceTable.add(face2);
+    faceTable.add(face3);
+    faceTable.add(face4);
+    faceTable.add(face5);
   }
 
 public:
   LimitedIo limitedIo;
 
+  FaceTable faceTable;
   Forwarder forwarder;
   StrategyTester<S>& strategy;
   Fib& fib;
diff --git a/tests/daemon/fw/strategy-no-route.t.cpp b/tests/daemon/fw/strategy-no-route.t.cpp
index 4ebd5cf..26b7874 100644
--- a/tests/daemon/fw/strategy-no-route.t.cpp
+++ b/tests/daemon/fw/strategy-no-route.t.cpp
@@ -53,19 +53,21 @@
 public:
   StrategyNoRouteFixture()
     : limitedIo(this)
+    , forwarder(faceTable)
     , strategy(choose<StrategyTester<S>>(forwarder))
     , fib(forwarder.getFib())
     , pit(forwarder.getPit())
     , face1(make_shared<DummyFace>())
     , face2(make_shared<DummyFace>())
   {
-    forwarder.addFace(face1);
-    forwarder.addFace(face2);
+    faceTable.add(face1);
+    faceTable.add(face2);
   }
 
 public:
   LimitedIo limitedIo;
 
+  FaceTable faceTable;
   Forwarder forwarder;
   StrategyTester<S>& strategy;
   Fib& fib;
diff --git a/tests/daemon/fw/strategy-scope-control.t.cpp b/tests/daemon/fw/strategy-scope-control.t.cpp
index 643e0ee..268ae67 100644
--- a/tests/daemon/fw/strategy-scope-control.t.cpp
+++ b/tests/daemon/fw/strategy-scope-control.t.cpp
@@ -54,6 +54,7 @@
 public:
   StrategyScopeControlFixture()
     : limitedIo(this)
+    , forwarder(faceTable)
     , strategy(choose<StrategyTester<S>>(forwarder))
     , fib(forwarder.getFib())
     , pit(forwarder.getPit())
@@ -62,15 +63,16 @@
     , localFace3(make_shared<DummyFace>("dummy://3", "dummy://3", ndn::nfd::FACE_SCOPE_LOCAL))
     , localFace4(make_shared<DummyFace>("dummy://4", "dummy://4", ndn::nfd::FACE_SCOPE_LOCAL))
   {
-    forwarder.addFace(nonLocalFace1);
-    forwarder.addFace(nonLocalFace2);
-    forwarder.addFace(localFace3);
-    forwarder.addFace(localFace4);
+    faceTable.add(nonLocalFace1);
+    faceTable.add(nonLocalFace2);
+    faceTable.add(localFace3);
+    faceTable.add(localFace4);
   }
 
 public:
   LimitedIo limitedIo;
 
+  FaceTable faceTable;
   Forwarder forwarder;
   StrategyTester<S>& strategy;
   Fib& fib;
diff --git a/tests/daemon/fw/strategy.t.cpp b/tests/daemon/fw/strategy.t.cpp
index 41b0f8d..8b27986 100644
--- a/tests/daemon/fw/strategy.t.cpp
+++ b/tests/daemon/fw/strategy.t.cpp
@@ -83,13 +83,14 @@
 
 BOOST_AUTO_TEST_CASE(FaceTableAccess)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   FaceTableAccessTestStrategy strategy(forwarder);
 
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  faceTable.add(face1);
+  faceTable.add(face2);
   FaceId id1 = face1->getId();
   FaceId id2 = face2->getId();
 
diff --git a/tests/daemon/fw/topology-tester.cpp b/tests/daemon/fw/topology-tester.cpp
index 6a70ead..92495d4 100644
--- a/tests/daemon/fw/topology-tester.cpp
+++ b/tests/daemon/fw/topology-tester.cpp
@@ -197,9 +197,7 @@
 TopologyTester::addForwarder(const std::string& label)
 {
   size_t i = m_forwarders.size();
-  m_forwarders.push_back(make_unique<Forwarder>());
-  m_forwarderLabels.push_back(label);
-  BOOST_ASSERT(m_forwarders.size() == m_forwarderLabels.size());
+  m_forwarders.push_back(make_unique<TopologyForwarder>(label));
   return i;
 }
 
@@ -207,12 +205,11 @@
 TopologyTester::makeFace(TopologyNode i, const FaceUri& localUri, const FaceUri& remoteUri,
                          ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType)
 {
-  Forwarder& forwarder = this->getForwarder(i);
   unique_ptr<GenericLinkService> service = m_wantPcap ? make_unique<TopologyPcapLinkService>() :
                                                         make_unique<GenericLinkService>();
   auto transport = make_unique<InternalForwarderTransport>(localUri, remoteUri, scope, linkType);
   auto face = make_shared<Face>(std::move(service), std::move(transport));
-  forwarder.addFace(face);
+  m_forwarders.at(i)->faceTable.add(face);
   return face;
 }
 
@@ -230,7 +227,7 @@
   BOOST_ASSERT(forwarders.size() <= 2 || linkType != ndn::nfd::LINK_TYPE_POINT_TO_POINT);
 
   for (TopologyNode i : forwarders) {
-    FaceUri localUri("topology://" + m_forwarderLabels.at(i) + "/" + label);
+    FaceUri localUri("topology://" + m_forwarders.at(i)->label + "/" + label);
     auto face = makeFace(i, localUri, remoteUri, ndn::nfd::FACE_SCOPE_NON_LOCAL, linkType);
     link->addFace(i, std::move(face));
   }
@@ -242,8 +239,8 @@
 shared_ptr<TopologyAppLink>
 TopologyTester::addAppFace(const std::string& label, TopologyNode i)
 {
-  FaceUri localUri("topology://" + m_forwarderLabels.at(i) + "/local/" + label);
-  FaceUri remoteUri("topology://" + m_forwarderLabels.at(i) + "/app/" + label);
+  FaceUri localUri("topology://" + m_forwarders.at(i)->label + "/local/" + label);
+  FaceUri remoteUri("topology://" + m_forwarders.at(i)->label + "/app/" + label);
   auto face = makeFace(i, localUri, remoteUri, ndn::nfd::FACE_SCOPE_LOCAL, ndn::nfd::LINK_TYPE_POINT_TO_POINT);
 
   auto al = make_shared<TopologyAppLink>(std::move(face));
@@ -263,8 +260,8 @@
 TopologyTester::addBareLink(const std::string& label, TopologyNode i, ndn::nfd::FaceScope scope,
                             ndn::nfd::LinkType linkType)
 {
-  FaceUri localUri("topology://" + m_forwarderLabels.at(i) + "/local/" + label);
-  FaceUri remoteUri("topology://" + m_forwarderLabels.at(i) + "/bare/" + label);
+  FaceUri localUri("topology://" + m_forwarders.at(i)->label + "/local/" + label);
+  FaceUri remoteUri("topology://" + m_forwarders.at(i)->label + "/bare/" + label);
   auto face = makeFace(i, localUri, remoteUri, scope, linkType);
 
   auto bl = make_shared<TopologyBareLink>(std::move(face));
@@ -272,12 +269,6 @@
   return bl;
 }
 
-void
-TopologyTester::enablePcap(bool isEnabled)
-{
-  m_wantPcap = isEnabled;
-}
-
 TopologyPcap&
 TopologyTester::getPcap(const Face& face)
 {
diff --git a/tests/daemon/fw/topology-tester.hpp b/tests/daemon/fw/topology-tester.hpp
index 9243476..6e5cb95 100644
--- a/tests/daemon/fw/topology-tester.hpp
+++ b/tests/daemon/fw/topology-tester.hpp
@@ -260,7 +260,7 @@
   Forwarder&
   getForwarder(TopologyNode i)
   {
-    return *m_forwarders.at(i);
+    return m_forwarders.at(i)->forwarder;
   }
 
   /** \brief sets strategy on forwarder \p i
@@ -310,7 +310,10 @@
   /** \brief enables packet capture on every forwarder face
    */
   void
-  enablePcap(bool isEnabled = true);
+  enablePcap(bool isEnabled = true)
+  {
+    m_wantPcap = isEnabled;
+  }
 
   /** \return captured packets on a forwarder face
    *  \pre enablePcap(true) is in effect when the face was created
@@ -342,12 +345,26 @@
            ndn::nfd::FaceScope scope, ndn::nfd::LinkType linkType);
 
 private:
-  bool m_wantPcap = false;
-  std::vector<unique_ptr<Forwarder>> m_forwarders;
-  std::vector<std::string> m_forwarderLabels;
+  class TopologyForwarder
+  {
+  public:
+    explicit
+    TopologyForwarder(const std::string& label)
+      : label(label)
+    {
+    }
+
+  public:
+    std::string label;
+    FaceTable faceTable;
+    Forwarder forwarder{faceTable};
+  };
+
+  std::vector<unique_ptr<TopologyForwarder>> m_forwarders;
   std::vector<shared_ptr<TopologyLink>> m_links;
   std::vector<shared_ptr<TopologyAppLink>> m_appLinks;
   std::vector<shared_ptr<TopologyBareLink>> m_bareLinks;
+  bool m_wantPcap = false;
 };
 
 } // namespace tests
diff --git a/tests/daemon/fw/unsolicited-data-policy.t.cpp b/tests/daemon/fw/unsolicited-data-policy.t.cpp
index 11eafe1..21894ca 100644
--- a/tests/daemon/fw/unsolicited-data-policy.t.cpp
+++ b/tests/daemon/fw/unsolicited-data-policy.t.cpp
@@ -42,11 +42,6 @@
 class UnsolicitedDataPolicyFixture : public GlobalIoTimeFixture
 {
 protected:
-  UnsolicitedDataPolicyFixture()
-    : cs(forwarder.getCs())
-  {
-  }
-
   /** \tparam Policy policy type, or void to keep default policy
    */
   template<typename Policy>
@@ -72,8 +67,9 @@
   }
 
 protected:
-  Forwarder forwarder;
-  Cs& cs;
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  Cs& cs{forwarder.getCs()};
 };
 
 template<>
@@ -117,7 +113,7 @@
 
   auto face1 = make_shared<DummyFace>("dummy://", "dummy://",
                                       ndn::nfd::FACE_SCOPE_LOCAL);
-  forwarder.addFace(face1);
+  faceTable.add(face1);
 
   shared_ptr<Data> data1 = makeData("/unsolicited-from-local");
   forwarder.onIncomingData(FaceEndpoint(*face1, 0), *data1);
@@ -125,7 +121,7 @@
 
   auto face2 = make_shared<DummyFace>("dummy://", "dummy://",
                                       ndn::nfd::FACE_SCOPE_NON_LOCAL);
-  forwarder.addFace(face2);
+  faceTable.add(face2);
 
   shared_ptr<Data> data2 = makeData("/unsolicited-from-non-local");
   forwarder.onIncomingData(FaceEndpoint(*face2, 0), *data2);
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index 8a418e5..0930374 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -46,8 +46,7 @@
 {
 public:
   FaceManagerFixture()
-    : m_faceTable(m_forwarder.getFaceTable())
-    , m_faceSystem(m_faceTable, make_shared<ndn::net::NetworkMonitorStub>(0))
+    : m_faceSystem(m_faceTable, make_shared<ndn::net::NetworkMonitorStub>(0))
     , m_manager(m_faceSystem, m_dispatcher, *m_authenticator)
   {
     setTopPrefix();
@@ -113,7 +112,6 @@
   }
 
 protected:
-  FaceTable& m_faceTable;
   FaceSystem m_faceSystem;
   FaceManager m_manager;
 };
diff --git a/tests/daemon/mgmt/fib-manager.t.cpp b/tests/daemon/mgmt/fib-manager.t.cpp
index 4907a61..048f76d 100644
--- a/tests/daemon/mgmt/fib-manager.t.cpp
+++ b/tests/daemon/mgmt/fib-manager.t.cpp
@@ -40,7 +40,6 @@
 public:
   FibManagerFixture()
     : m_fib(m_forwarder.getFib())
-    , m_faceTable(m_forwarder.getFaceTable())
     , m_manager(m_fib, m_faceTable, m_dispatcher, *m_authenticator)
   {
     setTopPrefix();
@@ -126,7 +125,6 @@
 
 protected:
   Fib&       m_fib;
-  FaceTable& m_faceTable;
   FibManager m_manager;
 };
 
@@ -144,8 +142,7 @@
     return os << "NO_NEXTHOP";
   case FibManagerFixture::CheckNextHopResult::WRONG_COST:
     return os << "WRONG_COST";
-  };
-
+  }
   return os << static_cast<int>(result);
 }
 
diff --git a/tests/daemon/mgmt/forwarder-status-manager.t.cpp b/tests/daemon/mgmt/forwarder-status-manager.t.cpp
index e40e20d..132375a 100644
--- a/tests/daemon/mgmt/forwarder-status-manager.t.cpp
+++ b/tests/daemon/mgmt/forwarder-status-manager.t.cpp
@@ -35,13 +35,15 @@
 {
 protected:
   ForwarderStatusManagerFixture()
-    : m_manager(m_forwarder, m_dispatcher)
+    : m_forwarder(m_faceTable)
+    , m_manager(m_forwarder, m_dispatcher)
     , m_startTime(time::system_clock::now())
   {
     setTopPrefix();
   }
 
 protected:
+  FaceTable m_faceTable;
   Forwarder m_forwarder;
   ForwarderStatusManager m_manager;
   time::system_clock::TimePoint m_startTime;
diff --git a/tests/daemon/mgmt/manager-common-fixture.hpp b/tests/daemon/mgmt/manager-common-fixture.hpp
index b5bae0d..3557627 100644
--- a/tests/daemon/mgmt/manager-common-fixture.hpp
+++ b/tests/daemon/mgmt/manager-common-fixture.hpp
@@ -171,7 +171,8 @@
   setPrivilege(const std::string& privilege);
 
 protected:
-  Forwarder m_forwarder;
+  FaceTable m_faceTable;
+  Forwarder m_forwarder{m_faceTable};
   shared_ptr<CommandAuthenticator> m_authenticator = CommandAuthenticator::create();
 };
 
diff --git a/tests/daemon/mgmt/tables-config-section.t.cpp b/tests/daemon/mgmt/tables-config-section.t.cpp
index cfcc3ba..dfce51e 100644
--- a/tests/daemon/mgmt/tables-config-section.t.cpp
+++ b/tests/daemon/mgmt/tables-config-section.t.cpp
@@ -40,7 +40,8 @@
 {
 protected:
   TablesConfigSectionFixture()
-    : cs(forwarder.getCs())
+    : forwarder(faceTable)
+    , cs(forwarder.getCs())
     , strategyChoice(forwarder.getStrategyChoice())
     , networkRegionTable(forwarder.getNetworkRegionTable())
     , tablesConfig(forwarder)
@@ -62,6 +63,7 @@
   }
 
 protected:
+  FaceTable faceTable;
   Forwarder forwarder;
   Cs& cs;
   StrategyChoice& strategyChoice;
diff --git a/tests/daemon/table/cleanup.t.cpp b/tests/daemon/table/cleanup.t.cpp
index ae83f78..b7395a3 100644
--- a/tests/daemon/table/cleanup.t.cpp
+++ b/tests/daemon/table/cleanup.t.cpp
@@ -74,14 +74,15 @@
 
 BOOST_AUTO_TEST_CASE(RemoveFibNexthops)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   NameTree& nameTree = forwarder.getNameTree();
   Fib& fib = forwarder.getFib();
 
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   // {}
   size_t nNameTreeEntriesBefore = nameTree.size();
@@ -130,13 +131,14 @@
 
 BOOST_AUTO_TEST_CASE(DeletePitInOutRecords)
 {
-  Forwarder forwarder;
+  FaceTable faceTable;
+  Forwarder forwarder(faceTable);
   Pit& pit = forwarder.getPit();
 
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  faceTable.add(face1);
+  faceTable.add(face2);
 
   // {}
   BOOST_CHECK_EQUAL(pit.size(), 0);
diff --git a/tests/daemon/table/measurements-accessor.t.cpp b/tests/daemon/table/measurements-accessor.t.cpp
index aeed38f..1c5a850 100644
--- a/tests/daemon/table/measurements-accessor.t.cpp
+++ b/tests/daemon/table/measurements-accessor.t.cpp
@@ -62,7 +62,6 @@
 {
 protected:
   MeasurementsAccessorFixture()
-    : measurements(forwarder.getMeasurements())
   {
     const Name strategyP("/measurements-accessor-test-strategy-P/%FD%01");
     const Name strategyQ("/measurements-accessor-test-strategy-Q/%FD%01");
@@ -81,8 +80,9 @@
   }
 
 protected:
-  Forwarder forwarder;
-  Measurements& measurements;
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  Measurements& measurements{forwarder.getMeasurements()};
   MeasurementsAccessor* accessor1;
   MeasurementsAccessor* accessor2;
   MeasurementsAccessor* accessor3;
diff --git a/tests/daemon/table/strategy-choice.t.cpp b/tests/daemon/table/strategy-choice.t.cpp
index 339903e..8c52b54 100644
--- a/tests/daemon/table/strategy-choice.t.cpp
+++ b/tests/daemon/table/strategy-choice.t.cpp
@@ -36,9 +36,6 @@
 {
 protected:
   StrategyChoiceFixture()
-    : sc(forwarder.getStrategyChoice())
-    , strategyNameP("/strategy-choice-P/%FD%00")
-    , strategyNameQ("/strategy-choice-Q/%FD%00")
   {
     DummyStrategy::registerAs(strategyNameP);
     DummyStrategy::registerAs(strategyNameQ);
@@ -77,11 +74,12 @@
   }
 
 protected:
-  Forwarder forwarder;
-  StrategyChoice& sc;
+  FaceTable faceTable;
+  Forwarder forwarder{faceTable};
+  StrategyChoice& sc{forwarder.getStrategyChoice()};
 
-  const Name strategyNameP;
-  const Name strategyNameQ;
+  const Name strategyNameP = "/strategy-choice-P/%FD%00";
+  const Name strategyNameQ = "/strategy-choice-Q/%FD%00";
 };
 
 BOOST_AUTO_TEST_SUITE(Table)