mgmt: report face MTU in faces/list and faces/query datasets

This commit also contains an overall cleanup of FaceManager
and extends the FaceDataset test case.

Change-Id: I8c8290b0dc04b25582e66a5c6dad3cca4dd226eb
Refs: #4763, #3325
diff --git a/daemon/mgmt/face-manager.cpp b/daemon/mgmt/face-manager.cpp
index b1e934f..2299927 100644
--- a/daemon/mgmt/face-manager.cpp
+++ b/daemon/mgmt/face-manager.cpp
@@ -30,10 +30,11 @@
 #include "face/protocol-factory.hpp"
 #include "fw/face-table.hpp"
 
-#include <boost/logic/tribool.hpp>
-
 #include <ndn-cxx/lp/tags.hpp>
 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
+#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
+#include <ndn-cxx/mgmt/nfd/face-query-filter.hpp>
+#include <ndn-cxx/mgmt/nfd/face-status.hpp>
 
 namespace nfd {
 
@@ -47,19 +48,14 @@
   , m_faceTable(faceSystem.getFaceTable())
 {
   // register handlers for ControlCommand
-  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create",
-    bind(&FaceManager::createFace, this, _2, _3, _4, _5));
-
-  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update",
-    bind(&FaceManager::updateFace, this, _2, _3, _4, _5));
-
-  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy",
-    bind(&FaceManager::destroyFace, this, _2, _3, _4, _5));
+  registerCommandHandler<ndn::nfd::FaceCreateCommand>("create", bind(&FaceManager::createFace, this, _4, _5));
+  registerCommandHandler<ndn::nfd::FaceUpdateCommand>("update", bind(&FaceManager::updateFace, this, _3, _4, _5));
+  registerCommandHandler<ndn::nfd::FaceDestroyCommand>("destroy", bind(&FaceManager::destroyFace, this, _4, _5));
 
   // register handlers for StatusDataset
-  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _1, _2, _3));
-  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _1, _2, _3));
-  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _1, _2, _3));
+  registerStatusDatasetHandler("list", bind(&FaceManager::listFaces, this, _3));
+  registerStatusDatasetHandler("channels", bind(&FaceManager::listChannels, this, _3));
+  registerStatusDatasetHandler("query", bind(&FaceManager::queryFaces, this, _2, _3));
 
   // register notification stream
   m_postNotification = registerNotificationStream("events");
@@ -73,8 +69,7 @@
 }
 
 void
-FaceManager::createFace(const Name& topPrefix, const Interest& interest,
-                        const ControlParameters& parameters,
+FaceManager::createFace(const ControlParameters& parameters,
                         const ndn::mgmt::CommandContinuation& done)
 {
   FaceUri remoteUri;
@@ -134,8 +129,13 @@
   }
   try {
     factory->createFace({remoteUri, localUri, faceParams},
-                        bind(&FaceManager::afterCreateFaceSuccess, this, parameters, _1, done),
-                        bind(&FaceManager::afterCreateFaceFailure, this, _1, _2, done));
+                        [this, parameters, done] (const auto& face) {
+                          this->afterCreateFaceSuccess(face, parameters, done);
+                        },
+                        [done] (uint32_t status, const std::string& reason) {
+                          NFD_LOG_DEBUG("Face creation failed: " << reason);
+                          done(ControlResponse(status, reason));
+                        });
   }
   catch (const std::runtime_error& error) {
     NFD_LOG_ERROR("Face creation failed: " << error.what());
@@ -149,15 +149,61 @@
   }
 }
 
+template<typename T>
+static void
+copyMtu(const Face& face, T& to)
+{
+  auto transport = face.getTransport();
+  BOOST_ASSERT(transport != nullptr);
+
+  if (transport->getMtu() > 0) {
+    to.setMtu(std::min(static_cast<size_t>(transport->getMtu()), ndn::MAX_NDN_PACKET_SIZE));
+  }
+  else if (transport->getMtu() == face::MTU_UNLIMITED) {
+    to.setMtu(ndn::MAX_NDN_PACKET_SIZE);
+  }
+}
+
+static ControlParameters
+makeUpdateFaceResponse(const Face& face)
+{
+  ControlParameters params;
+  params.setFaceId(face.getId())
+        .setFacePersistency(face.getPersistency());
+
+  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+  if (linkService != nullptr) {
+    const auto& options = linkService->getOptions();
+    params.setBaseCongestionMarkingInterval(options.baseCongestionMarkingInterval)
+          .setDefaultCongestionThreshold(options.defaultCongestionThreshold)
+          .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false)
+          .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled, false)
+          .setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, options.allowCongestionMarking, false);
+  }
+
+  return params;
+}
+
+static ControlParameters
+makeCreateFaceResponse(const Face& face)
+{
+  ControlParameters params = makeUpdateFaceResponse(face);
+  params.setUri(face.getRemoteUri().toString())
+        .setLocalUri(face.getLocalUri().toString());
+
+  copyMtu(face, params);
+
+  return params;
+}
+
 void
