fw: refine pipelines, dispatch to strategy

refs #1345 #1255

Change-Id: If1cfc26049f87318103fc09c3b211ebf1eb3ebaa
diff --git a/daemon/fw/available-strategies.cpp b/daemon/fw/available-strategies.cpp
new file mode 100644
index 0000000..ec29cdd
--- /dev/null
+++ b/daemon/fw/available-strategies.cpp
@@ -0,0 +1,41 @@
+/* -*- 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 "best-route-strategy.hpp"
+#include "broadcast-strategy.hpp"
+#include "client-control-strategy.hpp"
+#include "ncc-strategy.hpp"
+
+namespace nfd {
+namespace fw {
+
+shared_ptr<Strategy>
+makeDefaultStrategy(Forwarder& forwarder)
+{
+  return make_shared<BestRouteStrategy>(boost::ref(forwarder));
+}
+
+template<typename S>
+inline void
+installStrategy(Forwarder& forwarder)
+{
+  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
+  if (!strategyChoice.hasStrategy(S::STRATEGY_NAME)) {
+    strategyChoice.install(make_shared<S>(boost::ref(forwarder)));
+  }
+}
+
+void
+installStrategies(Forwarder& forwarder)
+{
+  installStrategy<BestRouteStrategy>(forwarder);
+  installStrategy<BroadcastStrategy>(forwarder);
+  installStrategy<ClientControlStrategy>(forwarder);
+  installStrategy<NccStrategy>(forwarder);
+}
+
+} // namespace fw
+} // namespace nfd
diff --git a/daemon/fw/available-strategies.hpp b/daemon/fw/available-strategies.hpp
new file mode 100644
index 0000000..db1422b
--- /dev/null
+++ b/daemon/fw/available-strategies.hpp
@@ -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.
+ */
+
+#ifndef NFD_FW_AVAILABLE_STRATEGIES_HPP
+#define NFD_FW_AVAILABLE_STRATEGIES_HPP
+
+#include "strategy.hpp"
+
+namespace nfd {
+namespace fw {
+
+shared_ptr<Strategy>
+makeDefaultStrategy(Forwarder& forwarder);
+
+void
+installStrategies(Forwarder& forwarder);
+
+} // namespace fw
+} // namespace nfd
+
+#endif // NFD_FW_AVAILABLE_STRATEGIES_HPP
diff --git a/daemon/fw/best-route-strategy.cpp b/daemon/fw/best-route-strategy.cpp
index 19458e9..8f87270 100644
--- a/daemon/fw/best-route-strategy.cpp
+++ b/daemon/fw/best-route-strategy.cpp
@@ -9,8 +9,10 @@
 namespace nfd {
 namespace fw {
 
-BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder)
-  : Strategy(forwarder, "ndn:/localhost/nfd/strategy/best-route")
+const Name BestRouteStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/best-route");
+
+BestRouteStrategy::BestRouteStrategy(Forwarder& forwarder, const Name& name)
+  : Strategy(forwarder, name)
 {
 }
 
diff --git a/daemon/fw/best-route-strategy.hpp b/daemon/fw/best-route-strategy.hpp
index 4d7a5b0..0f087f8 100644
--- a/daemon/fw/best-route-strategy.hpp
+++ b/daemon/fw/best-route-strategy.hpp
@@ -19,8 +19,7 @@
 class BestRouteStrategy : public Strategy
 {
 public:
-  explicit
-  BestRouteStrategy(Forwarder& forwarder);
+  BestRouteStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
   
   virtual
   ~BestRouteStrategy();
@@ -30,6 +29,9 @@
                        const Interest& interest,
                        shared_ptr<fib::Entry> fibEntry,
                        shared_ptr<pit::Entry> pitEntry);
+
+public:
+  static const Name STRATEGY_NAME;
 };
 
 } // namespace fw
diff --git a/daemon/fw/broadcast-strategy.cpp b/daemon/fw/broadcast-strategy.cpp
index 4cc4e5f..3e8c2bf 100644
--- a/daemon/fw/broadcast-strategy.cpp
+++ b/daemon/fw/broadcast-strategy.cpp
@@ -9,8 +9,10 @@
 namespace nfd {
 namespace fw {
 
-BroadcastStrategy::BroadcastStrategy(Forwarder& forwarder)
-  : Strategy(forwarder, "ndn:/localhost/nfd/strategy/broadcast")
+const Name BroadcastStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/broadcast");
+
+BroadcastStrategy::BroadcastStrategy(Forwarder& forwarder, const Name& name)
+  : Strategy(forwarder, name)
 {
 }
 
diff --git a/daemon/fw/broadcast-strategy.hpp b/daemon/fw/broadcast-strategy.hpp
index 41868ed..69c6ce6 100644
--- a/daemon/fw/broadcast-strategy.hpp
+++ b/daemon/fw/broadcast-strategy.hpp
@@ -19,8 +19,7 @@
 class BroadcastStrategy : public Strategy
 {
 public:
-  explicit
-  BroadcastStrategy(Forwarder& forwarder);
+  BroadcastStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
   
   virtual
   ~BroadcastStrategy();
@@ -30,6 +29,9 @@
                        const Interest& interest,
                        shared_ptr<fib::Entry> fibEntry,
                        shared_ptr<pit::Entry> pitEntry);
+
+public:
+  static const Name STRATEGY_NAME;
 };
 
 } // namespace fw
diff --git a/daemon/fw/client-control-strategy.cpp b/daemon/fw/client-control-strategy.cpp
index eacd604..5028879 100644
--- a/daemon/fw/client-control-strategy.cpp
+++ b/daemon/fw/client-control-strategy.cpp
@@ -11,8 +11,10 @@
 
 NFD_LOG_INIT("ClientControlStrategy");
 
-ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder)
-  : BestRouteStrategy(forwarder)
+const Name ClientControlStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/client-control");
+
+ClientControlStrategy::ClientControlStrategy(Forwarder& forwarder, const Name& name)
+  : BestRouteStrategy(forwarder, name)
 {
 }
 
diff --git a/daemon/fw/client-control-strategy.hpp b/daemon/fw/client-control-strategy.hpp
index 48f45b3..e5e8539 100644
--- a/daemon/fw/client-control-strategy.hpp
+++ b/daemon/fw/client-control-strategy.hpp
@@ -18,8 +18,7 @@
 class ClientControlStrategy : public BestRouteStrategy
 {
 public:
-  explicit
-  ClientControlStrategy(Forwarder& forwarder);
+  ClientControlStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
 
   virtual
   ~ClientControlStrategy();
@@ -29,6 +28,9 @@
                        const Interest& interest,
                        shared_ptr<fib::Entry> fibEntry,
                        shared_ptr<pit::Entry> pitEntry);
