rib: redesign of remote prefix registration

Change-Id: I8418de6d5bb9615af898df5dbf9ed4cc2cb6a43a
Refs: #3211, #2413
diff --git a/tests/rib/auto-prefix-propagator.t.cpp b/tests/rib/auto-prefix-propagator.t.cpp
new file mode 100644
index 0000000..67e7b1b
--- /dev/null
+++ b/tests/rib/auto-prefix-propagator.t.cpp
@@ -0,0 +1,671 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "rib/auto-prefix-propagator.hpp"
+
+#include "tests/test-common.hpp"
+#include "tests/identity-management-fixture.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace nfd {
+namespace rib {
+namespace tests {
+
+NFD_LOG_INIT("AutoPrefixPropagatorTest");
+
+const Name TEST_LINK_LOCAL_NFD_PREFIX("/localhop/nfd");
+const time::milliseconds TEST_PREFIX_PROPAGATION_TIMEOUT(1000);
+
+class AutoPrefixPropagatorFixture : public nfd::tests::IdentityManagementFixture
+                                  , public nfd::tests::UnitTestTimeFixture
+{
+public:
+  AutoPrefixPropagatorFixture()
+    : m_face(ndn::util::makeDummyClientFace(nfd::tests::UnitTestTimeFixture::g_io, {true, true}))
+    , m_controller(*m_face, m_keyChain)
+    , m_propagator(m_controller, m_keyChain, m_rib)
+    , m_requests(m_face->sentInterests)
+    , m_entries(m_propagator.m_propagatedEntries)
+  {
+    m_propagator.enable();
+    m_propagator.m_controlParameters
+      .setCost(15)
+      .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client.
+      .setFaceId(0);// the remote hub will take the input face as the faceId.
+    m_propagator.m_commandOptions
+      .setPrefix(TEST_LINK_LOCAL_NFD_PREFIX)
+      .setTimeout(TEST_PREFIX_PROPAGATION_TIMEOUT);
+  }
+
+public: // helpers for test
+  bool
+  insertEntryToRib(const Name& name, const uint64_t& faceId = 0)
+  {
+    if (m_rib.find(name) != m_rib.end()) {
+      NFD_LOG_INFO("RIB entry already exists: " << name);
+      return false;
+    }
+
+    Route route;
+    route.faceId = faceId;
+    m_rib.insert(name, route);
+    advanceClocks(time::milliseconds(1));
+
+    return m_rib.find(name) != m_rib.end(); // return whether afterInserEntry will be triggered
+  }
+
+  bool
+  eraseEntryFromRib(const Name& name)
+  {
+    if (m_rib.find(name) == m_rib.end()) {
+      NFD_LOG_INFO("RIB entry does not exist: " << name);
+      return false;
+    }
+
+    std::vector<Route> routeList;
+    std::copy(m_rib.find(name)->second->begin(), m_rib.find(name)->second->end(),
+              std::back_inserter(routeList));
+    for (auto&& route : routeList) {
+      m_rib.erase(name, route);
+    }
+    advanceClocks(time::milliseconds(1));
+
+    return m_rib.find(name) == m_rib.end(); // return whether afterEraseEntry will be triggered
+  }
+
+  void
+  connectToHub()
+  {
+    insertEntryToRib("/localhop/nfd");
+  }
+
+  void
+  disconnectFromHub()
+  {
+    eraseEntryFromRib("/localhop/nfd");
+  }
+
+public: // helpers for check
+  enum class CheckRequestResult {
+    OK,
+    OUT_OF_BOUNDARY,
+    INVALID_N_COMPONENTS,
+    WRONG_COMMAND_PREFIX,
+    WRONG_VERB,
+    INVALID_PARAMETERS,
+    WRONG_REGISTERING_PREFIX
+  };
+
+  /**
+   * @brief check a request at specified index
+   *
+   * @param idx the index of the specified request in m_requests
+   * @param verb the expected verb of request
+   * @param registeringPrefix the expected registering prefix of request
+
+   * @retval OK the specified request has a valid name, the right verb, a valid ControlParameters
+   *            and the right registering prefix
+   * @retval OUT_OF_BOUNDARY the specified index out of boundary
+   * @retval INVALID_N_COMPONENTS the number of components of the request name is invalid
+   * @retval WRONG_COMMAND_PREFIX the command prefix of the request is wrong
+   * @retval WRONG_VERB the command verb of the request is wrong
+   * @retval INVALID_PARAMETERS no valid parameters can be decoded from the request's name
+   * @retval WRONG_REGISTERING_PREFIX the registering prefix of the request is wrong
+   */
+  CheckRequestResult
+  checkRequest(size_t idx, const std::string& verb, const Name& registeringPrefix)
+  {
+    Name requestName;
+    try {
+      requestName = m_requests.at(idx).getName();
+    }
+    catch (const std::out_of_range&) {
+      return CheckRequestResult::OUT_OF_BOUNDARY;
+    }
+
+    if (requestName.size() < 5) {
+      return CheckRequestResult::INVALID_N_COMPONENTS;
+    }
+
+    if (requestName.getPrefix(2) != TEST_LINK_LOCAL_NFD_PREFIX) {
+      return CheckRequestResult::WRONG_COMMAND_PREFIX;
+    }
+
+    if (requestName.get(3) != Name::Component(verb)) {
+      return CheckRequestResult::WRONG_VERB;
+    }
+
+    ControlParameters parameters;
+    try {
+      parameters.wireDecode(requestName.get(4).blockFromValue());
+    }
+    catch (const tlv::Error&) {
+      return CheckRequestResult::INVALID_PARAMETERS;
+    }
+
+    if (parameters.getName() != registeringPrefix) {
+      return CheckRequestResult::WRONG_REGISTERING_PREFIX;
+    }
+
+    return CheckRequestResult::OK;
+  }
+
+protected:
+  shared_ptr<ndn::util::DummyClientFace>     m_face;
+  ndn::nfd::Controller                       m_controller;
+  Rib                                        m_rib;
+  AutoPrefixPropagator                       m_propagator;
+  std::vector<Interest>&                     m_requests; // store sent out requests
+  AutoPrefixPropagator::PropagatedEntryList& m_entries; // store propagated entries
+};
+
+std::ostream&
+operator<<(std::ostream &os, const AutoPrefixPropagatorFixture::CheckRequestResult& result)
+{
+  switch (result) {
+  case AutoPrefixPropagatorFixture::CheckRequestResult::OK:
+    os << "OK";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::OUT_OF_BOUNDARY:
+    os << "OUT_OF_BOUNDARY";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_N_COMPONENTS:
+    os << "INVALID_N_COMPONENTS";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_COMMAND_PREFIX:
+    os << "WRONG_COMMAND_PREFIX";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_VERB:
+    os << "WRONG_VERB";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_PARAMETERS:
+    os << "INVALID_PARAMETERS";
+    break;
+  case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_REGISTERING_PREFIX:
+    os << "WRONG_REGISTERING_PREFIX";
+    break;
+  default:
+    break;
+  }
+
+  return os;
+}
+
+BOOST_AUTO_TEST_SUITE(Rib)
+
+BOOST_FIXTURE_TEST_SUITE(TestAutoPrefixPropagator, AutoPrefixPropagatorFixture)
+
+BOOST_AUTO_TEST_CASE(EnableDisable)
+{
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  auto testPropagateRevokeBasic = [this] () -> bool {
+    m_propagator.m_propagatedEntries.clear();
+
+    if (!insertEntryToRib("/test/A/app")) {
+      return false;
+    }
+    m_entries["/test/A"].succeed(nullptr);
+    if (!eraseEntryFromRib("/test/A/app")) {
+      return false;
+    }
+    return true;
+  };
+
+  m_propagator.disable();
+  BOOST_REQUIRE(testPropagateRevokeBasic());
+  BOOST_CHECK(m_requests.empty());
+
+  m_propagator.enable();
+  BOOST_REQUIRE(testPropagateRevokeBasic());
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_CASE(LoadConfiguration)
+{
+  ConfigFile config;
+  config.addSectionHandler("auto_prefix_propagate",
+                           bind(&AutoPrefixPropagator::loadConfig, &m_propagator, _1));
+
+  const std::string CONFIG_STRING =
+    "auto_prefix_propagate\n"
+    "{\n"
+    "  cost 11\n"
+    "  timeout 22\n"
+    "  refresh_interval 33\n"
+    "  base_retry_wait 44\n"
+    "  max_retry_wait 55\n"
+    "}";
+  config.parse(CONFIG_STRING, true, "test-auto-prefix-propagator");
+
+  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getCost(), 11);
+  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getOrigin(), ndn::nfd::ROUTE_ORIGIN_CLIENT);
+  BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getFaceId(), 0);
+
+  BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getPrefix(), TEST_LINK_LOCAL_NFD_PREFIX);
+  BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getTimeout(), time::milliseconds(22));
+
+  BOOST_CHECK_EQUAL(m_propagator.m_refreshInterval, time::seconds(33));
+  BOOST_CHECK_EQUAL(m_propagator.m_baseRetryWait, time::seconds(44));
+  BOOST_CHECK_EQUAL(m_propagator.m_maxRetryWait, time::seconds(55));
+}
+
+BOOST_AUTO_TEST_SUITE(Helpers)
+
+BOOST_AUTO_TEST_CASE(GetPrefixPropagationParameters)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(addIdentity("/test/A/B"));
+  BOOST_REQUIRE(addIdentity("/test/C/nrd"));
+
+  auto parameters1 = m_propagator.getPrefixPropagationParameters("/none/A/B/app");
+  auto parameters2 = m_propagator.getPrefixPropagationParameters("/test/A/B/app");
+  auto parameters3 = m_propagator.getPrefixPropagationParameters("/test/C/D/app");
+
+  BOOST_CHECK(!parameters1.isValid);
+
+  BOOST_CHECK(parameters2.isValid);
+  BOOST_CHECK_EQUAL(parameters2.parameters.getName(), "/test/A");
+  BOOST_CHECK_EQUAL(parameters2.options.getSigningInfo().getSignerName(), "/test/A");
+
+  BOOST_CHECK(parameters3.isValid);
+  BOOST_CHECK_EQUAL(parameters3.parameters.getName(), "/test/C");
+  BOOST_CHECK_EQUAL(parameters3.options.getSigningInfo().getSignerName(), "/test/C/nrd");
+}
+
+BOOST_AUTO_TEST_CASE(CheckCurrentPropagatedPrefix)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(addIdentity("/test/B/nrd"));
+  BOOST_REQUIRE(addIdentity("/test/A/B"));
+
+  BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/E")); // does not exist
+  BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/A/B")); // has a better option
+  BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/A"));
+  BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/B"));
+}
+
+BOOST_AUTO_TEST_CASE(RedoPropagation)
+{
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(addIdentity("/test/B"));
+  BOOST_REQUIRE(addIdentity("/test/B/C"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
+  BOOST_REQUIRE(insertEntryToRib("/test/B/C/app"));
+  BOOST_REQUIRE(insertEntryToRib("/test/B/D/app"));
+
+  auto testRedoPropagation = [this] (const Name& signingIdentity) {
+    m_requests.clear();
+
+    m_entries[signingIdentity].setSigningIdentity(signingIdentity);
+
+    auto parameters = m_propagator.m_controlParameters;
+    auto options = m_propagator.m_commandOptions;
+    ndn::security::SigningInfo info(ndn::security::SigningInfo::SIGNER_TYPE_ID, signingIdentity);
+    m_propagator.redoPropagation(m_entries.find(signingIdentity),
+                                  parameters.setName(signingIdentity),
+                                  options.setSigningInfo(info),
+                                  time::seconds(0));
+    advanceClocks(time::milliseconds(1));
+  };
+
+  testRedoPropagation("/test/A"); // current propagated prefix still works
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+  BOOST_CHECK(m_entries.find("test/A") != m_entries.end());
+
+  BOOST_CHECK_NO_THROW(m_keyChain.deleteIdentity("/test/B"));
+  testRedoPropagation("/test/B"); // signingIdentity no longer exists
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B/C"), CheckRequestResult::OK);
+  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
+  BOOST_CHECK(m_entries.find("/test/B/C") != m_entries.end());
+
+  testRedoPropagation("/test/B"); // no alternative identity
+  BOOST_CHECK(m_requests.empty());
+  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
+
+  m_entries["/test/B/C"].succeed(nullptr);
+  testRedoPropagation("/test/B"); // alternative identity has been propagated
+  BOOST_CHECK(m_requests.empty());
+  BOOST_CHECK(m_entries.find("/test/B") == m_entries.end());
+
+  BOOST_REQUIRE(addIdentity("/test/B/"));
+  testRedoPropagation("/test/B/C"); // better option exists: /test/B
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B"), CheckRequestResult::OK);
+  BOOST_CHECK(m_entries.find("test/B/C") == m_entries.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END() // Helpers
+
+BOOST_AUTO_TEST_SUITE(PropagateRevokeSemantics)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  connectToHub(); // ensure connectivity to the hub
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app")); // ensure afterInsertEntry signal emitted
+  m_entries["/test/A"].succeed(nullptr); // ensure there is a valid entry inserted
+  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app")); // ensure afterEraseEntry signal emitted
+
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_CASE(LocalPrefix)
+{
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/localhost/A"));
+
+  BOOST_REQUIRE(insertEntryToRib("/localhost/A/app"));
+  BOOST_CHECK(m_requests.empty());
+
+  m_propagator.m_propagatedEntries["/localhost/A"].succeed(nullptr);
+  BOOST_REQUIRE(eraseEntryFromRib("/localhost/A/app"));
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(InvalidPropagationParameters)
+{
+  connectToHub();
+
+  // no identity can be found
+  BOOST_CHECK(!m_propagator.getPrefixPropagationParameters("/test/A/app").isValid);
+
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries["/test/A"].succeed(nullptr);
+  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app"));
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(NoHubConnectivity)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries["/test/A"].succeed(nullptr);
+  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app"));
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(PropagatedEntryExists)
+{
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app1"));
+
+  m_requests.clear();
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); // /test/A has been propagated by /test/A/app1
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(PropagatedEntryShouldKeep)
+{
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app1"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app2"));
+
+  m_requests.clear();
+  BOOST_REQUIRE(eraseEntryFromRib("/test/A/app2")); // /test/A should be kept for /test/A/app1
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(BackOffRetryPolicy)
+{
+  m_propagator.m_commandOptions.setTimeout(time::milliseconds(1));
+  m_propagator.m_baseRetryWait = time::seconds(1);
+  m_propagator.m_maxRetryWait = time::seconds(2);
+
+  connectToHub();
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
+
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+
+  advanceClocks(time::milliseconds(1), 1050); // wait for the 1st retry
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 2);
+  BOOST_CHECK_EQUAL(checkRequest(1, "register", "/test/A"), CheckRequestResult::OK);
+
+  advanceClocks(time::milliseconds(1), 2050); // wait for the 2nd retry, 2 times
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 3);
+  BOOST_CHECK_EQUAL(checkRequest(2, "register", "/test/A"), CheckRequestResult::OK);
+
+  advanceClocks(time::milliseconds(1), 2050); // wait for the 3rd retry, reach the upper bound
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 4);
+  BOOST_CHECK_EQUAL(checkRequest(3, "register", "/test/A"), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PropagateRevokeSemantics
+
+BOOST_AUTO_TEST_SUITE(PropagatedEntryStateChanges)
+
+BOOST_AUTO_TEST_CASE(AfterRibInsert)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  auto testAfterRibInsert = [this] (const Name& ribEntryPrefix) {
+    m_requests.clear();
+    m_propagator.m_propagatedEntries.clear(); // ensure entry does not exist
+
+    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
+    m_propagator.afterRibInsert(propagateParameters.parameters, propagateParameters.options);
+    advanceClocks(time::milliseconds(1));
+  };
+
+  testAfterRibInsert("/test/A/app1");
+  BOOST_CHECK(m_requests.empty()); // no connectivity now
+  BOOST_CHECK(m_entries.find("/test/A") != m_entries.end());
+
+  connectToHub();
+  testAfterRibInsert("/test/A/app2");
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+  BOOST_CHECK(m_entries.find("/test/A") != m_entries.end());
+}
+
+BOOST_AUTO_TEST_CASE(AfterRibErase)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  auto testAfterRibInsert = [this] (const Name& localUnregPrefix) {
+    m_requests.clear();
+
+    auto propagateParameters = m_propagator.getPrefixPropagationParameters(localUnregPrefix);
+    m_propagator.afterRibErase(propagateParameters.parameters.unsetCost(),
+                               propagateParameters.options);
+    advanceClocks(time::milliseconds(1));
+  };
+
+  m_entries["/test/A"].succeed(nullptr);
+  testAfterRibInsert("/test/A/app");
+  BOOST_CHECK(m_requests.empty()); // no connectivity
+  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
+
+  connectToHub();
+  m_entries["/test/A"].fail(nullptr);
+  testAfterRibInsert("/test/A/app");
+  BOOST_CHECK(m_requests.empty()); // previous propagation has not succeeded
+  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
+
+  m_entries["/test/A"].succeed(nullptr);
+  testAfterRibInsert("/test/A/app");
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK);
+  BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased
+}
+
+BOOST_AUTO_TEST_CASE(AfterHubConnectDisconnect)
+{
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  BOOST_REQUIRE(addIdentity("/test/B"));
+  BOOST_REQUIRE(addIdentity("/test/C"));
+  BOOST_REQUIRE(insertEntryToRib("/test/A/app"));
+  BOOST_REQUIRE(insertEntryToRib("/test/B/app"));
+
+  // recorder the prefixes that will be propagated in order
+  std::vector<Name> propagatedPrefixes;
+
+  BOOST_CHECK(m_requests.empty()); // no request because there is no connectivity to the hub now
+  BOOST_REQUIRE_EQUAL(m_entries.size(), 2); // valid entries will be kept
+
+  connectToHub(); // 2 cached entries will be processed
+  for (auto&& entry : m_entries) {
+    propagatedPrefixes.push_back(entry.first);
+  }
+
+  BOOST_REQUIRE(insertEntryToRib("/test/C/app")); // will be processed directly
+  propagatedPrefixes.push_back("/test/C");
+  BOOST_REQUIRE_EQUAL(m_entries.size(), 3);
+
+  BOOST_REQUIRE(m_entries["/test/A"].isPropagating());
+  BOOST_REQUIRE(m_entries["/test/B"].isPropagating());
+  BOOST_REQUIRE(m_entries["/test/C"].isPropagating());
+
+  disconnectFromHub(); // all 3 entries are initialized
+  BOOST_CHECK(m_entries["/test/A"].isNew());
+  BOOST_CHECK(m_entries["/test/B"].isNew());
+  BOOST_CHECK(m_entries["/test/C"].isNew());
+
+  connectToHub(); // all 3 entries will be processed
+  for (auto&& entry : m_entries) {
+    propagatedPrefixes.push_back(entry.first);
+  }
+
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 6);
+  BOOST_REQUIRE_EQUAL(propagatedPrefixes.size(), 6);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", propagatedPrefixes[0]), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(1, "register", propagatedPrefixes[1]), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(2, "register", propagatedPrefixes[2]), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(3, "register", propagatedPrefixes[3]), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(4, "register", propagatedPrefixes[4]), CheckRequestResult::OK);
+  BOOST_CHECK_EQUAL(checkRequest(5, "register", propagatedPrefixes[5]), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_CASE(AfterPropagateSucceed)
+{
+  bool wasRefreshEventTriggered = false;
+  auto testAfterPropagateSucceed = [&] (const Name& ribEntryPrefix) {
+    m_requests.clear();
+    wasRefreshEventTriggered = false;
+
+    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
+    m_propagator.afterPropagateSucceed(propagateParameters.parameters, propagateParameters.options,
+                                       [&]{ wasRefreshEventTriggered = true; });
+    advanceClocks(time::milliseconds(1));
+  };
+
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  m_propagator.m_refreshInterval = time::seconds(0); // event will be executed at once
+  m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state
+
+  testAfterPropagateSucceed("/test/A/app"); // will trigger refresh event
+  BOOST_CHECK(wasRefreshEventTriggered);
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state
+  testAfterPropagateSucceed("/test/A/app"); // will call startRevocation
+  BOOST_CHECK(!wasRefreshEventTriggered);
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_CASE(AfterPropagateFail)
+{
+  bool wasRetryEventTriggered = false;
+  auto testAfterPropagateFail = [&] (const Name& ribEntryPrefix) {
+    m_requests.clear();
+    wasRetryEventTriggered = false;
+
+    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
+    m_propagator.afterPropagateFail(400, "test", propagateParameters.parameters, propagateParameters.options,
+                                     time::seconds(0), [&]{ wasRetryEventTriggered = true; });
+    advanceClocks(time::milliseconds(1));
+  };
+
+  BOOST_REQUIRE(addIdentity("/test/A"));
+  m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state
+
+  testAfterPropagateFail("/test/A/app"); // will trigger retry event
+  BOOST_CHECK(wasRetryEventTriggered);
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state
+  testAfterPropagateFail("/test/A/app"); // will do nothing
+  BOOST_CHECK(!wasRetryEventTriggered);
+  BOOST_CHECK(m_requests.empty());
+}
+
+BOOST_AUTO_TEST_CASE(AfterRevokeSucceed)
+{
+  auto testAfterRevokeSucceed = [&] (const Name& ribEntryPrefix) {
+    m_requests.clear();
+    auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix);
+    m_propagator.afterRevokeSucceed(propagateParameters.parameters,
+                                    propagateParameters.options,
+                                    time::seconds(0));
+    advanceClocks(time::milliseconds(1));
+  };
+
+  BOOST_REQUIRE(addIdentity("/test/A"));
+
+  testAfterRevokeSucceed("/test/A/app"); // in RELEASED state
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries["/test/A"].fail(nullptr); // in PROPAGATE_FAIL state
+  testAfterRevokeSucceed("/test/A/app");
+  BOOST_CHECK(m_requests.empty());
+
+  m_entries["/test/A"].succeed(nullptr); // in PROPAGATED state
+  testAfterRevokeSucceed("/test/A/app");
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+
+  m_entries["/test/A"].startPropagation(); // in PROPAGATING state
+  testAfterRevokeSucceed("/test/A/app");
+  BOOST_REQUIRE_EQUAL(m_requests.size(), 1);
+  BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // PropagatedEntryStateChanges
+
+BOOST_AUTO_TEST_SUITE_END() // TestAutoPrefixPropagator
+BOOST_AUTO_TEST_SUITE_END() // Rib
+
+} // namespace tests
+} // namespace rib
+} // namespace nfd
diff --git a/tests/rib/propagated-entry.t.cpp b/tests/rib/propagated-entry.t.cpp
new file mode 100644
index 0000000..8c8b1d2
--- /dev/null
+++ b/tests/rib/propagated-entry.t.cpp
@@ -0,0 +1,88 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2015,  Regents of the University of California,
+ *                           Arizona Board of Regents,
+ *                           Colorado State University,
+ *                           University Pierre & Marie Curie, Sorbonne University,
+ *                           Washington University in St. Louis,
+ *                           Beijing Institute of Technology,
+ *                           The University of Memphis.
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "rib/propagated-entry.hpp"
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace rib {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Rib)
+
+BOOST_FIXTURE_TEST_SUITE(TestPropagatedEntry, nfd::tests::BaseFixture)
+
+BOOST_AUTO_TEST_CASE(Identity)
+{
+  PropagatedEntry entry;
+  BOOST_CHECK(entry.m_signingIdentity.empty());
+
+  entry.setSigningIdentity("/test");
+  BOOST_CHECK_EQUAL(entry.m_signingIdentity, "/test");
+  BOOST_CHECK_EQUAL(entry.getSigningIdentity(), "/test");
+}
+
+BOOST_AUTO_TEST_CASE(Start)
+{
+  PropagatedEntry entry;
+  BOOST_CHECK(!entry.isPropagating());
+
+  entry.startPropagation();
+  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATING, entry.m_propagationStatus);
+  BOOST_CHECK(entry.isPropagating());
+}
+
+BOOST_AUTO_TEST_CASE(Succeed)
+{
+  PropagatedEntry entry;
+  entry.succeed(nullptr);
+  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATED, entry.m_propagationStatus);
+  BOOST_CHECK(entry.isPropagated());
+}
+
+BOOST_AUTO_TEST_CASE(Fail)
+{
+  PropagatedEntry entry;
+  entry.fail(nullptr);
+  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATE_FAIL, entry.m_propagationStatus);
+  BOOST_CHECK(entry.isPropagateFail());
+}
+
+BOOST_AUTO_TEST_CASE(Initialize)
+{
+  PropagatedEntry entry;
+  entry.startPropagation();
+  BOOST_CHECK_EQUAL(PropagationStatus::PROPAGATING, entry.m_propagationStatus);
+
+  entry.initialize();
+  BOOST_CHECK_EQUAL(PropagationStatus::NEW, entry.m_propagationStatus);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestPropagatedEntry
+BOOST_AUTO_TEST_SUITE_END() // Rib
+
+} // namespace tests
+} // namespace rib
+} // namespace nfd
diff --git a/tests/rib/remote-registrator.t.cpp b/tests/rib/remote-registrator.t.cpp
deleted file mode 100644
index dc41cda..0000000
--- a/tests/rib/remote-registrator.t.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "rib/remote-registrator.hpp"
-
-#include "tests/limited-io.hpp"
-#include "tests/identity-management-fixture.hpp"
-#include <ndn-cxx/util/dummy-client-face.hpp>
-
-namespace nfd {
-namespace rib {
-namespace tests {
-
-class RemoteRegistratorFixture : public nfd::tests::IdentityManagementFixture
-                               , public nfd::tests::UnitTestTimeFixture
-{
-public:
-  RemoteRegistratorFixture()
-    : face(ndn::util::makeDummyClientFace(getGlobalIoService()))
-    , controller(make_shared<ndn::nfd::Controller>(std::ref(*face), m_keyChain))
-    , remoteRegistrator(make_shared<RemoteRegistrator>(std::ref(*controller),
-                                                       m_keyChain,
-                                                       rib))
-    , COMMAND_PREFIX("/localhop/nfd/rib")
-    , REGISTER_VERB("register")
-    , UNREGISTER_VERB("unregister")
-  {
-    readConfig();
-
-    remoteRegistrator->enable();
-
-    advanceClocks(time::milliseconds(1));
-    face->sentInterests.clear();
-  }
-
-  void
-  readConfig(bool isSetRetry = false)
-  {
-    ConfigFile config;
-    config.addSectionHandler("remote_register",
-                             bind(&RemoteRegistrator::loadConfig, remoteRegistrator, _1));
-
-
-    if (isSetRetry) {
-      const std::string CONFIG_STRING =
-      "remote_register\n"
-      "{\n"
-      "  cost 15\n"
-      "  timeout 1000\n"
-      "  retry 1\n"
-      "  refresh_interval 5\n"
-      "}";
-
-      config.parse(CONFIG_STRING, true, "test-remote-register");
-    }
-    else {
-      const std::string CONFIG_STRING =
-      "remote_register\n"
-      "{\n"
-      "  cost 15\n"
-      "  timeout 100000\n"
-      "  retry 0\n"
-      "  refresh_interval 5\n"
-      "}";
-
-      config.parse(CONFIG_STRING, true, "test-remote-register");
-    }
-  }
-
-  void
-  waitForTimeout()
-  {
-    advanceClocks(time::milliseconds(100), time::seconds(1));
-  }
-
-  void
-  insertEntryWithIdentity(Name identity,
-                          name::Component appName = DEFAULT_APP_NAME,
-                          uint64_t faceId = 0)
-  {
-    BOOST_CHECK_EQUAL(addIdentity(identity), true);
-
-    Route route;
-    route.faceId = faceId;
-
-    rib.insert(identity.append(appName), route);
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  insertEntryWithoutIdentity(Name identity,
-                             name::Component appName = DEFAULT_APP_NAME,
-                             uint64_t faceId = 0)
-  {
-    Route route;
-    route.faceId = faceId;
-
-    rib.insert(identity.append(appName), route);
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  eraseEntryWithIdentity(Name identity,
-                         name::Component appName = DEFAULT_APP_NAME,
-                         uint64_t faceId = 0)
-  {
-    BOOST_CHECK_EQUAL(addIdentity(identity), true);
-
-    Route route;
-    route.faceId = faceId;
-
-    rib.erase(identity.append(appName), route);
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  eraseEntryWithoutIdentity(Name identity,
-                            name::Component appName = DEFAULT_APP_NAME,
-                            uint64_t faceId = 0)
-  {
-    Route route;
-    route.faceId = faceId;
-
-    rib.erase(identity.append(appName), route);
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  eraseFace(uint64_t faceId)
-  {
-    for (const Rib::NameAndRoute& item : rib.findRoutesWithFaceId(faceId)) {
-      rib.erase(item.first, item.second);
-    }
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  connectToHub()
-  {
-    rib.insert(Name("/localhop/nfd"), Route());
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  disconnectToHub()
-  {
-    rib.erase(Name("/localhop/nfd"), Route());
-
-    advanceClocks(time::milliseconds(1));
-  }
-
-  void
-  extractParameters(Interest& interest, Name::Component& verb,
-                    ndn::nfd::ControlParameters& extractedParameters)
-  {
-    const Name& name = interest.getName();
-    verb = name[COMMAND_PREFIX.size()];
-    const Name::Component& parameterComponent = name[COMMAND_PREFIX.size() + 1];
-
-    Block rawParameters = parameterComponent.blockFromValue();
-    extractedParameters.wireDecode(rawParameters);
-  }
-
-public:
-  Rib rib;
-  shared_ptr<ndn::util::DummyClientFace> face;
-  shared_ptr<ndn::nfd::Controller> controller;
-  shared_ptr<RemoteRegistrator> remoteRegistrator;
-
-  const Name COMMAND_PREFIX;
-  const name::Component REGISTER_VERB;
-  const name::Component UNREGISTER_VERB;
-
-  static const name::Component DEFAULT_APP_NAME;
-};
-
-const name::Component RemoteRegistratorFixture::DEFAULT_APP_NAME("app");
-
-BOOST_FIXTURE_TEST_SUITE(TestRemoteRegistrator, RemoteRegistratorFixture)
-
-BOOST_FIXTURE_TEST_CASE(AutoTest, RemoteRegistratorFixture)
-{
-  BOOST_REQUIRE_EQUAL(1, 1);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterWithoutConnection, RemoteRegistratorFixture)
-{
-  insertEntryWithIdentity("/remote/register");
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterWithoutIdentity, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  insertEntryWithoutIdentity("/remote/register");
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterWithHubPrefix, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterWithLocalPrefix, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  insertEntryWithIdentity("/localhost/prefix");
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterBasic, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-  insertEntryWithIdentity(identity);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 1);
-
-  Interest& request = face->sentInterests[0];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterAdvanced, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-  Name identityAddRib("/remote/register/rib");
-  insertEntryWithIdentity(identityAddRib);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 1);
-
-  Interest& request = face->sentInterests[0];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterWithRedundantCallback, RemoteRegistratorFixture)
-{
-  remoteRegistrator->enable();
-
-  connectToHub();
-
-  Name identity("/remote/register");
-  insertEntryWithIdentity(identity);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 1);
-
-  Interest& request = face->sentInterests[0];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(RegisterRetry, RemoteRegistratorFixture)
-{
-  // setRetry
-  readConfig(true);
-
-  connectToHub();
-
-  Name identity("/remote/register");
-  insertEntryWithIdentity(identity);
-
-  waitForTimeout();
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  Interest& requestFirst  = face->sentInterests[0];
-  Interest& requestSecond = face->sentInterests[1];
-
-  ndn::nfd::ControlParameters extractedParametersFirst, extractedParametersSecond;
-  Name::Component verbFirst, verbSecond;
-  extractParameters(requestFirst,  verbFirst,  extractedParametersFirst);
-  extractParameters(requestSecond, verbSecond, extractedParametersSecond);
-
-  BOOST_CHECK_EQUAL(verbFirst,  REGISTER_VERB);
-  BOOST_CHECK_EQUAL(verbSecond, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParametersFirst.getName(),  identity);
-  BOOST_CHECK_EQUAL(extractedParametersSecond.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(UnregisterWithoutInsert, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  eraseEntryWithIdentity("/remote/register");
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(UnregisterWithoutConnection, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  disconnectToHub();
-
-  Name indentity("/remote/register");
-  remoteRegistrator->m_regEntries.insert(
-            nfd::rib::RemoteRegistrator::RegisteredEntry(indentity, scheduler::EventId()));
-
-  eraseEntryWithIdentity(indentity);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 0);
-}
-
-BOOST_FIXTURE_TEST_CASE(UnregisterWithoutSuccessfullRegistration,
-                        RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-
-  insertEntryWithIdentity(identity);
-
-  eraseEntryWithIdentity(identity);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 1);
-
-  Interest& request = face->sentInterests[0];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(UnregisterBasic, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-
-  insertEntryWithIdentity(identity);
-
-  scheduler::EventId event;
-
-  remoteRegistrator->m_regEntries.insert(
-          nfd::rib::RemoteRegistrator::RegisteredEntry(identity, event));
-
-  eraseEntryWithIdentity(identity);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  Interest& request = face->sentInterests[1];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, UNREGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(UnregisterAdvanced, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identityShort("/remote/register");
-  Name identityLong("/remote/register/long");
-
-  scheduler::EventId eventShort;
-  scheduler::EventId eventLong;
-
-  insertEntryWithIdentity(identityShort, name::Component("appA"));
-
-  remoteRegistrator->m_regEntries.insert(
-          nfd::rib::RemoteRegistrator::RegisteredEntry(identityShort,
-                                                       eventShort));
-
-  insertEntryWithIdentity(identityShort, name::Component("appB"));
-
-  insertEntryWithIdentity(identityLong);
-
-  remoteRegistrator->m_regEntries.insert(
-          nfd::rib::RemoteRegistrator::RegisteredEntry(identityLong,
-                                                       eventLong));
-
-  // two registration commands are generated for identityShort and identityLong
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  eraseEntryWithIdentity(identityShort, name::Component("appA"));
-
-  // no unregistration command is generated as appB also exists
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  eraseEntryWithIdentity(identityShort, name::Component("appB"));
-
-  // one unregistration command is generated for identityShort
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 3);
-
-  Interest& request = face->sentInterests[2];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, UNREGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identityShort);
-}
-
-BOOST_FIXTURE_TEST_CASE(EraseFace, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-  uint64_t faceId = 517;
-
-  insertEntryWithIdentity(identity, DEFAULT_APP_NAME, faceId);
-
-  scheduler::EventId event;
-
-  remoteRegistrator->m_regEntries.insert(
-          nfd::rib::RemoteRegistrator::RegisteredEntry(identity, event));
-
-  eraseFace(faceId);
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  Interest& request = face->sentInterests[1];
-
-  ndn::nfd::ControlParameters extractedParameters;
-  Name::Component verb;
-  extractParameters(request, verb, extractedParameters);
-
-  BOOST_CHECK_EQUAL(verb, UNREGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters.getName(), identity);
-}
-
-BOOST_FIXTURE_TEST_CASE(RebuildConnection, RemoteRegistratorFixture)
-{
-  connectToHub();
-
-  Name identity("/remote/register");
-
-  insertEntryWithIdentity(identity);
-
-  scheduler::EventId event;
-
-  remoteRegistrator->m_regEntries.insert(
-          nfd::rib::RemoteRegistrator::RegisteredEntry(identity, event));
-
-  disconnectToHub();
-
-  connectToHub();
-
-  BOOST_REQUIRE_EQUAL(face->sentInterests.size(), 2);
-
-  Interest& request1 = face->sentInterests[0];
-  Interest& request2 = face->sentInterests[1];
-
-  ndn::nfd::ControlParameters extractedParameters1, extractedParameters2;
-  Name::Component verb1, verb2;
-  extractParameters(request1, verb1, extractedParameters1);
-  extractParameters(request2, verb2, extractedParameters2);
-
-  BOOST_CHECK_EQUAL(verb1, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(verb2, REGISTER_VERB);
-  BOOST_CHECK_EQUAL(extractedParameters1.getName(),
-                    extractedParameters2.getName());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace rib
-} // namespace nfd