-FaceManager::afterCreateFaceSuccess(const ControlParameters& parameters,
-                                    const shared_ptr<Face>& face,
+FaceManager::afterCreateFaceSuccess(const shared_ptr<Face>& face,
+                                    const ControlParameters& parameters,
                                     const ndn::mgmt::CommandContinuation& done)
 {
-  if (face->getId() != face::INVALID_FACEID) {// Face already exists
+  if (face->getId() != face::INVALID_FACEID) { // Face already exists
     NFD_LOG_TRACE("Attempted to create duplicate face of " << face->getId());
-
-    ControlParameters response = collectFaceProperties(*face, true);
+    ControlParameters response = makeCreateFaceResponse(*face);
     done(ControlResponse(409, "Face with remote URI already exists").setBody(response.wireEncode()));
     return;
   }
@@ -171,29 +217,47 @@
 
   m_faceTable.add(face);
 
-  ControlParameters response = collectFaceProperties(*face, true);
+  ControlParameters response = makeCreateFaceResponse(*face);
   done(ControlResponse(200, "OK").setBody(response.wireEncode()));
 }
 
-void
-FaceManager::afterCreateFaceFailure(uint32_t status,
-                                    const std::string& reason,
-                                    const ndn::mgmt::CommandContinuation& done)
+static void
+updateLinkServiceOptions(Face& face, const ControlParameters& parameters)
 {
-  NFD_LOG_DEBUG("Face creation failed: " << reason);
+  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+  if (linkService == nullptr) {
+    return;
+  }
+  auto options = linkService->getOptions();
 
-  done(ControlResponse(status, reason));
+  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
+      face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
+    options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
+  }
+  if (parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
+    options.reliabilityOptions.isEnabled = parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
+  }
+  if (parameters.hasFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
+    options.allowCongestionMarking = parameters.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED);
+  }
+  if (parameters.hasBaseCongestionMarkingInterval()) {
+    options.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
+  }
+  if (parameters.hasDefaultCongestionThreshold()) {
+    options.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
+  }
+
+  linkService->setOptions(options);
 }
 
 void
-FaceManager::updateFace(const Name& topPrefix, const Interest& interest,
+FaceManager::updateFace(const Interest& interest,
                         const ControlParameters& parameters,
                         const ndn::mgmt::CommandContinuation& done)
 {
   FaceId faceId = parameters.getFaceId();
-  if (faceId == 0) {
-    // Self-updating
-    shared_ptr<lp::IncomingFaceIdTag> incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
+  if (faceId == 0) { // Self-update
+    auto incomingFaceIdTag = interest.getTag<lp::IncomingFaceIdTag>();
     if (incomingFaceIdTag == nullptr) {
       NFD_LOG_TRACE("unable to determine face for self-update");
       done(ControlResponse(404, "No FaceId specified and IncomingFaceId not available"));
@@ -203,7 +267,6 @@
   }
 
   Face* face = m_faceTable.get(faceId);
-
   if (face == nullptr) {
     NFD_LOG_TRACE("invalid face specified");
     done(ControlResponse(404, "Specified face does not exist"));
@@ -242,18 +305,15 @@
   if (parameters.hasFacePersistency()) {
     face->setPersistency(parameters.getFacePersistency());
   }
-  setLinkServiceOptions(*face, parameters);
+  updateLinkServiceOptions(*face, parameters);
 
-  // Set ControlResponse fields
-  response = collectFaceProperties(*face, false);
-  response.unsetMtu(); // This parameter is only included with the response to faces/create and FaceStatus
-
+  // Prepare and send ControlResponse
+  response = makeUpdateFaceResponse(*face);
   done(ControlResponse(200, "OK").setBody(response.wireEncode()));
 }
 
 void
-FaceManager::destroyFace(const Name& topPrefix, const Interest& interest,
-                         const ControlParameters& parameters,
+FaceManager::destroyFace(const ControlParameters& parameters,
                          const ndn::mgmt::CommandContinuation& done)
 {
   Face* face = m_faceTable.get(parameters.getFaceId());
@@ -264,83 +324,75 @@
   done(ControlResponse(200, "OK").setBody(parameters.wireEncode()));
 }
 
-void
-FaceManager::setLinkServiceOptions(Face& face,
-                                   const ControlParameters& parameters)
+template<typename T>
+static void
+copyFaceProperties(const Face& face, T& to)
 {
-  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
-  BOOST_ASSERT(linkService != nullptr);
+  to.setFaceId(face.getId())
+    .setRemoteUri(face.getRemoteUri().toString())
+    .setLocalUri(face.getLocalUri().toString())
+    .setFaceScope(face.getScope())
+    .setFacePersistency(face.getPersistency())
+    .setLinkType(face.getLinkType());
 
-  auto options = linkService->getOptions();
-  if (parameters.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED) &&
-      face.getScope() == ndn::nfd::FACE_SCOPE_LOCAL) {
-    options.allowLocalFields = parameters.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
+  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
+  if (linkService != nullptr) {
+    const auto& options = linkService->getOptions();
+    to.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields)
+      .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled)
+      .setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, options.allowCongestionMarking);
   }
-  if (parameters.hasFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED)) {
-    options.reliabilityOptions.isEnabled = parameters.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED);
-  }
-  if (parameters.hasFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED)) {
-    options.allowCongestionMarking = parameters.getFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED);
-  }
-  if (parameters.hasBaseCongestionMarkingInterval()) {
-    options.baseCongestionMarkingInterval = parameters.getBaseCongestionMarkingInterval();
-  }
-  if (parameters.hasDefaultCongestionThreshold()) {
-    options.defaultCongestionThreshold = parameters.getDefaultCongestionThreshold();
-  }
-  linkService->setOptions(options);
 }
 