+
+public:
+  static const Name STRATEGY_NAME;
 };
 
 } // namespace fw
diff --git a/daemon/fw/forwarder.cpp b/daemon/fw/forwarder.cpp
index 6c9f3ce..3a8a91f 100644
--- a/daemon/fw/forwarder.cpp
+++ b/daemon/fw/forwarder.cpp
@@ -5,14 +5,16 @@
  */
 
 #include "forwarder.hpp"
-#include "core/logger.hpp"
-#include "best-route-strategy.hpp"
+#include "available-strategies.hpp"
 
 namespace nfd {
 
 NFD_LOG_INIT("Forwarder");
 
-const Name Forwarder::s_localhostName("ndn:/localhost");
+using fw::Strategy;
+
+const ndn::Milliseconds Forwarder::DEFAULT_INTEREST_LIFETIME(static_cast<ndn::Milliseconds>(4000));
+const Name Forwarder::LOCALHOST_NAME("ndn:/localhost");
 
 Forwarder::Forwarder()
   : m_faceTable(*this)
@@ -20,24 +22,29 @@
   , m_fib(m_nameTree)
   , m_pit(m_nameTree)
   , m_measurements(m_nameTree)
-  , m_strategyChoice(m_nameTree, make_shared<fw::BestRouteStrategy>(boost::ref(*this)))
+  , m_strategyChoice(m_nameTree, fw::makeDefaultStrategy(*this))
 {
-  m_strategy = make_shared<fw::BestRouteStrategy>(boost::ref(*this));
+  fw::installStrategies(*this);
 }
 
 void
 Forwarder::onIncomingInterest(Face& inFace, const Interest& interest)
 {
   // receive Interest
-  NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() << " interest=" << interest.getName());
+  NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
+                " interest=" << interest.getName());
   const_cast<Interest&>(interest).setIncomingFaceId(inFace.getId());
+  if (interest.getInterestLifetime() < 0) {
+    const_cast<Interest&>(interest).setInterestLifetime(DEFAULT_INTEREST_LIFETIME);
+  }
 
   // /localhost scope control
-  bool violatesLocalhost = !inFace.isLocal() &&
-                           s_localhostName.isPrefixOf(interest.getName());
-  if (violatesLocalhost) {
-    NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId()
-      << " interest=" << interest.getName() << " violates /localhost");
+  bool isViolatingLocalhost = !inFace.isLocal() &&
+                              LOCALHOST_NAME.isPrefixOf(interest.getName());
+  if (isViolatingLocalhost) {
+    NFD_LOG_DEBUG("onIncomingInterest face=" << inFace.getId() <<
+                  " interest=" << interest.getName() << " violates /localhost");
+    // (drop)
     return;
   }
 
@@ -55,9 +62,9 @@
   // cancel unsatisfy & straggler timer
   this->cancelUnsatisfyAndStragglerTimer(pitEntry);
 
+  // is pending?
   const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
   bool isPending = inRecords.begin() == inRecords.end();
-
   if (!isPending) {
     // CS lookup
     const Data* csMatch = m_cs.find(interest);
@@ -73,46 +80,71 @@
   // insert InRecord
   pitEntry->insertOrUpdateInRecord(inFace.shared_from_this(), interest);
 
-  // app chosen nexthops
-  bool isAppChosenNexthops = false; // TODO get from local control header
-  if (isAppChosenNexthops) {
-    // TODO foreach chosen nexthop: goto outgoing Interest pipeline
-    return;
-  }
-
   // FIB lookup
   shared_ptr<fib::Entry> fibEntry = m_fib.findLongestPrefixMatch(*pitEntry);
 
   // dispatch to strategy
-  this->dispatchToStrategy(inFace, interest, fibEntry, pitEntry);
+  this->dispatchToStrategy(pitEntry, bind(&Strategy::afterReceiveInterest, _1,
+    boost::cref(inFace), boost::cref(interest), fibEntry, pitEntry));
 }
 
 void
 Forwarder::onInterestLoop(Face& inFace, const Interest& interest,
                           shared_ptr<pit::Entry> pitEntry)
 {
-  NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() << " interest=" << interest.getName());
+  NFD_LOG_DEBUG("onInterestLoop face=" << inFace.getId() <<
+                " interest=" << interest.getName());
 
-  // do nothing, which means Interest is dropped
+  // (drop)
+}
+
+/** \brief compare two InRecords for picking outgoing Interest
+ *  \return true if b is preferred over a
+ *
+ *  This function should be passed to std::max_element over InRecordCollection.
+ *  The outgoing Interest picked is the last incoming Interest
+ *  that does not come from outFace.
+ *  If all InRecords come from outFace, it's fine to pick that. This happens when
+ *  there's only one InRecord that comes from outFace. The legit use is for
+ *  vehicular network; otherwise, strategy shouldn't send to the sole inFace.
+ */
+static inline bool
+compare_pickInterest(const pit::InRecord& a, const pit::InRecord& b, const Face* outFace)
+{
+  bool isOutFaceA = a.getFace().get() == outFace;
+  bool isOutFaceB = b.getFace().get() == outFace;
+
+  if (!isOutFaceA && isOutFaceB) {
+    return false;
+  }
+  if (isOutFaceA && !isOutFaceB) {
+    return true;
+  }
+
+  return a.getLastRenewed() > b.getLastRenewed();
 }
 
 void
 Forwarder::onOutgoingInterest(shared_ptr<pit::Entry> pitEntry, Face& outFace)
 {
-  NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() << " interest=" << pitEntry->getName());
+  NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
+                " interest=" << pitEntry->getName());
 
   // /localhost scope control
-  bool violatesLocalhost = !outFace.isLocal() &&
-                           s_localhostName.isPrefixOf(pitEntry->getName());
-  if (violatesLocalhost) {
-    NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId()
-      << " interest=" << pitEntry->getName() << " violates /localhost");
+  bool isViolatingLocalhost = !outFace.isLocal() &&
+                              LOCALHOST_NAME.isPrefixOf(pitEntry->getName());
+  if (isViolatingLocalhost) {
+    NFD_LOG_DEBUG("onOutgoingInterest face=" << outFace.getId() <<
+                  " interest=" << pitEntry->getName() << " violates /localhost");
     return;
   }
 
   // pick Interest
