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/access-strategy.t.cpp b/tests/daemon/fw/access-strategy.t.cpp
index ddc0092..fa211a6 100644
--- a/tests/daemon/fw/access-strategy.t.cpp
+++ b/tests/daemon/fw/access-strategy.t.cpp
@@ -47,7 +47,8 @@
 // code style rule 3.25. This is necessary because some lines ends with '\' which
 // would cause "multi-line comment" compiler warning if '//' comments are used.
 
-BOOST_FIXTURE_TEST_SUITE(FwAccessStrategy, UnitTestTimeFixture)
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, UnitTestTimeFixture)
 
 class TwoLaptopsFixture : public UnitTestTimeFixture
 {
@@ -65,14 +66,14 @@
      *      +---------+             +---------+
      */
 
-    router = topo.addForwarder();
-    laptopA = topo.addForwarder();
-    laptopB = topo.addForwarder();
+    router = topo.addForwarder("R");
+    laptopA = topo.addForwarder("A");
+    laptopB = topo.addForwarder("B");
 
     topo.setStrategy<fw::AccessStrategy>(router);
 
-    linkA = topo.addLink(time::milliseconds(10), {router, laptopA});
-    linkB = topo.addLink(time::milliseconds(20), {router, laptopB});
+    linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
+    linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
   }
 
 protected:
@@ -115,19 +116,19 @@
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
   topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
 
-  shared_ptr<TopologyAppLink> producer = topo.addAppFace(laptopA, "ndn:/laptops/A");
-  topo.addEchoProducer(*producer->getClientFace());
+  shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
+  topo.addEchoProducer(producer->getClientFace());
 
-  shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
-  topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/A",
+  shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
+  topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
                            time::milliseconds(100), 100);
 
   this->advanceClocks(time::milliseconds(5), time::seconds(12));
 
   // most Interests should be satisfied, and few Interests can go to wrong laptop
-  BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
-  BOOST_CHECK_GE(linkA->getFace(router)->m_sentInterests.size(), 97);
-  BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 5);
+  BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().getNOutDatas(), 97);
+  BOOST_CHECK_GE(linkA->getFace(router).getCounters().getNOutInterests(), 97);
+  BOOST_CHECK_LE(linkB->getFace(router).getCounters().getNOutInterests(), 5);
 }
 
 BOOST_FIXTURE_TEST_CASE(FastSlowProducer, TwoLaptopsFixture)
@@ -160,21 +161,21 @@
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
   topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
 
-  shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/BOTH");
-  topo.addEchoProducer(*producerA->getClientFace());
-  shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/BOTH");
-  topo.addEchoProducer(*producerB->getClientFace());
+  shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
+  topo.addEchoProducer(producerA->getClientFace());
+  shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
+  topo.addEchoProducer(producerB->getClientFace());
 
-  shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
-  topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/BOTH",
+  shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
+  topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
                            time::milliseconds(100), 100);
 
   this->advanceClocks(time::milliseconds(5), time::seconds(12));
 
   // most Interests should be satisfied, and few Interests can go to slower laptopB
-  BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
-  BOOST_CHECK_GE(linkA->getFace(router)->m_sentInterests.size(), 90);
-  BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 15);
+  BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().getNOutDatas(), 97);
+  BOOST_CHECK_GE(linkA->getFace(router).getCounters().getNOutInterests(), 90);
+  BOOST_CHECK_LE(linkB->getFace(router).getCounters().getNOutInterests(), 15);
 }
 
 BOOST_FIXTURE_TEST_CASE(ProducerMobility, TwoLaptopsFixture)
@@ -207,13 +208,13 @@
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
   topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
 
-  shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/M");
-  topo.addEchoProducer(*producerA->getClientFace());
-  shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/M");
-  topo.addEchoProducer(*producerB->getClientFace());
+  shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
+  topo.addEchoProducer(producerA->getClientFace());
+  shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
+  topo.addEchoProducer(producerB->getClientFace());
 
-  shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
-  topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/M",
+  shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
+  topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
                            time::milliseconds(100), 100);
 
   // producer is initially on laptopA
@@ -221,19 +222,19 @@
   this->advanceClocks(time::milliseconds(5), time::seconds(6));
 
   // few Interests can go to laptopB
-  BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 5);
+  BOOST_CHECK_LE(linkB->getFace(router).getCounters().getNOutInterests(), 5);
 
   // producer moves to laptopB
   producerA->fail();
   producerB->recover();
-  linkA->getFace(router)->m_sentInterests.clear();
+  const_cast<FaceCounters&>(linkA->getFace(router).getCounters()).getNOutInterests().set(0);
   this->advanceClocks(time::milliseconds(5), time::seconds(6));
 
   // few additional Interests can go to laptopA
