fw: move Forwarder::lookupFib to Strategy::lookupFib

refs #3664

Change-Id: Ib4dd2354d853f7d6455bf08bb6b863b5f77076c1
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 7fad250..502a071 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -527,66 +527,6 @@
   ++m_counters.nOutNacks;
 }
 
-const fib::Entry&
-Forwarder::lookupFib(const pit::Entry& pitEntry) const
-{
-  const Interest& interest = pitEntry.getInterest();
-  // has Link object?
-  if (!interest.hasLink()) {
-    // FIB lookup with Interest name
-    const fib::Entry& fibEntry = m_fib.findLongestPrefixMatch(pitEntry);
-    NFD_LOG_TRACE("lookupFib noLinkObject found=" << fibEntry.getPrefix());
-    return fibEntry;
-  }
-
-  const Link& link = interest.getLink();
-
-  // in producer region?
-  if (m_networkRegionTable.isInProducerRegion(link)) {
-    // FIB lookup with Interest name
-    const fib::Entry& fibEntry = m_fib.findLongestPrefixMatch(pitEntry);
-    NFD_LOG_TRACE("lookupFib inProducerRegion found=" << fibEntry.getPrefix());
-    return fibEntry;
-  }
-
-  // has SelectedDelegation?
-  if (interest.hasSelectedDelegation()) {
-    // FIB lookup with SelectedDelegation
-    Name selectedDelegation = interest.getSelectedDelegation();
-    const fib::Entry& fibEntry = m_fib.findLongestPrefixMatch(selectedDelegation);
-    NFD_LOG_TRACE("lookupFib hasSelectedDelegation=" << selectedDelegation << " found=" << fibEntry.getPrefix());
-    return fibEntry;
-  }
-
-  // FIB lookup with first delegation Name
-  const fib::Entry& fibEntry0 = m_fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
-  // in default-free zone?
-  bool isDefaultFreeZone = !(fibEntry0.getPrefix().size() == 0 && fibEntry0.hasNextHops());
-  if (!isDefaultFreeZone) {
-    NFD_LOG_TRACE("onContentStoreMiss inConsumerRegion found=" << fibEntry0.getPrefix());
-    return fibEntry0;
-  }
-
-  // choose and set SelectedDelegation
-  for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
-    const Name& delegationName = delegation.second;
-    const fib::Entry& fibEntry = m_fib.findLongestPrefixMatch(delegationName);
-    if (fibEntry.hasNextHops()) {
-      /// \todo Don't modify in-record Interests.
-      ///       Set SelectedDelegation in outgoing Interest pipeline.
-      std::for_each(pitEntry.in_begin(), pitEntry.in_end(),
-        [&delegationName] (const pit::InRecord& inR) {
-          const_cast<Interest&>(inR.getInterest()).setSelectedDelegation(delegationName);
-        });
-      NFD_LOG_TRACE("onContentStoreMiss enterDefaultFreeZone"
-                    << " setSelectedDelegation=" << delegationName);
-      return fibEntry;
-    }
-  }
-  BOOST_ASSERT(false);
-  return fibEntry0;
-}
-
 static inline bool
 compare_InRecord_expiry(const pit::InRecord& a, const pit::InRecord& b)
 {
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index 00645ba..44e8eb1 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -173,11 +173,6 @@
     return m_networkRegionTable;
   }
 
-  /** \brief performs a FIB lookup, considering Link object if present
-   */
-  const fib::Entry&
-  lookupFib(const pit::Entry& pitEntry) const;
-
 PUBLIC_WITH_TESTS_ELSE_PRIVATE: // pipelines
   /** \brief incoming Interest pipeline
    */
diff --git a/daemon/fw/strategy.cpp b/daemon/fw/strategy.cpp
index 7e668b6..efe1fac 100644
--- a/daemon/fw/strategy.cpp
+++ b/daemon/fw/strategy.cpp
@@ -87,5 +87,67 @@
   // warning: don't loop on pitEntry->getInRecords(), because in-record is deleted when sending Nack
 }
 