-  const Interest& interest = pitEntry->getInterest();
-  // TODO pick the last incoming Interest
+  const pit::InRecordCollection& inRecords = pitEntry->getInRecords();
+  pit::InRecordCollection::const_iterator pickedInRecord = std::max_element(
+    inRecords.begin(), inRecords.end(), bind(&compare_pickInterest, _1, _2, &outFace));
+  BOOST_ASSERT(pickedInRecord != inRecords.end());
+  const Interest& interest = pickedInRecord->getInterest();
 
   // insert OutRecord
   pitEntry->insertOrUpdateOutRecord(outFace.shared_from_this(), interest);
@@ -139,9 +171,10 @@
   NFD_LOG_DEBUG("onInterestUnsatisfied interest=" << pitEntry->getName());
 
   // invoke PIT unsatisfied callback
-  // TODO
+  this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeExpirePendingInterest, _1,
+    pitEntry));
 
-  // PIT erase
+  // PIT delete
   m_pit.erase(pitEntry);
 }
 
@@ -153,11 +186,12 @@
   const_cast<Data&>(data).setIncomingFaceId(inFace.getId());
 
   // /localhost scope control
-  bool violatesLocalhost = !inFace.isLocal() &&
-                           s_localhostName.isPrefixOf(data.getName());
-  if (violatesLocalhost) {
-    NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId()
-      << " data=" << data.getName() << " violates /localhost");
+  bool isViolatingLocalhost = !inFace.isLocal() &&
+                              LOCALHOST_NAME.isPrefixOf(data.getName());
+  if (isViolatingLocalhost) {
+    NFD_LOG_DEBUG("onIncomingData face=" << inFace.getId() <<
+                  " data=" << data.getName() << " violates /localhost");
+    // (drop)
     return;
   }
 
@@ -199,7 +233,8 @@
     this->setStragglerTimer(pitEntry);
 
     // invoke PIT satisfy callback
-    // TODO
+    this->dispatchToStrategy(pitEntry, bind(&Strategy::beforeSatisfyPendingInterest, _1,
+      pitEntry, boost::cref(inFace), boost::cref(data)));
   }
 
   // foreach pending downstream
@@ -214,13 +249,15 @@
 Forwarder::onDataUnsolicited(Face& inFace, const Data& data)
 {
   // accept to cache?
-  bool acceptToCache = false;// TODO decision
+  bool acceptToCache = inFace.isLocal();
   if (acceptToCache) {
     // CS insert
-    m_cs.insert(data);
+    m_cs.insert(data, true);
   }
 
-  NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() << " data=" << data.getName() << " acceptToCache=" << acceptToCache);
+  NFD_LOG_DEBUG("onDataUnsolicited face=" << inFace.getId() <<
+                " data=" << data.getName() <<
+                (acceptToCache ? " cached" : " not cached"));
 }
 
 void
@@ -229,16 +266,16 @@
   NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() << " data=" << data.getName());
 
   // /localhost scope control
-  bool violatesLocalhost = !outFace.isLocal() &&
-                           s_localhostName.isPrefixOf(data.getName());
-  if (violatesLocalhost) {
-    NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId()
-      << " data=" << data.getName() << " violates /localhost");
+  bool isViolatingLocalhost = !outFace.isLocal() &&
+                              LOCALHOST_NAME.isPrefixOf(data.getName());
+  if (isViolatingLocalhost) {
+    NFD_LOG_DEBUG("onOutgoingData face=" << outFace.getId() <<
+                  " data=" << data.getName() << " violates /localhost");
+    // (drop)
     return;
   }
 
-  // traffic manager
-  // pass through
+  // TODO traffic manager
 
   // send Data
   outFace.sendData(data);
@@ -284,14 +321,4 @@
   scheduler::cancel(pitEntry->m_stragglerTimer);
 }
 
-void
-Forwarder::dispatchToStrategy(const Face& inFace,
-                              const Interest& interest,
-                              shared_ptr<fib::Entry> fibEntry,
-                              shared_ptr<pit::Entry> pitEntry)
-{
-  m_strategy->afterReceiveInterest(inFace, interest, fibEntry, pitEntry);
-  // TODO dispatch according to fibEntry
-}
-
 } // namespace nfd
diff --git a/daemon/fw/forwarder.hpp b/daemon/fw/forwarder.hpp
index d9d23bc..8e7c0d2 100644
--- a/daemon/fw/forwarder.hpp
+++ b/daemon/fw/forwarder.hpp
@@ -130,11 +130,15 @@
   VIRTUAL_WITH_TESTS void
   cancelUnsatisfyAndStragglerTimer(shared_ptr<pit::Entry> pitEntry);
 
-  VIRTUAL_WITH_TESTS void
-  dispatchToStrategy(const Face& inFace,
-                     const Interest& interest,
-                     shared_ptr<fib::Entry> fibEntry,
-                     shared_ptr<pit::Entry> pitEntry);
+  /// call trigger (method) on the effective strategy of pitEntry
+#ifdef WITH_TESTS
+  virtual void
+  dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> trigger);
+#else
+  template<class Function>
+  void
+  dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, Function trigger);
+#endif
 
 private:
   FaceTable m_faceTable;
@@ -147,10 +151,8 @@
   Measurements   m_measurements;
   StrategyChoice m_strategyChoice;
 
-  /// the active strategy (only one strategy in mock)
-  shared_ptr<fw::Strategy> m_strategy;
-
-  static const Name s_localhostName;
+  static const ndn::Milliseconds DEFAULT_INTEREST_LIFETIME;
+  static const Name LOCALHOST_NAME;
 
   // allow Strategy (base class) to enter pipelines
   friend class fw::Strategy;
@@ -222,6 +224,19 @@
   return m_strategyChoice;
 }
 
