mgmt: send FACE_EVENT_UP and FACE_EVENT_DOWN notifications

refs #3794

Change-Id: I98cc9db2652454d8fd09975b619433046e9bc7ca
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index 325b344..8a4907c 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -30,6 +30,7 @@
 
 #include "nfd-manager-common-fixture.hpp"
 #include "../face/dummy-face.hpp"
+#include "../face/dummy-transport.hpp"
 
 #include <ndn-cxx/encoding/tlv.hpp>
 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
@@ -284,7 +285,7 @@
 
   std::map<std::string, shared_ptr<TestChannel>> addedChannels;
   size_t nEntries = 404;
-  for (size_t i = 0 ; i < nEntries ; i ++) {
+  for (size_t i = 0; i < nEntries; i++) {
     auto channel = factory->addChannel("test" + boost::lexical_cast<std::string>(i) + "://");
     addedChannels[channel->getUri().toString()] = channel;
   }
@@ -309,49 +310,113 @@
 
 BOOST_AUTO_TEST_SUITE(Notifications)
 
-BOOST_AUTO_TEST_CASE(FaceEventNotification)
+BOOST_AUTO_TEST_CASE(FaceEventCreated)
 {
-  auto addedFace = addFace(); // trigger FACE_EVENT_CREATED notification
-  BOOST_CHECK_NE(addedFace->getId(), -1);
-  int64_t faceId = addedFace->getId();
+  auto face = addFace(); // trigger FACE_EVENT_CREATED notification
+  BOOST_CHECK_NE(face->getId(), face::INVALID_FACEID);
+  FaceId faceId = face->getId();
+
+  BOOST_CHECK_EQUAL(m_manager.m_faceStateChangeConn.count(faceId), 1);
 
   // check notification
-  {
-    Block payload;
-    ndn::nfd::FaceEventNotification notification;
-    BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
-    BOOST_CHECK_NO_THROW(payload = m_responses[0].getContent().blockFromValue());
-    BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
-    BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
-    BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_CREATED);
-    BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
-    BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
-    BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
-    BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
-    BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
-    BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
-  }
+  Block payload;
+  ndn::nfd::FaceEventNotification notification;
+  BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
+  BOOST_CHECK_NO_THROW(payload = m_responses.back().getContent().blockFromValue());
+  BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
+  BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
+  BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_CREATED);
+  BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
+  BOOST_CHECK_EQUAL(notification.getRemoteUri(), face->getRemoteUri().toString());
+  BOOST_CHECK_EQUAL(notification.getLocalUri(), face->getLocalUri().toString());
+  BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
+  BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
+  BOOST_CHECK_EQUAL(notification.getFlags(), 0x0);
+}
 
-  addedFace->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
+BOOST_AUTO_TEST_CASE(FaceEventDownUp)
+{
+  auto face = addFace();
+  BOOST_CHECK_NE(face->getId(), face::INVALID_FACEID);
+  FaceId faceId = face->getId();
+
+  // trigger FACE_EVENT_DOWN notification
+  dynamic_cast<face::tests::DummyTransport*>(face->getTransport())->setState(face::FaceState::DOWN);
   advanceClocks(time::milliseconds(1), 10);
+  BOOST_CHECK_EQUAL(face->getState(), face::FaceState::DOWN);
 
   // check notification
   {
     Block payload;
     ndn::nfd::FaceEventNotification notification;
     BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
-    BOOST_CHECK_NO_THROW(payload = m_responses[1].getContent().blockFromValue());
+    BOOST_CHECK_NO_THROW(payload = m_responses.back().getContent().blockFromValue());
     BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
     BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
-    BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DESTROYED);
+    BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DOWN);
     BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
-    BOOST_CHECK_EQUAL(notification.getRemoteUri(), addedFace->getRemoteUri().toString());
-    BOOST_CHECK_EQUAL(notification.getLocalUri(), addedFace->getLocalUri().toString());
+    BOOST_CHECK_EQUAL(notification.getRemoteUri(), face->getRemoteUri().toString());
+    BOOST_CHECK_EQUAL(notification.getLocalUri(), face->getLocalUri().toString());
     BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
     BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
     BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
+    BOOST_CHECK_EQUAL(notification.getFlags(), 0x0);
   }
-  BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
+
+  // trigger FACE_EVENT_UP notification
+  dynamic_cast<face::tests::DummyTransport*>(face->getTransport())->setState(face::FaceState::UP);
+  advanceClocks(time::milliseconds(1), 10);
+  BOOST_CHECK_EQUAL(face->getState(), face::FaceState::UP);
+
+  // check notification
+  {
+    Block payload;
+    ndn::nfd::FaceEventNotification notification;
+    BOOST_REQUIRE_EQUAL(m_responses.size(), 3);
+    BOOST_CHECK_NO_THROW(payload = m_responses.back().getContent().blockFromValue());
+    BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
+    BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
+    BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_UP);
+    BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
+    BOOST_CHECK_EQUAL(notification.getRemoteUri(), face->getRemoteUri().toString());
+    BOOST_CHECK_EQUAL(notification.getLocalUri(), face->getLocalUri().toString());
+    BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
+    BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+    BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
+    BOOST_CHECK_EQUAL(notification.getFlags(), 0x0);
+  }
+}
+
+BOOST_AUTO_TEST_CASE(FaceEventDestroyed)
+{
+  auto face = addFace();
+  BOOST_CHECK_NE(face->getId(), face::INVALID_FACEID);
+  FaceId faceId = face->getId();
+
+  BOOST_CHECK_EQUAL(m_manager.m_faceStateChangeConn.count(faceId), 1);
+
+  face->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
+  advanceClocks(time::milliseconds(1), 10);
+
+  // check notification
+  Block payload;
+  ndn::nfd::FaceEventNotification notification;
+  BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
+  BOOST_CHECK_NO_THROW(payload = m_responses.back().getContent().blockFromValue());
+  BOOST_CHECK_EQUAL(payload.type(), ndn::tlv::nfd::FaceEventNotification);
+  BOOST_CHECK_NO_THROW(notification.wireDecode(payload));
+  BOOST_CHECK_EQUAL(notification.getKind(), ndn::nfd::FACE_EVENT_DESTROYED);
+  BOOST_CHECK_EQUAL(notification.getFaceId(), faceId);
+  BOOST_CHECK_EQUAL(notification.getRemoteUri(), face->getRemoteUri().toString());
+  BOOST_CHECK_EQUAL(notification.getLocalUri(), face->getLocalUri().toString());
+  BOOST_CHECK_EQUAL(notification.getFaceScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
+  BOOST_CHECK_EQUAL(notification.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(notification.getLinkType(), ndn::nfd::LinkType::LINK_TYPE_POINT_TO_POINT);
+  BOOST_CHECK_EQUAL(notification.getFlags(), 0x0);
+
+  BOOST_CHECK_EQUAL(face->getId(), face::INVALID_FACEID);
+  BOOST_CHECK_EQUAL(m_manager.m_faceStateChangeConn.count(faceId), 0);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // Notifications