+const fib::Entry&
+Strategy::lookupFib(const pit::Entry& pitEntry) const
+{
+  const Fib& fib = m_forwarder.getFib();
+  const NetworkRegionTable& nrt = m_forwarder.getNetworkRegionTable();
+
+  const Interest& interest = pitEntry.getInterest();
+  // has Link object?
+  if (!interest.hasLink()) {
+    // FIB lookup with Interest name
+    const fib::Entry& fibEntry = fib.findLongestPrefixMatch(pitEntry);
+    NFD_LOG_TRACE("lookupFib noLinkObject found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  const Link& link = interest.getLink();
+
+  // in producer region?
+  if (nrt.isInProducerRegion(link)) {
+    // FIB lookup with Interest name
+    const fib::Entry& fibEntry = fib.findLongestPrefixMatch(pitEntry);
+    NFD_LOG_TRACE("lookupFib inProducerRegion found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  // has SelectedDelegation?
+  if (interest.hasSelectedDelegation()) {
+    // FIB lookup with SelectedDelegation
+    Name selectedDelegation = interest.getSelectedDelegation();
+    const fib::Entry& fibEntry = fib.findLongestPrefixMatch(selectedDelegation);
+    NFD_LOG_TRACE("lookupFib hasSelectedDelegation=" << selectedDelegation << " found=" << fibEntry.getPrefix());
+    return fibEntry;
+  }
+
+  // FIB lookup with first delegation Name
+  const fib::Entry& fibEntry0 = fib.findLongestPrefixMatch(link.getDelegations().begin()->second);
+  // in default-free zone?
+  bool isDefaultFreeZone = !(fibEntry0.getPrefix().size() == 0 && fibEntry0.hasNextHops());
+  if (!isDefaultFreeZone) {
+    NFD_LOG_TRACE("lookupFib inConsumerRegion found=" << fibEntry0.getPrefix());
+    return fibEntry0;
+  }
+
+  // choose and set SelectedDelegation
+  for (const std::pair<uint32_t, Name>& delegation : link.getDelegations()) {
+    const Name& delegationName = delegation.second;
+    const fib::Entry& fibEntry = fib.findLongestPrefixMatch(delegationName);
+    if (fibEntry.hasNextHops()) {
+      /// \todo Don't modify in-record Interests.
+      ///       Set SelectedDelegation in outgoing Interest pipeline.
+      std::for_each(pitEntry.in_begin(), pitEntry.in_end(),
+        [&delegationName] (const pit::InRecord& inR) {
+          const_cast<Interest&>(inR.getInterest()).setSelectedDelegation(delegationName);
+        });
+      NFD_LOG_TRACE("lookupFib enterDefaultFreeZone setSelectedDelegation=" << delegationName);
+      return fibEntry;
+    }
+  }
+  BOOST_ASSERT(false);
+  return fibEntry0;
+}
+
 } // namespace fw
 } // namespace nfd
diff --git a/daemon/fw/strategy.hpp b/daemon/fw/strategy.hpp
index 5cea6a6..5b3cb2b 100644
--- a/daemon/fw/strategy.hpp
+++ b/daemon/fw/strategy.hpp
@@ -179,11 +179,10 @@
             std::initializer_list<const Face*> exceptFaces = std::initializer_list<const Face*>());
 
 protected: // accessors
+  /** \brief performs a FIB lookup, considering Link object if present
+   */
   const fib::Entry&
-  lookupFib(const pit::Entry& pitEntry)
-  {
-    return m_forwarder.lookupFib(pitEntry);
-  }
+  lookupFib(const pit::Entry& pitEntry) const;
 
   MeasurementsAccessor&
   getMeasurements()
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index b771129..85be529 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -721,110 +721,6 @@
   BOOST_CHECK_EQUAL(pit.size(), 0);
 }
 