+#ifdef WITH_TESTS
+inline void
+Forwarder::dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> trigger)
+#else
+template<class Function>
+inline void
+Forwarder::dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, Function trigger)
+#endif
+{
+  fw::Strategy& strategy = m_strategyChoice.findEffectiveStrategy(*pitEntry);
+  trigger(&strategy);
+}
+
 } // namespace nfd
 
 #endif // NFD_FW_FORWARDER_HPP
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index 101e847..d8928f5 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -9,8 +9,10 @@
 namespace nfd {
 namespace fw {
 
-NccStrategy::NccStrategy(Forwarder& forwarder)
-  : Strategy(forwarder, "ndn:/localhost/nfd/strategy/ncc")
+const Name NccStrategy::STRATEGY_NAME("ndn:/localhost/nfd/strategy/ncc");
+
+NccStrategy::NccStrategy(Forwarder& forwarder, const Name& name)
+  : Strategy(forwarder, name)
 {
 }
 
diff --git a/daemon/fw/ncc-strategy.hpp b/daemon/fw/ncc-strategy.hpp
index 6e915aa..ff9bcf3 100644
--- a/daemon/fw/ncc-strategy.hpp
+++ b/daemon/fw/ncc-strategy.hpp
@@ -17,8 +17,7 @@
 class NccStrategy : public Strategy
 {
 public:
-  explicit
-  NccStrategy(Forwarder& forwarder);
+  NccStrategy(Forwarder& forwarder, const Name& name = STRATEGY_NAME);
 
   virtual
   ~NccStrategy();
@@ -102,6 +101,9 @@
   void
   timeoutOnBestFace(weak_ptr<pit::Entry> pitEntryWeak);
 
+public:
+  static const Name STRATEGY_NAME;
+
 protected:
   static const time::Duration DEFER_FIRST_WITHOUT_BEST_FACE;
   static const time::Duration DEFER_RANGE_WITHOUT_BEST_FACE;
diff --git a/daemon/table/pit-face-record.hpp b/daemon/table/pit-face-record.hpp
index 2068729..3ad0462 100644
--- a/daemon/table/pit-face-record.hpp
+++ b/daemon/table/pit-face-record.hpp
@@ -38,7 +38,7 @@
   getLastRenewed() const;
   
   /** \brief gives the time point this record expires
-   *  \return{ getLastRenewed() + InterestLifetime }
+   *  \return getLastRenewed() + InterestLifetime
    */
   time::Point
   getExpiry() const;
diff --git a/daemon/table/pit-in-record.cpp b/daemon/table/pit-in-record.cpp
index 6963da2..573ee85 100644
--- a/daemon/table/pit-in-record.cpp
+++ b/daemon/table/pit-in-record.cpp
@@ -19,6 +19,12 @@
 {
 }
 
+void
+InRecord::update(const Interest& interest)
+{
+  this->FaceRecord::update(interest);
+  m_interest = const_cast<Interest&>(interest).shared_from_this();
+}
 
 } // namespace pit
 } // namespace nfd
diff --git a/daemon/table/pit-in-record.hpp b/daemon/table/pit-in-record.hpp
index 1f4e1e1..3dd7420 100644
--- a/daemon/table/pit-in-record.hpp
+++ b/daemon/table/pit-in-record.hpp
@@ -20,10 +20,26 @@
 public:
   explicit
   InRecord(shared_ptr<Face> face);
-  
+
   InRecord(const InRecord& other);
+
+  void
+  update(const Interest& interest);
+
+  const Interest&
+  getInterest() const;
+
+private:
+  shared_ptr<Interest> m_interest;
 };
 
+inline const Interest&
+InRecord::getInterest() const
+{
+  BOOST_ASSERT(static_cast<bool>(m_interest));
+  return *m_interest;
+}
+
 } // namespace pit
 } // namespace nfd
 
diff --git a/tests/fw/dummy-strategy.hpp b/tests/fw/dummy-strategy.hpp
new file mode 100644
index 0000000..81b9e70
--- /dev/null
+++ b/tests/fw/dummy-strategy.hpp
@@ -0,0 +1,68 @@
+/* -*- 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_FW_DUMMY_STRATEGY_HPP
+#define NFD_TEST_FW_DUMMY_STRATEGY_HPP
+
+#include "fw/strategy.hpp"
+
+namespace nfd {
+namespace tests {
+
+/** \brief strategy for unit testing
+ *
+ *  Triggers on DummyStrategy are recorded but does nothing
+ */
+class DummyStrategy : public fw::Strategy
+{
+public:
+  DummyStrategy(Forwarder& forwarder, const Name& name)
+    : Strategy(forwarder, name)
+  {
+  }
+  
+  virtual void
+  afterReceiveInterest(const Face& inFace,
+                       const Interest& interest,
+                       shared_ptr<fib::Entry> fibEntry,
+                       shared_ptr<pit::Entry> pitEntry)
+  {
+    ++m_afterReceiveInterest_count;
+    
+    if (static_cast<bool>(m_interestOutFace)) {
+      this->sendInterest(pitEntry, m_interestOutFace);
+    }
+    else {
+      this->rejectPendingInterest(pitEntry);
+    }
+  }
+  
+  virtual void
+  beforeSatisfyPendingInterest(shared_ptr<pit::Entry> pitEntry,
+                               const Face& inFace, const Data& data)
+  {
+    ++m_beforeSatisfyPendingInterest_count;
+  }
+
+  virtual void
+  beforeExpirePendingInterest(shared_ptr<pit::Entry> pitEntry)
+  {
+    ++m_beforeExpirePendingInterest_count;
+  }
+
+public:
+  int m_afterReceiveInterest_count;
+  int m_beforeSatisfyPendingInterest_count;
+  int m_beforeExpirePendingInterest_count;
+  
+  /// outFace to use in afterReceiveInterest, nullptr to reject
+  shared_ptr<Face> m_interestOutFace;
+};
+
+} // namespace tests
+} // namespace nfd
+
+#endif // TEST_FW_DUMMY_STRATEGY_HPP
diff --git a/tests/fw/forwarder.cpp b/tests/fw/forwarder.cpp
index ecd06ac..419a7ba 100644
--- a/tests/fw/forwarder.cpp
+++ b/tests/fw/forwarder.cpp
@@ -6,9 +6,10 @@
 
 #include "fw/forwarder.hpp"
 #include "tests/face/dummy-face.hpp"
-#include <ndn-cpp-dev/security/key-chain.hpp>
+#include "dummy-strategy.hpp"
 
 #include "tests/test-common.hpp"