-  BOOST_CHECK_LE(linkA->getFace(router)->m_sentInterests.size(), 5);
+  BOOST_CHECK_LE(linkA->getFace(router).getCounters().getNOutInterests(), 5);
 
   // most Interests should be satisfied
-  BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
+  BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().getNOutDatas(), 97);
 }
 
 BOOST_FIXTURE_TEST_CASE(Bidirectional, TwoLaptopsFixture)
@@ -263,23 +264,23 @@
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
   topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
 
-  shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/A");
-  topo.addEchoProducer(*producerA->getClientFace());
-  shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/B");
-  topo.addEchoProducer(*producerB->getClientFace());
+  shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
+  topo.addEchoProducer(producerA->getClientFace());
+  shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
+  topo.addEchoProducer(producerB->getClientFace());
 
-  shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace(laptopA);
-  topo.addIntervalConsumer(*consumerAB->getClientFace(), "ndn:/laptops/B",
+  shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
+  topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
                            time::milliseconds(100), 100);
-  shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace(laptopB);
-  topo.addIntervalConsumer(*consumerBA->getClientFace(), "ndn:/laptops/A",
+  shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
+  topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
                            time::milliseconds(100), 100);
 
   this->advanceClocks(time::milliseconds(5), time::seconds(12));
 
   // most Interests should be satisfied
-  BOOST_CHECK_GE(consumerAB->getForwarderFace()->m_sentDatas.size(), 97);
-  BOOST_CHECK_GE(consumerBA->getForwarderFace()->m_sentDatas.size(), 97);
+  BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().getNOutDatas(), 97);
+  BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().getNOutDatas(), 97);
 }
 
 BOOST_FIXTURE_TEST_CASE(PacketLoss, TwoLaptopsFixture)
@@ -308,25 +309,25 @@
   // laptopA has prefix in router FIB; laptopB is unused in this test case
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
 
-  shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/A");
-  topo.addEchoProducer(*producerA->getClientFace());
+  shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
+  topo.addEchoProducer(producerA->getClientFace());
 
-  shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
+  shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
 
   // Interest 1 completes normally
   shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
   bool hasData1 = false;
-  consumer->getClientFace()->expressInterest(*interest1,
-                                             bind([&hasData1] { hasData1 = true; }));
+  consumer->getClientFace().expressInterest(*interest1,
+                                            bind([&hasData1] { hasData1 = true; }));
   this->advanceClocks(time::milliseconds(5), time::seconds(1));
   BOOST_CHECK_EQUAL(hasData1, true);
 
   // Interest 2 experiences a packet loss on initial transmission
   shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
   bool hasData2a = false, hasTimeout2a = false;
-  consumer->getClientFace()->expressInterest(*interest2a,
-                                             bind([&hasData2a] { hasData2a = true; }),
-                                             bind([&hasTimeout2a] { hasTimeout2a = true; }));
+  consumer->getClientFace().expressInterest(*interest2a,
+                                            bind([&hasData2a] { hasData2a = true; }),
+                                            bind([&hasTimeout2a] { hasTimeout2a = true; }));
   producerA->fail();
   this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
   BOOST_CHECK_EQUAL(hasData2a, false);
@@ -335,8 +336,8 @@
   // Interest 2 retransmission is suppressed
   shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
   bool hasData2b = false;
-  consumer->getClientFace()->expressInterest(*interest2b,
-                                             bind([&hasData2b] { hasData2b = true; }));
+  consumer->getClientFace().expressInterest(*interest2b,
+                                            bind([&hasData2b] { hasData2b = true; }));
   producerA->recover();
   this->advanceClocks(time::milliseconds(5), time::seconds(1));
   BOOST_CHECK_EQUAL(hasData2b, false);
@@ -344,8 +345,8 @@
   // Interest 2 retransmission gets through, and is answered
   shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
   bool hasData2c = false;
-  consumer->getClientFace()->expressInterest(*interest2c,
-                                             bind([&hasData2c] { hasData2c = true; }));
+  consumer->getClientFace().expressInterest(*interest2c,
+                                            bind([&hasData2c] { hasData2c = true; }));
   this->advanceClocks(time::milliseconds(5), time::seconds(1));
   BOOST_CHECK_EQUAL(hasData2c, true);
 }
@@ -357,17 +358,18 @@
   topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
 
   // send Interests from laptopA to router
-  shared_ptr<TopologyAppLink> consumer = topo.addAppFace(laptopA);
-  topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/net",
+  shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
+  topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
                            time::milliseconds(100), 10);
 
   this->advanceClocks(time::milliseconds(5), time::seconds(2));
 
   // Interest shouldn't loop back from router
-  BOOST_CHECK_EQUAL(linkA->getFace(router)->m_sentInterests.size(), 0);
+  BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().getNOutInterests(), 0);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
+BOOST_AUTO_TEST_SUITE_END() // Fw
 
 } // namespace tests
 } // namespace fw