Recalculate routing table after face destroy event

refs: #2635

Change-Id: I7abbb638515af4a55c4241c4242a496a8cf8ca88
diff --git a/tests/test-nlsr.cpp b/tests/test-nlsr.cpp
index ec53820..74a3f47 100644
--- a/tests/test-nlsr.cpp
+++ b/tests/test-nlsr.cpp
@@ -20,10 +20,13 @@
  *
  **/
 
- #include "test-common.hpp"
- #include "dummy-face.hpp"
+#include "test-common.hpp"
+#include "dummy-face.hpp"
 
- #include "nlsr.hpp"
+#include "nlsr.hpp"
+
+#include <ndn-cxx/management/nfd-face-event-notification.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
 
 namespace nlsr {
 namespace test {
@@ -106,6 +109,80 @@
   BOOST_CHECK_EQUAL(rt.getRoutingCalcInterval(), ndn::time::seconds(9));
 }
 
+BOOST_FIXTURE_TEST_CASE(FaceDestroyEvent, UnitTestTimeFixture)
+{
+  shared_ptr<ndn::util::DummyClientFace> face = ndn::util::makeDummyClientFace(g_ioService);
+  Nlsr nlsr(g_ioService, g_scheduler, ndn::ref(*face));
+
+  // Simulate loading configuration file
+  ConfParameter& conf = nlsr.getConfParameter();
+  conf.setNetwork("/ndn");
+  conf.setSiteName("/site");
+  conf.setRouterName("/%C1.router/this-router");
+  conf.setAdjLsaBuildInterval(0);
+  conf.setRoutingCalcInterval(0);
+
+  // Add active neighbors
+  AdjacencyList& neighbors = nlsr.getAdjacencyList();
+
+  uint64_t destroyFaceId = 128;
+
+  // Create a neighbor whose Face will be destroyed
+  Adjacent failNeighbor("/ndn/neighborA", "uri://faceA", 10, Adjacent::STATUS_ACTIVE, 0,
+                        destroyFaceId);
+  neighbors.insert(failNeighbor);
+
+  // Create an additional neighbor so an adjacency LSA can be built after the face is destroyed
+  Adjacent otherNeighbor("/ndn/neighborB", "uri://faceB", 25, Adjacent::STATUS_ACTIVE, 0, 256);
+  neighbors.insert(otherNeighbor);
+
+  nlsr.initialize();
+
+  // Simulate successful HELLO responses
+  nlsr.getLsdb().scheduleAdjLsaBuild();
+
+  // Run the scheduler to build an adjacency LSA
+  this->advanceClocks(ndn::time::milliseconds(1));
+
+  // Make sure an adjacency LSA was built
+  ndn::Name key = ndn::Name(nlsr.getConfParameter().getRouterPrefix()).append(AdjLsa::TYPE_STRING);
+  AdjLsa* lsa = nlsr.getLsdb().findAdjLsa(key);
+  BOOST_REQUIRE(lsa != nullptr);
+
+  uint32_t lastAdjLsaSeqNo = nlsr.getSequencingManager().getAdjLsaSeq();
+
+  // Make sure the routing table was calculated
+  RoutingTableEntry* rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
+  BOOST_REQUIRE(rtEntry != nullptr);
+  BOOST_REQUIRE_EQUAL(rtEntry->getNexthopList().getSize(), 1);
+
+  // Receive FaceEventDestroyed notification
+  ndn::nfd::FaceEventNotification event;
+  event.setKind(ndn::nfd::FACE_EVENT_DESTROYED)
+       .setFaceId(destroyFaceId);
+
+  shared_ptr<ndn::Data> data = make_shared<ndn::Data>("/localhost/nfd/faces/events/%FE%00");
+  data->setContent(event.wireEncode());
+  nlsr.getKeyChain().sign(*data);
+
+  face->receive(*data);
+
+  // Run the scheduler to build an adjacency LSA
+  this->advanceClocks(ndn::time::milliseconds(1));
+
+  Adjacent updatedNeighbor = neighbors.getAdjacent(failNeighbor.getName());
+
+  BOOST_CHECK_EQUAL(updatedNeighbor.getFaceId(), 0);
+  BOOST_CHECK_EQUAL(updatedNeighbor.getInterestTimedOutNo(),
+                    nlsr.getConfParameter().getInterestRetryNumber());
+  BOOST_CHECK_EQUAL(updatedNeighbor.getStatus(), Adjacent::STATUS_INACTIVE);
+  BOOST_CHECK_EQUAL(nlsr.getSequencingManager().getAdjLsaSeq(), lastAdjLsaSeqNo + 1);
+
+  // Make sure the routing table was recalculated
+  rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
+  BOOST_CHECK(rtEntry == nullptr);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
 
 } //namespace test