+#include "tests/core/limited-io.hpp"
 
 namespace nfd {
 namespace tests {
@@ -22,12 +23,9 @@
   Name nameA  ("ndn:/A");
   Name nameAB ("ndn:/A/B");
   Name nameABC("ndn:/A/B/C");
-  Interest interestAB(nameAB);
-  interestAB.setInterestLifetime(4000);
-  shared_ptr<Data> dataABC = make_shared<Data>(nameABC);
-  ndn::SignatureSha256WithRsa fakeSignature;
-  fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
-  dataABC->setSignature(fakeSignature);
+  shared_ptr<Interest> interestAB = makeInterest(nameAB);
+  interestAB->setInterestLifetime(4000);
+  shared_ptr<Data> dataABC = makeData(nameABC);
 
   shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
   shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
@@ -42,7 +40,7 @@
   shared_ptr<fib::Entry> fibEntry = fibInsertResult.first;
   fibEntry->addNextHop(face2, 0);
 
-  face1->receiveInterest(interestAB);
+  face1->receiveInterest(*interestAB);
   g_io.run();
   g_io.reset();
   BOOST_REQUIRE_EQUAL(face2->m_sentInterests.size(), 1);
@@ -72,10 +70,7 @@
 
 protected:
   virtual void
-  dispatchToStrategy(const Face& inFace,
-                     const Interest& interest,
-                     shared_ptr<fib::Entry> fibEntry,
-                     shared_ptr<pit::Entry> pitEntry)
+  dispatchToStrategy(shared_ptr<pit::Entry> pitEntry, function<void(fw::Strategy*)> f)
   {
     ++m_dispatchToStrategy_count;
   }
@@ -93,61 +88,51 @@
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
-  shared_ptr<Data> d1, d2, d3, d4;
-  shared_ptr<Interest> i1, i2, i3, i4;
-  
-  ndn::SignatureSha256WithRsa fakeSignature;
-  fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
-
   // local face, /localhost: OK
   forwarder.m_dispatchToStrategy_count = 0;
-  i1 = make_shared<Interest>(Name("/localhost/A1"));
+  shared_ptr<Interest> i1 = makeInterest("/localhost/A1");
   forwarder.onIncomingInterest(*face1, *i1);
   BOOST_CHECK_EQUAL(forwarder.m_dispatchToStrategy_count, 1);
 
   // non-local face, /localhost: violate
   forwarder.m_dispatchToStrategy_count = 0;
-  i2 = make_shared<Interest>(Name("/localhost/A2"));
+  shared_ptr<Interest> i2 = makeInterest("/localhost/A2");
   forwarder.onIncomingInterest(*face2, *i2);
   BOOST_CHECK_EQUAL(forwarder.m_dispatchToStrategy_count, 0);
 
   // local face, non-/localhost: OK
   forwarder.m_dispatchToStrategy_count = 0;
-  i3 = make_shared<Interest>(Name("/A3"));
+  shared_ptr<Interest> i3 = makeInterest("/A3");
   forwarder.onIncomingInterest(*face1, *i3);
   BOOST_CHECK_EQUAL(forwarder.m_dispatchToStrategy_count, 1);
 
   // non-local face, non-/localhost: OK
   forwarder.m_dispatchToStrategy_count = 0;
-  i4 = make_shared<Interest>(Name("/A4"));
+  shared_ptr<Interest> i4 = makeInterest("/A4");
   forwarder.onIncomingInterest(*face2, *i4);
   BOOST_CHECK_EQUAL(forwarder.m_dispatchToStrategy_count, 1);
 
   // local face, /localhost: OK
   forwarder.m_onDataUnsolicited_count = 0;
-  d1 = make_shared<Data>(Name("/localhost/B1"));
-  d1->setSignature(fakeSignature);
+  shared_ptr<Data> d1 = makeData("/localhost/B1");
   forwarder.onIncomingData(*face1, *d1);
   BOOST_CHECK_EQUAL(forwarder.m_onDataUnsolicited_count, 1);
 
   // non-local face, /localhost: OK
   forwarder.m_onDataUnsolicited_count = 0;
-  d2 = make_shared<Data>(Name("/localhost/B2"));
-  d2->setSignature(fakeSignature);
+  shared_ptr<Data> d2 = makeData("/localhost/B2");
   forwarder.onIncomingData(*face2, *d2);
   BOOST_CHECK_EQUAL(forwarder.m_onDataUnsolicited_count, 0);
 
   // local face, non-/localhost: OK
   forwarder.m_onDataUnsolicited_count = 0;
-  d3 = make_shared<Data>(Name("/B3"));
-  d3->setSignature(fakeSignature);
+  shared_ptr<Data> d3 = makeData("/B3");
   forwarder.onIncomingData(*face1, *d3);
   BOOST_CHECK_EQUAL(forwarder.m_onDataUnsolicited_count, 1);
 
   // non-local face, non-/localhost: OK
   forwarder.m_onDataUnsolicited_count = 0;
-  d4 = make_shared<Data>(Name("/B4"));
-  d4->setSignature(fakeSignature);
+  shared_ptr<Data> d4 = makeData("/B4");
   forwarder.onIncomingData(*face2, *d4);
   BOOST_CHECK_EQUAL(forwarder.m_onDataUnsolicited_count, 1);
 }
@@ -164,33 +149,33 @@
   Pit& pit = forwarder.getPit();
 
   // local face, /localhost: OK
-  Interest interestA1 = Interest("/localhost/A1");
-  shared_ptr<pit::Entry> pitA1 = pit.insert(interestA1).first;
-  pitA1->insertOrUpdateInRecord(face3, interestA1);
+  shared_ptr<Interest> interestA1 = makeInterest("/localhost/A1");
+  shared_ptr<pit::Entry> pitA1 = pit.insert(*interestA1).first;
+  pitA1->insertOrUpdateInRecord(face3, *interestA1);
   face1->m_sentInterests.clear();
   forwarder.onOutgoingInterest(pitA1, *face1);
   BOOST_CHECK_EQUAL(face1->m_sentInterests.size(), 1);
 
   // non-local face, /localhost: violate
-  Interest interestA2 = Interest("/localhost/A2");
-  shared_ptr<pit::Entry> pitA2 = pit.insert(interestA2).first;
-  pitA2->insertOrUpdateInRecord(face3, interestA1);
+  shared_ptr<Interest> interestA2 = makeInterest("/localhost/A2");
+  shared_ptr<pit::Entry> pitA2 = pit.insert(*interestA2).first;
+  pitA2->insertOrUpdateInRecord(face3, *interestA2);
   face2->m_sentInterests.clear();
   forwarder.onOutgoingInterest(pitA2, *face2);
   BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 0);
 
   // local face, non-/localhost: OK
-  Interest interestA3 = Interest("/A3");
-  shared_ptr<pit::Entry> pitA3 = pit.insert(interestA3).first;
-  pitA3->insertOrUpdateInRecord(face3, interestA3);
+  shared_ptr<Interest> interestA3 = makeInterest("/A3");
+  shared_ptr<pit::Entry> pitA3 = pit.insert(*interestA3).first;
+  pitA3->insertOrUpdateInRecord(face3, *interestA3);
   face1->m_sentInterests.clear();
   forwarder.onOutgoingInterest(pitA3, *face1);
   BOOST_CHECK_EQUAL(face1->m_sentInterests.size(), 1);
 
   // non-local face, non-/localhost: OK
