face: EthernetTransport

This commit replaces NDNLPv1 fragmentation and reassembly
with NDNLPv2 fragmentation and reassembly.

Change-Id: I10751157fcced94d441167ce470aaed79c12bb54
Refs: #3170
diff --git a/tests/daemon/face/ethernet-transport.t.cpp b/tests/daemon/face/ethernet-transport.t.cpp
new file mode 100644
index 0000000..85c799d
--- /dev/null
+++ b/tests/daemon/face/ethernet-transport.t.cpp
@@ -0,0 +1,60 @@
+/* -*- 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-transport.hpp"
+#include "transport-properties.hpp"
+
+#include "network-interface-fixture.hpp"
+
+namespace nfd {
+namespace face {
+namespace tests {
+
+using namespace nfd::tests;
+
+BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestEthernetTransport, NetworkInterfaceFixture)
+
+BOOST_AUTO_TEST_CASE(StaticProperties)
+{
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
+
+  auto netif = m_interfaces.front();
+  EthernetTransport transport(netif, ethernet::getDefaultMulticastAddress());
+  checkStaticPropertiesInitialized(transport);
+
+  BOOST_CHECK_EQUAL(transport.getLocalUri(), FaceUri::fromDev(netif.name));
+  BOOST_CHECK_EQUAL(transport.getRemoteUri(), FaceUri(ethernet::getDefaultMulticastAddress()));
+  BOOST_CHECK_EQUAL(transport.getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
+  BOOST_CHECK_EQUAL(transport.getPersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+  BOOST_CHECK_EQUAL(transport.getLinkType(), ndn::nfd::LINK_TYPE_MULTI_ACCESS);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestEthernetTransport
+BOOST_AUTO_TEST_SUITE_END() // Face
+
+} // namespace tests
+} // namespace face
+} // namespace nfd
diff --git a/tests/daemon/face/ethernet.t.cpp b/tests/daemon/face/ethernet.t.cpp
index 7d97016..0098436 100644
--- a/tests/daemon/face/ethernet.t.cpp
+++ b/tests/daemon/face/ethernet.t.cpp
@@ -23,11 +23,11 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "face/ethernet-face.hpp"
 #include "face/ethernet-factory.hpp"
+#include "face/ethernet-transport.hpp"
 
-#include "core/network-interface.hpp"
-#include "tests/test-common.hpp"
+#include "face/lp-face-wrapper.hpp"
+#include "network-interface-fixture.hpp"
 
 #include <pcap/pcap.h>
 
@@ -35,36 +35,10 @@
 namespace tests {
 
 BOOST_AUTO_TEST_SUITE(Face)
+BOOST_FIXTURE_TEST_SUITE(TestEthernet, NetworkInterfaceFixture)
 
 using nfd::Face;
 
-class InterfacesFixture : protected BaseFixture
-{
-protected:
-  InterfacesFixture()
-  {
-    EthernetFactory factory;
-
-    for (const auto& netif : listNetworkInterfaces()) {
-      if (!netif.isLoopback() && netif.isUp()) {
-        try {
-          factory.createMulticastFace(netif, ethernet::getBroadcastAddress());
-        }
-        catch (Face::Error&) {
-          continue;
-        }
-
-        m_interfaces.push_back(netif);
-      }
-    }
-  }
-
-protected:
-  std::vector<NetworkInterfaceInfo> m_interfaces;
-};
-
-BOOST_FIXTURE_TEST_SUITE(TestEthernet, InterfacesFixture)
-
 BOOST_AUTO_TEST_CASE(GetChannels)
 {
   EthernetFactory factory;
@@ -75,31 +49,19 @@
 
 BOOST_AUTO_TEST_CASE(MulticastFacesMap)
 {
-  if (m_interfaces.empty()) {
-    BOOST_WARN_MESSAGE(false, "No interfaces available for pcap, "
-                              "cannot perform MulticastFacesMap test");
-    return;
-  }
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
 
   EthernetFactory factory;
-  shared_ptr<EthernetFace> face1 = factory.createMulticastFace(m_interfaces.front(),
-                                                               ethernet::getBroadcastAddress());
-  shared_ptr<EthernetFace> face1bis = factory.createMulticastFace(m_interfaces.front(),
-                                                                  ethernet::getBroadcastAddress());
+  auto face1 = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
+  auto face1bis = factory.createMulticastFace(m_interfaces.front(), ethernet::getBroadcastAddress());
   BOOST_CHECK_EQUAL(face1, face1bis);
 
-  if (m_interfaces.size() > 1) {
-    shared_ptr<EthernetFace> face2 = factory.createMulticastFace(m_interfaces.back(),
-                                                                 ethernet::getBroadcastAddress());
-    BOOST_CHECK_NE(face1, face2);
-  }
-  else {
-    BOOST_WARN_MESSAGE(false, "Only one interface available for pcap, "
-                              "cannot test second EthernetFace creation");
-  }
+  auto face2 = factory.createMulticastFace(m_interfaces.front(), ethernet::getDefaultMulticastAddress());
+  BOOST_CHECK_NE(face1, face2);
 
-  shared_ptr<EthernetFace> face3 = factory.createMulticastFace(m_interfaces.front(),
-                                     ethernet::getDefaultMulticastAddress());
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(2);
+
+  auto face3 = factory.createMulticastFace(m_interfaces.back(), ethernet::getBroadcastAddress());
   BOOST_CHECK_NE(face1, face3);
 }
 
@@ -128,19 +90,14 @@
 
 BOOST_AUTO_TEST_CASE(SendPacket)
 {
-  if (m_interfaces.empty()) {
-    BOOST_WARN_MESSAGE(false, "No interfaces available for pcap, "
-                              "cannot perform SendPacket test");
-    return;
-  }
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
 
   EthernetFactory factory;
-  shared_ptr<EthernetFace> face = factory.createMulticastFace(m_interfaces.front(),
-                                    ethernet::getDefaultMulticastAddress());
+  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_PERSISTENT);
+  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() + "]");
@@ -162,40 +119,23 @@
   face->sendData    (*data2    );
 
   BOOST_CHECK_EQUAL(face->getCounters().nOutBytes,
-                    14 * 4 + // 4 NDNLP headers
                     interest1->wireEncode().size() +
                     data1->wireEncode().size() +
                     interest2->wireEncode().size() +
                     data2->wireEncode().size());
-
-//  m_ioRemaining = 4;
-//  m_ioService.run();
-//  m_ioService.reset();
-
-//  BOOST_REQUIRE_EQUAL(m_face1_receivedInterests.size(), 1);
-//  BOOST_REQUIRE_EQUAL(m_face1_receivedDatas    .size(), 1);
-//  BOOST_REQUIRE_EQUAL(m_face2_receivedInterests.size(), 1);
-//  BOOST_REQUIRE_EQUAL(m_face2_receivedDatas    .size(), 1);
-
-//  BOOST_CHECK_EQUAL(m_face1_receivedInterests[0].getName(), interest2.getName());
-//  BOOST_CHECK_EQUAL(m_face1_receivedDatas    [0].getName(), data2.getName());
-//  BOOST_CHECK_EQUAL(m_face2_receivedInterests[0].getName(), interest1.getName());
-//  BOOST_CHECK_EQUAL(m_face2_receivedDatas    [0].getName(), data1.getName());
 }
 
 BOOST_AUTO_TEST_CASE(ProcessIncomingPacket)
 {
-  if (m_interfaces.empty()) {
-    BOOST_WARN_MESSAGE(false, "No interfaces available for pcap, "
-                              "cannot perform ProcessIncomingPacket test");
-    return;
-  }
+  SKIP_IF_NETWORK_INTERFACE_COUNT_LT(1);
 
   EthernetFactory factory;
-  shared_ptr<EthernetFace> face = factory.createMulticastFace(m_interfaces.front(),
-                                    ethernet::getDefaultMulticastAddress());
+  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;
 
@@ -206,7 +146,7 @@
 
   // check that packet data is not accessed if pcap didn't capture anything (caplen == 0)
   static const pcap_pkthdr zeroHeader{};
-  face->processIncomingPacket(&zeroHeader, nullptr);
+  transport->processIncomingPacket(&zeroHeader, nullptr);
   BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
   BOOST_CHECK_EQUAL(recInterests.size(), 0);
   BOOST_CHECK_EQUAL(recDatas.size(), 0);
@@ -215,7 +155,7 @@
   pcap_pkthdr runtHeader{};
   runtHeader.caplen = ethernet::HDR_LEN + 6;
   static const uint8_t packet2[ethernet::HDR_LEN + 6]{};
-  face->processIncomingPacket(&runtHeader, packet2);
+  transport->processIncomingPacket(&runtHeader, packet2);
   BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
   BOOST_CHECK_EQUAL(recInterests.size(), 0);
   BOOST_CHECK_EQUAL(recDatas.size(), 0);
@@ -227,10 +167,10 @@
     0x01, 0x00, 0x5e, 0x00, 0x17, 0xaa, // destination address
     0x02, 0x00, 0x00, 0x00, 0x00, 0x02, // source address
     0x86, 0x24,       // NDN ethertype
-    tlv::NdnlpData,   // TLV type
+    tlv::Interest,    // TLV type
     0xfd, 0xff, 0xff  // TLV length (invalid because greater than buffer size)
   };
-  face->processIncomingPacket(&validHeader, packet3);
+  transport->processIncomingPacket(&validHeader, packet3);
   BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 0);
   BOOST_CHECK_EQUAL(recInterests.size(), 0);
   BOOST_CHECK_EQUAL(recDatas.size(), 0);
@@ -243,44 +183,41 @@
     0x00,             // TLV type (invalid)
     0x00              // TLV length
   };
-  face->processIncomingPacket(&validHeader, packet4);
+  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 NDNLP header, but invalid payload
+  // 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
-    tlv::NdnlpData,     0x0e,     // NDNLP header
-    tlv::NdnlpSequence, 0x08,
-    0, 0, 0, 0, 0, 0, 0, 0,
-    tlv::NdnlpPayload,  0x02,
-    0x00,             // NDN TLV type (invalid)
-    0x00              // NDN TLV length
+    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
   };
-  face->processIncomingPacket(&validHeader, packet5);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 18);
+  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 NDNLP header, and valid NDN (interest) packet
+  // 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
-    tlv::NdnlpData, 0x24,               // NDNLP TLV type and length
-    0x51, 0x08, 0x00, 0x00, 0x00, 0x00, // rest of NDNLP header
-    0x00, 0x00, 0x00, 0x00, 0x54, 0x18,
-    tlv::Interest, 0x16,                // NDN TLV type and length
+    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
   };
-  face->processIncomingPacket(&validHeader, packet6);
-  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 56);
+  transport->processIncomingPacket(&validHeader, packet6);
+  BOOST_CHECK_EQUAL(face->getCounters().nInBytes, 36);
   BOOST_CHECK_EQUAL(recInterests.size(), 1);
   BOOST_CHECK_EQUAL(recDatas.size(), 0);
 }
diff --git a/tests/daemon/face/ndnlp.t.cpp b/tests/daemon/face/ndnlp.t.cpp
deleted file mode 100644
index b372769..0000000
--- a/tests/daemon/face/ndnlp.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/ndnlp-sequence-generator.hpp"
-#include "face/ndnlp-slicer.hpp"
-#include "face/ndnlp-partial-message-store.hpp"
-
-#include "tests/test-common.hpp"
-
-#include <boost/scoped_array.hpp>
-
-namespace nfd {
-namespace ndnlp {
-namespace tests {
-
-using namespace nfd::tests;
-
-BOOST_FIXTURE_TEST_SUITE(FaceNdnlp, BaseFixture)
-
-BOOST_AUTO_TEST_CASE(SequenceBlock)
-{
-  ndnlp::SequenceBlock sb(0x8000, 2);
-  BOOST_CHECK_EQUAL(sb.count(), 2);
-  BOOST_CHECK_EQUAL(sb[0], 0x8000);
-  BOOST_CHECK_EQUAL(sb[1], 0x8001);
-  BOOST_CHECK_THROW(sb[2], std::out_of_range);
-}
-
-// sequence number can safely wrap around
-BOOST_AUTO_TEST_CASE(SequenceBlockWrap)
-{
-  ndnlp::SequenceBlock sb(std::numeric_limits<uint64_t>::max(), 2);
-  BOOST_CHECK_EQUAL(sb[0], std::numeric_limits<uint64_t>::max());
-  BOOST_CHECK_EQUAL(sb[1], std::numeric_limits<uint64_t>::min());
-  BOOST_CHECK_EQUAL(sb[1] - sb[0], 1);
-}
-
-BOOST_AUTO_TEST_CASE(SequenceGenerator)
-{
-  ndnlp::SequenceGenerator seqgen;
-
-  ndnlp::SequenceBlock sb1 = seqgen.nextBlock(2);
-  BOOST_CHECK_EQUAL(sb1.count(), 2);
-
-  ndnlp::SequenceBlock sb2 = seqgen.nextBlock(1);
-  BOOST_CHECK_NE(sb1[0], sb2[0]);
-  BOOST_CHECK_NE(sb1[1], sb2[0]);
-}
-
-// slice a Block to one fragment
-BOOST_AUTO_TEST_CASE(Slice1)
-{
-  uint8_t blockValue[60];
-  memset(blockValue, 0xcc, sizeof(blockValue));
-  Block block = ndn::dataBlock(0x01, blockValue, sizeof(blockValue));
-
-  ndnlp::Slicer slicer(9000);
-  ndnlp::PacketArray pa = slicer.slice(block);
-
-  BOOST_REQUIRE_EQUAL(pa->size(), 1);
-
-  const Block& pkt = pa->at(0);
-  BOOST_CHECK_EQUAL(pkt.type(), static_cast<uint32_t>(tlv::NdnlpData));
-  pkt.parse();
-
-  const Block::element_container& elements = pkt.elements();
-  BOOST_REQUIRE_EQUAL(elements.size(), 2);
-
-  const Block& sequenceElement = elements[0];
-  BOOST_CHECK_EQUAL(sequenceElement.type(), static_cast<uint32_t>(tlv::NdnlpSequence));
-  BOOST_REQUIRE_EQUAL(sequenceElement.value_size(), sizeof(uint64_t));
-
-  const Block& payloadElement = elements[1];
-  BOOST_CHECK_EQUAL(payloadElement.type(), static_cast<uint32_t>(tlv::NdnlpPayload));
-  size_t payloadSize = payloadElement.value_size();
-  BOOST_CHECK_EQUAL(payloadSize, block.size());
-
-  BOOST_CHECK_EQUAL_COLLECTIONS(payloadElement.value_begin(), payloadElement.value_end(),
-                                block.begin(),                block.end());
-}
-
-// slice a Block to four fragments
-BOOST_AUTO_TEST_CASE(Slice4)
-{
-  uint8_t blockValue[5050];
-  memset(blockValue, 0xcc, sizeof(blockValue));
-  Block block = ndn::dataBlock(0x01, blockValue, sizeof(blockValue));
-
-  ndnlp::Slicer slicer(1500);
-  ndnlp::PacketArray pa = slicer.slice(block);
-
-  BOOST_REQUIRE_EQUAL(pa->size(), 4);
-
-  uint64_t seq0 = 0xdddd;
-
-  size_t totalPayloadSize = 0;
-
-  for (size_t i = 0; i < 4; ++i) {
-    const Block& pkt = pa->at(i);
-    BOOST_CHECK_EQUAL(pkt.type(), static_cast<uint32_t>(tlv::NdnlpData));
-    pkt.parse();
-
-    const Block::element_container& elements = pkt.elements();
-    BOOST_REQUIRE_EQUAL(elements.size(), 4);
-
-    const Block& sequenceElement = elements[0];
-    BOOST_CHECK_EQUAL(sequenceElement.type(), static_cast<uint32_t>(tlv::NdnlpSequence));
-    BOOST_REQUIRE_EQUAL(sequenceElement.value_size(), sizeof(uint64_t));
-    uint64_t seq = be64toh(*reinterpret_cast<const uint64_t*>(
-                             &*sequenceElement.value_begin()));
-    if (i == 0) {
-      seq0 = seq;
-    }
-    BOOST_CHECK_EQUAL(seq, seq0 + i);
-
-    const Block& fragIndexElement = elements[1];
-    BOOST_CHECK_EQUAL(fragIndexElement.type(), static_cast<uint32_t>(tlv::NdnlpFragIndex));
-    uint64_t fragIndex = ndn::readNonNegativeInteger(fragIndexElement);
-    BOOST_CHECK_EQUAL(fragIndex, i);
-
-    const Block& fragCountElement = elements[2];
-    BOOST_CHECK_EQUAL(fragCountElement.type(), static_cast<uint32_t>(tlv::NdnlpFragCount));
-    uint64_t fragCount = ndn::readNonNegativeInteger(fragCountElement);
-    BOOST_CHECK_EQUAL(fragCount, 4);
-
-    const Block& payloadElement = elements[3];
-    BOOST_CHECK_EQUAL(payloadElement.type(), static_cast<uint32_t>(tlv::NdnlpPayload));
-    size_t payloadSize = payloadElement.value_size();
-    totalPayloadSize += payloadSize;
-  }
-
-  BOOST_CHECK_EQUAL(totalPayloadSize, block.size());
-}
-
-class ReassembleFixture : protected UnitTestTimeFixture
-{
-protected:
-  ReassembleFixture()
-    : slicer(1500)
-    , pms(time::milliseconds(100))
-  {
-    pms.onReceive.connect([this] (const Block& block) {
-      received.push_back(block);
-    });
-  }
-
-  Block
-  makeBlock(size_t valueLength)
-  {
-    boost::scoped_array<uint8_t> blockValue(new uint8_t[valueLength]);
-    memset(blockValue.get(), 0xcc, valueLength);
-    return ndn::dataBlock(0x01, blockValue.get(), valueLength);
-  }
-
-  void
-  receiveNdnlpData(const Block& block)
-  {
-    bool isOk = false;
-    ndnlp::NdnlpData pkt;
-    std::tie(isOk, pkt) = ndnlp::NdnlpData::fromBlock(block);
-    BOOST_REQUIRE(isOk);
-    pms.receive(pkt);
-  }
-
-protected:
-  ndnlp::Slicer slicer;
-  ndnlp::PartialMessageStore pms;
-
-  static const time::nanoseconds IDLE_DURATION;
-
-  // received network layer packets
-  std::vector<Block> received;
-};
-
-// reassemble one fragment into one Block
-BOOST_FIXTURE_TEST_CASE(Reassemble1, ReassembleFixture)
-{
-  Block block = makeBlock(60);
-  ndnlp::PacketArray pa = slicer.slice(block);
-  BOOST_REQUIRE_EQUAL(pa->size(), 1);
-
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->receiveNdnlpData(pa->at(0));
-
-  BOOST_REQUIRE_EQUAL(received.size(), 1);
-  BOOST_CHECK_EQUAL_COLLECTIONS(received.at(0).begin(), received.at(0).end(),
-                                block.begin(),          block.end());
-}
-
-// reassemble four and two fragments into two Blocks
-BOOST_FIXTURE_TEST_CASE(Reassemble4and2, ReassembleFixture)
-{
-  Block block = makeBlock(5050);
-  ndnlp::PacketArray pa = slicer.slice(block);
-  BOOST_REQUIRE_EQUAL(pa->size(), 4);
-
-  Block block2 = makeBlock(2000);
-  ndnlp::PacketArray pa2 = slicer.slice(block2);
-  BOOST_REQUIRE_EQUAL(pa2->size(), 2);
-
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->receiveNdnlpData(pa->at(0));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa2->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa2->at(0));
-  BOOST_CHECK_EQUAL(received.size(), 1);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(3));
-  BOOST_CHECK_EQUAL(received.size(), 1);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(2));
-
-  BOOST_REQUIRE_EQUAL(received.size(), 2);
-  BOOST_CHECK_EQUAL_COLLECTIONS(received.at(1).begin(), received.at(1).end(),
-                                block.begin(),          block.end());
-  BOOST_CHECK_EQUAL_COLLECTIONS(received.at(0).begin(), received.at(0).end(),
-                                block2.begin(),         block2.end());
-}
-
-// reassemble four fragments into one Block, but another two fragments are expired
-BOOST_FIXTURE_TEST_CASE(ReassembleTimeout, ReassembleFixture)
-{
-  Block block = makeBlock(5050);
-  ndnlp::PacketArray pa = slicer.slice(block);
-  BOOST_REQUIRE_EQUAL(pa->size(), 4);
-
-  Block block2 = makeBlock(2000);
-  ndnlp::PacketArray pa2 = slicer.slice(block2);
-  BOOST_REQUIRE_EQUAL(pa2->size(), 2);
-
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->receiveNdnlpData(pa->at(0));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa2->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(1));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(3));
-  BOOST_CHECK_EQUAL(received.size(), 0);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa->at(2));
-  BOOST_CHECK_EQUAL(received.size(), 1);
-  this->advanceClocks(time::milliseconds(40));
-
-  this->receiveNdnlpData(pa2->at(0)); // last fragment was received 160ms ago, expired
-  BOOST_CHECK_EQUAL(received.size(), 1);
-  this->advanceClocks(time::milliseconds(40));
-
-  BOOST_REQUIRE_EQUAL(received.size(), 1);
-  BOOST_CHECK_EQUAL_COLLECTIONS(received.at(0).begin(), received.at(0).end(),
-                                block.begin(),          block.end());
-}
-
-BOOST_AUTO_TEST_SUITE_END()
-
-} // namespace tests
-} // namespace ndnlp
-} // namespace nfd
diff --git a/tests/daemon/face/network-interface-fixture.hpp b/tests/daemon/face/network-interface-fixture.hpp
new file mode 100644
index 0000000..3fb7af8
--- /dev/null
+++ b/tests/daemon/face/network-interface-fixture.hpp
@@ -0,0 +1,71 @@
+/* -*- 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_NETWORK_INTERFACE_FIXTURE_HPP
+#define NFD_TESTS_NETWORK_INTERFACE_FIXTURE_HPP
+
+#include "core/network-interface.hpp"
+#include "face/ethernet-transport.hpp"
+
+#include "test-common.hpp"
+
+namespace nfd {
+namespace tests {
+
+class NetworkInterfaceFixture : protected BaseFixture
+{
+protected:
+  NetworkInterfaceFixture()
+  {
+    for (const auto& netif : listNetworkInterfaces()) {
+      if (!netif.isLoopback() && netif.isUp()) {
+        try {
+          face::EthernetTransport transport(netif, ethernet::getBroadcastAddress());
+          m_interfaces.push_back(netif);
+        }
+        catch (const face::EthernetTransport::Error&) {
+          // pass
+        }
+      }
+    }
+  }
+
+protected:
+  std::vector<NetworkInterfaceInfo> m_interfaces;
+};
+
+#define SKIP_IF_NETWORK_INTERFACE_COUNT_LT(n) \
+  do {                                        \
+    if (this->m_interfaces.size() < (n)) {    \
+      BOOST_WARN_MESSAGE(false, "skipping assertions that require " \
+                                #n " or more network interfaces");  \
+      return;                                 \
+    }                                         \
+  } while (false)
+
+} // namespace tests
+} // namespace nfd
+
+#endif // NFD_TESTS_NETWORK_INTERFACE_FIXTURE_HPP