-BOOST_AUTO_TEST_CASE(LinkDelegation)
-{
-  Forwarder forwarder;
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
-  forwarder.addFace(face1);
-  forwarder.addFace(face2);
-
-  Fib& fib = forwarder.getFib();
-  Pit& pit = forwarder.getPit();
-  NetworkRegionTable& nrt = forwarder.getNetworkRegionTable();
-
-  shared_ptr<Link> link = makeLink("/net/ndnsim", {{10, "/telia/terabits"}, {20, "/ucla/cs"}});
-
-  // consumer region
-  nrt.clear();
-  nrt.insert("/arizona/cs/avenir");
-  fib.insert("/").first->addNextHop(*face2, 10);
-
-  auto interest1 = makeInterest("/net/ndnsim/www/1.html");
-  interest1->setLink(link->wireEncode());
-  shared_ptr<pit::Entry> pit1 = pit.insert(*interest1).first;
-  pit1->insertOrUpdateInRecord(*face1, *interest1);
-
-  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit1).getPrefix(), "/");
-  BOOST_CHECK_EQUAL(interest1->hasSelectedDelegation(), false);
-
-  fib.insert("/").first->removeNextHop(*face2);
-
-  // first default-free router, both delegations are available
-  nrt.clear();
-  nrt.insert("/arizona/cs/hobo");
-  fib.insert("/telia").first->addNextHop(*face2, 10);
-  fib.insert("/ucla").first->addNextHop(*face2, 10);
-
-  auto interest2 = makeInterest("/net/ndnsim/www/2.html");
-  interest2->setLink(link->wireEncode());
-  shared_ptr<pit::Entry> pit2 = pit.insert(*interest2).first;
-  pit2->insertOrUpdateInRecord(*face1, *interest2);
-
-  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit2).getPrefix(), "/telia");
-  BOOST_REQUIRE_EQUAL(interest2->hasSelectedDelegation(), true);
-  BOOST_CHECK_EQUAL(interest2->getSelectedDelegation(), "/telia/terabits");
-
-  fib.erase("/telia");
-  fib.erase("/ucla");
-
-  // first default-free router, only second delegation is available
-  nrt.clear();
-  nrt.insert("/arizona/cs/hobo");
-  fib.insert("/ucla").first->addNextHop(*face2, 10);
-
-  auto interest3 = makeInterest("/net/ndnsim/www/3.html");
-  interest3->setLink(link->wireEncode());
-  shared_ptr<pit::Entry> pit3 = pit.insert(*interest3).first;
-  pit3->insertOrUpdateInRecord(*face1, *interest3);
-
-  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit3).getPrefix(), "/ucla");
-  BOOST_REQUIRE_EQUAL(interest3->hasSelectedDelegation(), true);
-  BOOST_CHECK_EQUAL(interest3->getSelectedDelegation(), "/ucla/cs");
-
-  fib.erase("/ucla");
-
-  // default-free router, chosen SelectedDelegation
-  nrt.clear();
-  nrt.insert("/ucsd/caida/click");
-  fib.insert("/telia").first->addNextHop(*face2, 10);
-  fib.insert("/ucla").first->addNextHop(*face2, 10);
-
-  auto interest4 = makeInterest("/net/ndnsim/www/4.html");
-  interest4->setLink(link->wireEncode());
-  interest4->setSelectedDelegation("/ucla/cs");
-  shared_ptr<pit::Entry> pit4 = pit.insert(*interest4).first;
-  pit4->insertOrUpdateInRecord(*face1, *interest4);
-
-  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit4).getPrefix(), "/ucla");
-  BOOST_REQUIRE_EQUAL(interest4->hasSelectedDelegation(), true);
-  BOOST_CHECK_EQUAL(interest4->getSelectedDelegation(), "/ucla/cs");
-
-  fib.erase("/telia");
-  fib.erase("/ucla");
-
-  // producer region
-  nrt.clear();
-  nrt.insert("/ucla/cs/spurs");
-  fib.insert("/").first->addNextHop(*face2, 10);
-  fib.insert("/ucla").first->addNextHop(*face2, 10);
-  fib.insert("/net/ndnsim").first->addNextHop(*face2, 10);
-
-  auto interest5 = makeInterest("/net/ndnsim/www/5.html");
-  interest5->setLink(link->wireEncode());
-  interest5->setSelectedDelegation("/ucla/cs");
-  shared_ptr<pit::Entry> pit5 = pit.insert(*interest5).first;
-  pit5->insertOrUpdateInRecord(*face1, *interest5);
-
-  BOOST_CHECK_EQUAL(forwarder.lookupFib(*pit1).getPrefix(), "/net/ndnsim");
-  BOOST_REQUIRE_EQUAL(interest5->hasSelectedDelegation(), true);
-  BOOST_CHECK_EQUAL(interest5->getSelectedDelegation(), "/ucla/cs");
-
-  fib.insert("/").first->removeNextHop(*face2);
-  fib.erase("/ucla");
-  fib.erase("/ndnsim");
-}
-
 
 class MalformedPacketFixture : public UnitTestTimeFixture
 {
diff --git a/tests/daemon/fw/strategy.t.cpp b/tests/daemon/fw/strategy.t.cpp
index f4b4543..10e13cb 100644
--- a/tests/daemon/fw/strategy.t.cpp
+++ b/tests/daemon/fw/strategy.t.cpp
@@ -98,6 +98,143 @@
   BOOST_CHECK((strategy.removedFaces == std::vector<FaceId>{id2, id1}));
 }
 