-  Interest interestA4 = Interest("/A4");
-  shared_ptr<pit::Entry> pitA4 = pit.insert(interestA4).first;
-  pitA4->insertOrUpdateInRecord(face3, interestA4);
+  shared_ptr<Interest> interestA4 = makeInterest("/A4");
+  shared_ptr<pit::Entry> pitA4 = pit.insert(*interestA4).first;
+  pitA4->insertOrUpdateInRecord(face3, *interestA4);
   face2->m_sentInterests.clear();
   forwarder.onOutgoingInterest(pitA4, *face2);
   BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 1);
@@ -216,6 +201,63 @@
   BOOST_CHECK_EQUAL(face2->m_sentDatas.size(), 1);
 }
 
+BOOST_AUTO_TEST_CASE(StrategyDispatch)
+{
+  LimitedIo limitedIo;
+  Forwarder forwarder;
+  shared_ptr<Face> face1 = make_shared<DummyFace>();
+  shared_ptr<Face> face2 = make_shared<DummyFace>();
+  forwarder.addFace(face1);
+  forwarder.addFace(face2);
+
+  StrategyChoice& strategyChoice = forwarder.getStrategyChoice();
+  shared_ptr<DummyStrategy> strategyP = make_shared<DummyStrategy>(
+                                        boost::ref(forwarder), "ndn:/strategyP");
+  shared_ptr<DummyStrategy> strategyQ = make_shared<DummyStrategy>(
+                                        boost::ref(forwarder), "ndn:/strategyQ");
+  strategyChoice.install(strategyP);
+  strategyChoice.install(strategyQ);
+  strategyChoice.insert("ndn:/" , strategyP->getName());
+  strategyChoice.insert("ndn:/B", strategyQ->getName());
+
+  shared_ptr<Interest> interest1 = makeInterest("ndn:/A/1");
+  strategyP->m_afterReceiveInterest_count = 0;
+  strategyP->m_interestOutFace = face2;
+  forwarder.onInterest(*face1, *interest1);
+  BOOST_CHECK_EQUAL(strategyP->m_afterReceiveInterest_count, 1);
+
+  shared_ptr<Interest> interest2 = makeInterest("ndn:/B/2");
+  strategyQ->m_afterReceiveInterest_count = 0;
+  strategyQ->m_interestOutFace = face2;
+  forwarder.onInterest(*face1, *interest2);
+  BOOST_CHECK_EQUAL(strategyQ->m_afterReceiveInterest_count, 1);
+
+  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(5));
+
+  shared_ptr<Data> data1 = makeData("ndn:/A/1/a");
+  strategyP->m_beforeSatisfyPendingInterest_count = 0;
+  forwarder.onData(*face2, *data1);
+  BOOST_CHECK_EQUAL(strategyP->m_beforeSatisfyPendingInterest_count, 1);
+
+  shared_ptr<Data> data2 = makeData("ndn:/B/2/b");
+  strategyQ->m_beforeSatisfyPendingInterest_count = 0;
+  forwarder.onData(*face2, *data2);
+  BOOST_CHECK_EQUAL(strategyQ->m_beforeSatisfyPendingInterest_count, 1);
+
+  shared_ptr<Interest> interest3 = makeInterest("ndn:/A/3");
+  interest3->setInterestLifetime(30);
+  forwarder.onInterest(*face1, *interest3);
+  shared_ptr<Interest> interest4 = makeInterest("ndn:/B/4");
+  interest4->setInterestLifetime(5000);
+  forwarder.onInterest(*face1, *interest4);
+
+  strategyP->m_beforeExpirePendingInterest_count = 0;
+  strategyQ->m_beforeExpirePendingInterest_count = 0;
+  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(100));
+  BOOST_CHECK_EQUAL(strategyP->m_beforeExpirePendingInterest_count, 1);
+  BOOST_CHECK_EQUAL(strategyQ->m_beforeExpirePendingInterest_count, 0);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } // namespace tests
diff --git a/tests/fw/ncc-strategy.cpp b/tests/fw/ncc-strategy.cpp
index bb3f640..d980c49 100644
--- a/tests/fw/ncc-strategy.cpp
+++ b/tests/fw/ncc-strategy.cpp
@@ -47,7 +47,7 @@
   Pit& pit = forwarder.getPit();
 
   // first Interest: strategy knows nothing and follows routing
-  shared_ptr<Interest> interest1p = make_shared<Interest>("ndn:/0Jm1ajrW/%00");
+  shared_ptr<Interest> interest1p = makeInterest("ndn:/0Jm1ajrW/%00");
   Interest& interest1 = *interest1p;
   interest1.setInterestLifetime(8000);
   shared_ptr<pit::Entry> pitEntry1 = pit.insert(interest1).first;
@@ -66,13 +66,13 @@
   BOOST_CHECK_EQUAL(strategy->m_sendInterestHistory[1].get<1>(), face2);
 
   // face2 responds
-  shared_ptr<Data> data1p = make_shared<Data>("ndn:/0Jm1ajrW/%00");
+  shared_ptr<Data> data1p = makeData("ndn:/0Jm1ajrW/%00");
   Data& data1 = *data1p;
   strategy->beforeSatisfyPendingInterest(pitEntry1, *face2, data1);
   limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(500));
 
   // second Interest: strategy knows face2 is best
-  shared_ptr<Interest> interest2p = make_shared<Interest>("ndn:/0Jm1ajrW/%00%01");
+  shared_ptr<Interest> interest2p = makeInterest("ndn:/0Jm1ajrW/%00%01");
   Interest& interest2 = *interest2p;
   interest2.setInterestLifetime(8000);
   shared_ptr<pit::Entry> pitEntry2 = pit.insert(interest2).first;
diff --git a/tests/fw/strategy-tester.hpp b/tests/fw/strategy-tester.hpp
index 571492c..71eb61b 100644
--- a/tests/fw/strategy-tester.hpp
+++ b/tests/fw/strategy-tester.hpp
@@ -24,7 +24,7 @@
 public:
   explicit
   StrategyTester(Forwarder& forwarder)
-    : S(forwarder)
+    : S(forwarder, Name(S::STRATEGY_NAME).append("tester"))
   {
   }
   
