fw: Nack in pipelines and best-route strategy

* in PIT out-record, add last incoming Nack field
* create incoming Nack pipeline
* create outgoing Nack pipeline
* modify Interest loop pipeline to send Nack upon duplicate Nonce
* in strategy API, add after receive Nack trigger and send Nack action
* in best-route strategy, send Nack-NoRoute before rejecting pending Interest
* in best-route strategy, process incoming Nack

Other changes include:

* Pit::find
* StrategyTester saved arguments structs
* TopologyTester transmit at Transport level

refs #3156

Change-Id: I7868561c0838231083d471261200aeb280cc6e9d
diff --git a/tests/daemon/fw/multicast-strategy.t.cpp b/tests/daemon/fw/multicast-strategy.t.cpp
index c67c408..3476cd3 100644
--- a/tests/daemon/fw/multicast-strategy.t.cpp
+++ b/tests/daemon/fw/multicast-strategy.t.cpp
@@ -35,7 +35,8 @@
 
 using namespace nfd::tests;
 
-BOOST_FIXTURE_TEST_SUITE(FwMulticastStrategy, BaseFixture)
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestMulticastStrategy, BaseFixture)
 
 BOOST_AUTO_TEST_CASE(Forward2)
 {
@@ -62,21 +63,17 @@
   pitEntry->insertOrUpdateInRecord(face3, *interest);
 
   strategy.afterReceiveInterest(*face3, *interest, fibEntry, pitEntry);
-  BOOST_CHECK_EQUAL(strategy.m_rejectPendingInterestHistory.size(), 0);
-  BOOST_CHECK_EQUAL(strategy.m_sendInterestHistory.size(), 2);
-  bool hasFace1 = false;
-  bool hasFace2 = false;
-  for (std::vector<MulticastStrategyTester::SendInterestArgs>::iterator it =
-       strategy.m_sendInterestHistory.begin();
-       it != strategy.m_sendInterestHistory.end(); ++it) {
-    if (it->get<1>() == face1) {
-      hasFace1 = true;
-    }
-    if (it->get<1>() == face2) {
-      hasFace2 = true;
-    }
-  }
-  BOOST_CHECK(hasFace1 && hasFace2);
+  BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 0);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 2);
+  std::set<FaceId> sentInterestFaceIds;
+  std::transform(strategy.sendInterestHistory.begin(), strategy.sendInterestHistory.end(),
+                 std::inserter(sentInterestFaceIds, sentInterestFaceIds.end()),
+                 [] (const MulticastStrategyTester::SendInterestArgs& args) {
+                   return args.outFaceId;
+                 });
+  std::set<FaceId> expectedInterestFaceIds{face1->getId(), face2->getId()};
+  BOOST_CHECK_EQUAL_COLLECTIONS(sentInterestFaceIds.begin(), sentInterestFaceIds.end(),
+                                expectedInterestFaceIds.begin(), expectedInterestFaceIds.end());
 }
 
 BOOST_AUTO_TEST_CASE(RejectScope)
@@ -100,8 +97,8 @@
   pitEntry->insertOrUpdateInRecord(face1, *interest);
 
   strategy.afterReceiveInterest(*face1, *interest, fibEntry, pitEntry);
-  BOOST_CHECK_EQUAL(strategy.m_rejectPendingInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy.m_sendInterestHistory.size(), 0);
+  BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 0);
 }
 
 BOOST_AUTO_TEST_CASE(RejectLoopback)
@@ -123,11 +120,12 @@
   pitEntry->insertOrUpdateInRecord(face1, *interest);
 
   strategy.afterReceiveInterest(*face1, *interest, fibEntry, pitEntry);
-  BOOST_CHECK_EQUAL(strategy.m_rejectPendingInterestHistory.size(), 1);
-  BOOST_CHECK_EQUAL(strategy.m_sendInterestHistory.size(), 0);
+  BOOST_CHECK_EQUAL(strategy.rejectPendingInterestHistory.size(), 1);
+  BOOST_CHECK_EQUAL(strategy.sendInterestHistory.size(), 0);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestMulticastStrategy
+BOOST_AUTO_TEST_SUITE_END() // Fw
 
 } // namespace tests
 } // namespace fw