table: mock PIT
refs #1128
Change-Id: I8943ad07d93422dc456fd051b2e4c0d5f38bc227
diff --git a/daemon/table/pit-entry.cpp b/daemon/table/pit-entry.cpp
new file mode 100644
index 0000000..e11abef
--- /dev/null
+++ b/daemon/table/pit-entry.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-entry.hpp"
+#include <algorithm>
+
+namespace ndn {
+namespace pit {
+
+Entry::Entry(const Interest& interest)
+ : m_interest(interest)
+{
+}
+
+const Name&
+Entry::getName() const
+{
+ return m_interest.getName();
+}
+
+const InRecordCollection&
+Entry::getInRecords() const
+{
+ return m_inRecords;
+}
+
+const OutRecordCollection&
+Entry::getOutRecords() const
+{
+ return m_outRecords;
+}
+
+bool
+Entry::isNonceSeen(uint32_t nonce) const
+{
+ return m_nonces.count(nonce) > 0;
+}
+
+static inline bool
+predicate_FaceRecord_Face(const FaceRecord& faceRecord, shared_ptr<Face> face)
+{
+ return faceRecord.getFace() == face;
+}
+
+InRecordCollection::iterator
+Entry::insertOrUpdateInRecord(shared_ptr<Face> face, const Interest& interest)
+{
+ InRecordCollection::iterator it = std::find_if(m_inRecords.begin(),
+ m_inRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+ if (it == m_inRecords.end()) {
+ m_inRecords.push_front(InRecord(face));
+ it = m_inRecords.begin();
+ }
+
+ it->update(interest);
+ m_nonces.insert(interest.getNonce());
+ return it;
+}
+
+void
+Entry::deleteInRecords()
+{
+ m_inRecords.clear();
+}
+
+OutRecordCollection::iterator
+Entry::insertOrUpdateOutRecord(shared_ptr<Face> face, const Interest& interest)
+{
+ OutRecordCollection::iterator it = std::find_if(m_outRecords.begin(),
+ m_outRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+ if (it == m_outRecords.end()) {
+ m_outRecords.push_front(OutRecord(face));
+ it = m_outRecords.begin();
+ }
+
+ it->update(interest);
+ m_nonces.insert(interest.getNonce());
+ return it;
+}
+
+void
+Entry::deleteOutRecord(shared_ptr<Face> face)
+{
+ OutRecordCollection::iterator it = std::find_if(m_outRecords.begin(),
+ m_outRecords.end(), bind(&predicate_FaceRecord_Face, _1, face));
+ if (it != m_outRecords.end()) {
+ m_outRecords.erase(it);
+ }
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-entry.hpp b/daemon/table/pit-entry.hpp
new file mode 100644
index 0000000..97de5e2
--- /dev/null
+++ b/daemon/table/pit-entry.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_ENTRY_HPP
+#define NFD_TABLE_PIT_ENTRY_HPP
+
+#include "pit-in-record.hpp"
+#include "pit-out-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class InRecordCollection
+ * \brief represents an unordered collection of InRecords
+ */
+typedef std::list< InRecord> InRecordCollection;
+
+/** \class OutRecordCollection
+ * \brief represents an unordered collection of OutRecords
+ */
+typedef std::list<OutRecord> OutRecordCollection;
+
+/** \class Entry
+ * \brief represents a PIT entry
+ */
+class Entry : noncopyable
+{
+public:
+ explicit
+ Entry(const Interest& interest);
+
+ const Interest&
+ getInterest() const;
+
+ /** \return{ Interest Name }
+ */
+ const Name&
+ getName() const;
+
+ const InRecordCollection&
+ getInRecords() const;
+
+ const OutRecordCollection&
+ getOutRecords() const;
+
+ /** \brief determines whether nonce is seen before
+ * in an incoming or outgoing Interest
+ */
+ bool
+ isNonceSeen(uint32_t nonce) const;
+
+ /** \brief inserts a InRecord for face, and updates it with interest
+ * If InRecord for face exists, the existing one is updated.
+ * \return{ an iterator to the InRecord }
+ */
+ InRecordCollection::iterator
+ insertOrUpdateInRecord(shared_ptr<Face> face, const Interest& interest);
+
+ /// deletes all InRecords
+ void
+ deleteInRecords();
+
+ /** \brief inserts a OutRecord for face, and updates it with interest
+ * If OutRecord for face exists, the existing one is updated.
+ * \return{ an iterator to the OutRecord }
+ */
+ OutRecordCollection::iterator
+ insertOrUpdateOutRecord(shared_ptr<Face> face, const Interest& interest);
+
+ /// deletes one OutRecord for face if exists
+ void
+ deleteOutRecord(shared_ptr<Face> face);
+
+private:
+ std::set<uint32_t> m_nonces;
+ const Interest m_interest;
+ InRecordCollection m_inRecords;
+ OutRecordCollection m_outRecords;
+};
+
+inline const Interest&
+Entry::getInterest() const
+{
+ return m_interest;
+}
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_ENTRY_HPP
diff --git a/daemon/table/pit-face-record.cpp b/daemon/table/pit-face-record.cpp
new file mode 100644
index 0000000..89aef1e
--- /dev/null
+++ b/daemon/table/pit-face-record.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+FaceRecord::FaceRecord(shared_ptr<Face> face)
+ : m_face(face)
+ , m_lastNonce(0)
+ , m_lastRenewed(0)
+ , m_expiry(0)
+{
+}
+
+FaceRecord::FaceRecord(const FaceRecord& other)
+ : m_face(other.m_face)
+ , m_lastNonce(other.m_lastNonce)
+ , m_lastRenewed(other.m_lastRenewed)
+ , m_expiry(other.m_expiry)
+{
+}
+
+void
+FaceRecord::update(const Interest& interest)
+{
+ m_lastNonce = interest.getNonce();
+ m_lastRenewed = time::now();
+ m_expiry = m_lastRenewed + time::milliseconds(interest.getInterestLifetime());
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-face-record.hpp b/daemon/table/pit-face-record.hpp
new file mode 100644
index 0000000..d2dfe2c
--- /dev/null
+++ b/daemon/table/pit-face-record.hpp
@@ -0,0 +1,83 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_FACE_RECORD_HPP
+#define NFD_TABLE_PIT_FACE_RECORD_HPP
+
+#include "face/face.hpp"
+#include "core/time.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class FaceRecord
+ * \brief contains information about an Interest
+ * on an incoming or outgoing face
+ * \note This is an implementation detail to extract common functionality
+ * of InRecord and OutRecord
+ */
+class FaceRecord
+{
+public:
+ explicit
+ FaceRecord(shared_ptr<Face> face);
+
+ FaceRecord(const FaceRecord& other);
+
+ shared_ptr<Face>
+ getFace() const;
+
+ uint32_t
+ getLastNonce() const;
+
+ time::Point
+ getLastRenewed() const;
+
+ /** \brief gives the time point this record expires
+ * \return{ getLastRenewed() + InterestLifetime }
+ */
+ time::Point
+ getExpiry() const;
+
+ /// updates lastNonce, lastRenewed, expiry fields
+ void
+ update(const Interest& interest);
+
+private:
+ shared_ptr<Face> m_face;
+ uint32_t m_lastNonce;
+ time::Point m_lastRenewed;
+ time::Point m_expiry;
+};
+
+inline shared_ptr<Face>
+FaceRecord::getFace() const
+{
+ return m_face;
+}
+
+inline uint32_t
+FaceRecord::getLastNonce() const
+{
+ return m_lastNonce;
+}
+
+inline time::Point
+FaceRecord::getLastRenewed() const
+{
+ return m_lastRenewed;
+}
+
+inline time::Point
+FaceRecord::getExpiry() const
+{
+ return m_expiry;
+}
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_FACE_RECORD_HPP
diff --git a/daemon/table/pit-in-record.cpp b/daemon/table/pit-in-record.cpp
new file mode 100644
index 0000000..662f074
--- /dev/null
+++ b/daemon/table/pit-in-record.cpp
@@ -0,0 +1,24 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-in-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+InRecord::InRecord(shared_ptr<Face> face)
+ : FaceRecord(face)
+{
+}
+
+InRecord::InRecord(const InRecord& other)
+ : FaceRecord(other)
+{
+}
+
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-in-record.hpp b/daemon/table/pit-in-record.hpp
new file mode 100644
index 0000000..9539ce3
--- /dev/null
+++ b/daemon/table/pit-in-record.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_IN_RECORD_HPP
+#define NFD_TABLE_PIT_IN_RECORD_HPP
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class InRecord
+ * \brief contains information about an Interest from an incoming face
+ */
+class InRecord : public FaceRecord
+{
+public:
+ explicit
+ InRecord(shared_ptr<Face> face);
+
+ InRecord(const InRecord& other);
+};
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_IN_RECORD_HPP
diff --git a/daemon/table/pit-out-record.cpp b/daemon/table/pit-out-record.cpp
new file mode 100644
index 0000000..ce4db8c
--- /dev/null
+++ b/daemon/table/pit-out-record.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit-out-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+OutRecord::OutRecord(shared_ptr<Face> face)
+ : FaceRecord(face)
+{
+}
+
+OutRecord::OutRecord(const OutRecord& other)
+ : FaceRecord(other)
+{
+}
+
+} // namespace pit
+} // namespace ndn
diff --git a/daemon/table/pit-out-record.hpp b/daemon/table/pit-out-record.hpp
new file mode 100644
index 0000000..83ff3e1
--- /dev/null
+++ b/daemon/table/pit-out-record.hpp
@@ -0,0 +1,30 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_OUT_RECORD_HPP
+#define NFD_TABLE_PIT_OUT_RECORD_HPP
+
+#include "pit-face-record.hpp"
+
+namespace ndn {
+namespace pit {
+
+/** \class OutRecord
+ * \brief contains information about an Interest toward an outgoing face
+ */
+class OutRecord : public FaceRecord
+{
+public:
+ explicit
+ OutRecord(shared_ptr<Face> face);
+
+ OutRecord(const OutRecord& other);
+};
+
+} // namespace pit
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_IN_RECORD_HPP
diff --git a/daemon/table/pit.cpp b/daemon/table/pit.cpp
new file mode 100644
index 0000000..7742266
--- /dev/null
+++ b/daemon/table/pit.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "pit.hpp"
+#include <algorithm>
+
+namespace ndn {
+
+Pit::Pit()
+{
+}
+
+Pit::~Pit()
+{
+}
+
+static inline bool
+operator==(const Exclude& a, const Exclude& b)
+{
+ const Block& aBlock = a.wireEncode();
+ const Block& bBlock = b.wireEncode();
+ return aBlock.size() == bBlock.size() &&
+ 0 == memcmp(aBlock.wire(), bBlock.wire(), aBlock.size());
+}
+
+static inline bool
+predicate_PitEntry_similar_Interest(shared_ptr<pit::Entry> entry,
+ const Interest& interest)
+{
+ const Interest& pi = entry->getInterest();
+ return pi.getName().equals(interest.getName()) &&
+ pi.getMinSuffixComponents() == interest.getMinSuffixComponents() &&
+ pi.getMaxSuffixComponents() == interest.getMaxSuffixComponents() &&
+ // TODO PublisherPublicKeyLocator (ndn-cpp-dev #1157)
+ pi.getExclude() == interest.getExclude() &&
+ pi.getChildSelector() == interest.getChildSelector() &&
+ pi.getMustBeFresh() == interest.getMustBeFresh();
+}
+
+std::pair<shared_ptr<pit::Entry>, bool>
+Pit::insert(const Interest& interest)
+{
+ std::list<shared_ptr<pit::Entry> >::iterator it = std::find_if(
+ m_table.begin(), m_table.end(),
+ bind(&predicate_PitEntry_similar_Interest, _1, interest));
+ if (it != m_table.end()) return std::make_pair(*it, false);
+
+ shared_ptr<pit::Entry> entry = make_shared<pit::Entry>(interest);
+ m_table.push_back(entry);
+ return std::make_pair(entry, true);
+}
+
+shared_ptr<pit::DataMatchResult>
+Pit::findAllDataMatches(const Data& data) const
+{
+ shared_ptr<pit::DataMatchResult> result = make_shared<pit::DataMatchResult>();
+ for (std::list<shared_ptr<pit::Entry> >::const_iterator it = m_table.begin();
+ it != m_table.end(); ++it) {
+ shared_ptr<pit::Entry> entry = *it;
+ if (entry->getInterest().matchesName(data.getName())) {
+ result->push_back(entry);
+ }
+ }
+ return result;
+}
+
+void
+Pit::remove(shared_ptr<pit::Entry> pitEntry)
+{
+ m_table.remove(pitEntry);
+}
+
+} // namespace ndn
diff --git a/daemon/table/pit.hpp b/daemon/table/pit.hpp
new file mode 100644
index 0000000..44dc252
--- /dev/null
+++ b/daemon/table/pit.hpp
@@ -0,0 +1,57 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TABLE_PIT_HPP
+#define NFD_TABLE_PIT_HPP
+
+#include "pit-entry.hpp"
+namespace ndn {
+namespace pit {
+
+/** \class DataMatchResult
+ * \brief an unordered iterable of all PIT entries matching Data
+ * This type shall support:
+ * iterator<shared_ptr<pit::Entry>> begin()
+ * iterator<shared_ptr<pit::Entry>> end()
+ */
+typedef std::vector<shared_ptr<pit::Entry> > DataMatchResult;
+
+} // namespace pit
+
+/** \class Pit
+ * \brief represents the PIT
+ */
+class Pit : noncopyable
+{
+public:
+ Pit();
+
+ ~Pit();
+
+ /** \brief inserts a FIB entry for prefix
+ * If an entry for exact same prefix exists, that entry is returned.
+ * \return{ the entry, and true for new entry, false for existing entry }
+ */
+ std::pair<shared_ptr<pit::Entry>, bool>
+ insert(const Interest& interest);
+
+ /** \brief performs a Data match
+ * \return{ an iterable of all PIT entries matching data }
+ */
+ shared_ptr<pit::DataMatchResult>
+ findAllDataMatches(const Data& data) const;
+
+ /// removes a PIT entry
+ void
+ remove(shared_ptr<pit::Entry> pitEntry);
+
+private:
+ std::list<shared_ptr<pit::Entry> > m_table;
+};
+
+} // namespace ndn
+
+#endif // NFD_TABLE_PIT_HPP
diff --git a/tests/face/dummy-face.hpp b/tests/face/dummy-face.hpp
new file mode 100644
index 0000000..a960380
--- /dev/null
+++ b/tests/face/dummy-face.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NFD_TEST_FACE_DUMMY_FACE_HPP
+#define NFD_TEST_FACE_DUMMY_FACE_HPP
+
+#include "face/face.hpp"
+
+namespace ndn {
+
+/** \class DummyFace
+ * \brief provides a Face that cannot communicate
+ * for unit testing only
+ */
+class DummyFace : public Face
+{
+public:
+ DummyFace(FaceId id)
+ : Face(id)
+ {
+ }
+
+ virtual void
+ sendInterest(const Interest &interest)
+ {
+ }
+
+ virtual void
+ sendData(const Data &data)
+ {
+ }
+};
+
+} // namespace ndn
+
+#endif // TEST_FACE_DUMMY_FACE_HPP
diff --git a/tests/face/face.cpp b/tests/face/face.cpp
index b453110..e84ab03 100644
--- a/tests/face/face.cpp
+++ b/tests/face/face.cpp
@@ -5,6 +5,7 @@
*/
#include "face/face.hpp"
+#include "dummy-face.hpp"
#include <boost/test/unit_test.hpp>
@@ -12,28 +13,9 @@
BOOST_AUTO_TEST_SUITE(FaceFace)
-class FaceTestFace : public Face
-{
-public:
- FaceTestFace()
- : Face(1)
- {
- }
-
- virtual void
- sendInterest(const Interest &interest)
- {
- }
-
- virtual void
- sendData(const Data &data)
- {
- }
-};
-
BOOST_AUTO_TEST_CASE(Description)
{
- FaceTestFace face;
+ DummyFace face(1);
face.setDescription("3pFsKrvWr");
BOOST_CHECK_EQUAL(face.getDescription(), "3pFsKrvWr");
}
diff --git a/tests/table/fib.cpp b/tests/table/fib.cpp
index f1ce0b8..1a4e2fc 100644
--- a/tests/table/fib.cpp
+++ b/tests/table/fib.cpp
@@ -5,37 +5,19 @@
*/
#include "table/fib.hpp"
+#include "../face/dummy-face.hpp"
#include <boost/test/unit_test.hpp>
namespace ndn {
-class FibTestFace : public Face
-{
-public:
- FibTestFace(FaceId id)
- : Face(id)
- {
- }
-
- virtual void
- sendInterest(const Interest &interest)
- {
- }
-
- virtual void
- sendData(const Data &data)
- {
- }
-};
-
BOOST_AUTO_TEST_SUITE(TableFib)
BOOST_AUTO_TEST_CASE(Entry)
{
Name prefix("ndn:/pxWhfFza");
- boost::shared_ptr<FibTestFace> face1 = make_shared<FibTestFace>(1);
- boost::shared_ptr<FibTestFace> face2 = make_shared<FibTestFace>(2);
+ shared_ptr<Face> face1 = make_shared<DummyFace>(1);
+ shared_ptr<Face> face2 = make_shared<DummyFace>(2);
fib::Entry entry(prefix);
BOOST_CHECK(entry.getPrefix().equals(prefix));
@@ -184,8 +166,8 @@
BOOST_AUTO_TEST_CASE(RemoveNextHopFromAllEntries)
{
- boost::shared_ptr<FibTestFace> face1 = make_shared<FibTestFace>(1);
- boost::shared_ptr<FibTestFace> face2 = make_shared<FibTestFace>(2);
+ shared_ptr<Face> face1 = make_shared<DummyFace>(1);
+ shared_ptr<Face> face2 = make_shared<DummyFace>(2);
Name nameA("ndn:/A");
Name nameB("ndn:/B");
diff --git a/tests/table/pit.cpp b/tests/table/pit.cpp
new file mode 100644
index 0000000..c9b4112
--- /dev/null
+++ b/tests/table/pit.cpp
@@ -0,0 +1,277 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (C) 2014 Named Data Networking Project
+ * See COPYING for copyright and distribution information.
+ */
+
+#include "table/pit.hpp"
+#include "../face/dummy-face.hpp"
+
+#include <boost/test/unit_test.hpp>
+
+namespace ndn {
+
+BOOST_AUTO_TEST_SUITE(TablePit)
+
+BOOST_AUTO_TEST_CASE(Entry)
+{
+ shared_ptr<Face> face1 = make_shared<DummyFace>(1);
+ shared_ptr<Face> face2 = make_shared<DummyFace>(2);
+ Name name("ndn:/KuYfjtRq");
+ Interest interest(name);
+ Interest interest1(name, static_cast<Milliseconds>(2528));
+ interest1.setNonce(25559);
+ Interest interest2(name, static_cast<Milliseconds>(6464));
+ interest2.setNonce(19004);
+ Interest interest3(name, static_cast<Milliseconds>(3585));
+ interest3.setNonce(24216);
+ Interest interest4(name, static_cast<Milliseconds>(8795));
+ interest4.setNonce(17365);
+
+ pit::Entry entry(interest);
+
+ BOOST_CHECK(entry.getInterest().getName().equals(name));
+ BOOST_CHECK(entry.getName().equals(name));
+
+ // isNonceSeen should not record the Nonce
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), false);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), false);
+
+ const pit::InRecordCollection& inRecords1 = entry.getInRecords();
+ BOOST_CHECK_EQUAL(inRecords1.size(), 0);
+ const pit::OutRecordCollection& outRecords1 = entry.getOutRecords();
+ BOOST_CHECK_EQUAL(outRecords1.size(), 0);
+
+ // insert InRecord
+ time::Point before1 = time::now();
+ pit::InRecordCollection::iterator in1 =
+ entry.insertOrUpdateInRecord(face1, interest1);
+ time::Point after1 = time::now();
+ const pit::InRecordCollection& inRecords2 = entry.getInRecords();
+ BOOST_CHECK_EQUAL(inRecords2.size(), 1);
+ BOOST_CHECK(in1 == inRecords2.begin());
+ BOOST_CHECK_EQUAL(in1->getFace(), face1);
+ BOOST_CHECK_EQUAL(in1->getLastNonce(), interest1.getNonce());
+ BOOST_CHECK_GE(in1->getLastRenewed(), before1);
+ BOOST_CHECK_LE(in1->getLastRenewed(), after1);
+ BOOST_CHECK_LE(std::abs(in1->getExpiry() - in1->getLastRenewed()
+ - time::milliseconds(interest1.getInterestLifetime())),
+ (after1 - before1));
+
+ // insert OutRecord
+ time::Point before2 = time::now();
+ pit::OutRecordCollection::iterator out1 =
+ entry.insertOrUpdateOutRecord(face1, interest1);
+ time::Point after2 = time::now();
+ const pit::OutRecordCollection& outRecords2 = entry.getOutRecords();
+ BOOST_CHECK_EQUAL(outRecords2.size(), 1);
+ BOOST_CHECK(out1 == outRecords2.begin());
+ BOOST_CHECK_EQUAL(out1->getFace(), face1);
+ BOOST_CHECK_EQUAL(out1->getLastNonce(), interest1.getNonce());
+ BOOST_CHECK_GE(out1->getLastRenewed(), before2);
+ BOOST_CHECK_LE(out1->getLastRenewed(), after2);
+ BOOST_CHECK_LE(std::abs(out1->getExpiry() - out1->getLastRenewed()
+ - time::milliseconds(interest1.getInterestLifetime())),
+ (after2 - before2));
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), false);
+
+ // update InRecord
+ time::Point before3 = time::now();
+ pit::InRecordCollection::iterator in2 =
+ entry.insertOrUpdateInRecord(face1, interest2);
+ time::Point after3 = time::now();
+ const pit::InRecordCollection& inRecords3 = entry.getInRecords();
+ BOOST_CHECK_EQUAL(inRecords3.size(), 1);
+ BOOST_CHECK(in2 == inRecords3.begin());
+ BOOST_CHECK_EQUAL(in2->getFace(), face1);
+ BOOST_CHECK_EQUAL(in2->getLastNonce(), interest2.getNonce());
+ BOOST_CHECK_LE(std::abs(in2->getExpiry() - in2->getLastRenewed()
+ - time::milliseconds(interest2.getInterestLifetime())),
+ (after3 - before3));
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest3.getNonce()), false);
+
+ // insert another InRecord
+ pit::InRecordCollection::iterator in3 =
+ entry.insertOrUpdateInRecord(face2, interest3);
+ const pit::InRecordCollection& inRecords4 = entry.getInRecords();
+ BOOST_CHECK_EQUAL(inRecords4.size(), 2);
+ BOOST_CHECK_EQUAL(in3->getFace(), face2);
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest3.getNonce()), true);
+
+ // delete all InRecords
+ entry.deleteInRecords();
+ const pit::InRecordCollection& inRecords5 = entry.getInRecords();
+ BOOST_CHECK_EQUAL(inRecords5.size(), 0);
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest3.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest4.getNonce()), false);
+
+ // insert another OutRecord
+ pit::OutRecordCollection::iterator out2 =
+ entry.insertOrUpdateOutRecord(face2, interest4);
+ const pit::OutRecordCollection& outRecords3 = entry.getOutRecords();
+ BOOST_CHECK_EQUAL(outRecords3.size(), 2);
+ BOOST_CHECK_EQUAL(out2->getFace(), face2);
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest3.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest4.getNonce()), true);
+
+ // delete OutRecord
+ entry.deleteOutRecord(face2);
+ const pit::OutRecordCollection& outRecords4 = entry.getOutRecords();
+ BOOST_REQUIRE_EQUAL(outRecords4.size(), 1);
+ BOOST_CHECK_EQUAL(outRecords4.begin()->getFace(), face1);
+
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest1.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest2.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest3.getNonce()), true);
+ BOOST_CHECK_EQUAL(entry.isNonceSeen(interest4.getNonce()), true);
+}
+
+BOOST_AUTO_TEST_CASE(Insert)
+{
+ Name name1("ndn:/5vzBNnMst");
+ Name name2("ndn:/igSGfEIM62");
+ Exclude exclude0;
+ Exclude exclude1;
+ exclude1.excludeOne(Name::Component("u26p47oep"));
+ Exclude exclude2;
+ exclude2.excludeOne(Name::Component("FG1Ni6nYcf"));
+
+ // base
+ Interest interestA(name1, -1, -1, exclude0, -1, false, -1, -1.0, 0);
+ // A+exclude1
+ Interest interestB(name1, -1, -1, exclude1, -1, false, -1, -1.0, 0);
+ // A+exclude2
+ Interest interestC(name1, -1, -1, exclude2, -1, false, -1, -1.0, 0);
+ // A+MinSuffixComponents
+ Interest interestD(name1, 2, -1, exclude0, -1, false, -1, -1.0, 0);
+ // A+MaxSuffixComponents
+ Interest interestE(name1, -1, 4, exclude0, -1, false, -1, -1.0, 0);
+ // A+ChildSelector
+ Interest interestF(name1, -1, -1, exclude0, 1, false, -1, -1.0, 0);
+ // A+MustBeFresh
+ Interest interestG(name1, -1, -1, exclude0, -1, true, -1, -1.0, 0);
+ // A+Scope
+ Interest interestH(name1, -1, -1, exclude0, -1, false, 2, -1.0, 0);
+ // A+InterestLifetime
+ Interest interestI(name1, -1, -1, exclude0, -1, false, -1, 2000, 0);
+ // A+Nonce
+ Interest interestJ(name1, -1, -1, exclude0, -1, false, -1, -1.0, 2192);
+ // different Name+exclude1
+ Interest interestK(name2, -1, -1, exclude1, -1, false, -1, -1.0, 0);
+
+ Pit pit;
+ std::pair<shared_ptr<pit::Entry>, bool> insertResult;
+
+ insertResult = pit.insert(interestA);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestB);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestC);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestD);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestE);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestF);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestG);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interestH);
+ BOOST_CHECK_EQUAL(insertResult.second, false);// only guiders differ
+
+ insertResult = pit.insert(interestI);
+ BOOST_CHECK_EQUAL(insertResult.second, false);// only guiders differ
+
+ insertResult = pit.insert(interestJ);
+ BOOST_CHECK_EQUAL(insertResult.second, false);// only guiders differ
+
+ insertResult = pit.insert(interestK);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+}
+
+BOOST_AUTO_TEST_CASE(Remove)
+{
+ Interest interest(Name("ndn:/z88Admz6A2"));
+
+ Pit pit;
+ std::pair<shared_ptr<pit::Entry>, bool> insertResult;
+
+ insertResult = pit.insert(interest);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+
+ insertResult = pit.insert(interest);
+ BOOST_CHECK_EQUAL(insertResult.second, false);
+
+ pit.remove(insertResult.first);
+
+ insertResult = pit.insert(interest);
+ BOOST_CHECK_EQUAL(insertResult.second, true);
+}
+
+
+BOOST_AUTO_TEST_CASE(FindAllDataMatches)
+{
+ Name nameA ("ndn:/A");
+ Name nameAB ("ndn:/A/B");
+ Name nameABC("ndn:/A/B/C");
+ Name nameD ("ndn:/D");
+ Interest interestA (nameA );
+ Interest interestAB(nameAB);
+ Interest interestD (nameD );
+
+ Pit pit;
+ pit.insert(interestA );
+ pit.insert(interestAB);
+ pit.insert(interestD );
+
+ Data data(nameABC);
+
+ shared_ptr<pit::DataMatchResult> matches = pit.findAllDataMatches(data);
+ int count = 0;
+ bool hasA = false;
+ bool hasAB = false;
+ bool hasD = false;
+ for (pit::DataMatchResult::iterator it = matches->begin();
+ it != matches->end(); ++it) {
+ ++count;
+ shared_ptr<pit::Entry> entry = *it;
+ if (entry->getName().equals(nameA )) {
+ hasA = true;
+ }
+ if (entry->getName().equals(nameAB)) {
+ hasAB = true;
+ }
+ if (entry->getName().equals(nameD )) {
+ hasD = true;
+ }
+ }
+ BOOST_CHECK_EQUAL(count, 2);
+ BOOST_CHECK_EQUAL(hasA , true);
+ BOOST_CHECK_EQUAL(hasAB, true);
+ BOOST_CHECK_EQUAL(hasD , false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace ndn