diff --git a/tests/mgmt/strategy-choice-manager.cpp b/tests/mgmt/strategy-choice-manager.cpp
index dd3291b..6577f6d 100644
--- a/tests/mgmt/strategy-choice-manager.cpp
+++ b/tests/mgmt/strategy-choice-manager.cpp
@@ -12,7 +12,7 @@
 #include "fw/forwarder.hpp"
 #include "fw/strategy.hpp"
 #include "tests/face/dummy-face.hpp"
-
+#include "tests/fw/dummy-strategy.hpp"
 
 #include "tests/test-common.hpp"
 #include "validation-common.hpp"
@@ -22,73 +22,18 @@
 
 NFD_LOG_INIT("StrategyChoiceManagerTest");
 
-class DummyStrategy : public fw::Strategy
-{
-public:
-  DummyStrategy(Forwarder& forwarder, const Name& strategyName)
-    : fw::Strategy(forwarder, strategyName)
-  {
-
-  }
-
-  virtual
-  ~DummyStrategy()
-  {
-
-  }
-
-  virtual void
-  afterReceiveInterest(const Face& inFace,
-                       const Interest& interest,
-                       shared_ptr<fib::Entry> fibEntry,
-                       shared_ptr<pit::Entry> pitEntry)
-  {
-
-  }
-};
-
-class TestStrategyA : public DummyStrategy
-{
-public:
-  TestStrategyA(Forwarder& forwarder)
-    : DummyStrategy(forwarder, "/localhost/nfd/strategy/test-strategy-a")
-  {
-  }
-
-  virtual
-  ~TestStrategyA()
-  {
-
-  }
-};
-
-class TestStrategyB : public DummyStrategy
-{
-public:
-  TestStrategyB(Forwarder& forwarder)
-    : DummyStrategy(forwarder, "/localhost/nfd/strategy/test-strategy-b")
-  {
-  }
-
-  virtual
-  ~TestStrategyB()
-  {
-
-  }
-};
-
 class StrategyChoiceManagerFixture : protected BaseFixture
 {
 public:
 
   StrategyChoiceManagerFixture()
-    : m_nameTree(1024)
-    , m_strategyChoice(m_nameTree, make_shared<TestStrategyA>(boost::ref(m_forwarder)))
+    : m_strategyChoice(m_forwarder.getStrategyChoice())
     , m_face(make_shared<InternalFace>())
     , m_manager(m_strategyChoice, m_face)
     , m_callbackFired(false)
   {
-
+    m_strategyChoice.install(make_shared<DummyStrategy>(boost::ref(m_forwarder), "/localhost/nfd/strategy/test-strategy-a"));
+    m_strategyChoice.insert("ndn:/", "/localhost/nfd/strategy/test-strategy-a");
   }
 
   virtual
@@ -193,8 +138,7 @@
 
 protected:
   Forwarder m_forwarder;
-  NameTree m_nameTree;
-  StrategyChoice m_strategyChoice;
+  StrategyChoice& m_strategyChoice;
   shared_ptr<InternalFace> m_face;
   StrategyChoiceManager m_manager;
 
@@ -207,7 +151,7 @@
 public:
   AllStrategiesFixture()
   {
-    m_strategyChoice.install(make_shared<TestStrategyB>(boost::ref(m_forwarder)));
+    m_strategyChoice.install(make_shared<DummyStrategy>(boost::ref(m_forwarder), "/localhost/nfd/strategy/test-strategy-b"));
   }
 
   virtual
diff --git a/tests/mgmt/validation-common.cpp b/tests/mgmt/validation-common.cpp
new file mode 100644
index 0000000..3ad1701
--- /dev/null
+++ b/tests/mgmt/validation-common.cpp
@@ -0,0 +1,33 @@
+/* -*- 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 "validation-common.hpp"
+
+#include <boost/test/unit_test.hpp>
+
+namespace nfd {
+namespace tests {
+
+const Name CommandIdentityGlobalFixture::s_identityName("/unit-test/CommandFixture/id");
+shared_ptr<ndn::IdentityCertificate> CommandIdentityGlobalFixture::s_certificate;
+
+CommandIdentityGlobalFixture::CommandIdentityGlobalFixture()
+{
+  BOOST_ASSERT(!static_cast<bool>(s_certificate));
+  s_certificate = m_keys.getCertificate(m_keys.createIdentity(s_identityName));
+}
+
+CommandIdentityGlobalFixture::~CommandIdentityGlobalFixture()
+{
+  s_certificate.reset();
+  m_keys.deleteIdentity(s_identityName);
+}
+
+BOOST_GLOBAL_FIXTURE(CommandIdentityGlobalFixture);
+
+} // namespace tests
+} // namespace nfd
+
diff --git a/tests/mgmt/validation-common.hpp b/tests/mgmt/validation-common.hpp
index 8e16103..9b876d9 100644
--- a/tests/mgmt/validation-common.hpp
+++ b/tests/mgmt/validation-common.hpp
@@ -4,9 +4,10 @@
  * See COPYING for copyright and distribution information.
  */
 
-#ifndef VALIDATION_COMMON_HPP
-#define VALIDATION_COMMON_HPP
+#ifndef NFD_TEST_MGMT_VALIDATION_COMMON_HPP
+#define NFD_TEST_MGMT_VALIDATION_COMMON_HPP
 
+#include "common.hpp"
 #include <ndn-cpp-dev/util/command-interest-generator.hpp>
 
 namespace nfd {
@@ -29,6 +30,30 @@
 //   shared_ptr<ndn::CommandInterestValidator> m_validator;
 // };
 
+/// a global fixture that holds the identity for CommandFixture
+class CommandIdentityGlobalFixture
+{
+public:
+  CommandIdentityGlobalFixture();
+
+  ~CommandIdentityGlobalFixture();
+  
+  static const Name& getIdentityName()
+  {
+    return s_identityName;
+  }
+  
+  static shared_ptr<ndn::IdentityCertificate> getCertificate()
+  {
+    BOOST_ASSERT(static_cast<bool>(s_certificate));
+    return s_certificate;
+  }
+
+private:
+  ndn::KeyChain m_keys;
+  static const Name s_identityName;
+  static shared_ptr<ndn::IdentityCertificate> s_certificate;
+};
 
 template<typename T>
 class CommandFixture : public T
@@ -37,33 +62,27 @@
   virtual
   ~CommandFixture()
   {
-    m_keys.deleteIdentity(m_identityName);
-
   }
 
   void
   generateCommand(Interest& interest)
   {
-    m_generator.generateWithIdentity(interest, m_identityName);
+    m_generator.generateWithIdentity(interest, getIdentityName());
   }
 
   const Name&
   getIdentityName() const
   {
-    return m_identityName;
+    return CommandIdentityGlobalFixture::getIdentityName();
   }
 
 protected:
   CommandFixture()
-    : m_identityName("/unit-test/CommandFixture/id"),
-      m_certificate(m_keys.getCertificate(m_keys.createIdentity(m_identityName)))
+    : m_certificate(CommandIdentityGlobalFixture::getCertificate())
   {
-
   }
 
 protected:
-  ndn::KeyChain m_keys;
-  const Name m_identityName;
   shared_ptr<ndn::IdentityCertificate> m_certificate;
   ndn::CommandInterestGenerator m_generator;
 };
@@ -82,7 +101,7 @@
   }
 };
 