-ControlParameters
-FaceManager::collectFaceProperties(const Face& face, bool wantUris)
+static ndn::nfd::FaceStatus
+makeFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
 {
+  ndn::nfd::FaceStatus status;
+  copyFaceProperties(face, status);
+
+  auto expirationTime = face.getExpirationTime();
+  if (expirationTime != time::steady_clock::TimePoint::max()) {
+    status.setExpirationPeriod(std::max(0_ms,
+                                        time::duration_cast<time::milliseconds>(expirationTime - now)));
+  }
+
   auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
-  BOOST_ASSERT(linkService != nullptr);
-  auto options = linkService->getOptions();
-
-  auto transport = face.getTransport();
-  BOOST_ASSERT(transport != nullptr);
-
-  ControlParameters params;
-  params.setFaceId(face.getId())
-        .setFacePersistency(face.getPersistency())
-        .setBaseCongestionMarkingInterval(options.baseCongestionMarkingInterval)
-        .setDefaultCongestionThreshold(options.defaultCongestionThreshold)
-        .setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, options.allowLocalFields, false)
-        .setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, options.reliabilityOptions.isEnabled, false)
-        .setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED, options.allowCongestionMarking, false);
-
-  if (transport->getMtu() > 0) {
-    params.setMtu(std::min<uint64_t>(transport->getMtu(), ndn::MAX_NDN_PACKET_SIZE));
-  }
-  else if (transport->getMtu() == face::MTU_UNLIMITED) {
-    params.setMtu(ndn::MAX_NDN_PACKET_SIZE);
+  if (linkService != nullptr) {
+    const auto& options = linkService->getOptions();
+    status.setBaseCongestionMarkingInterval(options.baseCongestionMarkingInterval)
+          .setDefaultCongestionThreshold(options.defaultCongestionThreshold);
   }
 
-  if (wantUris) {
-    params.setUri(face.getRemoteUri().toString())
-          .setLocalUri(face.getLocalUri().toString());
-  }
-  return params;
+  copyMtu(face, status);
+
+  const auto& counters = face.getCounters();
+  status.setNInInterests(counters.nInInterests)
+        .setNOutInterests(counters.nOutInterests)
+        .setNInData(counters.nInData)
+        .setNOutData(counters.nOutData)
+        .setNInNacks(counters.nInNacks)
+        .setNOutNacks(counters.nOutNacks)
+        .setNInBytes(counters.nInBytes)
+        .setNOutBytes(counters.nOutBytes);
+
+  return status;
 }
 
 void
