face: face refactoring completion

* delete old Face
* rename LpFace as Face
* eliminate LpFaceWrapper and use new Face

refs #3172

Change-Id: I08c3a5dfb4cc1b9834b30cccd9ab634535d0608c
diff --git a/tests/daemon/face/dummy-lp-face.cpp b/tests/daemon/face/dummy-face.cpp
similarity index 77%
rename from tests/daemon/face/dummy-lp-face.cpp
rename to tests/daemon/face/dummy-face.cpp
index 20fb20d..c4f6154 100644
--- a/tests/daemon/face/dummy-lp-face.cpp
+++ b/tests/daemon/face/dummy-face.cpp
@@ -23,14 +23,14 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "dummy-lp-face.hpp"
+#include "dummy-face.hpp"
 #include "dummy-transport.hpp"
 
 namespace nfd {
 namespace face {
 namespace tests {
 
-class DummyLpFace::LinkService : public face::LinkService
+class DummyFace::LinkService : public face::LinkService
 {
 public:
   void
@@ -51,28 +51,28 @@
     this->face::LinkService::receiveNack(nack);
   }
 
-  signal::Signal<LinkService> afterSend;
+  signal::Signal<LinkService, uint32_t> afterSend;
 
 private:
   virtual void
   doSendInterest(const Interest& interest) DECL_OVERRIDE
   {
     this->sentInterests.push_back(interest);
-    this->afterSend();
+    this->afterSend(tlv::Interest);
   }
 
   virtual void
   doSendData(const Data& data) DECL_OVERRIDE
   {
     this->sentData.push_back(data);
-    this->afterSend();
+    this->afterSend(tlv::Data);
   }
 
   virtual void
   doSendNack(const lp::Nack& nack) DECL_OVERRIDE
   {
     this->sentNacks.push_back(nack);
-    this->afterSend();
+    this->afterSend(lp::tlv::Nack);
   }
 
   virtual void
@@ -87,11 +87,11 @@
   std::vector<lp::Nack> sentNacks;
 };
 
-DummyLpFace::DummyLpFace(const std::string& localUri, const std::string& remoteUri,
-                         ndn::nfd::FaceScope scope, ndn::nfd::FacePersistency persistency,
-                         ndn::nfd::LinkType linkType)
-  : LpFace(make_unique<LinkService>(),
-           make_unique<DummyTransport>(localUri, remoteUri, scope, persistency, linkType))
+DummyFace::DummyFace(const std::string& localUri, const std::string& remoteUri,
+                     ndn::nfd::FaceScope scope, ndn::nfd::FacePersistency persistency,
+                     ndn::nfd::LinkType linkType)
+  : Face(make_unique<LinkService>(),
+         make_unique<DummyTransport>(localUri, remoteUri, scope, persistency, linkType))
   , afterSend(this->getLinkServiceInternal()->afterSend)
   , sentInterests(this->getLinkServiceInternal()->sentInterests)
   , sentData(this->getLinkServiceInternal()->sentData)
@@ -100,37 +100,37 @@
 }
 
 void
-DummyLpFace::setState(FaceState state)
+DummyFace::setState(FaceState state)
 {
   this->getTransportInternal()->setState(state);
 }
 
 void
-DummyLpFace::receiveInterest(const Interest& interest)
+DummyFace::receiveInterest(const Interest& interest)
 {
   this->getLinkServiceInternal()->receiveInterest(interest);
 }
 
 void
-DummyLpFace::receiveData(const Data& data)
+DummyFace::receiveData(const Data& data)
 {
   this->getLinkServiceInternal()->receiveData(data);
 }
 
 void
-DummyLpFace::receiveNack(const lp::Nack& nack)
+DummyFace::receiveNack(const lp::Nack& nack)
 {
   this->getLinkServiceInternal()->receiveNack(nack);
 }
 
-DummyLpFace::LinkService*
-DummyLpFace::getLinkServiceInternal()
+DummyFace::LinkService*
+DummyFace::getLinkServiceInternal()
 {
   return static_cast<LinkService*>(this->getLinkService());
 }
 
 DummyTransport*
-DummyLpFace::getTransportInternal()
+DummyFace::getTransportInternal()
 {
   return static_cast<DummyTransport*>(this->getTransport());
 }
diff --git a/tests/daemon/face/dummy-face.hpp b/tests/daemon/face/dummy-face.hpp
index 6ed7d46..34f2d09 100644
--- a/tests/daemon/face/dummy-face.hpp
+++ b/tests/daemon/face/dummy-face.hpp
@@ -29,71 +29,78 @@
 #include "face/face.hpp"
 
 namespace nfd {
+namespace face {
 namespace tests {
 
+class DummyTransport;
+
 /** \brief a Face for unit testing
+ *
+ *  The DummyFace has no underlying transport, but allows observing outgoing packets
+ *  and injecting incoming packets at network layer.
+ *  It's primarily used for forwarding test suites, but can be used in other tests as well.
+ *
+ *  Outgoing network-layer packets sent through the DummyFace are recorded in sent* vectors,
+ *  which can be observed in test cases.
+ *  Incoming network-layer packets can be injected from test cases through receive* method.
  */
 class DummyFace : public Face
 {
 public:
-  explicit
-  DummyFace(const std::string& remoteUri = "dummy://", const std::string& localUri = "dummy://",
-            bool isLocal = false)
-    : Face(FaceUri(remoteUri), FaceUri(localUri), isLocal)
-  {
-  }
+  class LinkService;
 
+  DummyFace(const std::string& localUri = "dummy://", const std::string& remoteUri = "dummy://",
+            ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL,
+            ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+            ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
+
+  /** \brief changes face state
+   *  \pre current state is not CLOSED or FAILED
+   */
   void
-  sendInterest(const Interest& interest) DECL_OVERRIDE
-  {
-    this->emitSignal(onSendInterest, interest);
-    m_sentInterests.push_back(interest);
-    this->afterSend();
-  }
+  setState(FaceState state);
 
+  /** \brief causes the face to receive an Interest
+   */
   void
-  sendData(const Data& data) DECL_OVERRIDE
-  {
-    this->emitSignal(onSendData, data);
-    m_sentDatas.push_back(data);
-    this->afterSend();
-  }
+  receiveInterest(const Interest& interest);
 
+  /** \brief causes the face to receive a Data
+   */
   void
-  close() DECL_OVERRIDE
-  {
-    this->fail("close");
-  }
+  receiveData(const Data& data);
 
+  /** \brief causes the face to receive a Nack
+   */
   void
-  receiveInterest(const Interest& interest)
-  {
-    this->emitSignal(onReceiveInterest, interest);
-  }
+  receiveNack(const lp::Nack& nack);
 
-  void
-  receiveData(const Data& data)
-  {
-    this->emitSignal(onReceiveData, data);
-  }
+  /** \brief signals after any network-layer packet is sent
+   *
+   *  The network-layer packet type is indicated as an argument,
+   *  which is either of tlv::Interest, tlv::Data, or lp::tlv::Nack.
+   *  The callback may retrieve the packet from sentInterests.back(), sentData.back(), or sentNacks.back().
+   */
+  signal::Signal<LinkService, uint32_t>& afterSend;
 
-  signal::Signal<DummyFace> afterSend;
+private:
+  LinkService*
+  getLinkServiceInternal();
+
+  DummyTransport*
+  getTransportInternal();
 
 public:
-  std::vector<Interest> m_sentInterests;
-  std::vector<Data> m_sentDatas;
+  std::vector<Interest>& sentInterests;
+  std::vector<Data>& sentData;
+  std::vector<lp::Nack>& sentNacks;
 };
 
-class DummyLocalFace : public DummyFace
-{
-public:
-  explicit
-  DummyLocalFace(const std::string& remoteUri = "dummy://", const std::string& localUri = "dummy://")
-    : DummyFace(remoteUri, localUri, true)
-  {
-  }
-};
+} // namespace tests
+} // namespace face
 
+namespace tests {
+using nfd::face::tests::DummyFace;
 } // namespace tests
 } // namespace nfd
 
diff --git a/tests/daemon/face/dummy-lp-face.hpp b/tests/daemon/face/dummy-lp-face.hpp
deleted file mode 100644
index 588cb59..0000000
--- a/tests/daemon/face/dummy-lp-face.hpp
+++ /dev/null
@@ -1,99 +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/>.
- */
-
-#ifndef NFD_TESTS_DAEMON_FACE_DUMMY_LP_FACE_HPP
-#define NFD_TESTS_DAEMON_FACE_DUMMY_LP_FACE_HPP
-
-#include "face/lp-face.hpp"
-
-namespace nfd {
-namespace face {
-namespace tests {
-
-class DummyTransport;
-
-/** \brief a LpFace for unit testing
- *
- *  The DummyLpFace allows observing outgoing network-layer packets,
- *  and allows incoming network-layer packets to be injected from a test suite.
- *  It's primarily used for forwarding test suites, but can be used in other tests as well.
- */
-class DummyLpFace : public LpFace
-{
-public:
-  class LinkService;
-
-  DummyLpFace(const std::string& localUri = "dummy://", const std::string& remoteUri = "dummy://",
-              ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL,
-              ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-              ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_POINT_TO_POINT);
-
-  /** \brief changes face state
-   *  \pre current state is not CLOSED or FAILED
-   */
-  void
-  setState(FaceState state);
-
-  /** \brief causes the face to receive an Interest
-   */
-  void
-  receiveInterest(const Interest& interest);
-
-  /** \brief causes the face to receive a Data
-   */
-  void
-  receiveData(const Data& data);
-
-  /** \brief causes the face to receive a Nack
-   */
-  void
-  receiveNack(const lp::Nack& nack);
-
-  /** \brief signals after any network-layer packet is sent
-   */
-  signal::Signal<LinkService>& afterSend;
-
-private:
-  LinkService*
-  getLinkServiceInternal();
-
-  DummyTransport*
-  getTransportInternal();
-
-public:
-  std::vector<Interest>& sentInterests;
-  std::vector<Data>& sentData;
-  std::vector<lp::Nack>& sentNacks;
-};
-
-} // namespace tests
-} // namespace face
-
-namespace tests {
-using nfd::face::tests::DummyLpFace;
-} // namespace tests
-} // namespace nfd
-
-#endif // NFD_TESTS_DAEMON_FACE_DUMMY_LP_FACE_HPP
diff --git a/tests/daemon/face/dummy-stream-sender.hpp b/tests/daemon/face/dummy-stream-sender.hpp
deleted file mode 100644
index 7cbb4e2..0000000
--- a/tests/daemon/face/dummy-stream-sender.hpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  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/>.
- */
-
-#ifndef NFD_TESTS_DAEMON_FACE_DUMMY_STREAM_SENDER_HPP
-#define NFD_TESTS_DAEMON_FACE_DUMMY_STREAM_SENDER_HPP
-
-#include "core/scheduler.hpp"
-#include "core/global-io.hpp"
-
-namespace nfd {
-namespace tests {
-
-
-template<class Protocol, class Dataset>
-class DummyStreamSender : public Dataset
-{
-public:
-  typedef typename Protocol::endpoint Endpoint;
-  typedef typename Protocol::socket Socket;
-
-  class Error : public std::runtime_error
-  {
-  public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
-  };
-
-  DummyStreamSender()
-    : socket(getGlobalIoService())
-  {
-  }
-
-  void
-  start(const Endpoint& endpoint)
-  {
-    socket.async_connect(endpoint,
-                         bind(&DummyStreamSender::onSuccessfullConnect, this, _1));
-  }
-
-  void
-  onSuccessfullConnect(const boost::system::error_code& error)
-  {
-    if (error)
-      {
-        BOOST_THROW_EXCEPTION(Error("Connection aborted"));
-      }
-
-    // This value may need to be adjusted if some dataset exceeds 100k
-    socket.set_option(boost::asio::socket_base::send_buffer_size(100000));
-
-    for (typename Dataset::Container::iterator i = this->data.begin();
-         i != this->data.end(); ++i)
-      {
-        socket.async_send(boost::asio::buffer(*i),
-                          bind(&DummyStreamSender::onSendFinished, this, _1, false));
-      }
-
-    socket.async_send(boost::asio::buffer(static_cast<const uint8_t*>(0), 0),
-                      bind(&DummyStreamSender::onSendFinished, this, _1, true));
-  }
-
-  void
-  onSendFinished(const boost::system::error_code& error, bool isFinal)
-  {
-    if (error) {
-      BOOST_THROW_EXCEPTION(Error("Connection aborted"));
-    }
-
-    if (isFinal) {
-      scheduler::schedule(ndn::time::seconds(1),
-                          bind(&DummyStreamSender::stop, this));
-    }
-  }
-
-  void
-  stop()
-  {
-    // Terminate test
-    boost::system::error_code error;
-    socket.shutdown(Socket::shutdown_both, error);
-    socket.close(error);
-  }
-
-public:
-  Socket socket;
-};
-
-} // namespace tests
-} // namespace nfd
-
-#endif // NFD_TESTS_DAEMON_FACE_DUMMY_STREAM_SENDER_HPP
diff --git a/tests/daemon/face/dummy-transport.hpp b/tests/daemon/face/dummy-transport.hpp
index ce2833b..f957e1e 100644
--- a/tests/daemon/face/dummy-transport.hpp
+++ b/tests/daemon/face/dummy-transport.hpp
@@ -91,6 +91,7 @@
   doClose() DECL_OVERRIDE
   {
     isClosed = true;
+    this->setState(TransportState::CLOSED);
   }
 
   virtual void
diff --git a/tests/daemon/face/ethernet-factory.t.cpp b/tests/daemon/face/ethernet-factory.t.cpp
new file mode 100644
index 0000000..6148b3b
--- /dev/null
+++ b/tests/daemon/face/ethernet-factory.t.cpp
@@ -0,0 +1,91 @@
+/* -*- 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 "face/ethernet-factory.hpp"
+
+#include "network-interface-fixture.hpp"
+
+namespace nfd {
+namespace tests {
+
+using nfd::face::tests::NetworkInterfaceFixture;
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestEthernetFactory, NetworkInterfaceFixture)
+
+BOOST_AUTO_TEST_CASE(GetChannels)
+{
+  EthernetFactory factory;
+
+  auto channels = factory.getChannels();
+  BOOST_CHECK_EQUAL(channels.empty(), true);
+}
+
+BOOST_AUTO_TEST_CASE(MulticastFacesMap)
+{
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
+
+  EthernetFactory factory;
+  auto face1 = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
+  auto face1bis = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
+  BOOST_CHECK_EQUAL(face1, face1bis);
+
+  auto face2 = factory.createMulticastFace(m_interfaces.front(), ethernet::getDefaultMulticastAddress());
+  BOOST_CHECK_NE(face1, face2);
+
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(2);
+
+  auto face3 = factory.createMulticastFace(m_interfaces.back(), ethernet::getBroadcastAddress());
+  BOOST_CHECK_NE(face1, face3);
+}
+
+BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
+{
+  EthernetFactory factory;
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
+                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestEthernetFactory
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/ethernet-transport.t.cpp b/tests/daemon/face/ethernet-transport.t.cpp
index 1e02173..f7948a2 100644
--- a/tests/daemon/face/ethernet-transport.t.cpp
+++ b/tests/daemon/face/ethernet-transport.t.cpp
@@ -52,6 +52,10 @@
   BOOST_CHECK_EQUAL(transport.getLinkType(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
 }
 
+// TODO add the equivalent of these test cases from ethernet.t.cpp as of commit:65caf200924b28748037750449e28bcb548dbc9c
+// SendPacket
+// ProcessIncomingPacket
+
 BOOST_AUTO_TEST_SUITE_END() // TestEthernetTransport
 BOOST_AUTO_TEST_SUITE_END() // Face
 
diff --git a/tests/daemon/face/ethernet.t.cpp b/tests/daemon/face/ethernet.t.cpp
deleted file mode 100644
index 2b1d2de..0000000
--- a/tests/daemon/face/ethernet.t.cpp
+++ /dev/null
@@ -1,231 +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 "face/ethernet-factory.hpp"
-#include "face/ethernet-transport.hpp"
-
-#include "face/lp-face-wrapper.hpp"
-#include "network-interface-fixture.hpp"
-
-#include <pcap/pcap.h>
-
-namespace nfd {
-namespace tests {
-
-using nfd::face::tests::NetworkInterfaceFixture;
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestEthernet, NetworkInterfaceFixture)
-
-using nfd::Face;
-
-BOOST_AUTO_TEST_CASE(GetChannels)
-{
-  EthernetFactory factory;
-
-  auto channels = factory.getChannels();
-  BOOST_CHECK_EQUAL(channels.empty(), true);
-}
-
-BOOST_AUTO_TEST_CASE(MulticastFacesMap)
-{
-  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
-
-  EthernetFactory factory;
-  auto face1 = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
-  auto face1bis = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
-  BOOST_CHECK_EQUAL(face1, face1bis);
-
-  auto face2 = factory.createMulticastFace(m_interfaces.front(), ethernet::getDefaultMulticastAddress());
-  BOOST_CHECK_NE(face1, face2);
-
-  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(2);
-
-  auto face3 = factory.createMulticastFace(m_interfaces.back(), ethernet::getBroadcastAddress());
-  BOOST_CHECK_NE(face1, face3);
-}
-
-BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
-{
-  EthernetFactory factory;
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
-                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ether://[08:00:27:01:01:01]"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-}
-
-BOOST_AUTO_TEST_CASE(SendPacket)
-{
-  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
-
-  EthernetFactory factory;
-  auto face = factory.createMulticastFace(m_interfaces.front(), ethernet::getDefaultMulticastAddress());
-
-  BOOST_REQUIRE(static_cast<bool>(face));
-  BOOST_CHECK_EQUAL(face->isLocal(), false);
-  BOOST_CHECK_EQUAL(face->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
-  BOOST_CHECK_EQUAL(face->isMultiAccess(), true);
-  BOOST_CHECK_EQUAL(face->getRemoteUri().toString(),
-                    "ether://[" + ethernet::getDefaultMulticastAddress().toString() + "]");
-  BOOST_CHECK_EQUAL(face->getLocalUri().toString(),
-                    "dev://" + m_interfaces.front().name);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
-  BOOST_CHECK_EQUAL(face->getCounters().nOutBytes, 0);
-
-  face->onFail.connect([] (const std::string& reason) { BOOST_FAIL(reason); });
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  face->sendInterest(*interest1);
-  face->sendData    (*data1    );
-  face->sendInterest(*interest2);
-  face->sendData    (*data2    );
-
-  BOOST_CHECK_EQUAL(face->getCounters().nOutBytes,
-                    interest1->wireEncode().size() +
-                    data1->wireEncode().size() +
-                    interest2->wireEncode().size() +
-                    data2->wireEncode().size());
-}
-
-BOOST_AUTO_TEST_CASE(ProcessIncomingPacket)
-{
-  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
-
-  EthernetFactory factory;
-  auto face = factory.createMulticastFace(m_interfaces.front(), ethernet::getDefaultMulticastAddress());
-  BOOST_REQUIRE(static_cast<bool>(face));
-
-  auto transport = dynamic_cast<face::EthernetTransport*>(face->getLpFace()->getTransport());
-  BOOST_REQUIRE(transport != nullptr);
-
-  std::vector<Interest> recInterests;
-  std::vector<Data>     recDatas;
-
-  face->onFail.connect([] (const std::string& reason) { BOOST_FAIL(reason); });
-  face->onReceiveInterest.connect(
-      [&recInterests] (const Interest& i) { recInterests.push_back(i); });
-  face->onReceiveData.connect([&recDatas] (const Data& d) { recDatas.push_back(d); });
-
-  // check that packet data is not accessed if pcap didn't capture anything (caplen == 0)
-  static const pcap_pkthdr zeroHeader{};
-  transport->processIncomingPacket(&zeroHeader, nullptr);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
-  BOOST_CHECK_EQUAL(recInterests.size(), 0);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-
-  // runt frame (too short)
-  pcap_pkthdr runtHeader{};
-  runtHeader.caplen = ethernet::HDR_LEN + 6;
-  static const uint8_t packet2[ethernet::HDR_LEN + 6]{};
-  transport->processIncomingPacket(&runtHeader, packet2);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
-  BOOST_CHECK_EQUAL(recInterests.size(), 0);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-
-  // valid frame, but TLV block has invalid length
-  pcap_pkthdr validHeader{};
-  validHeader.caplen = ethernet::HDR_LEN + ethernet::MIN_DATA_LEN;
-  static const uint8_t packet3[ethernet::HDR_LEN + ethernet::MIN_DATA_LEN]{
-    0x01, 0x00, 0x5e, 0x00, 0x17, 0xaa, // destination address
-    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, // source address
-    0x86, 0x24,       // NDN ethertype
-    tlv::Interest,    // TLV type
-    0xfd, 0xff, 0xff  // TLV length (invalid because greater than buffer size)
-  };
-  transport->processIncomingPacket(&validHeader, packet3);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
-  BOOST_CHECK_EQUAL(recInterests.size(), 0);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-
-  // valid frame, but TLV block has invalid type
-  static const uint8_t packet4[ethernet::HDR_LEN + ethernet::MIN_DATA_LEN]{
-    0x01, 0x00, 0x5e, 0x00, 0x17, 0xaa, // destination address
-    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, // source address
-    0x86, 0x24,       // NDN ethertype
-    0x00,             // TLV type (invalid)
-    0x00              // TLV length
-  };
-  transport->processIncomingPacket(&validHeader, packet4);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 2);
-  BOOST_CHECK_EQUAL(recInterests.size(), 0);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-
-  // valid frame and valid NDNLPv2 packet, but invalid network-layer packet
-  static const uint8_t packet5[ethernet::HDR_LEN + ethernet::MIN_DATA_LEN]{
-    0x01, 0x00, 0x5e, 0x00, 0x17, 0xaa, // destination address
-    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, // source address
-    0x86, 0x24,                         // NDN ethertype
-    lp::tlv::LpPacket, 0x04,            // start of NDNLPv2 packet
-    lp::tlv::Fragment, 0x02,            // single fragment
-    0x00,             // TLV type (invalid)
-    0x00              // TLV length
-  };
-  transport->processIncomingPacket(&validHeader, packet5);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 8);
-  BOOST_CHECK_EQUAL(recInterests.size(), 0);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-
-  // valid frame, valid NDNLPv2 packet, and valid NDN (interest) packet
-  static const uint8_t packet6[ethernet::HDR_LEN + ethernet::MIN_DATA_LEN]{
-    0x01, 0x00, 0x5e, 0x00, 0x17, 0xaa, // destination address
-    0x02, 0x00, 0x00, 0x00, 0x00, 0x02, // source address
-    0x86, 0x24,                         // NDN ethertype
-    lp::tlv::LpPacket, 0x1a,            // start of NDNLPv2 packet
-    lp::tlv::Fragment, 0x18,            // single fragment
-    tlv::Interest, 0x16,                // start of NDN packet
-    0x07, 0x0e, 0x08, 0x07, 0x65, 0x78, // payload
-    0x61, 0x6d, 0x70, 0x6c, 0x65, 0x08,
-    0x03, 0x66, 0x6f, 0x6f, 0x0a, 0x04,
-    0x03, 0xef, 0xe9, 0x7c
-  };
-  transport->processIncomingPacket(&validHeader, packet6);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 36);
-  BOOST_CHECK_EQUAL(recInterests.size(), 1);
-  BOOST_CHECK_EQUAL(recDatas.size(), 0);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestEthernet
-BOOST_AUTO_TEST_SUITE_END() // Face
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/face/face-history.hpp b/tests/daemon/face/face-history.hpp
deleted file mode 100644
index 263a23a..0000000
--- a/tests/daemon/face/face-history.hpp
+++ /dev/null
@@ -1,93 +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/>.
- */
-
-#ifndef NFD_TESTS_DAEMON_FACE_FACE_HISTORY_HPP
-#define NFD_TESTS_DAEMON_FACE_FACE_HISTORY_HPP
-
-#include "face/face.hpp"
-
-namespace nfd {
-namespace tests {
-
-/** \brief captures signals from Face
- */
-class FaceHistory : noncopyable
-{
-public:
-  explicit
-  FaceHistory(Face& face)
-    : m_limitedIo(nullptr)
-  {
-    this->construct(face);
-  }
-
-  FaceHistory(Face& face, LimitedIo& limitedIo)
-    : m_limitedIo(&limitedIo)
-  {
-    this->construct(face);
-  }
-
-private:
-  void
-  construct(Face& face)
-  {
-    m_receiveInterestConn = face.onReceiveInterest.connect([this] (const Interest& interest) {
-      this->receivedInterests.push_back(interest);
-      this->afterOp();
-    });
-    m_receiveDataConn = face.onReceiveData.connect([this] (const Data& data) {
-      this->receivedData.push_back(data);
-      this->afterOp();
-    });
-    m_failConn = face.onFail.connect([this] (const std::string& reason) {
-      this->failures.push_back(reason);
-      this->afterOp();
-    });
-  }
-
-  void
-  afterOp()
-  {
-    if (m_limitedIo != nullptr) {
-      m_limitedIo->afterOp();
-    }
-  }
-
-public:
-  std::vector<Interest> receivedInterests;
-  std::vector<Data> receivedData;
-  std::vector<std::string> failures;
-
-private:
-  LimitedIo* m_limitedIo;
-  signal::ScopedConnection m_receiveInterestConn;
-  signal::ScopedConnection m_receiveDataConn;
-  signal::ScopedConnection m_failConn;
-};
-
-} // namespace tests
-} // namespace nfd
-
-#endif // NFD_TESTS_DAEMON_FACE_FACE_HISTORY_HPP
diff --git a/tests/daemon/face/face.t.cpp b/tests/daemon/face/face.t.cpp
index 4a94a58..7d0dba0 100644
--- a/tests/daemon/face/face.t.cpp
+++ b/tests/daemon/face/face.t.cpp
@@ -24,60 +24,89 @@
  */
 
 #include "face/face.hpp"
-#include "dummy-face.hpp"
 
 #include "tests/test-common.hpp"
+#include "dummy-face.hpp"
 
 namespace nfd {
+namespace face {
 namespace tests {
 
-BOOST_FIXTURE_TEST_SUITE(FaceFace, BaseFixture)
+using namespace nfd::tests;
 
-BOOST_AUTO_TEST_CASE(Description)
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestFace, BaseFixture)
+
+// TODO add test cases for getLinkService, getTransport
+// TODO add a test case for static properties
+// TODO add a test case for getState
+
+BOOST_AUTO_TEST_CASE(LinkServiceSendReceive)
 {
-  DummyFace face;
-  face.setDescription("3pFsKrvWr");
-  BOOST_CHECK_EQUAL(face.getDescription(), "3pFsKrvWr");
+  auto face1 = make_shared<DummyFace>();
+
+  const size_t nInInterests = 192;
+  const size_t nInData = 91;
+  const size_t nInNacks = 29;
+  const size_t nOutInterests = 202;
+  const size_t nOutData = 128;
+  const size_t nOutNacks = 84;
+
+  size_t nReceivedInterests = 0;
+  size_t nReceivedData = 0;
+  size_t nReceivedNacks = 0;
+  face1->afterReceiveInterest.connect(bind([&nReceivedInterests] { ++nReceivedInterests; }));
+  face1->afterReceiveData.connect(bind([&nReceivedData] { ++nReceivedData; }));
+  face1->afterReceiveNack.connect(bind([&nReceivedNacks] { ++nReceivedNacks; }));
+
+  for (size_t i = 0; i < nInInterests; ++i) {
+    shared_ptr<Interest> interest = makeInterest("/JSQdqward4");
+    face1->receiveInterest(*interest);
+  }
+
+  for (size_t i = 0; i < nInData; ++i) {
+    shared_ptr<Data> data = makeData("/hT8FDigWn1");
+    face1->receiveData(*data);
+  }
+
+  for (size_t i = 0; i < nInNacks; ++i) {
+    lp::Nack nack = makeNack("/StnEVTj4Ex", 561, lp::NackReason::CONGESTION);
+    face1->receiveNack(nack);
+  }
+
+  for (size_t i = 0; i < nOutInterests; ++i) {
+    shared_ptr<Interest> interest = makeInterest("/XyUAFYQDmd");
+    face1->sendInterest(*interest);
+  }
+
+  for (size_t i = 0; i < nOutData; ++i) {
+    shared_ptr<Data> data = makeData("/GigPEtPH6");
+    face1->sendData(*data);
+  }
+
+  for (size_t i = 0; i < nOutNacks; ++i) {
+    lp::Nack nack = makeNack("/9xK6FbwIBM", 365, lp::NackReason::CONGESTION);
+    face1->sendNack(nack);
+  }
+
+  BOOST_CHECK_EQUAL(face1->getCounters().nInInterests, nInInterests);
+  BOOST_CHECK_EQUAL(face1->getCounters().nInData, nInData);
+  BOOST_CHECK_EQUAL(face1->getCounters().nInNacks, nInNacks);
+  BOOST_CHECK_EQUAL(face1->getCounters().nOutInterests, nOutInterests);
+  BOOST_CHECK_EQUAL(face1->getCounters().nOutData, nOutData);
+  BOOST_CHECK_EQUAL(face1->getCounters().nOutNacks, nOutNacks);
+
+  BOOST_CHECK_EQUAL(nReceivedInterests, nInInterests);
+  BOOST_CHECK_EQUAL(nReceivedData, nInData);
+  BOOST_CHECK_EQUAL(nReceivedNacks, nInNacks);
+  BOOST_CHECK_EQUAL(face1->sentInterests.size(), nOutInterests);
+  BOOST_CHECK_EQUAL(face1->sentData.size(), nOutData);
+  BOOST_CHECK_EQUAL(face1->sentNacks.size(), nOutNacks);
 }
 
-class FaceFailTestFace : public DummyFace
-{
-public:
-  FaceFailTestFace()
-    : failCount(0)
-  {
-    this->onFail.connect(bind(&FaceFailTestFace::failHandler, this, _1));
-  }
-
-  void
-  failOnce()
-  {
-    this->fail("reason");
-  }
-
-private:
-  void
-  failHandler(const std::string& reason)
-  {
-    BOOST_CHECK_EQUAL(reason, "reason");
-    ++this->failCount;
-  }
-
-public:
-  int failCount;
-};
-
-BOOST_AUTO_TEST_CASE(FailTwice)
-{
-  FaceFailTestFace face;
-  BOOST_CHECK_EQUAL(face.failCount, 0);
-  face.failOnce();
-  BOOST_CHECK_EQUAL(face.failCount, 1);
-  face.failOnce();
-  BOOST_CHECK_EQUAL(face.failCount, 1);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestFace
+BOOST_AUTO_TEST_SUITE_END() // Face
 
 } // namespace tests
+} // namespace face
 } // namespace nfd
diff --git a/tests/daemon/face/generic-link-service.t.cpp b/tests/daemon/face/generic-link-service.t.cpp
index 70e078d..888c222 100644
--- a/tests/daemon/face/generic-link-service.t.cpp
+++ b/tests/daemon/face/generic-link-service.t.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "face/generic-link-service.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 #include "dummy-transport.hpp"
 
 #include "tests/test-common.hpp"
@@ -37,6 +37,8 @@
 
 BOOST_AUTO_TEST_SUITE(Face)
 
+using nfd::Face;
+
 class GenericLinkServiceFixture : public BaseFixture
 {
 protected:
@@ -52,8 +54,8 @@
   void
   initialize(const GenericLinkService::Options& options)
   {
-    face.reset(new LpFace(make_unique<GenericLinkService>(options),
-                          make_unique<DummyTransport>()));
+    face.reset(new Face(make_unique<GenericLinkService>(options),
+                        make_unique<DummyTransport>()));
     service = static_cast<GenericLinkService*>(face->getLinkService());
     transport = static_cast<DummyTransport*>(face->getTransport());
 
@@ -66,7 +68,7 @@
   }
 
 protected:
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
   GenericLinkService* service;
   DummyTransport* transport;
   std::vector<Interest> receivedInterests;
diff --git a/tests/daemon/face/internal-face.t.cpp b/tests/daemon/face/internal-face.t.cpp
index cca385e..4371317 100644
--- a/tests/daemon/face/internal-face.t.cpp
+++ b/tests/daemon/face/internal-face.t.cpp
@@ -24,9 +24,8 @@
  */
 
 #include "face/internal-face.hpp"
-#include "face/lp-face-wrapper.hpp"
-#include "transport-test-common.hpp"
 
+#include "transport-test-common.hpp"
 #include "tests/identity-management-fixture.hpp"
 
 namespace nfd {
@@ -43,9 +42,7 @@
 public:
   InternalFaceFixture()
   {
-    std::tie(forwarderFaceW, clientFace) = makeInternalFace(m_keyChain);;
-    forwarderFace = static_pointer_cast<LpFaceWrapper>(forwarderFaceW)->getLpFace();
-    // TODO#3172 eliminate wrapper
+    std::tie(forwarderFace, clientFace) = makeInternalFace(m_keyChain);;
 
     forwarderFace->afterReceiveInterest.connect(
       [this] (const Interest& interest) { receivedInterests.push_back(interest); } );
@@ -56,8 +53,7 @@
   }
 
 protected:
-  shared_ptr<nfd::Face> forwarderFaceW;
-  LpFace* forwarderFace;
+  shared_ptr<nfd::Face> forwarderFace;
   shared_ptr<ndn::Face> clientFace;
 
   std::vector<Interest> receivedInterests;
@@ -199,7 +195,7 @@
   forwarderFace->close();
   this->advanceClocks(time::milliseconds(1), 10);
   BOOST_CHECK_EQUAL(forwarderFace->getState(), FaceState::CLOSED);
-  forwarderFaceW.reset();
+  forwarderFace.reset();
 
   shared_ptr<Interest> interest = makeInterest("/zpHsVesu0B");
   interest->setInterestLifetime(time::milliseconds(100));
diff --git a/tests/daemon/face/lp-face-wrapper.t.cpp b/tests/daemon/face/lp-face-wrapper.t.cpp
deleted file mode 100644
index 8217d77..0000000
--- a/tests/daemon/face/lp-face-wrapper.t.cpp
+++ /dev/null
@@ -1,162 +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 "face/lp-face-wrapper.hpp"
-#include "fw/forwarder.hpp"
-
-#include "tests/test-common.hpp"
-#include "dummy-lp-face.hpp"
-
-namespace nfd {
-namespace face {
-namespace tests {
-
-using namespace nfd::tests;
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestLpFaceWrapper, BaseFixture)
-
-BOOST_AUTO_TEST_CASE(SetId)
-{
-  Forwarder forwarder;
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-
-  BOOST_CHECK_EQUAL(face1->getId(), nfd::face::INVALID_FACEID);
-  BOOST_CHECK_EQUAL(face1w->getId(), nfd::INVALID_FACEID);
-
-  forwarder.addFace(face1w);
-
-  BOOST_CHECK_NE(face1->getId(), nfd::face::INVALID_FACEID);
-  BOOST_CHECK_NE(face1w->getId(), nfd::INVALID_FACEID);
-  BOOST_CHECK_EQUAL(face1->getId(), static_cast<face::FaceId>(face1w->getId()));
-}
-
-BOOST_AUTO_TEST_CASE(SetPersistency)
-{
-  unique_ptr<LpFace> face1u = make_unique<DummyLpFace>();
-  face1u->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-
-  auto face1w = make_shared<face::LpFaceWrapper>(std::move(face1u));
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_EQUAL(face1w->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-
-  face1w->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
-
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
-  BOOST_CHECK_EQUAL(face1w->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
-}
-
-BOOST_AUTO_TEST_CASE(Counters)
-{
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-
-  BOOST_CHECK(&face1->getCounters() == &face1w->getCounters());
-}
-
-BOOST_AUTO_TEST_CASE(FailSignal)
-{
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-
-  bool isFailed = false;
-  face1w->onFail.connect(bind([&isFailed] { isFailed = true; }));
-
-  face1->setState(FaceState::DOWN);
-  BOOST_CHECK(!isFailed);
-
-  face1->setState(FaceState::FAILED);
-  BOOST_CHECK(!isFailed);
-
-  face1->setState(FaceState::CLOSED);
-  BOOST_CHECK(isFailed);
-}
-
-BOOST_AUTO_TEST_CASE(SendReceive)
-{
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-
-  const size_t nInInterests = 192;
-  const size_t nInData = 91;
-  const size_t nInNacks = 29;
-  const size_t nOutInterests = 202;
-  const size_t nOutData = 128;
-  const size_t nOutNacks = 84;
-
-  size_t nReceivedInterests = 0;
-  size_t nReceivedData = 0;
-  size_t nReceivedNacks = 0;
-  face1w->onReceiveInterest.connect(bind([&nReceivedInterests] { ++nReceivedInterests; }));
-  face1w->onReceiveData.connect(bind([&nReceivedData] { ++nReceivedData; }));
-  face1w->onReceiveNack.connect(bind([&nReceivedNacks] { ++nReceivedNacks; }));
-
-  for (size_t i = 0; i < nInInterests; ++i) {
-    shared_ptr<Interest> interest = makeInterest("/JSQdqward4");
-    face1->receiveInterest(*interest);
-  }
-
-  for (size_t i = 0; i < nInData; ++i) {
-    shared_ptr<Data> data = makeData("/hT8FDigWn1");
-    face1->receiveData(*data);
-  }
-
-  for (size_t i = 0; i < nInNacks; ++i) {
-    lp::Nack nack = makeNack("/StnEVTj4Ex", 561, lp::NackReason::CONGESTION);
-    face1->receiveNack(nack);
-  }
-
-  for (size_t i = 0; i < nOutInterests; ++i) {
-    shared_ptr<Interest> interest = makeInterest("/XyUAFYQDmd");
-    face1w->sendInterest(*interest);
-  }
-
-  for (size_t i = 0; i < nOutData; ++i) {
-    shared_ptr<Data> data = makeData("/GigPEtPH6");
-    face1w->sendData(*data);
-  }
-
-  for (size_t i = 0; i < nOutNacks; ++i) {
-    lp::Nack nack = makeNack("/9xK6FbwIBM", 365, lp::NackReason::CONGESTION);
-    face1w->sendNack(nack);
-  }
-
-  BOOST_CHECK_EQUAL(nReceivedInterests, nInInterests);
-  BOOST_CHECK_EQUAL(nReceivedData, nInData);
-  BOOST_CHECK_EQUAL(nReceivedNacks, nInNacks);
-  BOOST_CHECK_EQUAL(face1->sentInterests.size(), nOutInterests);
-  BOOST_CHECK_EQUAL(face1->sentData.size(), nOutData);
-  BOOST_CHECK_EQUAL(face1->sentNacks.size(), nOutNacks);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace face
-} // namespace nfd
diff --git a/tests/daemon/face/lp-face.t.cpp b/tests/daemon/face/lp-face.t.cpp
deleted file mode 100644
index 92a3755..0000000
--- a/tests/daemon/face/lp-face.t.cpp
+++ /dev/null
@@ -1,108 +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 "face/lp-face.hpp"
-
-#include "tests/test-common.hpp"
-#include "dummy-lp-face.hpp"
-
-namespace nfd {
-namespace face {
-namespace tests {
-
-using namespace nfd::tests;
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestLpFace, BaseFixture)
-
-BOOST_AUTO_TEST_CASE(LinkServiceSendReceive)
-{
-  auto face1 = make_shared<DummyLpFace>();
-
-  const size_t nInInterests = 192;
-  const size_t nInData = 91;
-  const size_t nInNacks = 29;
-  const size_t nOutInterests = 202;
-  const size_t nOutData = 128;
-  const size_t nOutNacks = 84;
-
-  size_t nReceivedInterests = 0;
-  size_t nReceivedData = 0;
-  size_t nReceivedNacks = 0;
-  face1->afterReceiveInterest.connect(bind([&nReceivedInterests] { ++nReceivedInterests; }));
-  face1->afterReceiveData.connect(bind([&nReceivedData] { ++nReceivedData; }));
-  face1->afterReceiveNack.connect(bind([&nReceivedNacks] { ++nReceivedNacks; }));
-
-  for (size_t i = 0; i < nInInterests; ++i) {
-    shared_ptr<Interest> interest = makeInterest("/JSQdqward4");
-    face1->receiveInterest(*interest);
-  }
-
-  for (size_t i = 0; i < nInData; ++i) {
-    shared_ptr<Data> data = makeData("/hT8FDigWn1");
-    face1->receiveData(*data);
-  }
-
-  for (size_t i = 0; i < nInNacks; ++i) {
-    lp::Nack nack = makeNack("/StnEVTj4Ex", 561, lp::NackReason::CONGESTION);
-    face1->receiveNack(nack);
-  }
-
-  for (size_t i = 0; i < nOutInterests; ++i) {
-    shared_ptr<Interest> interest = makeInterest("/XyUAFYQDmd");
-    face1->sendInterest(*interest);
-  }
-
-  for (size_t i = 0; i < nOutData; ++i) {
-    shared_ptr<Data> data = makeData("/GigPEtPH6");
-    face1->sendData(*data);
-  }
-
-  for (size_t i = 0; i < nOutNacks; ++i) {
-    lp::Nack nack = makeNack("/9xK6FbwIBM", 365, lp::NackReason::CONGESTION);
-    face1->sendNack(nack);
-  }
-
-  BOOST_CHECK_EQUAL(face1->getCounters().nInInterests, nInInterests);
-  BOOST_CHECK_EQUAL(face1->getCounters().nInData, nInData);
-  BOOST_CHECK_EQUAL(face1->getCounters().nInNacks, nInNacks);
-  BOOST_CHECK_EQUAL(face1->getCounters().nOutInterests, nOutInterests);
-  BOOST_CHECK_EQUAL(face1->getCounters().nOutData, nOutData);
-  BOOST_CHECK_EQUAL(face1->getCounters().nOutNacks, nOutNacks);
-
-  BOOST_CHECK_EQUAL(nReceivedInterests, nInInterests);
-  BOOST_CHECK_EQUAL(nReceivedData, nInData);
-  BOOST_CHECK_EQUAL(nReceivedNacks, nInNacks);
-  BOOST_CHECK_EQUAL(face1->sentInterests.size(), nOutInterests);
-  BOOST_CHECK_EQUAL(face1->sentData.size(), nOutData);
-  BOOST_CHECK_EQUAL(face1->sentNacks.size(), nOutNacks);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace face
-} // namespace nfd
diff --git a/tests/daemon/face/null-face.t.cpp b/tests/daemon/face/null-face.t.cpp
index 16d1a11..4075245 100644
--- a/tests/daemon/face/null-face.t.cpp
+++ b/tests/daemon/face/null-face.t.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "face/null-face.hpp"
-#include "face/lp-face-wrapper.hpp"
+
 #include "transport-test-common.hpp"
 
 namespace nfd {
@@ -40,8 +40,7 @@
 
 BOOST_AUTO_TEST_CASE(StaticProperties)
 {
-  shared_ptr<Face> faceW = makeNullFace(FaceUri("testnull://hhppt12sy"));
-  LpFace* face = static_pointer_cast<LpFaceWrapper>(faceW)->getLpFace();
+  shared_ptr<Face> face = makeNullFace(FaceUri("testnull://hhppt12sy"));
   checkStaticPropertiesInitialized(*face->getTransport());
 
   BOOST_CHECK_EQUAL(face->getLocalUri(), FaceUri("testnull://hhppt12sy"));
diff --git a/tests/daemon/face/packet-datasets.cpp b/tests/daemon/face/packet-datasets.cpp
deleted file mode 100644
index 196fa86..0000000
--- a/tests/daemon/face/packet-datasets.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  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 "packet-datasets.hpp"
-#include "tests/test-common.hpp"
-
-#include <boost/foreach.hpp>
-
-namespace nfd {
-namespace tests {
-
-BOOST_FIXTURE_TEST_SUITE(Datasets, BaseFixture)
-
-BOOST_AUTO_TEST_CASE(Corrupted)
-{
-  {
-    typedef CorruptedInterest Dataset;
-    Dataset dataset;
-
-    BOOST_FOREACH(Dataset::Container::value_type& data, dataset.data)
-      {
-        Block block(data.buf(), data.size());
-
-        BOOST_CHECK_THROW((Interest(block)), tlv::Error);
-      }
-  }
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/face/packet-datasets.hpp b/tests/daemon/face/packet-datasets.hpp
deleted file mode 100644
index 95639c1..0000000
--- a/tests/daemon/face/packet-datasets.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014,  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/>.
- */
-
-#ifndef NFD_TESTS_DAEMON_FACE_PACKET_DATASETS_HPP
-#define NFD_TESTS_DAEMON_FACE_PACKET_DATASETS_HPP
-
-#include "tests/test-common.hpp"
-
-namespace nfd {
-namespace tests {
-
-class CorruptedInterest
-{
-public:
-  typedef std::vector<ndn::Buffer> Container;
-
-  static std::string
-  getName()
-  {
-    return "CorruptedInterest";
-  }
-
-  CorruptedInterest()
-  {
-    static const uint8_t interest[] = {
-      0x05, 0x1d, 0x07, 0x84, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x08, 0x03, 0x6e, 0x64,
-      0x6e, 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x09, 0x02, 0x12, 0x00, 0x0a, 0x01,
-      0x01
-    };
-
-    data.push_back(ndn::Buffer(interest, sizeof(interest)));
-  }
-public:
-  Container data;
-};
-
-typedef boost::mpl::vector<CorruptedInterest> CorruptedPackets;
-
-} // namespace tests
-} // namespace nfd
-
-#endif // NFD_TESTS_DAEMON_FACE_PACKET_DATASETS_HPP
diff --git a/tests/daemon/face/tcp-channel.t.cpp b/tests/daemon/face/tcp-channel.t.cpp
new file mode 100644
index 0000000..816761d
--- /dev/null
+++ b/tests/daemon/face/tcp-channel.t.cpp
@@ -0,0 +1,44 @@
+/* -*- 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 "face/tcp-channel.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestTcpChannel, BaseFixture)
+
+// TODO add the equivalent of these test cases from tcp.t.cpp as of commit:65caf200924b28748037750449e28bcb548dbc9c
+// MultipleAccepts
+// FaceClosing
+
+BOOST_AUTO_TEST_SUITE_END() // TestTcpChannel
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/tcp-factory.t.cpp b/tests/daemon/face/tcp-factory.t.cpp
new file mode 100644
index 0000000..ee796ab
--- /dev/null
+++ b/tests/daemon/face/tcp-factory.t.cpp
@@ -0,0 +1,258 @@
+/* -*- 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 "face/tcp-factory.hpp"
+
+#include "core/network-interface.hpp"
+#include "tests/test-common.hpp"
+#include "tests/limited-io.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestTcpFactory, BaseFixture)
+
+using nfd::Face;
+
+BOOST_AUTO_TEST_CASE(ChannelMap)
+{
+  TcpFactory factory;
+
+  shared_ptr<TcpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
+  shared_ptr<TcpChannel> channel1a = factory.createChannel("127.0.0.1", "20070");
+  BOOST_CHECK_EQUAL(channel1, channel1a);
+  BOOST_CHECK_EQUAL(channel1->getUri().toString(), "tcp4://127.0.0.1:20070");
+
+  shared_ptr<TcpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
+  BOOST_CHECK_NE(channel1, channel2);
+
+  shared_ptr<TcpChannel> channel3 = factory.createChannel("::1", "20071");
+  BOOST_CHECK_NE(channel2, channel3);
+  BOOST_CHECK_EQUAL(channel3->getUri().toString(), "tcp6://[::1]:20071");
+}
+
+BOOST_AUTO_TEST_CASE(GetChannels)
+{
+  TcpFactory factory;
+  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
+
+  std::vector<shared_ptr<const Channel>> expectedChannels;
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
+  expectedChannels.push_back(factory.createChannel("::1", "20071"));
+
+  for (const auto& ch : factory.getChannels()) {
+    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), ch);
+    BOOST_REQUIRE(pos != expectedChannels.end());
+    expectedChannels.erase(pos);
+  }
+  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
+}
+
+class FaceCreateFixture : public BaseFixture
+{
+public:
+  void
+  checkError(const std::string& errorActual, const std::string& errorExpected)
+  {
+    BOOST_CHECK_EQUAL(errorActual, errorExpected);
+  }
+
+  void
+  failIfError(const std::string& errorActual)
+  {
+    BOOST_FAIL("No error expected, but got: [" << errorActual << "]");
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(FaceCreate, FaceCreateFixture)
+{
+  TcpFactory factory;
+
+  factory.createFace(FaceUri("tcp4://127.0.0.1:6363"),
+                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::checkError, this, _1,
+                          "No channels available to connect to 127.0.0.1:6363"));
+
+  factory.createChannel("127.0.0.1", "20071");
+
+  factory.createFace(FaceUri("tcp4://127.0.0.1:20070"),
+                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::failIfError, this, _1));
+}
+
+BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
+{
+  TcpFactory factory;
+
+  factory.createChannel("127.0.0.1", "20070");
+  factory.createChannel("127.0.0.1", "20071");
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("tcp4://127.0.0.1:20070"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("tcp4://127.0.0.1:20071"),
+                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+}
+
+class FaceCreateTimeoutFixture : public BaseFixture
+{
+public:
+  void
+  onFaceCreated(const shared_ptr<Face>& newFace)
+  {
+    BOOST_CHECK_MESSAGE(false, "Timeout expected");
+    BOOST_CHECK(!static_cast<bool>(face1));
+    face1 = newFace;
+
+    limitedIo.afterOp();
+  }
+
+  void
+  onConnectFailed(const std::string& reason)
+  {
+    BOOST_CHECK_MESSAGE(true, reason);
+
+    limitedIo.afterOp();
+  }
+
+public:
+  LimitedIo limitedIo;
+
+  shared_ptr<Face> face1;
+};
+
+BOOST_FIXTURE_TEST_CASE(FaceCreateTimeout, FaceCreateTimeoutFixture)
+{
+  TcpFactory factory;
+  shared_ptr<TcpChannel> channel = factory.createChannel("0.0.0.0", "20070");
+
+  factory.createFace(FaceUri("tcp4://192.0.2.1:20070"),
+                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     bind(&FaceCreateTimeoutFixture::onFaceCreated, this, _1),
+                     bind(&FaceCreateTimeoutFixture::onConnectFailed, this, _1));
+
+  BOOST_CHECK_MESSAGE(limitedIo.run(1, time::seconds(10)) == LimitedIo::EXCEED_OPS,
+                      "TcpChannel error: cannot connect or cannot accept connection");
+
+  BOOST_CHECK_EQUAL(static_cast<bool>(face1), false);
+}
+
+class FakeNetworkInterfaceFixture : public BaseFixture
+{
+public:
+  FakeNetworkInterfaceFixture()
+  {
+    using namespace boost::asio::ip;
+
+    auto fakeInterfaces = make_shared<std::vector<NetworkInterfaceInfo>>();
+
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {0, "eth0",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("0.0.0.0")},
+        {address_v6::from_string("::")},
+        address_v4(),
+        IFF_UP});
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {1, "eth0",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("192.168.2.1"), address_v4::from_string("192.168.2.2")},
+        {},
+        address_v4::from_string("192.168.2.255"),
+        0});
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {2, "eth1",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("198.51.100.1")},
+        {address_v6::from_string("2001:db8::2"), address_v6::from_string("2001:db8::3")},
+        address_v4::from_string("198.51.100.255"),
+        IFF_MULTICAST | IFF_BROADCAST | IFF_UP});
+
+    setDebugNetworkInterfaces(fakeInterfaces);
+  }
+
+  ~FakeNetworkInterfaceFixture()
+  {
+    setDebugNetworkInterfaces(nullptr);
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(Bug2292, FakeNetworkInterfaceFixture)
+{
+  using namespace boost::asio::ip;
+
+  TcpFactory factory;
+  factory.prohibitEndpoint(tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<tcp::Endpoint> {
+                 tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(tcp::Endpoint(address_v6::from_string("2001:db8::1"), 2048));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<tcp::Endpoint> {
+                 tcp::Endpoint(address_v6::from_string("2001:db8::1"), 2048)
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(tcp::Endpoint(address_v4(), 1024));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 4);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<tcp::Endpoint> {
+                 tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
+                 tcp::Endpoint(address_v4::from_string("192.168.2.2"), 1024),
+                 tcp::Endpoint(address_v4::from_string("198.51.100.1"), 1024),
+                 tcp::Endpoint(address_v4::from_string("0.0.0.0"), 1024)
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(tcp::Endpoint(address_v6(), 2048));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 3);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<tcp::Endpoint> {
+                 tcp::Endpoint(address_v6::from_string("2001:db8::2"), 2048),
+                 tcp::Endpoint(address_v6::from_string("2001:db8::3"), 2048),
+                 tcp::Endpoint(address_v6::from_string("::"), 2048)
+               }));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestTcpFactory
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/tcp-transport-fixture.hpp b/tests/daemon/face/tcp-transport-fixture.hpp
index 38be67b..e68eff9 100644
--- a/tests/daemon/face/tcp-transport-fixture.hpp
+++ b/tests/daemon/face/tcp-transport-fixture.hpp
@@ -27,7 +27,7 @@
 #define NFD_TESTS_DAEMON_FACE_TCP_TRANSPORT_FIXTURE_HPP
 
 #include "face/tcp-transport.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
 #include "tests/limited-io.hpp"
@@ -73,9 +73,9 @@
     BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(1)), LimitedIo::EXCEED_OPS);
 
     localEp = sock.local_endpoint();
-    face = make_unique<LpFace>(make_unique<DummyReceiveLinkService>(),
-                               make_unique<TcpTransport>(std::move(sock),
-                                                         ndn::nfd::FACE_PERSISTENCY_PERSISTENT));
+    face = make_unique<Face>(make_unique<DummyReceiveLinkService>(),
+                             make_unique<TcpTransport>(std::move(sock),
+                                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT));
     transport = static_cast<TcpTransport*>(face->getTransport());
     receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
 
@@ -103,7 +103,7 @@
 
 private:
   tcp::acceptor acceptor;
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
 };
 
 } // namespace tests
diff --git a/tests/daemon/face/tcp.t.cpp b/tests/daemon/face/tcp.t.cpp
deleted file mode 100644
index 6d5fe19..0000000
--- a/tests/daemon/face/tcp.t.cpp
+++ /dev/null
@@ -1,758 +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 "face/tcp-channel.hpp"
-#include "face/tcp-factory.hpp"
-
-#include "core/network-interface.hpp"
-#include "tests/test-common.hpp"
-#include "tests/limited-io.hpp"
-#include "dummy-stream-sender.hpp"
-#include "packet-datasets.hpp"
-
-namespace nfd {
-namespace tests {
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestTcp, BaseFixture)
-
-using nfd::Face;
-
-BOOST_AUTO_TEST_CASE(ChannelMap)
-{
-  TcpFactory factory;
-
-  shared_ptr<TcpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
-  shared_ptr<TcpChannel> channel1a = factory.createChannel("127.0.0.1", "20070");
-  BOOST_CHECK_EQUAL(channel1, channel1a);
-  BOOST_CHECK_EQUAL(channel1->getUri().toString(), "tcp4://127.0.0.1:20070");
-
-  shared_ptr<TcpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
-  BOOST_CHECK_NE(channel1, channel2);
-
-  shared_ptr<TcpChannel> channel3 = factory.createChannel("::1", "20071");
-  BOOST_CHECK_NE(channel2, channel3);
-  BOOST_CHECK_EQUAL(channel3->getUri().toString(), "tcp6://[::1]:20071");
-}
-
-BOOST_AUTO_TEST_CASE(GetChannels)
-{
-  TcpFactory factory;
-  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
-
-  std::vector<shared_ptr<const Channel>> expectedChannels;
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
-  expectedChannels.push_back(factory.createChannel("::1", "20071"));
-
-  for (const auto& ch : factory.getChannels()) {
-    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), ch);
-    BOOST_REQUIRE(pos != expectedChannels.end());
-    expectedChannels.erase(pos);
-  }
-  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
-}
-
-class FaceCreateFixture : protected BaseFixture
-{
-public:
-  void
-  checkError(const std::string& errorActual, const std::string& errorExpected)
-  {
-    BOOST_CHECK_EQUAL(errorActual, errorExpected);
-  }
-
-  void
-  failIfError(const std::string& errorActual)
-  {
-    BOOST_FAIL("No error expected, but got: [" << errorActual << "]");
-  }
-};
-
-BOOST_FIXTURE_TEST_CASE(FaceCreate, FaceCreateFixture)
-{
-  TcpFactory factory;
-
-  factory.createFace(FaceUri("tcp4://127.0.0.1:6363"),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::checkError, this, _1,
-                          "No channels available to connect to 127.0.0.1:6363"));
-
-  factory.createChannel("127.0.0.1", "20071");
-
-  factory.createFace(FaceUri("tcp4://127.0.0.1:20070"),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::failIfError, this, _1));
-}
-
-BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
-{
-  TcpFactory factory;
-
-  factory.createChannel("127.0.0.1", "20070");
-  factory.createChannel("127.0.0.1", "20071");
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("tcp4://127.0.0.1:20070"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("tcp4://127.0.0.1:20071"),
-                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-}
-
-class EndToEndFixture : protected BaseFixture
-{
-public:
-  void
-  channel1_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    BOOST_CHECK(!static_cast<bool>(face1));
-    face1 = newFace;
-    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
-    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
-    face1->onFail.connect(bind(&EndToEndFixture::face1_onFail, this));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel1_onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveInterest(const Interest& interest)
-  {
-    face1_receivedInterests.push_back(interest);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveData(const Data& data)
-  {
-    face1_receivedDatas.push_back(data);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onFail()
-  {
-    g_io.post([this] {
-      face1.reset();
-      limitedIo.afterOp();
-    });
-  }
-
-  void
-  channel2_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    BOOST_CHECK(!static_cast<bool>(face2));
-    face2 = newFace;
-    face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
-    face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
-    face2->onFail.connect(bind(&EndToEndFixture::face2_onFail, this));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel2_onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face2_onReceiveInterest(const Interest& interest)
-  {
-    face2_receivedInterests.push_back(interest);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face2_onReceiveData(const Data& data)
-  {
-    face2_receivedDatas.push_back(data);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face2_onFail()
-  {
-    g_io.post([this] {
-      face2.reset();
-      limitedIo.afterOp();
-    });
-  }
-
-  void
-  channel_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    faces.push_back(newFace);
-    limitedIo.afterOp();
-  }
-
-  void
-  channel_onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  checkFaceList(size_t shouldBe)
-  {
-    BOOST_CHECK_EQUAL(faces.size(), shouldBe);
-  }
-
-  void
-  connect(const shared_ptr<TcpChannel>& channel,
-          const std::string& remoteHost,
-          const std::string& remotePort)
-  {
-    channel->connect(tcp::Endpoint(boost::asio::ip::address::from_string(remoteHost),
-                                   boost::lexical_cast<uint16_t>(remotePort)),
-                     bind(&EndToEndFixture::channel_onFaceCreated, this, _1),
-                     bind(&EndToEndFixture::channel_onConnectFailed, this, _1));
-  }
-
-public:
-  LimitedIo limitedIo;
-
-  shared_ptr<Face> face1;
-  std::vector<Interest> face1_receivedInterests;
-  std::vector<Data> face1_receivedDatas;
-  shared_ptr<Face> face2;
-  std::vector<Interest> face2_receivedInterests;
-  std::vector<Data> face2_receivedDatas;
-
-  std::list<shared_ptr<Face>> faces;
-};
-
-BOOST_FIXTURE_TEST_CASE(EndToEnd4, EndToEndFixture)
-{
-  TcpFactory factory1;
-
-  shared_ptr<TcpChannel> channel1 = factory1.createChannel("127.0.0.1", "20070");
-  factory1.createChannel("127.0.0.1", "20071");
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), false);
-
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), true);
-
-  TcpFactory factory2;
-
-  shared_ptr<TcpChannel> channel2 = factory2.createChannel("127.0.0.2", "20070");
-  factory2.createChannel("127.0.0.2", "20071");
-
-  factory2.createFace(FaceUri("tcp4://127.0.0.1:20070"),
-                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                      bind(&EndToEndFixture::channel2_onFaceCreated, this, _1),
-                      bind(&EndToEndFixture::channel2_onConnectFailed, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_REQUIRE(static_cast<bool>(face2));
-
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_EQUAL(face2->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
-  BOOST_CHECK_EQUAL(face1->isMultiAccess(), false);
-  BOOST_CHECK_EQUAL(face2->isMultiAccess(), false);
-
-  BOOST_CHECK_EQUAL(face2->getRemoteUri().toString(), "tcp4://127.0.0.1:20070");
-  BOOST_CHECK_EQUAL(face1->getLocalUri().toString(), "tcp4://127.0.0.1:20070");
-  // face1 has an unknown remoteUri, since the source port is automatically chosen by OS
-
-  BOOST_CHECK_EQUAL(face1->isLocal(), true);
-  BOOST_CHECK_EQUAL(face2->isLocal(), true);
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  face1->sendInterest(*interest1);
-  face1->sendInterest(*interest1);
-  face1->sendInterest(*interest1);
-  face1->sendData    (*data1    );
-  size_t nBytesSent1 = interest1->wireEncode().size() * 3 + data1->wireEncode().size();
-  face2->sendInterest(*interest2);
-  face2->sendData    (*data2    );
-  face2->sendData    (*data2    );
-  face2->sendData    (*data2    );
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot send or receive Interest/Data packets");
-
-  BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 3);
-  BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 3);
-  BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
-
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
-
-  // needed to ensure NOutBytes counters are accurate
-  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::seconds(1));
-
-  const face::FaceCounters& counters1 = face1->getCounters();
-  BOOST_CHECK_EQUAL(counters1.nInInterests, 1);
-  BOOST_CHECK_EQUAL(counters1.nInData, 3);
-  BOOST_CHECK_EQUAL(counters1.nOutInterests, 3);
-  BOOST_CHECK_EQUAL(counters1.nOutData, 1);
-  BOOST_CHECK_EQUAL(counters1.nOutBytes, nBytesSent1);
-
-  const face::FaceCounters& counters2 = face2->getCounters();
-  BOOST_CHECK_EQUAL(counters2.nInInterests, 3);
-  BOOST_CHECK_EQUAL(counters2.nInData, 1);
-  BOOST_CHECK_EQUAL(counters2.nOutInterests, 1);
-  BOOST_CHECK_EQUAL(counters2.nOutData, 3);
-  BOOST_CHECK_EQUAL(counters2.nInBytes, nBytesSent1);
-}
-
-BOOST_FIXTURE_TEST_CASE(EndToEnd6, EndToEndFixture)
-{
-  TcpFactory factory1;
-
-  shared_ptr<TcpChannel> channel1 = factory1.createChannel("::1", "20070");
-  shared_ptr<TcpChannel> channel2 = factory1.createChannel("::1", "20071");
-
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
-
-  TcpFactory factory2;
-
-  factory2.createChannel("::2", "20070");
-
-  factory2.createFace(FaceUri("tcp6://[::1]:20070"),
-                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                      bind(&EndToEndFixture::channel2_onFaceCreated, this, _1),
-                      bind(&EndToEndFixture::channel2_onConnectFailed, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_REQUIRE(static_cast<bool>(face2));
-
-  BOOST_CHECK_EQUAL(face2->getRemoteUri().toString(), "tcp6://[::1]:20070");
-  BOOST_CHECK_EQUAL(face1->getLocalUri().toString(), "tcp6://[::1]:20070");
-  // face1 has an unknown remoteUri, since the source port is automatically chosen by OS
-
-  BOOST_CHECK_EQUAL(face1->isLocal(), true);
-  BOOST_CHECK_EQUAL(face2->isLocal(), true);
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  face1->sendInterest(*interest1);
-  face1->sendData    (*data1    );
-  face2->sendInterest(*interest2);
-  face2->sendData    (*data2    );
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(4, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot send or receive Interest/Data packets");
-
-
-  BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 1);
-  BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
-
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
-}
-
-BOOST_FIXTURE_TEST_CASE(MultipleAccepts, EndToEndFixture)
-{
-  TcpFactory factory;
-
-  shared_ptr<TcpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
-  shared_ptr<TcpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
-
-  channel1->listen(bind(&EndToEndFixture::channel_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel_onConnectFailed, this, _1));
-
-  using namespace boost::asio;
-  channel2->connect(tcp::Endpoint(ip::address::from_string("127.0.0.1"), 20070),
-                    bind(&EndToEndFixture::channel_onFaceCreated, this, _1),
-                    bind(&EndToEndFixture::channel_onConnectFailed, this, _1),
-                    time::seconds(4)); // very short timeout
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-
-  BOOST_CHECK_EQUAL(faces.size(), 2);
-
-  shared_ptr<TcpChannel> channel3 = factory.createChannel("127.0.0.1", "20072");
-  channel3->connect(tcp::Endpoint(ip::address::from_string("127.0.0.1"), 20070),
-                    bind(&EndToEndFixture::channel_onFaceCreated, this, _1),
-                    bind(&EndToEndFixture::channel_onConnectFailed, this, _1),
-                    time::seconds(4)); // very short timeout
-
-
-  shared_ptr<TcpChannel> channel4 = factory.createChannel("127.0.0.1", "20073");
-
-  BOOST_CHECK_NE(channel3, channel4);
-
-  scheduler::schedule(time::seconds(1),
-                      bind(&EndToEndFixture::connect, this, channel4, "127.0.0.1", "20070"));
-
-  scheduler::schedule(time::milliseconds(500),
-                      bind(&EndToEndFixture::checkFaceList, this, 4));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(4,// 2 connects and 2 accepts
-                      time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept multiple connections");
-
-  BOOST_CHECK_EQUAL(faces.size(), 6);
-}
-
-BOOST_FIXTURE_TEST_CASE(FaceClosing, EndToEndFixture)
-{
-  TcpFactory factory;
-
-  shared_ptr<TcpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
-  shared_ptr<TcpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
-
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
-
-  using namespace boost::asio;
-  channel2->connect(tcp::Endpoint(ip::address::from_string("127.0.0.1"), 20070),
-                    bind(&EndToEndFixture::channel2_onFaceCreated, this, _1),
-                    bind(&EndToEndFixture::channel2_onConnectFailed, this, _1),
-                    time::seconds(4)); // very short timeout
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-  BOOST_CHECK_EQUAL(channel1->size(), 1);
-  BOOST_CHECK_EQUAL(channel2->size(), 1);
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_CHECK(static_cast<bool>(face2));
-
-  // Face::close must be invoked during io run to be counted as an op
-  scheduler::schedule(time::milliseconds(100), bind(&Face::close, face1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "FaceClosing error: cannot properly close faces");
-
-  // both faces should get closed
-  BOOST_CHECK(!static_cast<bool>(face1));
-  BOOST_CHECK(!static_cast<bool>(face2));
-
-  BOOST_CHECK_EQUAL(channel1->size(), 0);
-  BOOST_CHECK_EQUAL(channel2->size(), 0);
-}
-
-class SimpleEndToEndFixture : protected BaseFixture
-{
-public:
-  void
-  onFaceCreated(const shared_ptr<Face>& face)
-  {
-    face->onReceiveInterest.connect(bind(&SimpleEndToEndFixture::onReceiveInterest, this, _1));
-    face->onReceiveData.connect(bind(&SimpleEndToEndFixture::onReceiveData, this, _1));
-    face->onFail.connect(bind(&SimpleEndToEndFixture::onFail, this, face));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  onReceiveInterest(const Interest& interest)
-  {
-    receivedInterests.push_back(interest);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  onReceiveData(const Data& data)
-  {
-    receivedDatas.push_back(data);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  onFail(const shared_ptr<Face>& face)
-  {
-    limitedIo.afterOp();
-  }
-
-public:
-  LimitedIo limitedIo;
-
-  std::vector<Interest> receivedInterests;
-  std::vector<Data> receivedDatas;
-};
-
-BOOST_FIXTURE_TEST_CASE_TEMPLATE(FaceCorruptedInput, Dataset,
-                                 CorruptedPackets, SimpleEndToEndFixture)
-{
-  // test with non-local Face
-  boost::asio::ip::address_v4 someIpv4Address;
-  for (const auto& netif : listNetworkInterfaces()) {
-    if (!netif.isLoopback() && netif.isUp() && !netif.ipv4Addresses.empty()) {
-      someIpv4Address = netif.ipv4Addresses.front();
-      break;
-    }
-  }
-  if (someIpv4Address.is_unspecified()) {
-    BOOST_TEST_MESSAGE("Test with non-local Face cannot be run "
-                       "(no non-loopback interface with IPv4 address found)");
-    return;
-  }
-
-  TcpFactory factory;
-  tcp::Endpoint endpoint(someIpv4Address, 20070);
-
-  shared_ptr<TcpChannel> channel = factory.createChannel(endpoint);
-  channel->listen(bind(&SimpleEndToEndFixture::onFaceCreated,   this, _1),
-                  bind(&SimpleEndToEndFixture::onConnectFailed, this, _1));
-  BOOST_REQUIRE_EQUAL(channel->isListening(), true);
-
-  DummyStreamSender<boost::asio::ip::tcp, Dataset> sender;
-  sender.start(endpoint);
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(LimitedIo::UNLIMITED_OPS,
-                                    time::seconds(1)) == LimitedIo::EXCEED_TIME,
-                      "Exception thrown for " + Dataset::getName());
-}
-
-class FaceCreateTimeoutFixture : protected BaseFixture
-{
-public:
-  void
-  onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    BOOST_CHECK_MESSAGE(false, "Timeout expected");
-    BOOST_CHECK(!static_cast<bool>(face1));
-    face1 = newFace;
-
-    limitedIo.afterOp();
-  }
-
-  void
-  onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(true, reason);
-
-    limitedIo.afterOp();
-  }
-
-public:
-  LimitedIo limitedIo;
-
-  shared_ptr<Face> face1;
-};
-
-BOOST_FIXTURE_TEST_CASE(FaceCreateTimeout, FaceCreateTimeoutFixture)
-{
-  TcpFactory factory;
-  shared_ptr<TcpChannel> channel = factory.createChannel("0.0.0.0", "20070");
-
-  factory.createFace(FaceUri("tcp4://192.0.2.1:20070"),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     bind(&FaceCreateTimeoutFixture::onFaceCreated, this, _1),
-                     bind(&FaceCreateTimeoutFixture::onConnectFailed, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(1, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-  BOOST_CHECK_EQUAL(static_cast<bool>(face1), false);
-}
-
-BOOST_FIXTURE_TEST_CASE(Bug1856, EndToEndFixture)
-{
-  TcpFactory factory1;
-
-  shared_ptr<TcpChannel> channel1 = factory1.createChannel("127.0.0.1", "20070");
-  factory1.createChannel("127.0.0.1", "20071");
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), false);
-
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), true);
-
-  TcpFactory factory2;
-
-  shared_ptr<TcpChannel> channel2 = factory2.createChannel("127.0.0.2", "20070");
-  factory2.createChannel("127.0.0.2", "20071");
-
-  factory2.createFace(FaceUri("tcp4://127.0.0.1:20070"),
-                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                      bind(&EndToEndFixture::channel2_onFaceCreated, this, _1),
-                      bind(&EndToEndFixture::channel2_onConnectFailed, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "TcpChannel error: cannot connect or cannot accept connection");
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_REQUIRE(static_cast<bool>(face2));
-
-  std::ostringstream hugeName;
-  hugeName << "/huge-name/";
-  for (size_t i = 0; i < ndn::MAX_NDN_PACKET_SIZE; i++)
-    hugeName << 'a';
-
-  shared_ptr<Interest> interest = makeInterest("ndn:/KfczhUqVix");
-  shared_ptr<Interest> hugeInterest = makeInterest(hugeName.str());
-
-  face1->sendInterest(*hugeInterest);
-  face2->sendInterest(*interest);
-  face2->sendInterest(*interest);
-
-  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::seconds(1));
-  BOOST_TEST_MESSAGE("Unexpected assertion test passed");
-}
-
-class FakeNetworkInterfaceFixture : public BaseFixture
-{
-public:
-  FakeNetworkInterfaceFixture()
-  {
-    using namespace boost::asio::ip;
-
-    auto fakeInterfaces = make_shared<std::vector<NetworkInterfaceInfo>>();
-
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {0, "eth0",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("0.0.0.0")},
-        {address_v6::from_string("::")},
-        address_v4(),
-        IFF_UP});
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {1, "eth0",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("192.168.2.1"), address_v4::from_string("192.168.2.2")},
-        {},
-        address_v4::from_string("192.168.2.255"),
-        0});
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {2, "eth1",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("198.51.100.1")},
-        {address_v6::from_string("2001:db8::2"), address_v6::from_string("2001:db8::3")},
-        address_v4::from_string("198.51.100.255"),
-        IFF_MULTICAST | IFF_BROADCAST | IFF_UP});
-
-    setDebugNetworkInterfaces(fakeInterfaces);
-  }
-
-  ~FakeNetworkInterfaceFixture()
-  {
-    setDebugNetworkInterfaces(nullptr);
-  }
-};
-
-BOOST_FIXTURE_TEST_CASE(Bug2292, FakeNetworkInterfaceFixture)
-{
-  using namespace boost::asio::ip;
-
-  TcpFactory factory;
-  factory.prohibitEndpoint(tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<tcp::Endpoint> {
-                 tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(tcp::Endpoint(address_v6::from_string("2001:db8::1"), 2048));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<tcp::Endpoint> {
-                 tcp::Endpoint(address_v6::from_string("2001:db8::1"), 2048)
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(tcp::Endpoint(address_v4(), 1024));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 4);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<tcp::Endpoint> {
-                 tcp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
-                 tcp::Endpoint(address_v4::from_string("192.168.2.2"), 1024),
-                 tcp::Endpoint(address_v4::from_string("198.51.100.1"), 1024),
-                 tcp::Endpoint(address_v4::from_string("0.0.0.0"), 1024)
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(tcp::Endpoint(address_v6(), 2048));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 3);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<tcp::Endpoint> {
-                 tcp::Endpoint(address_v6::from_string("2001:db8::2"), 2048),
-                 tcp::Endpoint(address_v6::from_string("2001:db8::3"), 2048),
-                 tcp::Endpoint(address_v6::from_string("::"), 2048)
-               }));
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestTcp
-BOOST_AUTO_TEST_SUITE_END() // Face
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/face/transport.t.cpp b/tests/daemon/face/transport.t.cpp
index 8189859..9a59491 100644
--- a/tests/daemon/face/transport.t.cpp
+++ b/tests/daemon/face/transport.t.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "face/transport.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 #include "dummy-transport.hpp"
 #include "dummy-receive-link-service.hpp"
 #include "transport-test-common.hpp"
@@ -45,6 +45,8 @@
 
 BOOST_AUTO_TEST_SUITE(Face)
 
+using nfd::Face;
+
 class DummyTransportFixture : public BaseFixture
 {
 public:
@@ -60,14 +62,14 @@
   void
   initialize(unique_ptr<DummyTransport> transport = make_unique<DummyTransport>())
   {
-    this->face = make_unique<LpFace>(make_unique<DummyReceiveLinkService>(), std::move(transport));
+    this->face = make_unique<Face>(make_unique<DummyReceiveLinkService>(), std::move(transport));
     this->transport = static_cast<DummyTransport*>(face->getTransport());
     this->sentPackets = &this->transport->sentPackets;
     this->receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
   }
 
 public:
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
   DummyTransport* transport;
   std::vector<Transport::Packet>* sentPackets;
   std::vector<Transport::Packet>* receivedPackets;
diff --git a/tests/daemon/face/udp-channel.t.cpp b/tests/daemon/face/udp-channel.t.cpp
new file mode 100644
index 0000000..447ec0d
--- /dev/null
+++ b/tests/daemon/face/udp-channel.t.cpp
@@ -0,0 +1,47 @@
+/* -*- 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 "face/udp-channel.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestUdpChannel, BaseFixture)
+
+using nfd::Face;
+
+// TODO add the equivalent of these test cases from udp.t.cpp as of commit:65caf200924b28748037750449e28bcb548dbc9c
+// MultipleAccepts
+// ManualClose
+// IdleClose
+
+BOOST_AUTO_TEST_SUITE_END() // TestUdpChannel
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/udp-factory.t.cpp b/tests/daemon/face/udp-factory.t.cpp
new file mode 100644
index 0000000..837262c
--- /dev/null
+++ b/tests/daemon/face/udp-factory.t.cpp
@@ -0,0 +1,335 @@
+/* -*- 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 "face/udp-factory.hpp"
+
+#include "core/network-interface.hpp"
+#include "tests/test-common.hpp"
+#include "tests/limited-io.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestUdpFactory, BaseFixture)
+
+using nfd::Face;
+
+BOOST_AUTO_TEST_CASE(GetChannels)
+{
+  UdpFactory factory;
+  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
+
+  std::vector<shared_ptr<const Channel>> expectedChannels;
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
+  expectedChannels.push_back(factory.createChannel("::1", "20071"));
+
+  for (const auto& i : factory.getChannels()) {
+    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), i);
+    BOOST_REQUIRE(pos != expectedChannels.end());
+    expectedChannels.erase(pos);
+  }
+
+  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
+}
+
+class FactoryErrorCheck : public BaseFixture
+{
+public:
+  bool
+  isTheSameMulticastEndpoint(const UdpFactory::Error& e) {
+    return strcmp(e.what(),
+                  "Cannot create the requested UDP unicast channel, local "
+                  "endpoint is already allocated for a UDP multicast face") == 0;
+  }
+
+  bool
+  isNotMulticastAddress(const UdpFactory::Error& e) {
+    return strcmp(e.what(),
+                  "Cannot create the requested UDP multicast face, "
+                  "the multicast group given as input is not a multicast address") == 0;
+  }
+
+  bool
+  isTheSameUnicastEndpoint(const UdpFactory::Error& e) {
+    return strcmp(e.what(),
+                  "Cannot create the requested UDP multicast face, local "
+                  "endpoint is already allocated for a UDP unicast channel") == 0;
+  }
+
+  bool
+  isLocalEndpointOnDifferentGroup(const UdpFactory::Error& e) {
+    return strcmp(e.what(),
+                  "Cannot create the requested UDP multicast face, local "
+                  "endpoint is already allocated for a UDP multicast face "
+                  "on a different multicast group") == 0;
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(ChannelMapUdp, FactoryErrorCheck)
+{
+  using boost::asio::ip::udp;
+
+  UdpFactory factory = UdpFactory();
+
+  //to instantiate multicast face on a specific ip address, change interfaceIp
+  std::string interfaceIp = "0.0.0.0";
+
+  shared_ptr<UdpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
+  shared_ptr<UdpChannel> channel1a = factory.createChannel("127.0.0.1", "20070");
+  BOOST_CHECK_EQUAL(channel1, channel1a);
+  BOOST_CHECK_EQUAL(channel1->getUri().toString(), "udp4://127.0.0.1:20070");
+
+  shared_ptr<UdpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
+  BOOST_CHECK_NE(channel1, channel2);
+
+  shared_ptr<UdpChannel> channel3 = factory.createChannel(interfaceIp, "20070");
+
+  shared_ptr<UdpChannel> channel4 = factory.createChannel("::1", "20071");
+  BOOST_CHECK_NE(channel2, channel4);
+  BOOST_CHECK_EQUAL(channel4->getUri().toString(), "udp6://[::1]:20071");
+
+  //same endpoint of a unicast channel
+  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "224.0.0.1", "20070"),
+                        UdpFactory::Error, isTheSameUnicastEndpoint);
+
+  auto multicastFace1  = factory.createMulticastFace(interfaceIp, "224.0.0.1", "20072");
+  auto multicastFace1a = factory.createMulticastFace(interfaceIp, "224.0.0.1", "20072");
+  BOOST_CHECK_EQUAL(multicastFace1, multicastFace1a);
+
+  //same endpoint of a multicast face
+  BOOST_CHECK_EXCEPTION(factory.createChannel(interfaceIp, "20072"),
+                        UdpFactory::Error, isTheSameMulticastEndpoint);
+
+  //same multicast endpoint, different group
+  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "224.0.0.42", "20072"),
+                        UdpFactory::Error, isLocalEndpointOnDifferentGroup);
+
+  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "192.168.10.15", "20025"),
+                        UdpFactory::Error, isNotMulticastAddress);
+
+
+//  //Test commented because it required to be run in a machine that can resolve ipv6 query
+//  shared_ptr<UdpChannel> channel1v6 = factory.createChannel(//"::1",
+//                                                     "fe80::5e96:9dff:fe7d:9c8d%en1",
+//                                                     //"fe80::aa54:b2ff:fe08:27b8%wlan0",
+//                                                     "20070");
+//
+//  //the creation of multicastFace2 works properly. It has been disable because it needs an IP address of
+//  //an available network interface (different from the first one used)
+//  shared_ptr<MulticastUdpFace> multicastFace2 = factory.createMulticastFace("192.168.1.17",
+//                                                                            "224.0.0.1",
+//                                                                            "20073");
+//  BOOST_CHECK_NE(multicastFace1, multicastFace2);
+//
+//
+//  //ipv6 - work in progress
+//  shared_ptr<MulticastUdpFace> multicastFace3 = factory.createMulticastFace("fe80::5e96:9dff:fe7d:9c8d%en1",
+//                                                                            "FF01:0:0:0:0:0:0:2",
+//                                                                            "20073");
+//
+//  shared_ptr<MulticastUdpFace> multicastFace4 = factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
+//                                                                            "FF01:0:0:0:0:0:0:2",
+//                                                                            "20073");
+//
+//  BOOST_CHECK_EQUAL(multicastFace3, multicastFace4);
+//
+//  shared_ptr<MulticastUdpFace> multicastFace5 = factory.createMulticastFace("::1",
+//                                                                            "FF01:0:0:0:0:0:0:2",
+//                                                                            "20073");
+//
+//  BOOST_CHECK_NE(multicastFace3, multicastFace5);
+//
+//  //same local ipv6 endpoint for a different multicast group
+//  BOOST_CHECK_THROW(factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
+//                                                "FE01:0:0:0:0:0:0:2",
+//                                                "20073"),
+//                    UdpFactory::Error);
+//
+//  //same local ipv6 (expect for th port number) endpoint for a different multicast group
+//  BOOST_CHECK_THROW(factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
+//                                                "FE01:0:0:0:0:0:0:2",
+//                                                "20075"),
+//                    UdpFactory::Error);
+//
+//  BOOST_CHECK_THROW(factory.createMulticastFace("fa80::20a:9dff:fef6:12ff",
+//                                                "FE12:0:0:0:0:0:0:2",
+//                                                "20075"),
+//                    UdpFactory::Error);
+//
+//  //not a multicast ipv6
+//  BOOST_CHECK_THROW(factory.createMulticastFace("fa80::20a:9dff:fef6:12ff",
+//                                                "A112:0:0:0:0:0:0:2",
+//                                                "20075"),
+//                    UdpFactory::Error);
+}
+
+class FaceCreateFixture : protected BaseFixture
+{
+public:
+  void
+  checkError(const std::string& errorActual, const std::string& errorExpected)
+  {
+    BOOST_CHECK_EQUAL(errorActual, errorExpected);
+  }
+
+  void
+  failIfError(const std::string& errorActual)
+  {
+    BOOST_FAIL("No error expected, but got: [" << errorActual << "]");
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(FaceCreate, FaceCreateFixture)
+{
+  UdpFactory factory = UdpFactory();
+
+  factory.createFace(FaceUri("udp4://127.0.0.1:6363"),
+                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::checkError, this, _1,
+                          "No channels available to connect to 127.0.0.1:6363"));
+
+  factory.createChannel("127.0.0.1", "20071");
+
+  factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
+                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::failIfError, this, _1));
+  //test the upgrade
+  factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
+                     ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::failIfError, this, _1));
+
+  factory.createFace(FaceUri("udp4://127.0.0.1:20072"),
+                     ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                     bind([]{}),
+                     bind(&FaceCreateFixture::failIfError, this, _1));
+}
+
+BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
+{
+  UdpFactory factory;
+
+  factory.createChannel("127.0.0.1", "20070");
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
+                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+}
+
+class FakeNetworkInterfaceFixture : public BaseFixture
+{
+public:
+  FakeNetworkInterfaceFixture()
+  {
+    using namespace boost::asio::ip;
+
+    auto fakeInterfaces = make_shared<std::vector<NetworkInterfaceInfo>>();
+
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {0, "eth0",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("0.0.0.0")},
+        {address_v6::from_string("::")},
+        address_v4(),
+        IFF_UP});
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {1, "eth0",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("192.168.2.1"), address_v4::from_string("192.168.2.2")},
+        {},
+        address_v4::from_string("192.168.2.255"),
+        0});
+    fakeInterfaces->push_back(
+      NetworkInterfaceInfo {2, "eth1",
+        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
+        {address_v4::from_string("198.51.100.1")},
+        {address_v6::from_string("2001:db8::2"), address_v6::from_string("2001:db8::3")},
+        address_v4::from_string("198.51.100.255"),
+        IFF_MULTICAST | IFF_BROADCAST | IFF_UP});
+
+    setDebugNetworkInterfaces(fakeInterfaces);
+  }
+
+  ~FakeNetworkInterfaceFixture()
+  {
+    setDebugNetworkInterfaces(nullptr);
+  }
+};
+
+BOOST_FIXTURE_TEST_CASE(Bug2292, FakeNetworkInterfaceFixture)
+{
+  using namespace boost::asio::ip;
+
+  UdpFactory factory;
+  factory.prohibitEndpoint(udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<udp::Endpoint> {
+                 udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(udp::Endpoint(address_v6::from_string("2001:db8::1"), 2048));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<udp::Endpoint> {
+                 udp::Endpoint(address_v6::from_string("2001:db8::1"), 2048),
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(udp::Endpoint(address_v4(), 1024));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 6);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<udp::Endpoint> {
+                 udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
+                 udp::Endpoint(address_v4::from_string("192.168.2.2"), 1024),
+                 udp::Endpoint(address_v4::from_string("198.51.100.1"), 1024),
+                 udp::Endpoint(address_v4::from_string("198.51.100.255"), 1024),
+                 udp::Endpoint(address_v4::from_string("255.255.255.255"), 1024),
+                 udp::Endpoint(address_v4::from_string("0.0.0.0"), 1024)
+               }));
+
+  factory.m_prohibitedEndpoints.clear();
+  factory.prohibitEndpoint(udp::Endpoint(address_v6(), 2048));
+  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 3);
+  BOOST_CHECK((factory.m_prohibitedEndpoints ==
+               std::set<udp::Endpoint> {
+                 udp::Endpoint(address_v6::from_string("2001:db8::2"), 2048),
+                 udp::Endpoint(address_v6::from_string("2001:db8::3"), 2048),
+                 udp::Endpoint(address_v6::from_string("::"), 2048),
+               }));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestUdpFactory
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/udp.t.cpp b/tests/daemon/face/udp.t.cpp
deleted file mode 100644
index d38c908..0000000
--- a/tests/daemon/face/udp.t.cpp
+++ /dev/null
@@ -1,704 +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 "face/udp-channel.hpp"
-#include "face/udp-factory.hpp"
-
-#include "core/network-interface.hpp"
-#include "tests/test-common.hpp"
-#include "tests/limited-io.hpp"
-#include "face-history.hpp"
-
-namespace nfd {
-namespace tests {
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestUdp, BaseFixture)
-
-using nfd::Face;
-
-BOOST_AUTO_TEST_CASE(GetChannels)
-{
-  UdpFactory factory;
-  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
-
-  std::vector<shared_ptr<const Channel>> expectedChannels;
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
-  expectedChannels.push_back(factory.createChannel("::1", "20071"));
-
-  for (const auto& i : factory.getChannels()) {
-    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), i);
-    BOOST_REQUIRE(pos != expectedChannels.end());
-    expectedChannels.erase(pos);
-  }
-
-  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
-}
-
-class FactoryErrorCheck : protected BaseFixture
-{
-public:
-  bool
-  isTheSameMulticastEndpoint(const UdpFactory::Error& e) {
-    return strcmp(e.what(),
-                  "Cannot create the requested UDP unicast channel, local "
-                  "endpoint is already allocated for a UDP multicast face") == 0;
-  }
-
-  bool
-  isNotMulticastAddress(const UdpFactory::Error& e) {
-    return strcmp(e.what(),
-                  "Cannot create the requested UDP multicast face, "
-                  "the multicast group given as input is not a multicast address") == 0;
-  }
-
-  bool
-  isTheSameUnicastEndpoint(const UdpFactory::Error& e) {
-    return strcmp(e.what(),
-                  "Cannot create the requested UDP multicast face, local "
-                  "endpoint is already allocated for a UDP unicast channel") == 0;
-  }
-
-  bool
-  isLocalEndpointOnDifferentGroup(const UdpFactory::Error& e) {
-    return strcmp(e.what(),
-                  "Cannot create the requested UDP multicast face, local "
-                  "endpoint is already allocated for a UDP multicast face "
-                  "on a different multicast group") == 0;
-  }
-};
-
-BOOST_FIXTURE_TEST_CASE(ChannelMapUdp, FactoryErrorCheck)
-{
-  using boost::asio::ip::udp;
-
-  UdpFactory factory = UdpFactory();
-
-  //to instantiate multicast face on a specific ip address, change interfaceIp
-  std::string interfaceIp = "0.0.0.0";
-
-  shared_ptr<UdpChannel> channel1 = factory.createChannel("127.0.0.1", "20070");
-  shared_ptr<UdpChannel> channel1a = factory.createChannel("127.0.0.1", "20070");
-  BOOST_CHECK_EQUAL(channel1, channel1a);
-  BOOST_CHECK_EQUAL(channel1->getUri().toString(), "udp4://127.0.0.1:20070");
-
-  shared_ptr<UdpChannel> channel2 = factory.createChannel("127.0.0.1", "20071");
-  BOOST_CHECK_NE(channel1, channel2);
-
-  shared_ptr<UdpChannel> channel3 = factory.createChannel(interfaceIp, "20070");
-
-  shared_ptr<UdpChannel> channel4 = factory.createChannel("::1", "20071");
-  BOOST_CHECK_NE(channel2, channel4);
-  BOOST_CHECK_EQUAL(channel4->getUri().toString(), "udp6://[::1]:20071");
-
-  //same endpoint of a unicast channel
-  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "224.0.0.1", "20070"),
-                        UdpFactory::Error, isTheSameUnicastEndpoint);
-
-  auto multicastFace1  = factory.createMulticastFace(interfaceIp, "224.0.0.1", "20072");
-  auto multicastFace1a = factory.createMulticastFace(interfaceIp, "224.0.0.1", "20072");
-  BOOST_CHECK_EQUAL(multicastFace1, multicastFace1a);
-  BOOST_CHECK_EQUAL(multicastFace1->isLocal(), false);
-  BOOST_CHECK_EQUAL(multicastFace1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
-  BOOST_CHECK_EQUAL(multicastFace1->isMultiAccess(), true);
-
-  //same endpoint of a multicast face
-  BOOST_CHECK_EXCEPTION(factory.createChannel(interfaceIp, "20072"),
-                        UdpFactory::Error, isTheSameMulticastEndpoint);
-
-  //same multicast endpoint, different group
-  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "224.0.0.42", "20072"),
-                        UdpFactory::Error, isLocalEndpointOnDifferentGroup);
-
-  BOOST_CHECK_EXCEPTION(factory.createMulticastFace(interfaceIp, "192.168.10.15", "20025"),
-                        UdpFactory::Error, isNotMulticastAddress);
-
-
-//  //Test commented because it required to be run in a machine that can resolve ipv6 query
-//  shared_ptr<UdpChannel> channel1v6 = factory.createChannel(//"::1",
-//                                                     "fe80::5e96:9dff:fe7d:9c8d%en1",
-//                                                     //"fe80::aa54:b2ff:fe08:27b8%wlan0",
-//                                                     "20070");
-//
-//  //the creation of multicastFace2 works properly. It has been disable because it needs an IP address of
-//  //an available network interface (different from the first one used)
-//  shared_ptr<MulticastUdpFace> multicastFace2 = factory.createMulticastFace("192.168.1.17",
-//                                                                            "224.0.0.1",
-//                                                                            "20073");
-//  BOOST_CHECK_NE(multicastFace1, multicastFace2);
-//
-//
-//  //ipv6 - work in progress
-//  shared_ptr<MulticastUdpFace> multicastFace3 = factory.createMulticastFace("fe80::5e96:9dff:fe7d:9c8d%en1",
-//                                                                            "FF01:0:0:0:0:0:0:2",
-//                                                                            "20073");
-//
-//  shared_ptr<MulticastUdpFace> multicastFace4 = factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
-//                                                                            "FF01:0:0:0:0:0:0:2",
-//                                                                            "20073");
-//
-//  BOOST_CHECK_EQUAL(multicastFace3, multicastFace4);
-//
-//  shared_ptr<MulticastUdpFace> multicastFace5 = factory.createMulticastFace("::1",
-//                                                                            "FF01:0:0:0:0:0:0:2",
-//                                                                            "20073");
-//
-//  BOOST_CHECK_NE(multicastFace3, multicastFace5);
-//
-//  //same local ipv6 endpoint for a different multicast group
-//  BOOST_CHECK_THROW(factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
-//                                                "FE01:0:0:0:0:0:0:2",
-//                                                "20073"),
-//                    UdpFactory::Error);
-//
-//  //same local ipv6 (expect for th port number) endpoint for a different multicast group
-//  BOOST_CHECK_THROW(factory.createMulticastFace("fe80::aa54:b2ff:fe08:27b8%wlan0",
-//                                                "FE01:0:0:0:0:0:0:2",
-//                                                "20075"),
-//                    UdpFactory::Error);
-//
-//  BOOST_CHECK_THROW(factory.createMulticastFace("fa80::20a:9dff:fef6:12ff",
-//                                                "FE12:0:0:0:0:0:0:2",
-//                                                "20075"),
-//                    UdpFactory::Error);
-//
-//  //not a multicast ipv6
-//  BOOST_CHECK_THROW(factory.createMulticastFace("fa80::20a:9dff:fef6:12ff",
-//                                                "A112:0:0:0:0:0:0:2",
-//                                                "20075"),
-//                    UdpFactory::Error);
-}
-
-class FaceCreateFixture : protected BaseFixture
-{
-public:
-  void
-  checkError(const std::string& errorActual, const std::string& errorExpected)
-  {
-    BOOST_CHECK_EQUAL(errorActual, errorExpected);
-  }
-
-  void
-  failIfError(const std::string& errorActual)
-  {
-    BOOST_FAIL("No error expected, but got: [" << errorActual << "]");
-  }
-};
-
-BOOST_FIXTURE_TEST_CASE(FaceCreate, FaceCreateFixture)
-{
-  UdpFactory factory = UdpFactory();
-
-  factory.createFace(FaceUri("udp4://127.0.0.1:6363"),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::checkError, this, _1,
-                          "No channels available to connect to 127.0.0.1:6363"));
-
-  factory.createChannel("127.0.0.1", "20071");
-
-  factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::failIfError, this, _1));
-  //test the upgrade
-  factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
-                     ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::failIfError, this, _1));
-
-  factory.createFace(FaceUri("udp4://127.0.0.1:20072"),
-                     ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                     bind([]{}),
-                     bind(&FaceCreateFixture::failIfError, this, _1));
-}
-
-BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
-{
-  UdpFactory factory;
-
-  factory.createChannel("127.0.0.1", "20070");
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("udp4://127.0.0.1:20070"),
-                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-}
-
-class EndToEndIpv4
-{
-public:
-  static const std::string
-  getScheme()
-  {
-    return "udp4";
-  }
-
-  static const std::string
-  getLocalIp()
-  {
-    return "127.0.0.1";
-  }
-
-  static const std::string
-  getPort1()
-  {
-    return "20071";
-  }
-
-  static const std::string
-  getPort2()
-  {
-    return "20072";
-  }
-
-  static const std::string
-  getPort3()
-  {
-    return "20073";
-  }
-
-  static const FaceUri
-  getFaceUri1()
-  {
-    return FaceUri("udp4://127.0.0.1:20071");
-  }
-
-  static const FaceUri
-  getFaceUri2()
-  {
-    return FaceUri("udp4://127.0.0.1:20072");
-  }
-
-  static const FaceUri
-  getFaceUri3()
-  {
-    return FaceUri("udp4://127.0.0.1:20073");
-  }
-};
-
-class EndToEndIpv6
-{
-public:
-  static const std::string
-  getScheme()
-  {
-    return "udp6";
-  }
-
-  static const std::string
-  getLocalIp()
-  {
-    return "::1";
-  }
-
-  static const std::string
-  getPort1()
-  {
-    return "20071";
-  }
-
-  static const std::string
-  getPort2()
-  {
-    return "20072";
-  }
-
-  static const std::string
-  getPort3()
-  {
-    return "20073";
-  }
-
-  static const FaceUri
-  getFaceUri1()
-  {
-    return FaceUri("udp6://[::1]:20071");
-  }
-
-  static const FaceUri
-  getFaceUri2()
-  {
-    return FaceUri("udp6://[::1]:20072");
-  }
-
-  static const FaceUri
-  getFaceUri3()
-  {
-    return FaceUri("udp6://[::1]:20073");
-  }
-};
-
-typedef boost::mpl::list<EndToEndIpv4, EndToEndIpv6> EndToEndAddresses;
-
-// end to end communication
-BOOST_AUTO_TEST_CASE_TEMPLATE(EndToEnd, A, EndToEndAddresses)
-{
-  LimitedIo limitedIo;
-  UdpFactory factory;
-
-  shared_ptr<UdpChannel> channel1 = factory.createChannel(A::getLocalIp(), A::getPort1());
-
-  // face1 (on channel1) connects to face2 (on channel2, to be created)
-  shared_ptr<Face> face1;
-  unique_ptr<FaceHistory> history1;
-  factory.createFace(A::getFaceUri2(),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     [&] (shared_ptr<Face> newFace) {
-                       face1 = newFace;
-                       history1.reset(new FaceHistory(*face1, limitedIo));
-                       limitedIo.afterOp();
-                     },
-                     [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::seconds(1));
-  BOOST_REQUIRE(face1 != nullptr);
-  BOOST_CHECK_EQUAL(face1->getRemoteUri(), A::getFaceUri2());
-  BOOST_CHECK_EQUAL(face1->getLocalUri(), A::getFaceUri1());
-  BOOST_CHECK_EQUAL(face1->isLocal(), false); // UdpFace is never local
-  BOOST_CHECK_EQUAL(face1->getCounters().nInBytes, 0);
-  BOOST_CHECK_EQUAL(face1->getCounters().nOutBytes, 0);
-
-  // channel2 creation must be after face1 creation,
-  // otherwise channel2's endpoint would be prohibited
-  shared_ptr<UdpChannel> channel2 = factory.createChannel(A::getLocalIp(), A::getPort2());
-  shared_ptr<Face> face2;
-  unique_ptr<FaceHistory> history2;
-  channel2->listen([&] (shared_ptr<Face> newFace) {
-                     BOOST_CHECK(face2 == nullptr);
-                     face2 = newFace;
-                     history2.reset(new FaceHistory(*face2, limitedIo));
-                     limitedIo.afterOp();
-                   },
-                   [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::seconds(1));
-  BOOST_CHECK(face2 == nullptr); // face2 shouldn't be created until face1 sends something
-
-  shared_ptr<Interest> interest1 = makeInterest("/I1");
-  shared_ptr<Interest> interest2 = makeInterest("/I2");
-  shared_ptr<Data> data1 = makeData("/D1");
-  shared_ptr<Data> data2 = makeData("/D2");
-
-  // face1 sends to channel2, creates face2
-  face1->sendInterest(*interest1);
-  face1->sendData(*data1);
-  face1->sendData(*data1);
-  face1->sendData(*data1);
-  size_t nBytesSent1 = interest1->wireEncode().size() + 3 * data1->wireEncode().size();
-
-  limitedIo.run(5, time::seconds(1)); // 1 accept, 4 receives
-
-  BOOST_REQUIRE(face2 != nullptr);
-  BOOST_CHECK_EQUAL(face2->getRemoteUri(), A::getFaceUri1());
-  BOOST_CHECK_EQUAL(face2->getLocalUri(), A::getFaceUri2());
-  BOOST_CHECK_EQUAL(face2->isLocal(), false); // UdpFace is never local
-  BOOST_CHECK_EQUAL(face2->getCounters().nInBytes, nBytesSent1);
-  BOOST_CHECK_EQUAL(face2->getCounters().nOutBytes, 0);
-
-  BOOST_REQUIRE_EQUAL(history2->receivedInterests.size(), 1);
-  BOOST_CHECK_EQUAL(history2->receivedInterests.front().getName(), interest1->getName());
-  BOOST_REQUIRE_EQUAL(history2->receivedData.size(), 3);
-  BOOST_CHECK_EQUAL(history2->receivedData.front().getName(), data1->getName());
-
-  // face2 sends to face1
-  face2->sendInterest(*interest2);
-  face2->sendInterest(*interest2);
-  face2->sendInterest(*interest2);
-  face2->sendData(*data2);
-  size_t nBytesSent2 = 3 * interest2->wireEncode().size() + data2->wireEncode().size();
-
-  limitedIo.run(4, time::seconds(1)); // 4 receives
-
-  BOOST_REQUIRE_EQUAL(history1->receivedInterests.size(), 3);
-  BOOST_CHECK_EQUAL(history1->receivedInterests.front().getName(), interest2->getName());
-  BOOST_REQUIRE_EQUAL(history1->receivedData.size(), 1);
-  BOOST_CHECK_EQUAL(history1->receivedData.front().getName(), data2->getName());
-
-  // counters
-  const face::FaceCounters& counters1 = face1->getCounters();
-  BOOST_CHECK_EQUAL(counters1.nInInterests, 3);
-  BOOST_CHECK_EQUAL(counters1.nInData, 1);
-  BOOST_CHECK_EQUAL(counters1.nOutInterests, 1);
-  BOOST_CHECK_EQUAL(counters1.nOutData, 3);
-  BOOST_CHECK_EQUAL(counters1.nInBytes, nBytesSent2);
-  BOOST_CHECK_EQUAL(counters1.nOutBytes, nBytesSent1);
-
-  const face::FaceCounters& counters2 = face2->getCounters();
-  BOOST_CHECK_EQUAL(counters2.nInInterests, 1);
-  BOOST_CHECK_EQUAL(counters2.nInData, 3);
-  BOOST_CHECK_EQUAL(counters2.nOutInterests, 3);
-  BOOST_CHECK_EQUAL(counters2.nOutData, 1);
-  BOOST_CHECK_EQUAL(counters2.nInBytes, nBytesSent1);
-  BOOST_CHECK_EQUAL(counters2.nOutBytes, nBytesSent2);
-}
-
-// channel accepting multiple incoming connections
-BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleAccepts, A, EndToEndAddresses)
-{
-  LimitedIo limitedIo;
-  UdpFactory factory;
-
-  // channel1 is listening
-  shared_ptr<UdpChannel> channel1 = factory.createChannel(A::getLocalIp(), A::getPort1());
-  std::vector<shared_ptr<Face>> faces1;
-  channel1->listen([&] (shared_ptr<Face> newFace) {
-                     faces1.push_back(newFace);
-                     limitedIo.afterOp();
-                   },
-                   [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  // face2 (on channel2) connects to channel1
-  shared_ptr<UdpChannel> channel2 = factory.createChannel(A::getLocalIp(), A::getPort2());
-  BOOST_CHECK_NE(channel1, channel2);
-  shared_ptr<Face> face2;
-  boost::asio::ip::address ipAddress2 = boost::asio::ip::address::from_string(A::getLocalIp());
-  udp::Endpoint endpoint2(ipAddress2, boost::lexical_cast<uint16_t>(A::getPort1()));
-  channel2->connect(endpoint2,
-                    ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                    [&] (shared_ptr<Face> newFace) {
-                      face2 = newFace;
-                      limitedIo.afterOp();
-                    },
-                    [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::seconds(1)); // 1 create (on channel2)
-  BOOST_REQUIRE(face2 != nullptr);
-  BOOST_CHECK_EQUAL(faces1.size(), 0); // channel1 won't create face until face2 sends something
-
-  // face3 (on channel3) connects to channel1
-  shared_ptr<UdpChannel> channel3 = factory.createChannel(A::getLocalIp(), A::getPort3());
-  BOOST_CHECK_NE(channel1, channel3);
-  shared_ptr<Face> face3;
-  boost::asio::ip::address ipAddress3 = boost::asio::ip::address::from_string(A::getLocalIp());
-  udp::Endpoint endpoint3(ipAddress3, boost::lexical_cast<uint16_t>(A::getPort1()));
-  channel3->connect(endpoint3,
-                    ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                    [&] (shared_ptr<Face> newFace) {
-                      face3 = newFace;
-                      limitedIo.afterOp();
-                    },
-                    [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::seconds(1)); // 1 create (on channel3)
-  BOOST_REQUIRE(face3 != nullptr);
-  BOOST_CHECK_EQUAL(faces1.size(), 0); // channel1 won't create face until face3 sends something
-
-  // face2 sends to channel1
-  shared_ptr<Interest> interest2 = makeInterest("/I2");
-  face2->sendInterest(*interest2);
-  limitedIo.run(1, time::milliseconds(100)); // 1 accept (on channel1)
-  BOOST_REQUIRE_EQUAL(faces1.size(), 1);
-  BOOST_CHECK_EQUAL(channel1->size(), 1);
-  BOOST_CHECK_EQUAL(faces1.at(0)->getRemoteUri(), A::getFaceUri2());
-
-  // face3 sends to channel1
-  shared_ptr<Data> data3 = makeData("/D3");
-  face3->sendData(*data3);
-  limitedIo.run(1, time::milliseconds(100)); // 1 accept (on channel1)
-  BOOST_REQUIRE_EQUAL(faces1.size(), 2);
-  BOOST_CHECK_EQUAL(channel1->size(), 2);
-  BOOST_CHECK_EQUAL(faces1.at(1)->getRemoteUri(), A::getFaceUri3());
-}
-
-// manually close a face
-BOOST_AUTO_TEST_CASE_TEMPLATE(ManualClose, A, EndToEndAddresses)
-{
-  LimitedIo limitedIo;
-  UdpFactory factory;
-
-  shared_ptr<UdpChannel> channel1 = factory.createChannel(A::getLocalIp(), A::getPort1());
-  shared_ptr<Face> face1;
-  unique_ptr<FaceHistory> history1;
-  factory.createFace(A::getFaceUri2(),
-                     ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                     [&] (shared_ptr<Face> newFace) {
-                       face1 = newFace;
-                       history1.reset(new FaceHistory(*face1, limitedIo));
-                       limitedIo.afterOp();
-                     },
-                     [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::milliseconds(100));
-  BOOST_REQUIRE(face1 != nullptr);
-  BOOST_CHECK_EQUAL(channel1->size(), 1);
-
-  face1->close();
-  getGlobalIoService().poll();
-  BOOST_CHECK_EQUAL(history1->failures.size(), 1);
-  BOOST_CHECK_EQUAL(channel1->size(), 0);
-}
-
-// automatically close an idle incoming face
-BOOST_AUTO_TEST_CASE_TEMPLATE(IdleClose, A, EndToEndAddresses)
-{
-  LimitedIo limitedIo;
-  UdpFactory factory;
-
-  // channel1 is listening
-  shared_ptr<UdpChannel> channel1 = factory.createChannel(A::getLocalIp(), A::getPort1(),
-                                                          time::seconds(2));
-  shared_ptr<Face> face1;
-  unique_ptr<FaceHistory> history1;
-  channel1->listen([&] (shared_ptr<Face> newFace) {
-                     BOOST_CHECK(face1 == nullptr);
-                     face1 = newFace;
-                     history1.reset(new FaceHistory(*face1, limitedIo));
-                     limitedIo.afterOp();
-                   },
-                   [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  // face2 (on channel2) connects to channel1
-  shared_ptr<UdpChannel> channel2 = factory.createChannel(A::getLocalIp(), A::getPort2(),
-                                                          time::seconds(2));
-  shared_ptr<Face> face2;
-  unique_ptr<FaceHistory> history2;
-  boost::asio::ip::address ipAddress = boost::asio::ip::address::from_string(A::getLocalIp());
-  udp::Endpoint endpoint(ipAddress, boost::lexical_cast<uint16_t>(A::getPort1()));
-  channel2->connect(endpoint,
-                    ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                    [&] (shared_ptr<Face> newFace) {
-                      face2 = newFace;
-                      history2.reset(new FaceHistory(*face2, limitedIo));
-                      limitedIo.afterOp();
-                    },
-                    [] (const std::string& reason) { BOOST_ERROR(reason); });
-
-  limitedIo.run(1, time::milliseconds(100)); // 1 create (on channel2)
-  BOOST_REQUIRE(face2 != nullptr);
-  BOOST_CHECK_EQUAL(face2->getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
-  BOOST_CHECK_EQUAL(face2->isMultiAccess(), false);
-
-  // face2 sends to channel1, creates face1
-  shared_ptr<Interest> interest2 = makeInterest("/I2");
-  face2->sendInterest(*interest2);
-
-  limitedIo.run(2, time::seconds(1)); // 1 accept (on channel1), 1 receive (on face1)
-  BOOST_CHECK_EQUAL(channel1->size(), 1);
-  BOOST_REQUIRE(face1 != nullptr);
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_EQUAL(face1->isMultiAccess(), false);
-
-  limitedIo.defer(time::seconds(1));
-  BOOST_CHECK_EQUAL(history1->failures.size(), 0); // face1 is not idle
-  BOOST_CHECK_EQUAL(history2->failures.size(), 0); // face2 is outgoing face and never closed
-
-  limitedIo.defer(time::seconds(4));
-  BOOST_CHECK_EQUAL(history1->failures.size(), 1); // face1 is idle and automatically closed
-  BOOST_CHECK_EQUAL(channel1->size(), 0);
-  BOOST_CHECK_EQUAL(history2->failures.size(), 0); // face2 is outgoing face and never closed
-}
-
-class FakeNetworkInterfaceFixture : public BaseFixture
-{
-public:
-  FakeNetworkInterfaceFixture()
-  {
-    using namespace boost::asio::ip;
-
-    auto fakeInterfaces = make_shared<std::vector<NetworkInterfaceInfo>>();
-
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {0, "eth0",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("0.0.0.0")},
-        {address_v6::from_string("::")},
-        address_v4(),
-        IFF_UP});
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {1, "eth0",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("192.168.2.1"), address_v4::from_string("192.168.2.2")},
-        {},
-        address_v4::from_string("192.168.2.255"),
-        0});
-    fakeInterfaces->push_back(
-      NetworkInterfaceInfo {2, "eth1",
-        ethernet::Address::fromString("3e:15:c2:8b:65:00"),
-        {address_v4::from_string("198.51.100.1")},
-        {address_v6::from_string("2001:db8::2"), address_v6::from_string("2001:db8::3")},
-        address_v4::from_string("198.51.100.255"),
-        IFF_MULTICAST | IFF_BROADCAST | IFF_UP});
-
-    setDebugNetworkInterfaces(fakeInterfaces);
-  }
-
-  ~FakeNetworkInterfaceFixture()
-  {
-    setDebugNetworkInterfaces(nullptr);
-  }
-};
-
-BOOST_FIXTURE_TEST_CASE(Bug2292, FakeNetworkInterfaceFixture)
-{
-  using namespace boost::asio::ip;
-
-  UdpFactory factory;
-  factory.prohibitEndpoint(udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<udp::Endpoint> {
-                 udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(udp::Endpoint(address_v6::from_string("2001:db8::1"), 2048));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 1);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<udp::Endpoint> {
-                 udp::Endpoint(address_v6::from_string("2001:db8::1"), 2048),
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(udp::Endpoint(address_v4(), 1024));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 6);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<udp::Endpoint> {
-                 udp::Endpoint(address_v4::from_string("192.168.2.1"), 1024),
-                 udp::Endpoint(address_v4::from_string("192.168.2.2"), 1024),
-                 udp::Endpoint(address_v4::from_string("198.51.100.1"), 1024),
-                 udp::Endpoint(address_v4::from_string("198.51.100.255"), 1024),
-                 udp::Endpoint(address_v4::from_string("255.255.255.255"), 1024),
-                 udp::Endpoint(address_v4::from_string("0.0.0.0"), 1024)
-               }));
-
-  factory.m_prohibitedEndpoints.clear();
-  factory.prohibitEndpoint(udp::Endpoint(address_v6(), 2048));
-  BOOST_REQUIRE_EQUAL(factory.m_prohibitedEndpoints.size(), 3);
-  BOOST_CHECK((factory.m_prohibitedEndpoints ==
-               std::set<udp::Endpoint> {
-                 udp::Endpoint(address_v6::from_string("2001:db8::2"), 2048),
-                 udp::Endpoint(address_v6::from_string("2001:db8::3"), 2048),
-                 udp::Endpoint(address_v6::from_string("::"), 2048),
-               }));
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestUdp
-BOOST_AUTO_TEST_SUITE_END() // Face
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/face/unicast-udp-transport-fixture.hpp b/tests/daemon/face/unicast-udp-transport-fixture.hpp
index 6dd836a..1ec37b0 100644
--- a/tests/daemon/face/unicast-udp-transport-fixture.hpp
+++ b/tests/daemon/face/unicast-udp-transport-fixture.hpp
@@ -27,7 +27,7 @@
 #define NFD_TESTS_DAEMON_FACE_UNICAST_UDP_TRANSPORT_FIXTURE_HPP
 
 #include "face/unicast-udp-transport.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
 #include "tests/limited-io.hpp"
@@ -60,9 +60,9 @@
 
     remoteConnect(address);
 
-    face = make_unique<LpFace>(make_unique<DummyReceiveLinkService>(),
-                               make_unique<UnicastUdpTransport>(std::move(sock), persistency,
-                                                                time::seconds(3)));
+    face = make_unique<Face>(
+             make_unique<DummyReceiveLinkService>(),
+             make_unique<UnicastUdpTransport>(std::move(sock), persistency, time::seconds(3)));
     transport = static_cast<UnicastUdpTransport*>(face->getTransport());
     receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
 
@@ -99,7 +99,7 @@
   std::vector<Transport::Packet>* receivedPackets;
 
 private:
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
 };
 
 } // namespace tests
diff --git a/tests/daemon/face/unix-stream-channel.t.cpp b/tests/daemon/face/unix-stream-channel.t.cpp
new file mode 100644
index 0000000..86caa8d
--- /dev/null
+++ b/tests/daemon/face/unix-stream-channel.t.cpp
@@ -0,0 +1,45 @@
+/* -*- 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 "face/unix-stream-channel.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestUnixStreamChannel, BaseFixture)
+
+// TODO add the equivalent of these test cases from unix-stream.t.cpp as of commit:65caf200924b28748037750449e28bcb548dbc9c
+// MultipleAccepts
+
+// TODO add a test case to check a failed face is removed from the channel
+
+BOOST_AUTO_TEST_SUITE_END() // TestUnixStreamChannel
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/unix-stream-factory.t.cpp b/tests/daemon/face/unix-stream-factory.t.cpp
new file mode 100644
index 0000000..2be2536
--- /dev/null
+++ b/tests/daemon/face/unix-stream-factory.t.cpp
@@ -0,0 +1,103 @@
+/* -*- 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 "face/unix-stream-factory.hpp"
+
+#include "tests/test-common.hpp"
+#include "tests/limited-io.hpp"
+
+namespace nfd {
+namespace tests {
+
+#define CHANNEL_PATH1 "unix-stream-test.1.sock"
+#define CHANNEL_PATH2 "unix-stream-test.2.sock"
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestUnixStreamFactory, BaseFixture)
+
+using nfd::Face;
+
+BOOST_AUTO_TEST_CASE(ChannelMap)
+{
+  UnixStreamFactory factory;
+
+  shared_ptr<UnixStreamChannel> channel1 = factory.createChannel(CHANNEL_PATH1);
+  shared_ptr<UnixStreamChannel> channel1a = factory.createChannel(CHANNEL_PATH1);
+  BOOST_CHECK_EQUAL(channel1, channel1a);
+  std::string channel1uri = channel1->getUri().toString();
+  BOOST_CHECK_EQUAL(channel1uri.find("unix:///"), 0); // third '/' is the path separator
+  BOOST_CHECK_EQUAL(channel1uri.rfind(CHANNEL_PATH1),
+                    channel1uri.size() - std::string(CHANNEL_PATH1).size());
+
+  shared_ptr<UnixStreamChannel> channel2 = factory.createChannel(CHANNEL_PATH2);
+  BOOST_CHECK_NE(channel1, channel2);
+}
+
+BOOST_AUTO_TEST_CASE(GetChannels)
+{
+  UnixStreamFactory factory;
+  BOOST_CHECK(factory.getChannels().empty());
+
+  std::vector<shared_ptr<const Channel>> expectedChannels;
+  expectedChannels.push_back(factory.createChannel(CHANNEL_PATH1));
+  expectedChannels.push_back(factory.createChannel(CHANNEL_PATH2));
+
+  for (const auto& channel : factory.getChannels()) {
+    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), channel);
+    BOOST_REQUIRE(pos != expectedChannels.end());
+    expectedChannels.erase(pos);
+  }
+
+  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
+{
+  UnixStreamFactory factory;
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
+                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestUnixStreamFactory
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/unix-stream-transport-fixture.hpp b/tests/daemon/face/unix-stream-transport-fixture.hpp
index 38c9b5f..0101f10 100644
--- a/tests/daemon/face/unix-stream-transport-fixture.hpp
+++ b/tests/daemon/face/unix-stream-transport-fixture.hpp
@@ -27,7 +27,7 @@
 #define NFD_TESTS_DAEMON_FACE_UNIX_STREAM_TRANSPORT_FIXTURE_HPP
 
 #include "face/unix-stream-transport.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
 #include "tests/limited-io.hpp"
@@ -105,8 +105,8 @@
     BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(1)), LimitedIo::EXCEED_OPS);
 
     localEp = sock.local_endpoint();
-    face = make_unique<LpFace>(make_unique<DummyReceiveLinkService>(),
-                                make_unique<UnixStreamTransport>(std::move(sock)));
+    face = make_unique<Face>(make_unique<DummyReceiveLinkService>(),
+                             make_unique<UnixStreamTransport>(std::move(sock)));
     transport = static_cast<UnixStreamTransport*>(face->getTransport());
     receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
 
@@ -134,7 +134,7 @@
 
 private:
   AcceptorWithCleanup acceptor;
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
 };
 
 } // namespace tests
diff --git a/tests/daemon/face/unix-stream.t.cpp b/tests/daemon/face/unix-stream.t.cpp
deleted file mode 100644
index fc528c2..0000000
--- a/tests/daemon/face/unix-stream.t.cpp
+++ /dev/null
@@ -1,347 +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 "face/unix-stream-channel.hpp"
-#include "face/unix-stream-factory.hpp"
-#include "face/unix-stream-transport.hpp"
-
-#include "face/generic-link-service.hpp"
-#include "face/lp-face-wrapper.hpp"
-
-#include "tests/test-common.hpp"
-#include "tests/limited-io.hpp"
-#include "dummy-stream-sender.hpp"
-#include "packet-datasets.hpp"
-
-namespace nfd {
-namespace tests {
-
-#define CHANNEL_PATH1 "unix-stream-test.1.sock"
-#define CHANNEL_PATH2 "unix-stream-test.2.sock"
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestUnixStream, BaseFixture)
-
-using nfd::Face;
-using face::LpFaceWrapper;
-using face::UnixStreamTransport;
-
-BOOST_AUTO_TEST_CASE(ChannelMap)
-{
-  UnixStreamFactory factory;
-
-  shared_ptr<UnixStreamChannel> channel1 = factory.createChannel(CHANNEL_PATH1);
-  shared_ptr<UnixStreamChannel> channel1a = factory.createChannel(CHANNEL_PATH1);
-  BOOST_CHECK_EQUAL(channel1, channel1a);
-  std::string channel1uri = channel1->getUri().toString();
-  BOOST_CHECK_EQUAL(channel1uri.find("unix:///"), 0); // third '/' is the path separator
-  BOOST_CHECK_EQUAL(channel1uri.rfind(CHANNEL_PATH1),
-                    channel1uri.size() - std::string(CHANNEL_PATH1).size());
-
-  shared_ptr<UnixStreamChannel> channel2 = factory.createChannel(CHANNEL_PATH2);
-  BOOST_CHECK_NE(channel1, channel2);
-}
-
-BOOST_AUTO_TEST_CASE(GetChannels)
-{
-  UnixStreamFactory factory;
-  BOOST_CHECK(factory.getChannels().empty());
-
-  std::vector<shared_ptr<const Channel>> expectedChannels;
-  expectedChannels.push_back(factory.createChannel(CHANNEL_PATH1));
-  expectedChannels.push_back(factory.createChannel(CHANNEL_PATH2));
-
-  for (const auto& channel : factory.getChannels()) {
-    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), channel);
-    BOOST_REQUIRE(pos != expectedChannels.end());
-    expectedChannels.erase(pos);
-  }
-
-  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
-}
-
-BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
-{
-  UnixStreamFactory factory;
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
-                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("unix:///var/run/nfd.sock"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-}
-
-class EndToEndFixture : protected BaseFixture
-{
-public:
-  void
-  client_onConnect(const boost::system::error_code& error)
-  {
-    BOOST_CHECK_MESSAGE(!error, error.message());
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel1_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    BOOST_CHECK(!static_cast<bool>(face1));
-    face1 = static_pointer_cast<LpFaceWrapper>(newFace);
-    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
-    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel1_onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveInterest(const Interest& interest)
-  {
-    face1_receivedInterests.push_back(interest);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveData(const Data& data)
-  {
-    face1_receivedDatas.push_back(data);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face2_onReceiveInterest(const Interest& interest)
-  {
-    face2_receivedInterests.push_back(interest);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face2_onReceiveData(const Data& data)
-  {
-    face2_receivedDatas.push_back(data);
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    faces.push_back(static_pointer_cast<LpFaceWrapper>(newFace));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  channel_onConnectFailed(const std::string& reason)
-  {
-    BOOST_CHECK_MESSAGE(false, reason);
-
-    limitedIo.afterOp();
-  }
-
-  shared_ptr<LpFaceWrapper>
-  makeFace(UnixStreamTransport::protocol::socket&& socket)
-  {
-    auto linkService = make_unique<face::GenericLinkService>();
-    auto transport = make_unique<UnixStreamTransport>(std::move(socket));
-    auto lpFace = make_unique<LpFace>(std::move(linkService), std::move(transport));
-    return make_shared<LpFaceWrapper>(std::move(lpFace));
-  }
-
-protected:
-  LimitedIo limitedIo;
-
-  shared_ptr<LpFaceWrapper> face1;
-  std::vector<Interest> face1_receivedInterests;
-  std::vector<Data> face1_receivedDatas;
-  shared_ptr<LpFaceWrapper> face2;
-  std::vector<Interest> face2_receivedInterests;
-  std::vector<Data> face2_receivedDatas;
-
-  std::list<shared_ptr<LpFaceWrapper>> faces;
-};
-
-
-BOOST_FIXTURE_TEST_CASE(EndToEnd, EndToEndFixture)
-{
-  UnixStreamFactory factory;
-
-  shared_ptr<UnixStreamChannel> channel1 = factory.createChannel(CHANNEL_PATH1);
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1),
-                   bind(&EndToEndFixture::channel1_onConnectFailed, this, _1));
-
-  UnixStreamTransport::protocol::socket client(g_io);
-  client.async_connect(UnixStreamTransport::protocol::endpoint(CHANNEL_PATH1),
-                       bind(&EndToEndFixture::client_onConnect, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Connect");
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_CHECK_EQUAL(face1->isLocal(), true);
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_EQUAL(face1->isMultiAccess(), false);
-  BOOST_CHECK_EQUAL(face1->getRemoteUri().getScheme(), "fd");
-  BOOST_CHECK_NO_THROW(std::stoi(face1->getRemoteUri().getHost()));
-  std::string face1localUri = face1->getLocalUri().toString();
-  BOOST_CHECK_EQUAL(face1localUri.find("unix:///"), 0); // third '/' is the path separator
-  BOOST_CHECK_EQUAL(face1localUri.rfind(CHANNEL_PATH1),
-                    face1localUri.size() - std::string(CHANNEL_PATH1).size());
-
-  face2 = makeFace(std::move(client));
-  face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
-  face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  face1->sendInterest(*interest1);
-  face1->sendInterest(*interest1);
-  face1->sendInterest(*interest1);
-  face1->sendData    (*data1    );
-  size_t nBytesSent1 = interest1->wireEncode().size() * 3 + data1->wireEncode().size();
-  face2->sendInterest(*interest2);
-  face2->sendData    (*data2    );
-  face2->sendData    (*data2    );
-  face2->sendData    (*data2    );
-  size_t nBytesSent2 = interest2->wireEncode().size() + data2->wireEncode().size() * 3;
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Send/receive");
-
-  BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 3);
-  BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 3);
-  BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
-
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
-
-  // needed to ensure NOutBytes counters are accurate
-  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::seconds(1));
-
-  const face::FaceCounters& counters1 = face1->getCounters();
-  BOOST_CHECK_EQUAL(counters1.nInInterests, 1);
-  BOOST_CHECK_EQUAL(counters1.nInData, 3);
-  BOOST_CHECK_EQUAL(counters1.nOutInterests, 3);
-  BOOST_CHECK_EQUAL(counters1.nOutData, 1);
-  BOOST_CHECK_EQUAL(counters1.nInBytes, nBytesSent2);
-  BOOST_CHECK_EQUAL(counters1.nOutBytes, nBytesSent1);
-
-  const face::FaceCounters& counters2 = face2->getCounters();
-  BOOST_CHECK_EQUAL(counters2.nInInterests, 3);
-  BOOST_CHECK_EQUAL(counters2.nInData, 1);
-  BOOST_CHECK_EQUAL(counters2.nOutInterests, 1);
-  BOOST_CHECK_EQUAL(counters2.nOutData, 3);
-}
-
-BOOST_FIXTURE_TEST_CASE(MultipleAccepts, EndToEndFixture)
-{
-  UnixStreamFactory factory;
-
-  shared_ptr<UnixStreamChannel> channel = factory.createChannel(CHANNEL_PATH1);
-  channel->listen(bind(&EndToEndFixture::channel_onFaceCreated,   this, _1),
-                  bind(&EndToEndFixture::channel_onConnectFailed, this, _1));
-
-  UnixStreamTransport::protocol::socket client1(g_io);
-  client1.async_connect(UnixStreamTransport::protocol::endpoint(CHANNEL_PATH1),
-                        bind(&EndToEndFixture::client_onConnect, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "First connect");
-
-  BOOST_CHECK_EQUAL(faces.size(), 1);
-
-  UnixStreamTransport::protocol::socket client2(g_io);
-  client2.async_connect(UnixStreamTransport::protocol::endpoint(CHANNEL_PATH1),
-                        bind(&EndToEndFixture::client_onConnect, this, _1));
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Second connect");
-
-  BOOST_CHECK_EQUAL(faces.size(), 2);
-
-  // now close one of the faces
-  faces.front()->close();
-
-  // we should still be able to send/receive with the other one
-  face1 = faces.back();
-  face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
-  face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
-
-  face2 = makeFace(std::move(client2));
-  face2->onReceiveInterest.connect(bind(&EndToEndFixture::face2_onReceiveInterest, this, _1));
-  face2->onReceiveData.connect(bind(&EndToEndFixture::face2_onReceiveData, this, _1));
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  face1->sendInterest(*interest1);
-  face1->sendData    (*data1    );
-  face2->sendInterest(*interest2);
-  face2->sendData    (*data2    );
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(4, time::seconds(1)) == LimitedIo::EXCEED_OPS, "Send/receive");
-
-  BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 1);
-  BOOST_REQUIRE_EQUAL(face2_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(face2_receivedDatas    .size(), 1);
-
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest2->getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
-  BOOST_CHECK_EQUAL(face2_receivedInterests[0].getName(), interest1->getName());
-  BOOST_CHECK_EQUAL(face2_receivedDatas    [0].getName(), data1->getName());
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestUnixStream
-BOOST_AUTO_TEST_SUITE_END() // Face
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/face/websocket-channel.t.cpp b/tests/daemon/face/websocket-channel.t.cpp
new file mode 100644
index 0000000..9e10239
--- /dev/null
+++ b/tests/daemon/face/websocket-channel.t.cpp
@@ -0,0 +1,44 @@
+/* -*- 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 "face/websocket-channel.hpp"
+
+#include "tests/test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestWebSocketChannel, BaseFixture)
+
+// TODO add a test case to accept multiple incoming connections on a channel
+
+// TODO add a test case to check a failed face is removed from the channel
+
+BOOST_AUTO_TEST_SUITE_END() // TestWebSocketChannel
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/websocket-factory.t.cpp b/tests/daemon/face/websocket-factory.t.cpp
new file mode 100644
index 0000000..9e469e8
--- /dev/null
+++ b/tests/daemon/face/websocket-factory.t.cpp
@@ -0,0 +1,85 @@
+/* -*- 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 "face/websocket-factory.hpp"
+
+#include "tests/test-common.hpp"
+#include "tests/limited-io.hpp"
+
+namespace nfd {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestWebSocketFactory, BaseFixture)
+
+using nfd::Face;
+
+BOOST_AUTO_TEST_CASE(GetChannels)
+{
+  WebSocketFactory factory;
+  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
+
+  std::vector<shared_ptr<const Channel>> expectedChannels;
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
+  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
+  expectedChannels.push_back(factory.createChannel("::1", "20071"));
+
+  for (const auto& i : factory.getChannels()) {
+    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), i);
+    BOOST_REQUIRE(pos != expectedChannels.end());
+    expectedChannels.erase(pos);
+  }
+
+  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
+{
+  WebSocketFactory factory;
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
+                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+
+  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
+                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                       bind([]{}),
+                                       bind([]{})),
+                    ProtocolFactory::Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestWebSocketFactory
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/websocket-transport.t.cpp b/tests/daemon/face/websocket-transport.t.cpp
index ca9bd72..edee799 100644
--- a/tests/daemon/face/websocket-transport.t.cpp
+++ b/tests/daemon/face/websocket-transport.t.cpp
@@ -24,7 +24,7 @@
  */
 
 #include "face/websocket-transport.hpp"
-#include "face/lp-face.hpp"
+#include "face/face.hpp"
 #include "dummy-receive-link-service.hpp"
 #include "transport-test-common.hpp"
 
@@ -39,6 +39,8 @@
 
 BOOST_AUTO_TEST_SUITE(Face)
 
+using nfd::Face;
+
 /** \brief a fixture that accepts a single WebSocket connection from a client
  */
 class SingleWebSocketFixture : public BaseFixture
@@ -97,7 +99,7 @@
   void
   makeFace(const time::milliseconds& pingInterval = time::milliseconds(10000))
   {
-    face = make_unique<LpFace>(
+    face = make_unique<Face>(
              make_unique<DummyReceiveLinkService>(),
              make_unique<WebSocketTransport>(serverHdl, ref(server), pingInterval));
     transport = static_cast<WebSocketTransport*>(face->getTransport());
@@ -197,7 +199,7 @@
 
   websocket::Server server;
   websocketpp::connection_hdl serverHdl;
-  unique_ptr<LpFace> face;
+  unique_ptr<Face> face;
   WebSocketTransport* transport;
   std::vector<Transport::Packet>* serverReceivedPackets;
 
diff --git a/tests/daemon/face/websocket.t.cpp b/tests/daemon/face/websocket.t.cpp
deleted file mode 100644
index 3811635..0000000
--- a/tests/daemon/face/websocket.t.cpp
+++ /dev/null
@@ -1,306 +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 "face/websocket-channel.hpp"
-#include "face/websocket-factory.hpp"
-#include "face/websocketpp.hpp"
-
-#include "tests/test-common.hpp"
-#include "tests/limited-io.hpp"
-
-namespace nfd {
-namespace tests {
-
-BOOST_AUTO_TEST_SUITE(Face)
-BOOST_FIXTURE_TEST_SUITE(TestWebSocket, BaseFixture)
-
-using nfd::Face;
-
-BOOST_AUTO_TEST_CASE(GetChannels)
-{
-  WebSocketFactory factory;
-  BOOST_REQUIRE_EQUAL(factory.getChannels().empty(), true);
-
-  std::vector<shared_ptr<const Channel>> expectedChannels;
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20070"));
-  expectedChannels.push_back(factory.createChannel("127.0.0.1", "20071"));
-  expectedChannels.push_back(factory.createChannel("::1", "20071"));
-
-  for (const auto& i : factory.getChannels()) {
-    auto pos = std::find(expectedChannels.begin(), expectedChannels.end(), i);
-    BOOST_REQUIRE(pos != expectedChannels.end());
-    expectedChannels.erase(pos);
-  }
-
-  BOOST_CHECK_EQUAL(expectedChannels.size(), 0);
-}
-
-BOOST_AUTO_TEST_CASE(UnsupportedFaceCreate)
-{
-  WebSocketFactory factory;
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERMANENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
-                                       ndn::nfd::FACE_PERSISTENCY_ON_DEMAND,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-
-  BOOST_CHECK_THROW(factory.createFace(FaceUri("ws://127.0.0.1:20070"),
-                                       ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                                       bind([]{}),
-                                       bind([]{})),
-                    ProtocolFactory::Error);
-}
-
-class EndToEndFixture : protected BaseFixture
-{
-public:
-  void
-  channel1_onFaceCreated(const shared_ptr<Face>& newFace)
-  {
-    BOOST_CHECK(!static_cast<bool>(face1));
-    face1 = newFace;
-    face1->onReceiveInterest.connect(bind(&EndToEndFixture::face1_onReceiveInterest, this, _1));
-    face1->onReceiveData.connect(bind(&EndToEndFixture::face1_onReceiveData, this, _1));
-    face1->onFail.connect(bind(&EndToEndFixture::face1_onFail, this));
-
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveInterest(const Interest& interest)
-  {
-    face1_receivedInterests.push_back(interest);
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onReceiveData(const Data& data)
-  {
-    face1_receivedDatas.push_back(data);
-    limitedIo.afterOp();
-  }
-
-  void
-  face1_onFail()
-  {
-    g_io.post([this] {
-      face1.reset();
-      limitedIo.afterOp();
-    });
-  }
-
-  void
-  client1_onOpen(websocketpp::connection_hdl hdl)
-  {
-    handle = hdl;
-    limitedIo.afterOp();
-  }
-
-  void
-  client1_onClose(websocketpp::connection_hdl hdl)
-  {
-    limitedIo.afterOp();
-  }
-
-  void
-  client1_onFail(websocketpp::connection_hdl hdl)
-  {
-    limitedIo.afterOp();
-  }
-
-  bool
-  client1_onPing(websocketpp::connection_hdl hdl, std::string msg)
-  {
-    limitedIo.afterOp();
-    // Return false to suppress the pong response,
-    // which will cause timeout in the websocket channel
-    return false;
-  }
-
-  void
-  client1_sendInterest(const Interest& interest)
-  {
-    const Block& payload = interest.wireEncode();
-    client1.send(handle, payload.wire(), payload.size(), websocketpp::frame::opcode::binary);
-  }
-
-  void
-  client1_sendData(const Data& data)
-  {
-    const Block& payload = data.wireEncode();
-    client1.send(handle, payload.wire(), payload.size(), websocketpp::frame::opcode::binary);
-  }
-
-  void
-  client1_onMessage(websocketpp::connection_hdl hdl,
-                    websocketpp::config::asio_client::message_type::ptr msg)
-  {
-    bool isOk = false;
-    Block element;
-    const std::string& payload = msg->get_payload();
-    std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(payload.c_str()),
-                                                payload.size());
-    if (isOk)
-      {
-        try {
-          if (element.type() == tlv::Interest)
-            {
-              shared_ptr<Interest> i = make_shared<Interest>();
-              i->wireDecode(element);
-              client1_onReceiveInterest(*i);
-            }
-          else if (element.type() == tlv::Data)
-            {
-              shared_ptr<Data> d = make_shared<Data>();
-              d->wireDecode(element);
-              client1_onReceiveData(*d);
-            }
-        }
-        catch (tlv::Error&) {
-          // Do something?
-        }
-      }
-    limitedIo.afterOp();
-  }
-
-  void
-  client1_onReceiveInterest(const Interest& interest)
-  {
-    client1_receivedInterests.push_back(interest);
-    limitedIo.afterOp();
-  }
-
-  void
-  client1_onReceiveData(const Data& data)
-  {
-    client1_receivedDatas.push_back(data);
-    limitedIo.afterOp();
-  }
-
-public:
-  LimitedIo limitedIo;
-
-  shared_ptr<Face> face1;
-  std::vector<Interest> face1_receivedInterests;
-  std::vector<Data> face1_receivedDatas;
-  websocket::Client client1;
-  websocketpp::connection_hdl handle;
-  std::vector<Interest> client1_receivedInterests;
-  std::vector<Data> client1_receivedDatas;
-};
-
-BOOST_FIXTURE_TEST_CASE(EndToEnd4, EndToEndFixture)
-{
-  WebSocketFactory factory1;
-
-  shared_ptr<WebSocketChannel> channel1 = factory1.createChannel("127.0.0.1", "20070");
-  channel1->setPingInterval(time::milliseconds(3000));
-  channel1->setPongTimeout(time::milliseconds(1000));
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), false);
-
-  channel1->listen(bind(&EndToEndFixture::channel1_onFaceCreated,   this, _1));
-
-  BOOST_CHECK_EQUAL(channel1->isListening(), true);
-
-  // Clear all logging info from websocketpp library
-  client1.clear_access_channels(websocketpp::log::alevel::all);
-
-  client1.init_asio(&getGlobalIoService());
-  client1.set_open_handler(bind(&EndToEndFixture::client1_onOpen,   this, _1));
-  client1.set_close_handler(bind(&EndToEndFixture::client1_onClose, this, _1));
-  client1.set_fail_handler(bind(&EndToEndFixture::client1_onFail,   this, _1));
-  client1.set_message_handler(bind(&EndToEndFixture::client1_onMessage, this, _1, _2));
-  client1.set_ping_handler(bind(&EndToEndFixture::client1_onPing, this, _1, _2));
-
-  websocketpp::lib::error_code ec;
-  auto con = client1.get_connection("ws://127.0.0.1:20070", ec);
-  client1.connect(con);
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(2, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "WebSocketChannel error: cannot connect or cannot accept connection");
-
-  BOOST_CHECK_EQUAL(channel1->size(), 1);
-
-  BOOST_REQUIRE(static_cast<bool>(face1));
-  BOOST_CHECK_EQUAL(face1->isLocal(), true);
-  BOOST_CHECK_EQUAL(face1->getPersistency(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_EQUAL(face1->isMultiAccess(), false);
-  BOOST_CHECK_EQUAL(face1->getLocalUri().toString(), "ws://127.0.0.1:20070");
-
-  shared_ptr<Interest> interest1 = makeInterest("ndn:/TpnzGvW9R");
-  shared_ptr<Data>     data1     = makeData("ndn:/KfczhUqVix");
-  shared_ptr<Interest> interest2 = makeInterest("ndn:/QWiIMfj5sL");
-  shared_ptr<Data>     data2     = makeData("ndn:/XNBV796f");
-
-  client1_sendInterest(*interest1);
-  client1_sendInterest(*interest1);
-  client1_sendInterest(*interest1);
-  face1->sendData     (*data1);
-  face1->sendInterest (*interest2);
-  client1_sendData    (*data2);
-  client1_sendData    (*data2);
-  client1_sendData    (*data2);
-
-  size_t nBytesSent = data1->wireEncode().size() + interest2->wireEncode().size();
-  size_t nBytesReceived = interest1->wireEncode().size() * 3 + data2->wireEncode().size() * 3;
-
-  BOOST_CHECK_MESSAGE(limitedIo.run(8, time::seconds(10)) == LimitedIo::EXCEED_OPS,
-                      "WebSocketChannel error: cannot send or receive Interest/Data packets");
-
-  BOOST_REQUIRE_EQUAL(face1_receivedInterests.size(), 3);
-  BOOST_REQUIRE_EQUAL(face1_receivedDatas    .size(), 3);
-  BOOST_REQUIRE_EQUAL(client1_receivedInterests.size(), 1);
-  BOOST_REQUIRE_EQUAL(client1_receivedDatas    .size(), 1);
-
-  BOOST_CHECK_EQUAL(face1_receivedInterests[0].getName(), interest1->getName());
-  BOOST_CHECK_EQUAL(face1_receivedDatas    [0].getName(), data2->getName());
-  BOOST_CHECK_EQUAL(client1_receivedInterests[0].getName(), interest2->getName());
-  BOOST_CHECK_EQUAL(client1_receivedDatas    [0].getName(), data1->getName());
-
-  const face::FaceCounters& counters1 = face1->getCounters();
-  BOOST_CHECK_EQUAL(counters1.nInInterests, 3);
-  BOOST_CHECK_EQUAL(counters1.nInData, 3);
-  BOOST_CHECK_EQUAL(counters1.nOutInterests, 1);
-  BOOST_CHECK_EQUAL(counters1.nOutData, 1);
-  BOOST_CHECK_EQUAL(counters1.nInBytes, nBytesReceived);
-  BOOST_CHECK_EQUAL(counters1.nOutBytes, nBytesSent);
-
-  limitedIo.run(LimitedIo::UNLIMITED_OPS, time::seconds(8));
-  BOOST_CHECK_EQUAL(channel1->size(), 0);
-}
-
-BOOST_AUTO_TEST_SUITE_END() // TestWebSocket
-BOOST_AUTO_TEST_SUITE_END() // Face
-
-} // namespace tests
-} // namespace nfd
diff --git a/tests/daemon/fw/client-control-strategy.t.cpp b/tests/daemon/fw/client-control-strategy.t.cpp
index 8f0870b..e180ec9 100644
--- a/tests/daemon/fw/client-control-strategy.t.cpp
+++ b/tests/daemon/fw/client-control-strategy.t.cpp
@@ -44,10 +44,10 @@
   typedef StrategyTester<fw::ClientControlStrategy> ClientControlStrategyTester;
   ClientControlStrategyTester strategy(forwarder);
 
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  shared_ptr<DummyLocalFace> face4 = make_shared<DummyLocalFace>();
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>();
+  auto face4 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
diff --git a/tests/daemon/fw/face-table.t.cpp b/tests/daemon/fw/face-table.t.cpp
index 6610034..59bb7c8 100644
--- a/tests/daemon/fw/face-table.t.cpp
+++ b/tests/daemon/fw/face-table.t.cpp
@@ -32,52 +32,49 @@
 namespace nfd {
 namespace tests {
 
-BOOST_FIXTURE_TEST_SUITE(FwFaceTable, BaseFixture)
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestFaceTable, BaseFixture)
 
 BOOST_AUTO_TEST_CASE(AddRemove)
 {
   Forwarder forwarder;
 
   FaceTable& faceTable = forwarder.getFaceTable();
-  std::vector<FaceId> onAddHistory;
-  std::vector<FaceId> onRemoveHistory;
-  faceTable.onAdd.connect([&] (shared_ptr<Face> face) {
-    onAddHistory.push_back(face->getId());
-  });
-  faceTable.onRemove.connect([&] (shared_ptr<Face> face) {
-    onRemoveHistory.push_back(face->getId());
-  });
+  std::vector<FaceId> addHistory;
+  std::vector<FaceId> removeHistory;
+  faceTable.afterAdd.connect([&] (shared_ptr<Face> face) { addHistory.push_back(face->getId()); });
+  faceTable.beforeRemove.connect([&] (shared_ptr<Face> face) { removeHistory.push_back(face->getId()); });
 
   shared_ptr<Face> face1 = make_shared<DummyFace>();
   shared_ptr<Face> face2 = make_shared<DummyFace>();
 
-  BOOST_CHECK_EQUAL(face1->getId(), INVALID_FACEID);
-  BOOST_CHECK_EQUAL(face2->getId(), INVALID_FACEID);
+  BOOST_CHECK_EQUAL(face1->getId(), face::INVALID_FACEID);
+  BOOST_CHECK_EQUAL(face2->getId(), face::INVALID_FACEID);
 
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
-  BOOST_CHECK_NE(face1->getId(), INVALID_FACEID);
-  BOOST_CHECK_NE(face2->getId(), INVALID_FACEID);
+  BOOST_CHECK_NE(face1->getId(), face::INVALID_FACEID);
+  BOOST_CHECK_NE(face2->getId(), face::INVALID_FACEID);
   BOOST_CHECK_NE(face1->getId(), face2->getId());
-  BOOST_CHECK_GT(face1->getId(), FACEID_RESERVED_MAX);
-  BOOST_CHECK_GT(face2->getId(), FACEID_RESERVED_MAX);
+  BOOST_CHECK_GT(face1->getId(), face::FACEID_RESERVED_MAX);
+  BOOST_CHECK_GT(face2->getId(), face::FACEID_RESERVED_MAX);
 
   FaceId oldId1 = face1->getId();
   faceTable.add(face1);
   BOOST_CHECK_EQUAL(face1->getId(), oldId1);
   BOOST_CHECK_EQUAL(faceTable.size(), 2);
 
-  BOOST_REQUIRE_EQUAL(onAddHistory.size(), 2);
-  BOOST_CHECK_EQUAL(onAddHistory[0], face1->getId());
-  BOOST_CHECK_EQUAL(onAddHistory[1], face2->getId());
+  BOOST_REQUIRE_EQUAL(addHistory.size(), 2);
+  BOOST_CHECK_EQUAL(addHistory[0], face1->getId());
+  BOOST_CHECK_EQUAL(addHistory[1], face2->getId());
 
   face1->close();
 
-  BOOST_CHECK_EQUAL(face1->getId(), INVALID_FACEID);
+  BOOST_CHECK_EQUAL(face1->getId(), face::INVALID_FACEID);
 
-  BOOST_REQUIRE_EQUAL(onRemoveHistory.size(), 1);
-  BOOST_CHECK_EQUAL(onRemoveHistory[0], onAddHistory[0]);
+  BOOST_REQUIRE_EQUAL(removeHistory.size(), 1);
+  BOOST_CHECK_EQUAL(removeHistory[0], addHistory[0]);
 }
 
 BOOST_AUTO_TEST_CASE(AddReserved)
@@ -86,7 +83,7 @@
   FaceTable& faceTable = forwarder.getFaceTable();
 
   shared_ptr<Face> face1 = make_shared<DummyFace>();
-  BOOST_CHECK_EQUAL(face1->getId(), INVALID_FACEID);
+  BOOST_CHECK_EQUAL(face1->getId(), face::INVALID_FACEID);
 
   faceTable.addReserved(face1, 5);
   BOOST_CHECK_EQUAL(face1->getId(), 5);
@@ -146,7 +143,8 @@
   BOOST_CHECK(hasFace2);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestFaceTable
+BOOST_AUTO_TEST_SUITE_END() // Fw
 
 } // namespace tests
 } // namespace nfd
diff --git a/tests/daemon/fw/forwarder.t.cpp b/tests/daemon/fw/forwarder.t.cpp
index 67bce49..cfa5f71 100644
--- a/tests/daemon/fw/forwarder.t.cpp
+++ b/tests/daemon/fw/forwarder.t.cpp
@@ -25,8 +25,6 @@
 
 #include "fw/forwarder.hpp"
 #include "tests/daemon/face/dummy-face.hpp"
-#include "tests/daemon/face/dummy-lp-face.hpp"
-#include "face/lp-face-wrapper.hpp"
 #include "dummy-strategy.hpp"
 
 #include "tests/test-common.hpp"
@@ -51,10 +49,10 @@
   interestAB->setInterestLifetime(time::seconds(4));
   shared_ptr<Data> dataABC = makeData(nameABC);
 
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  face1->afterSend.connect(afterOp);
-  face2->afterSend.connect(afterOp);
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  face1->afterSend.connect(bind(afterOp));
+  face2->afterSend.connect(bind(afterOp));
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
@@ -66,10 +64,10 @@
   BOOST_CHECK_EQUAL(forwarder.getCounters().nOutInterests, 0);
   g_io.post([&] { face1->receiveInterest(*interestAB); });
   BOOST_CHECK_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
-  BOOST_REQUIRE_EQUAL(face2->m_sentInterests.size(), 1);
-  BOOST_CHECK_EQUAL(face2->m_sentInterests[0].getName(), nameAB);
-  BOOST_REQUIRE(face2->m_sentInterests[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
-  BOOST_CHECK_EQUAL(*face2->m_sentInterests[0].getTag<lp::IncomingFaceIdTag>(), face1->getId());
+  BOOST_REQUIRE_EQUAL(face2->sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face2->sentInterests[0].getName(), nameAB);
+  BOOST_REQUIRE(face2->sentInterests[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
+  BOOST_CHECK_EQUAL(*face2->sentInterests[0].getTag<lp::IncomingFaceIdTag>(), face1->getId());
   BOOST_CHECK_EQUAL(forwarder.getCounters().nInInterests, 1);
   BOOST_CHECK_EQUAL(forwarder.getCounters().nOutInterests, 1);
 
@@ -77,10 +75,10 @@
   BOOST_CHECK_EQUAL(forwarder.getCounters().nOutData, 0);
   g_io.post([&] { face2->receiveData(*dataABC); });
   BOOST_CHECK_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
-  BOOST_REQUIRE_EQUAL(face1->m_sentDatas.size(), 1);
-  BOOST_CHECK_EQUAL(face1->m_sentDatas[0].getName(), nameABC);
-  BOOST_REQUIRE(face1->m_sentDatas[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
-  BOOST_CHECK_EQUAL(*face1->m_sentDatas[0].getTag<lp::IncomingFaceIdTag>(), face2->getId());
+  BOOST_REQUIRE_EQUAL(face1->sentData.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentData[0].getName(), nameABC);
+  BOOST_REQUIRE(face1->sentData[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
+  BOOST_CHECK_EQUAL(*face1->sentData[0].getTag<lp::IncomingFaceIdTag>(), face2->getId());
   BOOST_CHECK_EQUAL(forwarder.getCounters().nInData, 1);
   BOOST_CHECK_EQUAL(forwarder.getCounters().nOutData, 1);
 }
@@ -90,9 +88,9 @@
   LimitedIo limitedIo;
   Forwarder forwarder;
 
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
@@ -115,12 +113,12 @@
   face1->receiveInterest(*interestA);
   limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(5));
   // Interest matching ContentStore should not be forwarded
-  BOOST_REQUIRE_EQUAL(face2->m_sentInterests.size(), 0);
+  BOOST_REQUIRE_EQUAL(face2->sentInterests.size(), 0);
 
-  BOOST_REQUIRE_EQUAL(face1->m_sentDatas.size(), 1);
+  BOOST_REQUIRE_EQUAL(face1->sentData.size(), 1);
   // IncomingFaceId field should be reset to represent CS
-  BOOST_REQUIRE(face1->m_sentDatas[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
-  BOOST_CHECK_EQUAL(*face1->m_sentDatas[0].getTag<lp::IncomingFaceIdTag>(), FACEID_CONTENT_STORE);
+  BOOST_REQUIRE(face1->sentData[0].getTag<lp::IncomingFaceIdTag>() != nullptr);
+  BOOST_CHECK_EQUAL(*face1->sentData[0].getTag<lp::IncomingFaceIdTag>(), face::FACEID_CONTENT_STORE);
 
   limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(500));
   // PIT entry should not be left behind
@@ -155,8 +153,8 @@
 BOOST_AUTO_TEST_CASE(ScopeLocalhostIncoming)
 {
   ScopeLocalhostIncomingTestForwarder forwarder;
-  shared_ptr<Face> face1 = make_shared<DummyLocalFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
+  auto face1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+  auto face2 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
@@ -212,9 +210,9 @@
 BOOST_AUTO_TEST_CASE(ScopeLocalhostOutgoing)
 {
   Forwarder forwarder;
-  shared_ptr<DummyLocalFace> face1 = make_shared<DummyLocalFace>();
-  shared_ptr<DummyFace>      face2 = make_shared<DummyFace>();
-  shared_ptr<Face>           face3 = make_shared<DummyLocalFace>();
+  auto face1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
@@ -224,62 +222,62 @@
   shared_ptr<Interest> interestA1 = makeInterest("/localhost/A1");
   shared_ptr<pit::Entry> pitA1 = pit.insert(*interestA1).first;
   pitA1->insertOrUpdateInRecord(face3, *interestA1);
-  face1->m_sentInterests.clear();
+  face1->sentInterests.clear();
   forwarder.onOutgoingInterest(pitA1, *face1);
-  BOOST_CHECK_EQUAL(face1->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentInterests.size(), 1);
 
   // non-local face, /localhost: violate
   shared_ptr<Interest> interestA2 = makeInterest("/localhost/A2");
   shared_ptr<pit::Entry> pitA2 = pit.insert(*interestA2).first;
   pitA2->insertOrUpdateInRecord(face3, *interestA2);
-  face2->m_sentInterests.clear();
+  face2->sentInterests.clear();
   forwarder.onOutgoingInterest(pitA2, *face2);
-  BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 0);
+  BOOST_CHECK_EQUAL(face2->sentInterests.size(), 0);
 
   // local face, non-/localhost: OK
   shared_ptr<Interest> interestA3 = makeInterest("/A3");
   shared_ptr<pit::Entry> pitA3 = pit.insert(*interestA3).first;
   pitA3->insertOrUpdateInRecord(face3, *interestA3);
-  face1->m_sentInterests.clear();
+  face1->sentInterests.clear();
   forwarder.onOutgoingInterest(pitA3, *face1);
-  BOOST_CHECK_EQUAL(face1->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentInterests.size(), 1);
 
   // non-local face, non-/localhost: OK
   shared_ptr<Interest> interestA4 = makeInterest("/A4");
   shared_ptr<pit::Entry> pitA4 = pit.insert(*interestA4).first;
   pitA4->insertOrUpdateInRecord(face3, *interestA4);
-  face2->m_sentInterests.clear();
+  face2->sentInterests.clear();
   forwarder.onOutgoingInterest(pitA4, *face2);
-  BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face2->sentInterests.size(), 1);
 
   // local face, /localhost: OK
-  face1->m_sentDatas.clear();
+  face1->sentData.clear();
   forwarder.onOutgoingData(Data("/localhost/B1"), *face1);
-  BOOST_CHECK_EQUAL(face1->m_sentDatas.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentData.size(), 1);
 
   // non-local face, /localhost: OK
-  face2->m_sentDatas.clear();
+  face2->sentData.clear();
   forwarder.onOutgoingData(Data("/localhost/B2"), *face2);
-  BOOST_CHECK_EQUAL(face2->m_sentDatas.size(), 0);
+  BOOST_CHECK_EQUAL(face2->sentData.size(), 0);
 
   // local face, non-/localhost: OK
-  face1->m_sentDatas.clear();
+  face1->sentData.clear();
   forwarder.onOutgoingData(Data("/B3"), *face1);
-  BOOST_CHECK_EQUAL(face1->m_sentDatas.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentData.size(), 1);
 
   // non-local face, non-/localhost: OK
-  face2->m_sentDatas.clear();
+  face2->sentData.clear();
   forwarder.onOutgoingData(Data("/B4"), *face2);
-  BOOST_CHECK_EQUAL(face2->m_sentDatas.size(), 1);
+  BOOST_CHECK_EQUAL(face2->sentData.size(), 1);
 }
 
 BOOST_AUTO_TEST_CASE(ScopeLocalhopOutgoing)
 {
   Forwarder forwarder;
-  shared_ptr<DummyLocalFace> face1 = make_shared<DummyLocalFace>();
-  shared_ptr<DummyFace>      face2 = make_shared<DummyFace>();
-  shared_ptr<DummyLocalFace> face3 = make_shared<DummyLocalFace>();
-  shared_ptr<DummyFace>      face4 = make_shared<DummyFace>();
+  auto face1 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
+  auto face4 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
@@ -290,59 +288,59 @@
   shared_ptr<Interest> interest1 = makeInterest("/localhop/1");
   shared_ptr<pit::Entry> pit1 = pit.insert(*interest1).first;
   pit1->insertOrUpdateInRecord(face1, *interest1);
-  face3->m_sentInterests.clear();
+  face3->sentInterests.clear();
   forwarder.onOutgoingInterest(pit1, *face3);
-  BOOST_CHECK_EQUAL(face3->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face3->sentInterests.size(), 1);
 
   // from non-local face, to local face: OK
   shared_ptr<Interest> interest2 = makeInterest("/localhop/2");
   shared_ptr<pit::Entry> pit2 = pit.insert(*interest2).first;
   pit2->insertOrUpdateInRecord(face2, *interest2);
-  face3->m_sentInterests.clear();
+  face3->sentInterests.clear();
   forwarder.onOutgoingInterest(pit2, *face3);
-  BOOST_CHECK_EQUAL(face3->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face3->sentInterests.size(), 1);
 
   // from local face, to non-local face: OK
   shared_ptr<Interest> interest3 = makeInterest("/localhop/3");
   shared_ptr<pit::Entry> pit3 = pit.insert(*interest3).first;
   pit3->insertOrUpdateInRecord(face1, *interest3);
-  face4->m_sentInterests.clear();
+  face4->sentInterests.clear();
   forwarder.onOutgoingInterest(pit3, *face4);
-  BOOST_CHECK_EQUAL(face4->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face4->sentInterests.size(), 1);
 
   // from non-local face, to non-local face: violate
   shared_ptr<Interest> interest4 = makeInterest("/localhop/4");
   shared_ptr<pit::Entry> pit4 = pit.insert(*interest4).first;
   pit4->insertOrUpdateInRecord(face2, *interest4);
-  face4->m_sentInterests.clear();
+  face4->sentInterests.clear();
   forwarder.onOutgoingInterest(pit4, *face4);
-  BOOST_CHECK_EQUAL(face4->m_sentInterests.size(), 0);
+  BOOST_CHECK_EQUAL(face4->sentInterests.size(), 0);
 
   // from local face and non-local face, to local face: OK
   shared_ptr<Interest> interest5 = makeInterest("/localhop/5");
   shared_ptr<pit::Entry> pit5 = pit.insert(*interest5).first;
   pit5->insertOrUpdateInRecord(face1, *interest5);
   pit5->insertOrUpdateInRecord(face2, *interest5);
-  face3->m_sentInterests.clear();
+  face3->sentInterests.clear();
   forwarder.onOutgoingInterest(pit5, *face3);
-  BOOST_CHECK_EQUAL(face3->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face3->sentInterests.size(), 1);
 
   // from local face and non-local face, to non-local face: OK
   shared_ptr<Interest> interest6 = makeInterest("/localhop/6");
   shared_ptr<pit::Entry> pit6 = pit.insert(*interest6).first;
   pit6->insertOrUpdateInRecord(face1, *interest6);
   pit6->insertOrUpdateInRecord(face2, *interest6);
-  face4->m_sentInterests.clear();
+  face4->sentInterests.clear();
   forwarder.onOutgoingInterest(pit6, *face4);
-  BOOST_CHECK_EQUAL(face4->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face4->sentInterests.size(), 1);
 }
 
 BOOST_AUTO_TEST_CASE(IncomingInterestStrategyDispatch)
 {
   LimitedIo limitedIo;
   Forwarder forwarder;
-  shared_ptr<Face> face1 = make_shared<DummyFace>();
-  shared_ptr<Face> face2 = make_shared<DummyFace>();
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
 
@@ -398,10 +396,10 @@
 {
   LimitedIo limitedIo;
   Forwarder forwarder;
-  shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
-  shared_ptr<DummyFace> face4 = make_shared<DummyFace>();
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>();
+  auto face4 = make_shared<DummyFace>();
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
@@ -424,10 +422,10 @@
   forwarder.onIncomingData(*face3, *dataD);
   limitedIo.run(LimitedIo::UNLIMITED_OPS, time::milliseconds(5));
 
-  BOOST_CHECK_EQUAL(face1->m_sentDatas.size(), 1);
-  BOOST_CHECK_EQUAL(face2->m_sentDatas.size(), 1);
-  BOOST_CHECK_EQUAL(face3->m_sentDatas.size(), 0);
-  BOOST_CHECK_EQUAL(face4->m_sentDatas.size(), 1);
+  BOOST_CHECK_EQUAL(face1->sentData.size(), 1);
+  BOOST_CHECK_EQUAL(face2->sentData.size(), 1);
+  BOOST_CHECK_EQUAL(face3->sentData.size(), 0);
+  BOOST_CHECK_EQUAL(face4->sentData.size(), 1);
 }
 
 BOOST_AUTO_TEST_CASE(IncomingNack)
@@ -435,11 +433,10 @@
   Forwarder forwarder;
   auto face1 = make_shared<DummyFace>();
   auto face2 = make_shared<DummyFace>();
-  auto face3 = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>(
-               "dummy://", "dummy://",
-               ndn::nfd::FACE_SCOPE_NON_LOCAL,
-               ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-               ndn::nfd::LINK_TYPE_MULTI_ACCESS));
+  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
+                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   forwarder.addFace(face3);
@@ -524,20 +521,15 @@
 BOOST_AUTO_TEST_CASE(OutgoingNack)
 {
   Forwarder forwarder;
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-  auto face2w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face2 = static_cast<DummyLpFace*>(face2w->getLpFace());
-  auto face3w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>(
-                "dummy://", "dummy://",
-                ndn::nfd::FACE_SCOPE_NON_LOCAL,
-                ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                ndn::nfd::LINK_TYPE_MULTI_ACCESS));
-  auto face3 = static_cast<DummyLpFace*>(face3w->getLpFace());
-  forwarder.addFace(face1w);
-  forwarder.addFace(face2w);
-  forwarder.addFace(face3w);
-  // TODO#3172 eliminate wrapper
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
+                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+  forwarder.addFace(face1);
+  forwarder.addFace(face2);
+  forwarder.addFace(face3);
 
   Pit& pit = forwarder.getPit();
 
@@ -547,68 +539,63 @@
   // don't send Nack if there's no in-record
   shared_ptr<Interest> interest1 = makeInterest("/fM5IVEtC", 719);
   shared_ptr<pit::Entry> pit1 = pit.insert(*interest1).first;
-  pit1->insertOrUpdateInRecord(face1w, *interest1);
+  pit1->insertOrUpdateInRecord(face1, *interest1);
 
   face2->sentNacks.clear();
-  forwarder.onOutgoingNack(pit1, *face2w, nackHeader);
+  forwarder.onOutgoingNack(pit1, *face2, nackHeader);
   BOOST_CHECK_EQUAL(face2->sentNacks.size(), 0);
 
   // send Nack with correct Nonce
   shared_ptr<Interest> interest2a = makeInterest("/Vi8tRm9MG3", 152);
   shared_ptr<pit::Entry> pit2 = pit.insert(*interest2a).first;
-  pit2->insertOrUpdateInRecord(face1w, *interest2a);
+  pit2->insertOrUpdateInRecord(face1, *interest2a);
   shared_ptr<Interest> interest2b = makeInterest("/Vi8tRm9MG3", 808);
-  pit2->insertOrUpdateInRecord(face2w, *interest2b);
+  pit2->insertOrUpdateInRecord(face2, *interest2b);
 
   face1->sentNacks.clear();
-  forwarder.onOutgoingNack(pit2, *face1w, nackHeader);
+  forwarder.onOutgoingNack(pit2, *face1, nackHeader);
   BOOST_REQUIRE_EQUAL(face1->sentNacks.size(), 1);
   BOOST_CHECK_EQUAL(face1->sentNacks.back().getReason(), lp::NackReason::CONGESTION);
   BOOST_CHECK_EQUAL(face1->sentNacks.back().getInterest().getNonce(), 152);
 
   // erase in-record
-  pit::InRecordCollection::const_iterator inRecord2a = pit2->getInRecord(*face1w);
+  pit::InRecordCollection::const_iterator inRecord2a = pit2->getInRecord(*face1);
   BOOST_CHECK(inRecord2a == pit2->getInRecords().end());
 
   // send Nack with correct Nonce
   face2->sentNacks.clear();
-  forwarder.onOutgoingNack(pit2, *face2w, nackHeader);
+  forwarder.onOutgoingNack(pit2, *face2, nackHeader);
   BOOST_REQUIRE_EQUAL(face2->sentNacks.size(), 1);
   BOOST_CHECK_EQUAL(face2->sentNacks.back().getReason(), lp::NackReason::CONGESTION);
   BOOST_CHECK_EQUAL(face2->sentNacks.back().getInterest().getNonce(), 808);
 
   // erase in-record
-  pit::InRecordCollection::const_iterator inRecord2b = pit2->getInRecord(*face1w);
+  pit::InRecordCollection::const_iterator inRecord2b = pit2->getInRecord(*face1);
   BOOST_CHECK(inRecord2b == pit2->getInRecords().end());
 
   // don't send Nack to multi-access face
   shared_ptr<Interest> interest2c = makeInterest("/Vi8tRm9MG3", 228);
-  pit2->insertOrUpdateInRecord(face3w, *interest2c);
+  pit2->insertOrUpdateInRecord(face3, *interest2c);
 
   face3->sentNacks.clear();
-  forwarder.onOutgoingNack(pit1, *face3w, nackHeader);
+  forwarder.onOutgoingNack(pit1, *face3, nackHeader);
   BOOST_CHECK_EQUAL(face3->sentNacks.size(), 0);
 }
 
 BOOST_AUTO_TEST_CASE(InterestLoopNack)
 {
   Forwarder forwarder;
-  auto face1w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face1 = static_cast<DummyLpFace*>(face1w->getLpFace());
-  auto face2w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>());
-  auto face2 = static_cast<DummyLpFace*>(face2w->getLpFace());
-  auto face3w = make_shared<face::LpFaceWrapper>(make_unique<DummyLpFace>(
-                "dummy://", "dummy://",
-                ndn::nfd::FACE_SCOPE_NON_LOCAL,
-                ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
-                ndn::nfd::LINK_TYPE_MULTI_ACCESS));
-  auto face3 = static_cast<DummyLpFace*>(face3w->getLpFace());
+  auto face1 = make_shared<DummyFace>();
+  auto face2 = make_shared<DummyFace>();
+  auto face3 = make_shared<DummyFace>("dummy://", "dummy://",
+                                      ndn::nfd::FACE_SCOPE_NON_LOCAL,
+                                      ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                                      ndn::nfd::LINK_TYPE_MULTI_ACCESS);
   auto face4 = make_shared<DummyFace>();
-  forwarder.addFace(face1w);
-  forwarder.addFace(face2w);
-  forwarder.addFace(face3w);
+  forwarder.addFace(face1);
+  forwarder.addFace(face2);
+  forwarder.addFace(face3);
   forwarder.addFace(face4);
-  // TODO#3172 eliminate wrapper
 
   Fib& fib = forwarder.getFib();
   shared_ptr<fib::Entry> fibEntry = fib.insert(Name("/zT4XwK0Hnx")).first;
@@ -658,8 +645,11 @@
   forwarder.addFace(face2);
 
   // cause an Interest sent out of face2 to loop back into face1 after a delay
-  face2->onSendInterest.connect([&face1] (const Interest& interest) {
-    scheduler::schedule(time::milliseconds(170), [&] { face1->receiveInterest(interest); });
+  face2->afterSend.connect([face1, face2] (uint32_t pktType) {
+    if (pktType == tlv::Interest) {
+      auto interest = make_shared<Interest>(face2->sentInterests.back());
+      scheduler::schedule(time::milliseconds(170), [face1, interest] { face1->receiveInterest(*interest); });
+    }
   });
 
   Fib& fib = forwarder.getFib();
@@ -676,7 +666,7 @@
   BOOST_ASSERT(time::milliseconds(25) * 40 < forwarder.getDeadNonceList().getLifetime());
   this->advanceClocks(time::milliseconds(25), 40);
 
-  BOOST_CHECK_EQUAL(face2->m_sentInterests.size(), 1);
+  BOOST_CHECK_EQUAL(face2->sentInterests.size(), 1);
 
   // It's unnecessary to check that Interest with duplicate Nonce can be forwarded again
   // after it's gone from Dead Nonce List, because the entry lifetime of Dead Nonce List
diff --git a/tests/daemon/fw/strategy.t.cpp b/tests/daemon/fw/strategy.t.cpp
index 44fead2..90654d7 100644
--- a/tests/daemon/fw/strategy.t.cpp
+++ b/tests/daemon/fw/strategy.t.cpp
@@ -36,7 +36,8 @@
 
 using namespace nfd::tests;
 
-BOOST_FIXTURE_TEST_SUITE(FwStrategy, BaseFixture)
+BOOST_AUTO_TEST_SUITE(Fw)
+BOOST_FIXTURE_TEST_SUITE(TestStrategy, BaseFixture)
 
 class FaceTableAccessTestStrategy : public DummyStrategy
 {
@@ -58,7 +59,7 @@
   {
     auto enumerable = this->getFaceTable() |
                       boost::adaptors::filtered([] (shared_ptr<Face> face) {
-                        return face->isLocal();
+                        return face->getScope() == ndn::nfd::FACE_SCOPE_LOCAL;
                       });
 
     std::vector<FaceId> results;
@@ -79,7 +80,7 @@
   FaceTableAccessTestStrategy strategy(forwarder);
 
   auto face1 = make_shared<DummyFace>();
-  auto face2 = make_shared<DummyLocalFace>();
+  auto face2 = make_shared<DummyFace>("dummy://", "dummy://", ndn::nfd::FACE_SCOPE_LOCAL);
   forwarder.addFace(face1);
   forwarder.addFace(face2);
   FaceId id1 = face1->getId();
@@ -94,7 +95,8 @@
   BOOST_CHECK((strategy.removedFaces == std::vector<FaceId>{id2, id1}));
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestStrategy
+BOOST_AUTO_TEST_SUITE_END() // Fw
 
 } // namespace tests
 } // namespace fw
diff --git a/tests/daemon/fw/topology-tester.cpp b/tests/daemon/fw/topology-tester.cpp
index 8b94abc..f1e54bb 100644
--- a/tests/daemon/fw/topology-tester.cpp
+++ b/tests/daemon/fw/topology-tester.cpp
@@ -34,7 +34,6 @@
 using face::InternalTransportBase;
 using face::InternalForwarderTransport;
 using face::InternalClientTransport;
-using face::LpFaceWrapper;
 using face::GenericLinkService;
 
 TopologyLink::TopologyLink(const time::nanoseconds& delay)
@@ -46,9 +45,9 @@
 }
 
 void
-TopologyLink::addFace(TopologyNode i, shared_ptr<LpFaceWrapper> face)
+TopologyLink::addFace(TopologyNode i, shared_ptr<Face> face)
 {
-  this->attachTransport(i, dynamic_cast<InternalTransportBase*>(face->getLpFace()->getTransport()));
+  this->attachTransport(i, dynamic_cast<InternalTransportBase*>(face->getTransport()));
   m_faces[i] = face;
 }
 
@@ -87,9 +86,9 @@
   });
 }
 
-TopologyAppLink::TopologyAppLink(shared_ptr<LpFaceWrapper> forwarderFace)
+TopologyAppLink::TopologyAppLink(shared_ptr<Face> forwarderFace)
   : m_face(forwarderFace)
-  , m_forwarderTransport(static_cast<InternalForwarderTransport*>(forwarderFace->getLpFace()->getTransport()))
+  , m_forwarderTransport(static_cast<InternalForwarderTransport*>(forwarderFace->getTransport()))
   , m_clientTransport(make_shared<InternalClientTransport>())
   , m_client(make_shared<ndn::Face>(m_clientTransport, getGlobalIoService()))
 {
@@ -136,11 +135,10 @@
     auto service = make_unique<GenericLinkService>();
     auto transport = make_unique<InternalForwarderTransport>(localUri, remoteUri,
                      ndn::nfd::FACE_SCOPE_NON_LOCAL, linkType);
-    auto face = make_unique<LpFace>(std::move(service), std::move(transport));
-    auto faceW = make_shared<LpFaceWrapper>(std::move(face));
+    auto face = make_shared<Face>(std::move(service), std::move(transport));
 
-    forwarder.addFace(faceW);
-    link->addFace(i, faceW);
+    forwarder.addFace(face);
+    link->addFace(i, face);
   }
 
   m_links.push_back(link); // keep a shared_ptr so callers don't have to
@@ -157,12 +155,11 @@
   auto service = make_unique<GenericLinkService>();
   auto transport = make_unique<InternalForwarderTransport>(localUri, remoteUri,
                    ndn::nfd::FACE_SCOPE_LOCAL, ndn::nfd::LINK_TYPE_POINT_TO_POINT);
-  auto face = make_unique<LpFace>(std::move(service), std::move(transport));
-  auto faceW = make_shared<LpFaceWrapper>(std::move(face));
+  auto face = make_shared<Face>(std::move(service), std::move(transport));
 
-  forwarder.addFace(faceW);
+  forwarder.addFace(face);
 
-  auto al = make_shared<TopologyAppLink>(faceW);
+  auto al = make_shared<TopologyAppLink>(face);
   m_appLinks.push_back(al); // keep a shared_ptr so callers don't have to
   return al;
 }
diff --git a/tests/daemon/fw/topology-tester.hpp b/tests/daemon/fw/topology-tester.hpp
index 9a10ad7..88d73da 100644
--- a/tests/daemon/fw/topology-tester.hpp
+++ b/tests/daemon/fw/topology-tester.hpp
@@ -32,7 +32,7 @@
 
 #include <ndn-cxx/face.hpp>
 #include "face/internal-transport.hpp"
-#include "face/lp-face-wrapper.hpp"
+#include "face/face.hpp"
 #include "fw/strategy.hpp"
 #include "tests/test-common.hpp"
 
@@ -70,8 +70,12 @@
     m_isUp = true;
   }
 
+  /** \brief attach a face to the link
+   *  \param i forwarder index
+   *  \param face a Face with InternalForwarderTransport
+   */
   void
-  addFace(TopologyNode i, shared_ptr<face::LpFaceWrapper> face);
+  addFace(TopologyNode i, shared_ptr<Face> face);
 
   /** \return a face of forwarder \p i which is attached to this link
    */
@@ -98,7 +102,7 @@
   bool m_isUp;
   time::nanoseconds m_delay;
   std::unordered_map<TopologyNode, face::InternalTransportBase*> m_transports;
-  std::unordered_map<TopologyNode, shared_ptr<face::LpFaceWrapper>> m_faces;
+  std::unordered_map<TopologyNode, shared_ptr<Face>> m_faces;
 };
 
 /** \brief represents a link to a local application
@@ -106,8 +110,11 @@
 class TopologyAppLink : noncopyable
 {
 public:
+  /** \brief constructor
+   *  \param forwarderFace a Face with InternalForwarderTransport
+   */
   explicit
-  TopologyAppLink(shared_ptr<face::LpFaceWrapper> forwarderFace);
+  TopologyAppLink(shared_ptr<Face> forwarderFace);
 
   /** \brief fail the link, cause packets to be dropped silently
    */
diff --git a/tests/daemon/mgmt/face-manager.t.cpp b/tests/daemon/mgmt/face-manager.t.cpp
index 02bcd78..a8f3015 100644
--- a/tests/daemon/mgmt/face-manager.t.cpp
+++ b/tests/daemon/mgmt/face-manager.t.cpp
@@ -37,6 +37,9 @@
 namespace nfd {
 namespace tests {
 
+BOOST_AUTO_TEST_SUITE(Mgmt)
+
+
 class FaceManagerFixture : public ManagerCommonFixture
 {
 public:
@@ -48,32 +51,74 @@
   }
 
 public:
-  template<typename Face>
+  enum AddFaceFlags {
+    REMOVE_LAST_NOTIFICATION = 1 << 0,
+    SET_SCOPE_LOCAL          = 1 << 1,
+    SET_URI_TEST             = 1 << 2,
+    RANDOMIZE_COUNTERS       = 1 << 3
+  };
+
+  /** \brief adds a face to the FaceTable
+   *  \param options bitwise OR'ed AddFaceFlags
+   */
   shared_ptr<Face>
-  addFace(bool wantRemoveLastNotification = false)
+  addFace(int flags = 0)
   {
-    auto face = make_shared<Face>();
+    std::string uri = "dummy://";
+    ndn::nfd::FaceScope scope = ndn::nfd::FACE_SCOPE_NON_LOCAL;
+
+    if ((flags & SET_SCOPE_LOCAL) != 0) {
+      scope = ndn::nfd::FACE_SCOPE_LOCAL;
+    }
+    if ((flags & SET_URI_TEST) != 0) {
+      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();
+      randomizeCounter(counters.nInInterests);
+      randomizeCounter(counters.nOutInterests);
+      randomizeCounter(counters.nInData);
+      randomizeCounter(counters.nOutData);
+      randomizeCounter(counters.nInNacks);
+      randomizeCounter(counters.nOutNacks);
+      randomizeCounter(counters.nInPackets);
+      randomizeCounter(counters.nOutPackets);
+      randomizeCounter(counters.nInBytes);
+      randomizeCounter(counters.nOutBytes);
+    }
+
     advanceClocks(time::milliseconds(1), 10); // wait for notification posted
-    if (wantRemoveLastNotification) {
+    if ((flags & REMOVE_LAST_NOTIFICATION) != 0) {
       m_responses.pop_back();
     }
+
     return face;
   }
 
+private:
+  template<typename T>
+  static typename std::enable_if<std::is_base_of<SimpleCounter, T>::value>::type
+  randomizeCounter(const T& counter)
+  {
+    const_cast<T&>(counter).set(ndn::random::generateWord64());
+  }
+
 protected:
   FaceTable& m_faceTable;
   FaceManager m_manager;
 };
 
-BOOST_FIXTURE_TEST_SUITE(Mgmt, FaceManagerFixture)
-BOOST_AUTO_TEST_SUITE(TestFaceManager)
+BOOST_FIXTURE_TEST_SUITE(TestFaceManager, FaceManagerFixture)
 
 BOOST_AUTO_TEST_SUITE(DestroyFace)
 
 BOOST_AUTO_TEST_CASE(Existing)
 {
-  auto addedFace = addFace<DummyFace>(true); // clear notification for creation
+  auto addedFace = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // clear notification for creation
 
   auto parameters = ControlParameters().setFaceId(addedFace->getId());
   auto command = makeControlCommandRequest("/localhost/nfd/faces/destroy", parameters);
@@ -86,7 +131,7 @@
   BOOST_CHECK_EQUAL(checkResponse(1, command->getName(), makeResponse(200, "OK", parameters)),
                     CheckResponseResult::OK);
 
-  BOOST_CHECK_EQUAL(addedFace->getId(), -1);
+  BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
 }
 
 BOOST_AUTO_TEST_CASE(NonExisting)
@@ -106,7 +151,7 @@
 
 BOOST_AUTO_TEST_CASE(FaceEvents)
 {
-  auto addedFace = addFace<DummyFace>(); // trigger FACE_EVENT_CREATED notification
+  auto addedFace = addFace(); // trigger FACE_EVENT_CREATED notification
   BOOST_CHECK_NE(addedFace->getId(), -1);
   int64_t faceId = addedFace->getId();
 
@@ -146,25 +191,9 @@
     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(addedFace->getId(), -1);
+  BOOST_CHECK_EQUAL(addedFace->getId(), face::INVALID_FACEID);
 }
 
-class TestFace : public DummyFace
-{
-public:
-  explicit
-  TestFace(const std::string& uri = "test://")
-    : DummyFace(uri, uri)
-  {
-    getMutableCounters().getNInInterests().set(ndn::random::generateWord64());
-    getMutableCounters().getNInDatas().set(ndn::random::generateWord64());
-    getMutableCounters().getNOutInterests().set(ndn::random::generateWord64());
-    getMutableCounters().getNOutDatas().set(ndn::random::generateWord64());
-    getMutableCounters().getNInBytes().set(ndn::random::generateWord64());
-    getMutableCounters().getNOutBytes().set(ndn::random::generateWord64());
-  }
-};
-
 // @todo Refactor when ndn::nfd::FaceStatus implementes operator!= and operator<<
 class FaceStatus : public ndn::nfd::FaceStatus
 {
@@ -179,16 +208,16 @@
 operator!=(const FaceStatus& left, const FaceStatus& right)
 {
   return left.getRemoteUri() != right.getRemoteUri() ||
-    left.getLocalUri() != right.getLocalUri() ||
-    left.getFaceScope() != right.getFaceScope() ||
-    left.getFacePersistency() != right.getFacePersistency() ||
-    left.getLinkType() != right.getLinkType() ||
-    left.getNInInterests() != right.getNInInterests() ||
-    left.getNInDatas() != right.getNInDatas() ||
-    left.getNOutInterests() != right.getNOutInterests() ||
-    left.getNOutDatas() != right.getNOutDatas() ||
-    left.getNInBytes() != right.getNInBytes() ||
-    left.getNOutBytes() != right.getNOutBytes();
+         left.getLocalUri() != right.getLocalUri() ||
+         left.getFaceScope() != right.getFaceScope() ||
+         left.getFacePersistency() != right.getFacePersistency() ||
+         left.getLinkType() != right.getLinkType() ||
+         left.getNInInterests() != right.getNInInterests() ||
+         left.getNInDatas() != right.getNInDatas() ||
+         left.getNOutInterests() != right.getNOutInterests() ||
+         left.getNOutDatas() != right.getNOutDatas() ||
+         left.getNInBytes() != right.getNInBytes() ||
+         left.getNOutBytes() != right.getNOutBytes();
 }
 
 std::ostream&
@@ -210,8 +239,8 @@
 BOOST_AUTO_TEST_CASE(FaceDataset)
 {
   size_t nEntries = 303;
-  for (size_t i = 0 ; i < nEntries ; i ++) {
-    addFace<TestFace>(true);
+  for (size_t i = 0; i < nEntries; ++i) {
+    addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST | RANDOMIZE_COUNTERS);
   }
 
   receiveInterest(makeInterest("/localhost/nfd/faces/list"));
@@ -237,9 +266,9 @@
 
 BOOST_AUTO_TEST_CASE(FaceQuery)
 {
-  auto face1 = addFace<DummyFace>(true); // dummy://
-  auto face2 = addFace<DummyLocalFace>(true); // dummy://, local
-  auto face3 = addFace<TestFace>(true); // test://
+  auto face1 = addFace(REMOVE_LAST_NOTIFICATION); // dummy://
+  auto face2 = addFace(REMOVE_LAST_NOTIFICATION | SET_SCOPE_LOCAL); // dummy://, local
+  auto face3 = addFace(REMOVE_LAST_NOTIFICATION | SET_URI_TEST); // test://
 
   auto generateQueryName = [] (const ndn::nfd::FaceQueryFilter& filter) {
     return Name("/localhost/nfd/faces/query").append(filter.wireEncode());
diff --git a/tests/daemon/mgmt/fib-manager.t.cpp b/tests/daemon/mgmt/fib-manager.t.cpp
index 945a07e..87856ed 100644
--- a/tests/daemon/mgmt/fib-manager.t.cpp
+++ b/tests/daemon/mgmt/fib-manager.t.cpp
@@ -80,7 +80,7 @@
    * @brief check whether the nexthop record is added / removed properly
    *
    * @param expectedNNextHops use -1 to skip this check
-   * @param faceId use FACEID_NULL to skip NextHopRecord checks
+   * @param faceId use face::FACEID_NULL to skip NextHopRecord checks
    * @param expectedCost use -1 to skip this check
    *
    * @retval OK FIB entry is found by exact match and has the expected number of nexthops;
@@ -92,7 +92,7 @@
    */
   CheckNextHopResult
   checkNextHop(const Name& prefix, ssize_t expectedNNextHops = -1,
-               FaceId faceId = FACEID_NULL, int32_t expectedCost = -1)
+               FaceId faceId = face::FACEID_NULL, int32_t expectedCost = -1)
   {
     auto entry = m_fib.findExactMatch(prefix);
     if (!static_cast<bool>(entry)) {
@@ -104,7 +104,7 @@
       return CheckNextHopResult::WRONG_N_NEXTHOPS;
     }
 
-    if (faceId != FACEID_NULL) {
+    if (faceId != face::FACEID_NULL) {
       for (auto&& record : nextHops) {
         if (record.getFace()->getId() == faceId) {
           return expectedCost != -1 && record.getCost() != static_cast<uint32_t>(expectedCost) ?
@@ -158,7 +158,7 @@
 BOOST_AUTO_TEST_CASE(UnknownFaceId)
 {
   auto command = makeControlCommandRequest("/localhost/nfd/fib/add-nexthop",
-                                           makeParameters("hello", FACEID_NULL, 101));
+                                           makeParameters("hello", face::FACEID_NULL, 101));
   receiveInterest(command);
   BOOST_REQUIRE_EQUAL(m_responses.size(), 1);
 
@@ -167,14 +167,15 @@
                     CheckResponseResult::OK);
 
   // double check that the next hop was not added
-  BOOST_CHECK_EQUAL(checkNextHop("/hello", -1, FACEID_NULL, 101), CheckNextHopResult::NO_FIB_ENTRY);
+  BOOST_CHECK_EQUAL(checkNextHop("/hello", -1, face::FACEID_NULL, 101), CheckNextHopResult::NO_FIB_ENTRY);
 }
 
 BOOST_AUTO_TEST_CASE(ImplicitFaceId)
 {
   auto face1 = addFace();
   auto face2 = addFace();
-  BOOST_REQUIRE(face1 != INVALID_FACEID && face2 != INVALID_FACEID);
+  BOOST_REQUIRE_NE(face1, face::INVALID_FACEID);
+  BOOST_REQUIRE_NE(face2, face::INVALID_FACEID);
 
   Name expectedName;
   ControlResponse expectedResponse;
@@ -203,7 +204,7 @@
 BOOST_AUTO_TEST_CASE(InitialAdd)
 {
   FaceId addedFaceId = addFace();
-  BOOST_REQUIRE(addedFaceId != INVALID_FACEID);
+  BOOST_REQUIRE_NE(addedFaceId, face::INVALID_FACEID);
 
   auto parameters = makeParameters("hello", addedFaceId, 101);
   auto command = makeControlCommandRequest("/localhost/nfd/fib/add-nexthop", parameters);
@@ -218,7 +219,7 @@
 BOOST_AUTO_TEST_CASE(ImplicitCost)
 {
   FaceId addedFaceId = addFace();
-  BOOST_REQUIRE(addedFaceId != INVALID_FACEID);
+  BOOST_REQUIRE_NE(addedFaceId, face::INVALID_FACEID);
 
   auto originalParameters = ControlParameters().setName("/hello").setFaceId(addedFaceId);
   auto parameters = makeParameters("/hello", addedFaceId, 0);
@@ -234,7 +235,7 @@
 BOOST_AUTO_TEST_CASE(AddToExisting)
 {
   FaceId face = addFace();
-  BOOST_CHECK(face != INVALID_FACEID);
+  BOOST_REQUIRE_NE(face, face::INVALID_FACEID);
 
   Name expectedName;
   ControlResponse expectedResponse;
@@ -280,7 +281,9 @@
   FaceId face1 = addFace();
   FaceId face2 = addFace();
   FaceId face3 = addFace();
-  BOOST_REQUIRE(face1 != INVALID_FACEID && face2 != INVALID_FACEID && face3 != INVALID_FACEID);
+  BOOST_REQUIRE_NE(face1, face::INVALID_FACEID);
+  BOOST_REQUIRE_NE(face2, face::INVALID_FACEID);
+  BOOST_REQUIRE_NE(face3, face::INVALID_FACEID);
 
   shared_ptr<fib::Entry> entry = m_fib.insert("/hello").first;
   entry->addNextHop(m_faceTable.get(face1), 101);
@@ -306,7 +309,7 @@
 BOOST_AUTO_TEST_CASE(PrefixNotFound)
 {
   FaceId addedFaceId = addFace();
-  BOOST_CHECK(addedFaceId != INVALID_FACEID);
+  BOOST_REQUIRE_NE(addedFaceId, face::INVALID_FACEID);
 
   auto parameters = makeParameters("hello", addedFaceId);
   auto command = makeControlCommandRequest("/localhost/nfd/fib/remove-nexthop", parameters);
@@ -321,7 +324,8 @@
 {
   auto face1 = addFace();
   auto face2 = addFace();
-  BOOST_REQUIRE(face1 != INVALID_FACEID && face2 != INVALID_FACEID);
+  BOOST_REQUIRE_NE(face1, face::INVALID_FACEID);
+  BOOST_REQUIRE_NE(face2, face::INVALID_FACEID);
 
   Name expectedName;
   ControlResponse expectedResponse;
@@ -355,7 +359,8 @@
 {
   auto face1 = addFace();
   auto face2 = addFace();
-  BOOST_REQUIRE(face1 != INVALID_FACEID && face2 != INVALID_FACEID);
+  BOOST_REQUIRE_NE(face1, face::INVALID_FACEID);
+  BOOST_REQUIRE_NE(face2, face::INVALID_FACEID);
 
   Name expectedName;
   ControlResponse expectedResponse;