+class LookupFibFixture : public BaseFixture
+{
+protected:
+  class TestStrategy : public DummyStrategy
+  {
+  public:
+    explicit
+    TestStrategy(Forwarder& forwarder)
+      : DummyStrategy(forwarder, Name("ndn:/strategy"))
+    {
+    }
+
+    const fib::Entry&
+    lookupFib(const pit::Entry& pitEntry) const
+    {
+      return this->Strategy::lookupFib(pitEntry);
+    }
+  };
+
+  LookupFibFixture()
+    : strategy(forwarder)
+    , fib(forwarder.getFib())
+    , pit(forwarder.getPit())
+    , nrt(forwarder.getNetworkRegionTable())
+  {
+  }
+
+protected:
+  Forwarder forwarder;
+  TestStrategy strategy;
+  Fib& fib;
+  Pit& pit;
+  NetworkRegionTable& nrt;
+};
+
+BOOST_FIXTURE_TEST_CASE(LookupFib, LookupFibFixture)
+{
+  /// \todo test lookupFib without Link
+  /// \todo split each step to a separate test case
+
+  shared_ptr<Face> face1 = make_shared<DummyFace>();
+  shared_ptr<Face> face2 = make_shared<DummyFace>();
+  forwarder.addFace(face1);
+  forwarder.addFace(face2);
+
+  shared_ptr<Link> link = makeLink("/net/ndnsim", {{10, "/telia/terabits"}, {20, "/ucla/cs"}});
+
+  // consumer region
+  nrt.clear();
+  nrt.insert("/arizona/cs/avenir");
+  fib.insert("/").first->addNextHop(*face2, 10);
+
+  auto interest1 = makeInterest("/net/ndnsim/www/1.html");
+  interest1->setLink(link->wireEncode());
+  shared_ptr<pit::Entry> pit1 = pit.insert(*interest1).first;
+  pit1->insertOrUpdateInRecord(*face1, *interest1);
+
+  BOOST_CHECK_EQUAL(strategy.lookupFib(*pit1).getPrefix(), "/");
+  BOOST_CHECK_EQUAL(interest1->hasSelectedDelegation(), false);
+
+  fib.insert("/").first->removeNextHop(*face2);
+
+  // first default-free router, both delegations are available
+  nrt.clear();
+  nrt.insert("/arizona/cs/hobo");
+  fib.insert("/telia").first->addNextHop(*face2, 10);
+  fib.insert("/ucla").first->addNextHop(*face2, 10);
+
+  auto interest2 = makeInterest("/net/ndnsim/www/2.html");
+  interest2->setLink(link->wireEncode());
+  shared_ptr<pit::Entry> pit2 = pit.insert(*interest2).first;
+  pit2->insertOrUpdateInRecord(*face1, *interest2);
+
+  BOOST_CHECK_EQUAL(strategy.lookupFib(*pit2).getPrefix(), "/telia");
+  BOOST_REQUIRE_EQUAL(interest2->hasSelectedDelegation(), true);
+  BOOST_CHECK_EQUAL(interest2->getSelectedDelegation(), "/telia/terabits");
+
+  fib.erase("/telia");
+  fib.erase("/ucla");
+
+  // first default-free router, only second delegation is available
+  nrt.clear();
+  nrt.insert("/arizona/cs/hobo");
+  fib.insert("/ucla").first->addNextHop(*face2, 10);
+
+  auto interest3 = makeInterest("/net/ndnsim/www/3.html");
+  interest3->setLink(link->wireEncode());
+  shared_ptr<pit::Entry> pit3 = pit.insert(*interest3).first;
+  pit3->insertOrUpdateInRecord(*face1, *interest3);
+
+  BOOST_CHECK_EQUAL(strategy.lookupFib(*pit3).getPrefix(), "/ucla");
+  BOOST_REQUIRE_EQUAL(interest3->hasSelectedDelegation(), true);
+  BOOST_CHECK_EQUAL(interest3->getSelectedDelegation(), "/ucla/cs");
+
+  fib.erase("/ucla");
+
+  // default-free router, chosen SelectedDelegation
+  nrt.clear();
+  nrt.insert("/ucsd/caida/click");
+  fib.insert("/telia").first->addNextHop(*face2, 10);
+  fib.insert("/ucla").first->addNextHop(*face2, 10);
+
+  auto interest4 = makeInterest("/net/ndnsim/www/4.html");
+  interest4->setLink(link->wireEncode());
+  interest4->setSelectedDelegation("/ucla/cs");
+  shared_ptr<pit::Entry> pit4 = pit.insert(*interest4).first;
+  pit4->insertOrUpdateInRecord(*face1, *interest4);
+
+  BOOST_CHECK_EQUAL(strategy.lookupFib(*pit4).getPrefix(), "/ucla");
+  BOOST_REQUIRE_EQUAL(interest4->hasSelectedDelegation(), true);
+  BOOST_CHECK_EQUAL(interest4->getSelectedDelegation(), "/ucla/cs");
+
+  fib.erase("/telia");
+  fib.erase("/ucla");
+
+  // producer region
+  nrt.clear();
+  nrt.insert("/ucla/cs/spurs");
+  fib.insert("/").first->addNextHop(*face2, 10);
+  fib.insert("/ucla").first->addNextHop(*face2, 10);
+  fib.insert("/net/ndnsim").first->addNextHop(*face2, 10);
+
+  auto interest5 = makeInterest("/net/ndnsim/www/5.html");
+  interest5->setLink(link->wireEncode());
+  interest5->setSelectedDelegation("/ucla/cs");
+  shared_ptr<pit::Entry> pit5 = pit.insert(*interest5).first;
+  pit5->insertOrUpdateInRecord(*face1, *interest5);
+
+  BOOST_CHECK_EQUAL(strategy.lookupFib(*pit1).getPrefix(), "/net/ndnsim");
+  BOOST_REQUIRE_EQUAL(interest5->hasSelectedDelegation(), true);
+  BOOST_CHECK_EQUAL(interest5->getSelectedDelegation(), "/ucla/cs");
+
+  fib.insert("/").first->removeNextHop(*face2);
+  fib.erase("/ucla");
+  fib.erase("/ndnsim");
+}
+
 BOOST_AUTO_TEST_SUITE_END() // TestStrategy
 BOOST_AUTO_TEST_SUITE_END() // Fw