-FaceManager::listFaces(const Name& topPrefix, const Interest& interest,
-                       ndn::mgmt::StatusDatasetContext& context)
+FaceManager::listFaces(ndn::mgmt::StatusDatasetContext& context)
 {
   auto now = time::steady_clock::now();
-  for (const Face& face : m_faceTable) {
-    ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
+  for (const auto& face : m_faceTable) {
+    ndn::nfd::FaceStatus status = makeFaceStatus(face, now);
     context.append(status.wireEncode());
   }
   context.end();
 }
 
 void
-FaceManager::listChannels(const Name& topPrefix, const Interest& interest,
-                          ndn::mgmt::StatusDatasetContext& context)
+FaceManager::listChannels(ndn::mgmt::StatusDatasetContext& context)
 {
-  std::set<const face::ProtocolFactory*> factories = m_faceSystem.listProtocolFactories();
+  auto factories = m_faceSystem.listProtocolFactories();
   for (const auto* factory : factories) {
     for (const auto& channel : factory->getChannels()) {
       ndn::nfd::ChannelStatus entry;
@@ -351,34 +403,8 @@
   context.end();
 }
 
-void
-FaceManager::queryFaces(const Name& topPrefix, const Interest& interest,
-                        ndn::mgmt::StatusDatasetContext& context)
-{
-  ndn::nfd::FaceQueryFilter faceFilter;
-  const Name& query = interest.getName();
-  try {
-    faceFilter.wireDecode(query[-1].blockFromValue());
-  }
-  catch (const tlv::Error& e) {
-    NFD_LOG_DEBUG("Malformed query filter: " << e.what());
-    return context.reject(ControlResponse(400, "Malformed filter"));
-  }
-
-  auto now = time::steady_clock::now();
-  for (const Face& face : m_faceTable) {
-    if (!matchFilter(faceFilter, face)) {
-      continue;
-    }
-    ndn::nfd::FaceStatus status = collectFaceStatus(face, now);
-    context.append(status.wireEncode());
-  }
-
-  context.end();
-}
-
-bool
-FaceManager::matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
+static bool
+matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face)
 {
   if (filter.hasFaceId() &&
       filter.getFaceId() != static_cast<uint64_t>(face.getId())) {
@@ -419,61 +445,27 @@
   return true;
 }
 
-ndn::nfd::FaceStatus
-FaceManager::collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now)
-{
-  ndn::nfd::FaceStatus status;
-
-  collectFaceProperties(face, status);
-
-  time::steady_clock::TimePoint expirationTime = face.getExpirationTime();
-  if (expirationTime != time::steady_clock::TimePoint::max()) {
-    status.setExpirationPeriod(std::max(0_ms,
-                                        time::duration_cast<time::milliseconds>(expirationTime - now)));
-  }
-
-  // Get LinkService options
-  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
-  if (linkService != nullptr) {
-    auto linkServiceOptions = linkService->getOptions();
-    status.setBaseCongestionMarkingInterval(linkServiceOptions.baseCongestionMarkingInterval);
-    status.setDefaultCongestionThreshold(linkServiceOptions.defaultCongestionThreshold);
-  }
-
-  const face::FaceCounters& counters = face.getCounters();
-  status.setNInInterests(counters.nInInterests)
-        .setNOutInterests(counters.nOutInterests)
-        .setNInData(counters.nInData)
-        .setNOutData(counters.nOutData)
-        .setNInNacks(counters.nInNacks)
-        .setNOutNacks(counters.nOutNacks)
-        .setNInBytes(counters.nInBytes)
-        .setNOutBytes(counters.nOutBytes);
-
-  return status;
-}
-
-template<typename FaceTraits>
 void
-FaceManager::collectFaceProperties(const Face& face, FaceTraits& traits)
+FaceManager::queryFaces(const Interest& interest,
+                        ndn::mgmt::StatusDatasetContext& context)
 {
-  traits.setFaceId(face.getId())
-        .setRemoteUri(face.getRemoteUri().toString())
-        .setLocalUri(face.getLocalUri().toString())
-        .setFaceScope(face.getScope())
-        .setFacePersistency(face.getPersistency())
-        .setLinkType(face.getLinkType());
-
-  // Set Flag bits
-  auto linkService = dynamic_cast<face::GenericLinkService*>(face.getLinkService());
-  if (linkService != nullptr) {
-    auto linkServiceOptions = linkService->getOptions();
-    traits.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, linkServiceOptions.allowLocalFields);
-    traits.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED,
-                      linkServiceOptions.reliabilityOptions.isEnabled);
-    traits.setFlagBit(ndn::nfd::BIT_CONGESTION_MARKING_ENABLED,
-                      linkServiceOptions.allowCongestionMarking);
+  ndn::nfd::FaceQueryFilter faceFilter;
+  try {
+    faceFilter.wireDecode(interest.getName()[-1].blockFromValue());
   }
+  catch (const tlv::Error& e) {
+    NFD_LOG_DEBUG("Malformed query filter: " << e.what());
+    return context.reject(ControlResponse(400, "Malformed filter"));
+  }
+
+  auto now = time::steady_clock::now();
+  for (const auto& face : m_faceTable) {
+    if (matchFilter(faceFilter, face)) {
+      ndn::nfd::FaceStatus status = makeFaceStatus(face, now);
+      context.append(status.wireEncode());
+    }
+  }
+  context.end();
 }
 
 void
@@ -481,7 +473,7 @@
 {
   ndn::nfd::FaceEventNotification notification;
   notification.setKind(kind);
-  collectFaceProperties(face, notification);
+  copyFaceProperties(face, notification);
 
   m_postNotification(notification.wireEncode());
 }
diff --git a/daemon/mgmt/face-manager.hpp b/daemon/mgmt/face-manager.hpp
index ee5115a..778e824 100644
--- a/daemon/mgmt/face-manager.hpp
+++ b/daemon/mgmt/face-manager.hpp
@@ -29,10 +29,6 @@
 #include "nfd-manager-base.hpp"
 #include "face/face-system.hpp"
 
-#include <ndn-cxx/mgmt/nfd/face-status.hpp>
-#include <ndn-cxx/mgmt/nfd/face-query-filter.hpp>
-#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
-
 namespace nfd {
 
 /**
@@ -46,67 +42,35 @@
               Dispatcher& dispatcher,
               CommandAuthenticator& authenticator);
 
-PUBLIC_WITH_TESTS_ELSE_PRIVATE: // ControlCommand
+private: // ControlCommand
   void
-  createFace(const Name& topPrefix, const Interest& interest,
+  createFace(const ControlParameters& parameters,
+             const ndn::mgmt::CommandContinuation& done);
+
+  void
+  updateFace(const Interest& interest,
              const ControlParameters& parameters,
              const ndn::mgmt::CommandContinuation& done);
 
   void
-  updateFace(const Name& topPrefix, const Interest& interest,
-             const ControlParameters& parameters,
-             const ndn::mgmt::CommandContinuation& done);
-
-  void
-  destroyFace(const Name& topPrefix, const Interest& interest,
-              const ControlParameters& parameters,
+  destroyFace(const ControlParameters& parameters,
               const ndn::mgmt::CommandContinuation& done);
 
-PUBLIC_WITH_TESTS_ELSE_PRIVATE: // helpers for ControlCommand
+private: // helpers for ControlCommand
   void
-  afterCreateFaceSuccess(const ControlParameters& parameters,
-                         const shared_ptr<Face>& newFace,
+  afterCreateFaceSuccess(const shared_ptr<Face>& face,
+                         const ControlParameters& parameters,
                          const ndn::mgmt::CommandContinuation& done);
 
+private: // StatusDataset
   void
-  afterCreateFaceFailure(uint32_t status,
-                         const std::string& reason,
-                         const ndn::mgmt::CommandContinuation& done);
-
-  static void
-  setLinkServiceOptions(Face& face, const ControlParameters& parameters);
-
-  static ControlParameters
-  collectFaceProperties(const Face& face, bool wantUris);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE: // StatusDataset
-  void
-  listFaces(const Name& topPrefix, const Interest& interest,
-            ndn::mgmt::StatusDatasetContext& context);
+  listFaces(ndn::mgmt::StatusDatasetContext& context);
 
   void
-  listChannels(const Name& topPrefix, const Interest& interest,
-               ndn::mgmt::StatusDatasetContext& context);
+  listChannels(ndn::mgmt::StatusDatasetContext& context);
 
   void
-  queryFaces(const Name& topPrefix, const Interest& interest,
-             ndn::mgmt::StatusDatasetContext& context);
-
-private: // helpers for StatusDataset handler
-  static bool
-  matchFilter(const ndn::nfd::FaceQueryFilter& filter, const Face& face);
-
-  /** \brief get status of face, including properties and counters
-   */
-  static ndn::nfd::FaceStatus
-  collectFaceStatus(const Face& face, const time::steady_clock::TimePoint& now);
-
-  /** \brief copy face properties into traits
-   *  \tparam FaceTraits either FaceStatus or FaceEventNotification
-   */
-  template<typename FaceTraits>
-  static void
-  collectFaceProperties(const Face& face, FaceTraits& traits);
+  queryFaces(const Interest& interest, ndn::mgmt::StatusDatasetContext& context);
 
 private: // NotificationStream
   void
diff --git a/tests/daemon/mgmt/cs-manager.t.cpp b/tests/daemon/mgmt/cs-manager.t.cpp
index 18e2cdc..1a485725 100644
--- a/tests/daemon/mgmt/cs-manager.t.cpp
+++ b/tests/daemon/mgmt/cs-manager.t.cpp
@@ -24,7 +24,9 @@
  */
 
 #include "mgmt/cs-manager.hpp"
+
 #include "nfd-manager-common-fixture.hpp"
+
 #include <ndn-cxx/mgmt/nfd/cs-info.hpp>
 
 namespace nfd {
@@ -199,7 +201,7 @@
 BOOST_AUTO_TEST_CASE(Info)
 {
   m_cs.setLimit(2681);
-  for (int i = 0; i < 310; ++i) {
+  for (uint64_t i = 0; i < 310; ++i) {
     m_cs.insert(*makeData(Name("/Q8H4oi4g").appendSequenceNumber(i)));
   }
   m_cs.enableAdmit(false);
@@ -207,7 +209,7 @@
   m_fwCnt.nCsHits.set(362);
   m_fwCnt.nCsMisses.set(1493);
 
-  receiveInterest(Interest("/localhost/nfd/cs/info"));
+  receiveInterest(Interest("/localhost/nfd/cs/info").setCanBePrefix(true));
   Block dataset = concatenateResponses();
   dataset.parse();
   BOOST_REQUIRE_EQUAL(dataset.elements_size(), 1);
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index d1266dd..a08c2dc 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -34,6 +34,9 @@
 #include <ndn-cxx/encoding/tlv.hpp>
 #include <ndn-cxx/encoding/tlv-nfd.hpp>
 #include <ndn-cxx/mgmt/nfd/channel-status.hpp>
+#include <ndn-cxx/mgmt/nfd/face-event-notification.hpp>
+#include <ndn-cxx/mgmt/nfd/face-query-filter.hpp>
+#include <ndn-cxx/mgmt/nfd/face-status.hpp>
 #include <ndn-cxx/net/network-monitor-stub.hpp>
 
 namespace nfd {
@@ -68,18 +71,18 @@
     std::string uri = "dummy://";
     ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL;
 
-    if ((flags & SET_SCOPE_LOCAL) != 0) {
+    if (flags & SET_SCOPE_LOCAL) {
       scope = ndn::nfd::FACE_SCOPE_LOCAL;
     }
-    if ((flags & SET_URI_TEST) != 0) {
+    if (flags & SET_URI_TEST) {
       uri = "test://";
     }
 
     auto face = make_shared<DummyFace>(uri, uri, scope);
     m_faceTable.add(face);
 
-    if ((flags & RANDOMIZE_COUNTERS) != 0) {
-      const face::FaceCounters& counters = face->getCounters();
+    if (flags & RANDOMIZE_COUNTERS) {
+      const auto& counters = face->getCounters();
       randomizeCounter(counters.nInInterests);
       randomizeCounter(counters.nOutInterests);
       randomizeCounter(counters.nInData);
@@ -92,8 +95,8 @@
       randomizeCounter(counters.nOutBytes);
     }
 
-    advanceClocks(time::milliseconds(1), 10); // wait for notification posted
-    if ((flags & REMOVE_LAST_NOTIFICATION) != 0) {
+    advanceClocks(1_ms, 10); // wait for notification posted
+    if (flags & REMOVE_LAST_NOTIFICATION) {
       m_responses.pop_back();
     }
 
@@ -154,12 +157,12 @@
 
 BOOST_AUTO_TEST_CASE(FaceDataset)
 {
-  const size_t nEntries = 303;
+  const size_t nEntries = 32;
   for (size_t i = 0; i < nEntries; ++i) {
     addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST | RANDOMIZE_COUNTERS);
   }
 
-  receiveInterest(Interest("/localhost/nfd/faces/list"));
+  receiveInterest(Interest("/localhost/nfd/faces/list").setCanBePrefix(true));
 
   Block content = concatenateResponses();
   content.parse();
@@ -171,9 +174,39 @@
     BOOST_CHECK(m_faceTable.get(decodedStatus.getFaceId()) != nullptr);
     faceIds.insert(decodedStatus.getFaceId());
   }
-
   BOOST_CHECK_EQUAL(faceIds.size(), nEntries);
-  // TODO#3325 check dataset contents including counter values
+
+  ndn::nfd::FaceStatus status(content.elements().front());
+  const Face* face = m_faceTable.get(status.getFaceId());
+  BOOST_REQUIRE(face != nullptr);
+
+  // check face properties
+  BOOST_CHECK_EQUAL(status.getRemoteUri(), face->getRemoteUri().toString());
+  BOOST_CHECK_EQUAL(status.getLocalUri(), face->getLocalUri().toString());
+  BOOST_CHECK_EQUAL(status.hasExpirationPeriod(),
+                    face->getExpirationTime() != time::steady_clock::time_point::max());
+  BOOST_CHECK_EQUAL(status.getFaceScope(), face->getScope());
+  BOOST_CHECK_EQUAL(status.getFacePersistency(), face->getPersistency());
+  BOOST_CHECK_EQUAL(status.getLinkType(), face->getLinkType());
+
+  // check link service properties
+  BOOST_CHECK_EQUAL(status.hasBaseCongestionMarkingInterval(), false);
+  BOOST_CHECK_EQUAL(status.hasDefaultCongestionThreshold(), false);
+  BOOST_CHECK_EQUAL(status.getFlags(), 0);
+
+  // check transport properties
+  BOOST_CHECK_EQUAL(status.hasMtu(), true);
+  BOOST_CHECK_EQUAL(status.getMtu(), ndn::MAX_NDN_PACKET_SIZE);
+
+  // check counters
+  BOOST_CHECK_EQUAL(status.getNInInterests(), face->getCounters().nInInterests);
+  BOOST_CHECK_EQUAL(status.getNInData(), face->getCounters().nInData);
+  BOOST_CHECK_EQUAL(status.getNInNacks(), face->getCounters().nInNacks);
+  BOOST_CHECK_EQUAL(status.getNOutInterests(), face->getCounters().nOutInterests);
+  BOOST_CHECK_EQUAL(status.getNOutData(), face->getCounters().nOutData);
+  BOOST_CHECK_EQUAL(status.getNOutNacks(), face->getCounters().nOutNacks);
+  BOOST_CHECK_EQUAL(status.getNInBytes(), face->getCounters().nInBytes);
+  BOOST_CHECK_EQUAL(status.getNOutBytes(), face->getCounters().nOutBytes);
 }
 
 BOOST_AUTO_TEST_CASE(FaceQuery)
@@ -184,20 +217,22 @@
   auto face2 = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // dummy://, local
   auto face3 = addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST); // test://
 
-  auto generateQueryName = [] (const FaceQueryFilter& filter) {
-    return Name("/localhost/nfd/faces/query").append(filter.wireEncode());
+  auto generateQuery = [] (const FaceQueryFilter& filter) {
+    return Interest(Name("/localhost/nfd/faces/query").append(filter.wireEncode()))
+           .setCanBePrefix(true);
   };
 
-  auto querySchemeName = generateQueryName(FaceQueryFilter().setUriScheme("dummy"));
-  auto queryIdName = generateQueryName(FaceQueryFilter().setFaceId(face1->getId()));
-  auto queryScopeName = generateQueryName(FaceQueryFilter().setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL));
+  auto schemeQuery = generateQuery(FaceQueryFilter().setUriScheme("dummy"));
+  auto idQuery = generateQuery(FaceQueryFilter().setFaceId(face1->getId()));
+  auto scopeQuery = generateQuery(FaceQueryFilter().setFaceScope(ndn::nfd::FACE_SCOPE_NON_LOCAL));
   auto invalidQueryName = Name("/localhost/nfd/faces/query")
                           .append(ndn::makeStringBlock(tlv::Content, "invalid"));
+  auto invalidQuery = Interest(invalidQueryName).setCanBePrefix(true);
 
-  receiveInterest(Interest(querySchemeName)); // face1 and face2 expected
-  receiveInterest(Interest(queryIdName)); // face1 expected
-  receiveInterest(Interest(queryScopeName)); // face1 and face3 expected
-  receiveInterest(Interest(invalidQueryName)); // nack expected
+  receiveInterest(schemeQuery); // face1 and face2 expected
+  receiveInterest(idQuery); // face1 expected
+  receiveInterest(scopeQuery); // face1 and face3 expected
+  receiveInterest(invalidQuery); // nack expected
 
   BOOST_REQUIRE_EQUAL(m_responses.size(), 4);
 
@@ -295,18 +330,17 @@
 
 BOOST_AUTO_TEST_CASE(ChannelDataset)
 {
-  m_faceSystem.m_factories["test"] =
-    make_unique<TestProtocolFactory>(m_faceSystem.makePFCtorParams());
+  m_faceSystem.m_factories["test"] = make_unique<TestProtocolFactory>(m_faceSystem.makePFCtorParams());
   auto factory = static_cast<TestProtocolFactory*>(m_faceSystem.getFactoryById("test"));
 
-  const size_t nEntries = 404;
+  const size_t nEntries = 42;
   std::map<std::string, shared_ptr<TestChannel>> addedChannels;
   for (size_t i = 0; i < nEntries; i++) {
     auto channel = factory->addChannel("test" + to_string(i) + "://");
     addedChannels[channel->getUri().toString()] = channel;
   }
 
-  receiveInterest(Interest("/localhost/nfd/faces/channels"));
+  receiveInterest(Interest("/localhost/nfd/faces/channels").setCanBePrefix(true));
 
   Block content = concatenateResponses();
   content.parse();
@@ -353,7 +387,7 @@
 
   // trigger FACE_EVENT_DOWN notification
   dynamic_cast<face::tests::DummyTransport*>(face->getTransport())->setState(face::FaceState::DOWN);
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(1_ms, 10);
   BOOST_CHECK_EQUAL(face->getState(), face::FaceState::DOWN);
 
   // check notification
@@ -374,7 +408,7 @@
 
   // trigger FACE_EVENT_UP notification
   dynamic_cast<face::tests::DummyTransport*>(face->getTransport())->setState(face::FaceState::UP);
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(1_ms, 10);
   BOOST_CHECK_EQUAL(face->getState(), face::FaceState::UP);
 
   // check notification
@@ -403,7 +437,7 @@
   BOOST_CHECK_EQUAL(m_manager.m_faceStateChangeConn.count(faceId), 1);
 
   face->close(); // trigger FaceDestroy FACE_EVENT_DESTROYED
-  advanceClocks(time::milliseconds(1), 10);
+  advanceClocks(1_ms, 10);
 
   // check notification
   BOOST_REQUIRE_EQUAL(m_responses.size(), 2);
diff --git a/tests/daemon/mgmt/fib-manager.t.cpp b/tests/daemon/mgmt/fib-manager.t.cpp
index e2986bc..f0a91ff 100644
--- a/tests/daemon/mgmt/fib-manager.t.cpp
+++ b/tests/daemon/mgmt/fib-manager.t.cpp
@@ -414,7 +414,7 @@
     fibEntry->addNextHop(*m_faceTable.get(addFace()), std::numeric_limits<uint8_t>::max() - 2);
   }
 
-  receiveInterest(Interest("/localhost/nfd/fib/list"));
+  receiveInterest(Interest("/localhost/nfd/fib/list").setCanBePrefix(true));
 
   Block content = concatenateResponses();
   content.parse();
diff --git a/tests/daemon/mgmt/strategy-choice-manager.t.cpp b/tests/daemon/mgmt/strategy-choice-manager.t.cpp
index b4718a9..817966e 100644
--- a/tests/daemon/mgmt/strategy-choice-manager.t.cpp
+++ b/tests/daemon/mgmt/strategy-choice-manager.t.cpp
@@ -28,6 +28,7 @@
 
 #include "nfd-manager-common-fixture.hpp"
 #include "../fw/dummy-strategy.hpp"
+
 #include <ndn-cxx/mgmt/nfd/strategy-choice.hpp>
 
 namespace nfd {
@@ -204,7 +205,7 @@
     expected[entry.getPrefix()] = entry.getStrategyInstanceName();
   }
 
-  for (int i = expected.size(); i < 1024; ++i) {
+  for (size_t i = expected.size(); i < 1024; ++i) {
     Name name("/SC");
     name.appendNumber(i);
     Name strategy = DummyStrategy::getStrategyName(i);
@@ -214,7 +215,8 @@
     expected[name] = strategy;
   }
 
-  receiveInterest(Interest("/localhost/nfd/strategy-choice/list"));
+  receiveInterest(Interest("/localhost/nfd/strategy-choice/list").setCanBePrefix(true));
+
   Block dataset = concatenateResponses();
   dataset.parse();
   BOOST_CHECK_EQUAL(dataset.elements_size(), expected.size());