fw: use dead Nonce list in pipelines

refs #1953

Change-Id: I0faef2a985b03fe96387c2e0181588713550b9ce
diff --git a/tests/daemon/fw/forwarder.cpp b/tests/daemon/fw/forwarder.cpp
index 6856d8f..930de00 100644
--- a/tests/daemon/fw/forwarder.cpp
+++ b/tests/daemon/fw/forwarder.cpp
@@ -424,6 +424,38 @@
   BOOST_CHECK_EQUAL(face4->m_sentDatas.size(), 1);
 }
 
+static inline void
+delayedInterestLoop(const time::nanoseconds& delay, DummyFace& face, const Interest& interest)
+{
+  scheduler::schedule(delay, bind(&DummyFace::receiveInterest, &face, cref(interest)));
+}
+
+BOOST_AUTO_TEST_CASE(Bug1953) // persistent loop with short InterestLifetime
+{
+  LimitedIo limitedIo;
+  Forwarder forwarder;
+  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
+  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
+  forwarder.addFace(face1);
+  forwarder.addFace(face2);
+
+  // cause an Interest sent out of face2 to loop back into face1 after a delay
+  face2->onSendInterest += bind(&delayedInterestLoop, time::milliseconds(170), ref(*face1), _1);
+
+  Fib& fib = forwarder.getFib();
+  shared_ptr<fib::Entry> fibEntry = fib.insert(Name("ndn:/A")).first;
+  fibEntry->addNextHop(face2, 0);
+
+  shared_ptr<Interest> interest = makeInterest("ndn:/A/1");
+  interest->setNonce(82101183);
+  interest->setInterestLifetime(time::milliseconds(50));
+  face1->receiveInterest(*interest);
+
+  limitedIo.defer(time::milliseconds(1000));
+
+  BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 1);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests
diff --git a/tests/daemon/table/dead-nonce-list.cpp b/tests/daemon/table/dead-nonce-list.cpp
index c8a59bb..970d537 100644
--- a/tests/daemon/table/dead-nonce-list.cpp
+++ b/tests/daemon/table/dead-nonce-list.cpp
@@ -41,14 +41,21 @@
   const uint32_t nonce2 = 0x1f46372b;
 
   DeadNonceList dnl;
-
+  BOOST_CHECK_EQUAL(dnl.size(), 0);
   BOOST_CHECK_EQUAL(dnl.has(nameA, nonce1), false);
+
   dnl.add(nameA, nonce1);
+  BOOST_CHECK_EQUAL(dnl.size(), 1);
   BOOST_CHECK_EQUAL(dnl.has(nameA, nonce1), true);
   BOOST_CHECK_EQUAL(dnl.has(nameA, nonce2), false);
   BOOST_CHECK_EQUAL(dnl.has(nameB, nonce1), false);
 }
 
