partial-sync: add unsubscribe feature

Change-Id: Ib32aa2c0acebb5be40bb8d99689a3ea18113a692
diff --git a/PSync/consumer.cpp b/PSync/consumer.cpp
index a55860b..6886605 100644
--- a/PSync/consumer.cpp
+++ b/PSync/consumer.cpp
@@ -59,6 +59,8 @@
     return false;
   }
 
+  NDN_LOG_DEBUG("Subscribing prefix: " << prefix);
+
   m_subscriptionList.emplace(prefix);
   m_bloomFilter.insert(prefix);
 
@@ -69,9 +71,30 @@
   return true;
 }
 
+bool
+Consumer::removeSubscription(const ndn::Name& prefix)
+{
+  if (!isSubscribed(prefix))
+    return false;
+
+  NDN_LOG_DEBUG("Unsubscribing prefix: " << prefix);
+
+  m_prefixes.erase(prefix);
+  m_subscriptionList.erase(prefix);
+
+  // Clear and reconstruct the bloom filter
+  m_bloomFilter.clear();
+
+  for (const auto& item : m_subscriptionList)
+    m_bloomFilter.insert(item);
+
+  return true;
+}
+
 void
 Consumer::stop()
 {
+  NDN_LOG_DEBUG("Canceling all the scheduled events");
   m_scheduler.cancelAllEvents();
 
   if (m_syncFetcher) {
diff --git a/PSync/consumer.hpp b/PSync/consumer.hpp
index 07c3443..203417f 100644
--- a/PSync/consumer.hpp
+++ b/PSync/consumer.hpp
@@ -107,6 +107,15 @@
   bool
   addSubscription(const ndn::Name& prefix, uint64_t seqNo, bool callSyncDataCb = true);
 
+  /**
+   * @brief Remove prefix from subscription list
+   *
+   * @param prefix prefix to be removed from the list
+   * @return true if prefix is removed, false if it is not present
+   */
+  bool
+  removeSubscription(const ndn::Name& prefix);
+
   std::set<ndn::Name>
   getSubscriptionList() const
   {
diff --git a/tests/test-consumer.cpp b/tests/test-consumer.cpp
index 79ee495..62715bb 100644
--- a/tests/test-consumer.cpp
+++ b/tests/test-consumer.cpp
@@ -45,6 +45,23 @@
   BOOST_CHECK(!consumer.addSubscription(subscription, 0));
 }
 
+BOOST_AUTO_TEST_CASE(RemoveSubscription)
+{
+  util::DummyClientFace face;
+  Consumer consumer(Name("/psync"), face,
+                    [] (const auto&) {},
+                    [] (const auto&) {},
+                    40, 0.001);
+
+  Name subscription("test");
+  consumer.addSubscription(subscription, 0);
+
+  BOOST_CHECK(consumer.isSubscribed(subscription));
+  BOOST_CHECK(consumer.removeSubscription(subscription));
+  BOOST_CHECK(!consumer.removeSubscription(subscription));
+  BOOST_CHECK(!consumer.isSubscribed(subscription));
+}
+
 BOOST_FIXTURE_TEST_CASE(ConstantTimeoutForFirstSegment, tests::IoFixture)
 {
   util::DummyClientFace face(m_io);