-} //namespace tests
+} // namespace tests
 } // namespace nfd
 
-#endif // VALIDATION_COMMON_HPP
+#endif // NFD_TEST_MGMT_VALIDATION_COMMON_HPP
diff --git a/tests/table/pit.cpp b/tests/table/pit.cpp
index 5cece6a..393c1bc 100644
--- a/tests/table/pit.cpp
+++ b/tests/table/pit.cpp
@@ -19,20 +19,24 @@
   shared_ptr<Face> face1 = make_shared<DummyFace>();
   shared_ptr<Face> face2 = make_shared<DummyFace>();
   Name name("ndn:/KuYfjtRq");
-  Interest interest(name);
-  Interest interest1(name, static_cast<ndn::Milliseconds>(2528));
-  interest1.setNonce(25559);
-  Interest interest2(name, static_cast<ndn::Milliseconds>(6464));
-  interest2.setNonce(19004);
-  Interest interest3(name, static_cast<ndn::Milliseconds>(3585));
-  interest3.setNonce(24216);
-  Interest interest4(name, static_cast<ndn::Milliseconds>(8795));
-  interest4.setNonce(17365);
+  shared_ptr<Interest> interest  = makeInterest(name);
+  shared_ptr<Interest> interest1 = makeInterest(name);
+  interest1->setInterestLifetime(static_cast<ndn::Milliseconds>(2528));
+  interest1->setNonce(25559);
+  shared_ptr<Interest> interest2 = makeInterest(name);
+  interest2->setInterestLifetime(static_cast<ndn::Milliseconds>(6464));
+  interest2->setNonce(19004);
+  shared_ptr<Interest> interest3 = makeInterest(name);
+  interest3->setInterestLifetime(static_cast<ndn::Milliseconds>(3585));
+  interest3->setNonce(24216);
+  shared_ptr<Interest> interest4 = makeInterest(name);
+  interest4->setInterestLifetime(static_cast<ndn::Milliseconds>(8795));
+  interest4->setNonce(17365);
   
-  pit::Entry entry(interest);
+  pit::Entry entry(*interest);
   
-  BOOST_CHECK(entry.getInterest().getName().equals(name));
-  BOOST_CHECK(entry.getName().equals(name));
+  BOOST_CHECK_EQUAL(entry.getInterest().getName(), name);
+  BOOST_CHECK_EQUAL(entry.getName(), name);
 
   const pit::InRecordCollection& inRecords1 = entry.getInRecords();
   BOOST_CHECK_EQUAL(inRecords1.size(), 0);
@@ -42,52 +46,52 @@
   // insert InRecord
   time::Point before1 = time::now();
   pit::InRecordCollection::iterator in1 =
-    entry.insertOrUpdateInRecord(face1, interest1);
+    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_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())),
+    - time::milliseconds(interest1->getInterestLifetime())),
     (after1 - before1));
   
   // insert OutRecord
   time::Point before2 = time::now();
   pit::OutRecordCollection::iterator out1 =
-    entry.insertOrUpdateOutRecord(face1, interest1);
+    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_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())),
+    - time::milliseconds(interest1->getInterestLifetime())),
     (after2 - before2));
   
   // update InRecord
   time::Point before3 = time::now();
   pit::InRecordCollection::iterator in2 =
-    entry.insertOrUpdateInRecord(face1, interest2);
+    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_EQUAL(in2->getLastNonce(), interest2->getNonce());
   BOOST_CHECK_LE(std::abs(in2->getExpiry() - in2->getLastRenewed()
-    - time::milliseconds(interest2.getInterestLifetime())),
+    - time::milliseconds(interest2->getInterestLifetime())),
     (after3 - before3));
 
   // insert another InRecord
   pit::InRecordCollection::iterator in3 =
-    entry.insertOrUpdateInRecord(face2, interest3);
+    entry.insertOrUpdateInRecord(face2, *interest3);
   const pit::InRecordCollection& inRecords4 = entry.getInRecords();
   BOOST_CHECK_EQUAL(inRecords4.size(), 2);
   BOOST_CHECK_EQUAL(in3->getFace(), face2);
@@ -99,7 +103,7 @@
 
   // insert another OutRecord
   pit::OutRecordCollection::iterator out2 =
-    entry.insertOrUpdateOutRecord(face2, interest4);
+    entry.insertOrUpdateOutRecord(face2, *interest4);
   const pit::OutRecordCollection& outRecords3 = entry.getOutRecords();
   BOOST_CHECK_EQUAL(outRecords3.size(), 2);
   BOOST_CHECK_EQUAL(out2->getFace(), face2);
diff --git a/tests/test-common.hpp b/tests/test-common.hpp
index c17607c..8095431 100644
--- a/tests/test-common.hpp
+++ b/tests/test-common.hpp
@@ -9,6 +9,7 @@
 
 #include <boost/test/unit_test.hpp>
 #include "core/global-io.hpp"
+#include <ndn-cpp-dev/security/key-chain.hpp>
 
 namespace nfd {
 namespace tests {
@@ -25,7 +26,7 @@
     : g_io(getGlobalIoService())
   {
   }
-  
+
   ~BaseFixture()
   {
     resetGlobalIoService();
@@ -36,6 +37,25 @@
   boost::asio::io_service& g_io;
 };
 
+
+inline shared_ptr<Interest>
+makeInterest(const Name& name)
+{
+  return make_shared<Interest>(name);
+}
+
+inline shared_ptr<Data>
+makeData(const Name& name)
+{
+  shared_ptr<Data> data = make_shared<Data>(name);
+
+  ndn::SignatureSha256WithRsa fakeSignature;
+  fakeSignature.setValue(ndn::dataBlock(tlv::SignatureValue, reinterpret_cast<const uint8_t*>(0), 0));
+  data->setSignature(fakeSignature);
+
+  return data;
+}
+
 } // namespace tests
 } // namespace nfd