+BOOST_AUTO_TEST_CASE(MinLifetime)
+{
+  BOOST_CHECK_THROW(DeadNonceList dnl(time::milliseconds::zero()), std::invalid_argument);
+}
+
 /// A Fixture that periodically inserts Nonces
 class PeriodicalInsertionFixture : public BaseFixture
 {
@@ -100,6 +107,8 @@
 
 BOOST_FIXTURE_TEST_CASE(Lifetime, PeriodicalInsertionFixture)
 {
+  BOOST_CHECK_EQUAL(dnl.getLifetime(), LIFETIME);
+
   LimitedIo limitedIo;
 
   const int RATE = DeadNonceList::INITIAL_CAPACITY / 2;
diff --git a/tests/daemon/table/pit.cpp b/tests/daemon/table/pit.cpp
index 566421f..8e73a12 100644
--- a/tests/daemon/table/pit.cpp
+++ b/tests/daemon/table/pit.cpp
@@ -33,27 +33,6 @@
 
 BOOST_FIXTURE_TEST_SUITE(TablePit, BaseFixture)
 
-BOOST_AUTO_TEST_CASE(NonceList)
-{
-  BOOST_REQUIRE_GE(pit::NonceList::CAPACITY, 32);
-  BOOST_REQUIRE_LE(pit::NonceList::CAPACITY, 4096);
-
-  pit::NonceList nl;
-  for (uint32_t nonce = 0; nonce < static_cast<uint32_t>(pit::NonceList::CAPACITY); ++nonce) {
-    BOOST_CHECK_EQUAL(nl.add(nonce), true);
-  }
-  BOOST_CHECK_EQUAL(nl.size(), pit::NonceList::CAPACITY);
-
-  BOOST_CHECK_EQUAL(nl.add(32), false);
-  BOOST_CHECK_EQUAL(nl.size(), pit::NonceList::CAPACITY);
-
-  BOOST_CHECK_EQUAL(nl.add(4096), true);
-  BOOST_CHECK_EQUAL(nl.size(), pit::NonceList::CAPACITY);
-
-  BOOST_CHECK_EQUAL(nl.add(0), true);// 0 is evicted
-  BOOST_CHECK_EQUAL(nl.size(), pit::NonceList::CAPACITY);
-}
-
 BOOST_AUTO_TEST_CASE(EntryInOutRecords)
 {
   shared_ptr<Face> face1 = make_shared<DummyFace>();
@@ -171,20 +150,68 @@
 
 BOOST_AUTO_TEST_CASE(EntryNonce)
 {
+  shared_ptr<Face> face1 = make_shared<DummyFace>();
+  shared_ptr<Face> face2 = make_shared<DummyFace>();
+
   shared_ptr<Interest> interest = makeInterest("ndn:/qtCQ7I1c");
+  interest->setNonce(25559);
 
-  pit::Entry entry(*interest);
+  pit::Entry entry0(*interest);
+  BOOST_CHECK_EQUAL(entry0.findNonce(25559, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry0.findNonce(25559, *face2), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry0.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry0.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
 
-  BOOST_CHECK_EQUAL(entry.addNonce(25559), true);
-  BOOST_CHECK_EQUAL(entry.addNonce(25559), false);
-  BOOST_CHECK_EQUAL(entry.addNonce(19004), true);
-  BOOST_CHECK_EQUAL(entry.addNonce(19004), false);
+  pit::Entry entry1(*interest);
+  entry1.insertOrUpdateInRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(entry1.findNonce(25559, *face1), pit::DUPLICATE_NONCE_IN_SAME);
+  BOOST_CHECK_EQUAL(entry1.findNonce(25559, *face2), pit::DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(entry1.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry1.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry2(*interest);
+  entry2.insertOrUpdateOutRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(entry2.findNonce(25559, *face1), pit::DUPLICATE_NONCE_OUT_SAME);
+  BOOST_CHECK_EQUAL(entry2.findNonce(25559, *face2), pit::DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(entry2.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry2.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry3(*interest);
+  entry3.insertOrUpdateInRecord(face1, *interest);
+  entry3.insertOrUpdateOutRecord(face1, *interest);
+  BOOST_CHECK_EQUAL(entry3.findNonce(25559, *face1),
+                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_OUT_SAME);
+  BOOST_CHECK_EQUAL(entry3.findNonce(25559, *face2),
+                    pit::DUPLICATE_NONCE_IN_OTHER | pit::DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(entry3.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry3.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry4(*interest);
+  entry4.insertOrUpdateInRecord(face1, *interest);
+  entry4.insertOrUpdateInRecord(face2, *interest);
+  BOOST_CHECK_EQUAL(entry4.findNonce(25559, *face1),
+                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(entry4.findNonce(25559, *face2),
+                    pit::DUPLICATE_NONCE_IN_SAME | pit::DUPLICATE_NONCE_IN_OTHER);
+  BOOST_CHECK_EQUAL(entry4.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry4.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
+
+  pit::Entry entry5(*interest);
+  entry5.insertOrUpdateOutRecord(face1, *interest);
+  entry5.insertOrUpdateOutRecord(face2, *interest);
+  BOOST_CHECK_EQUAL(entry5.findNonce(25559, *face1),
+                    pit::DUPLICATE_NONCE_OUT_SAME | pit::DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(entry5.findNonce(25559, *face2),
+                    pit::DUPLICATE_NONCE_OUT_SAME | pit::DUPLICATE_NONCE_OUT_OTHER);
+  BOOST_CHECK_EQUAL(entry5.findNonce(19004, *face1), pit::DUPLICATE_NONCE_NONE);
+  BOOST_CHECK_EQUAL(entry5.findNonce(19004, *face2), pit::DUPLICATE_NONCE_NONE);
 }
 
 BOOST_AUTO_TEST_CASE(EntryLifetime)
 {
   shared_ptr<Interest> interest = makeInterest("ndn:/7oIEurbgy6");
-  BOOST_ASSERT(interest->getInterestLifetime() < time::milliseconds::zero()); // library uses -1 to indicate unset lifetime
+  // library uses -1 to indicate unset lifetime
+  BOOST_ASSERT(interest->getInterestLifetime() < time::milliseconds::zero());
 
   shared_ptr<Face> face = make_shared<DummyFace>();
   pit::Entry entry(*interest);