face: NDNLPv2 fragmentation and reassembly

refs #3171

Change-Id: If29035b697b904ee49cb86d9248be488657c6f9e
diff --git a/tests/daemon/face/generic-link-service.t.cpp b/tests/daemon/face/generic-link-service.t.cpp
index ac01c7d..f3c3c7b 100644
--- a/tests/daemon/face/generic-link-service.t.cpp
+++ b/tests/daemon/face/generic-link-service.t.cpp
@@ -90,8 +90,12 @@
 
   face->sendInterest(*interest1);
 
+  BOOST_CHECK_EQUAL(service->getCounters().nOutInterests, 1);
   BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
-  BOOST_CHECK(transport->sentPackets.back().packet == interest1->wireEncode());
+  lp::Packet interest1pkt;
+  BOOST_REQUIRE_NO_THROW(interest1pkt.wireDecode(transport->sentPackets.back().packet));
+  BOOST_CHECK(interest1pkt.has<lp::FragmentField>());
+  BOOST_CHECK(!interest1pkt.has<lp::SequenceField>());
 }
 
 BOOST_AUTO_TEST_CASE(SendData)
@@ -105,8 +109,12 @@
 
   face->sendData(*data1);
 
+  BOOST_CHECK_EQUAL(service->getCounters().nOutData, 1);
   BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
-  BOOST_CHECK(transport->sentPackets.back().packet == data1->wireEncode());
+  lp::Packet data1pkt;
+  BOOST_REQUIRE_NO_THROW(data1pkt.wireDecode(transport->sentPackets.back().packet));
+  BOOST_CHECK(data1pkt.has<lp::FragmentField>());
+  BOOST_CHECK(!data1pkt.has<lp::SequenceField>());
 }
 
 BOOST_AUTO_TEST_CASE(SendNack)
@@ -120,11 +128,13 @@
 
   face->sendNack(nack1);
 
+  BOOST_CHECK_EQUAL(service->getCounters().nOutNacks, 1);
   BOOST_REQUIRE_EQUAL(transport->sentPackets.size(), 1);
   lp::Packet nack1pkt;
   BOOST_REQUIRE_NO_THROW(nack1pkt.wireDecode(transport->sentPackets.back().packet));
-  BOOST_CHECK_EQUAL(nack1pkt.has<lp::NackField>(), true);
-  BOOST_CHECK_EQUAL(nack1pkt.has<lp::FragmentField>(), true);
+  BOOST_CHECK(nack1pkt.has<lp::NackField>());
+  BOOST_CHECK(nack1pkt.has<lp::FragmentField>());
+  BOOST_CHECK(!nack1pkt.has<lp::SequenceField>());
 }
 
 BOOST_AUTO_TEST_CASE(ReceiveBareInterest)
@@ -138,6 +148,7 @@
 
   transport->receivePacket(interest1->wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1);
   BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1);
   BOOST_CHECK_EQUAL(receivedInterests.back(), *interest1);
 }
@@ -157,6 +168,7 @@
 
   transport->receivePacket(lpPacket.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInInterests, 1);
   BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1);
   BOOST_CHECK_EQUAL(receivedInterests.back(), *interest1);
 }
@@ -172,6 +184,7 @@
 
   transport->receivePacket(data1->wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInData, 1);
   BOOST_REQUIRE_EQUAL(receivedData.size(), 1);
   BOOST_CHECK_EQUAL(receivedData.back(), *data1);
 }
@@ -191,6 +204,7 @@
 
   transport->receivePacket(lpPacket.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInData, 1);
   BOOST_REQUIRE_EQUAL(receivedData.size(), 1);
   BOOST_CHECK_EQUAL(receivedData.back(), *data1);
 }
@@ -210,7 +224,10 @@
 
   transport->receivePacket(lpPacket.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNacks, 1);
   BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1);
+  BOOST_CHECK(receivedNacks.back().getReason() == nack1.getReason());
+  BOOST_CHECK(receivedNacks.back().getInterest() == nack1.getInterest());
 }
 
 BOOST_AUTO_TEST_CASE(ReceiveIdlePacket)
@@ -225,7 +242,8 @@
 
   BOOST_CHECK_NO_THROW(transport->receivePacket(lpPacket.wireEncode()));
 
-  // IDLE packet should be ignored
+  // IDLE packet should be ignored, but is not an error
+  BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0);
   BOOST_CHECK_EQUAL(receivedInterests.size(), 0);
   BOOST_CHECK_EQUAL(receivedData.size(), 0);
   BOOST_CHECK_EQUAL(receivedNacks.size(), 0);
@@ -236,9 +254,112 @@
 
 BOOST_AUTO_TEST_SUITE(Fragmentation)
 
+BOOST_AUTO_TEST_CASE(FragmentationDisabledExceedMtuDrop)
+{
+  // Initialize with Options that disable fragmentation
+  GenericLinkService::Options options;
+  options.allowFragmentation = false;
+  initialize(options);
+
+  transport->setMtu(55);
+
+  shared_ptr<Data> data = makeData("/test/data/123456789/987654321/123456789");
+  face->sendData(*data);
+
+  BOOST_CHECK_EQUAL(transport->sentPackets.size(), 0);
+  BOOST_CHECK_EQUAL(service->getCounters().nOutOverMtu, 1);
+}
+
+BOOST_AUTO_TEST_CASE(FragmentationUnlimitedMtu)
+{
+  // Initialize with Options that enable fragmentation
+  GenericLinkService::Options options;
+  options.allowFragmentation = true;
+  initialize(options);
+
+  transport->setMtu(MTU_UNLIMITED);
+
+  shared_ptr<Data> data = makeData("/test/data/123456789/987654321/123456789");
+  face->sendData(*data);
+
+  BOOST_CHECK_EQUAL(transport->sentPackets.size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(FragmentationUnderMtu)
+{
+  // Initialize with Options that enable fragmentation
+  GenericLinkService::Options options;
+  options.allowFragmentation = true;
+  initialize(options);
+
+  transport->setMtu(105);
+
+  shared_ptr<Data> data = makeData("/test/data/123456789/987654321/123456789");
+  face->sendData(*data);
+
+  BOOST_CHECK_EQUAL(transport->sentPackets.size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(FragmentationOverMtu)
+{
+  // Initialize with Options that enable fragmentation
+  GenericLinkService::Options options;
+  options.allowFragmentation = true;
+  initialize(options);
+
+  transport->setMtu(60);
+
+  shared_ptr<Data> data = makeData("/test/data/123456789/987654321/123456789");
+  face->sendData(*data);
+
+  BOOST_CHECK_GT(transport->sentPackets.size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(ReassembleFragments)
+{
+  // Initialize with Options that enables reassembly
+  GenericLinkService::Options options;
+  options.allowReassembly = true;
+  initialize(options);
+
+  shared_ptr<Interest> interest = makeInterest(
+    "/mt7P130BHXmtLm5dwaY5dpUM6SWYNN2B05g7y3UhsQuLvDdnTWdNnTeEiLuW3FAbJRSG3tzQ0UfaSEgG9rvYHmsKtgPMag1Hj4Tr");
+  lp::Packet packet(interest->wireEncode());
+
+  // fragment the packet
+  LpFragmenter fragmenter;
+  size_t mtu = 100;
+  bool isOk = false;
+  std::vector<lp::Packet> frags;
+  std::tie(isOk, frags) = fragmenter.fragmentPacket(packet, mtu);
+  BOOST_REQUIRE(isOk);
+  BOOST_CHECK_GT(frags.size(), 1);
+
+  // receive the fragments
+  for (ssize_t fragIndex = frags.size() - 1; fragIndex >= 0; --fragIndex) {
+    size_t sequence = 1000 + fragIndex;
+    frags[fragIndex].add<lp::SequenceField>(sequence);
+
+    transport->receivePacket(frags[fragIndex].wireEncode());
+
+    if (fragIndex > 0) {
+      BOOST_CHECK(receivedInterests.empty());
+      BOOST_CHECK_EQUAL(service->getCounters().nReassembling, 1);
+    }
+    else {
+      BOOST_CHECK_EQUAL(receivedInterests.size(), 1);
+      BOOST_CHECK_EQUAL(receivedInterests.back(), *interest);
+      BOOST_CHECK_EQUAL(service->getCounters().nReassembling, 0);
+    }
+  }
+}
+
 BOOST_AUTO_TEST_CASE(ReassemblyDisabledDropFragIndex)
 {
-  // TODO#3171 Initialize with Options that disables reassembly
+  // Initialize with Options that disables reassembly
+  GenericLinkService::Options options;
+  options.allowReassembly = false;
+  initialize(options);
 
   shared_ptr<Interest> interest = makeInterest("/IgFe6NvH");
   lp::Packet packet(interest->wireEncode());
@@ -246,12 +367,16 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0); // not an error
   BOOST_CHECK(receivedInterests.empty());
 }
 
 BOOST_AUTO_TEST_CASE(ReassemblyDisabledDropFragCount)
 {
-  // TODO#3171 Initialize with Options that disables reassembly
+  // Initialize with Options that disables reassembly
+  GenericLinkService::Options options;
+  options.allowReassembly = false;
+  initialize(options);
 
   shared_ptr<Interest> interest = makeInterest("/SeGmEjvIVX");
   lp::Packet packet(interest->wireEncode());
@@ -259,6 +384,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 0); // not an error
   BOOST_CHECK(receivedInterests.empty());
 }
 
@@ -298,6 +424,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error
   BOOST_CHECK(receivedInterests.empty());
 }
 
@@ -314,6 +441,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1);
   BOOST_CHECK(receivedData.empty());
 }
 
@@ -333,6 +461,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1);
   BOOST_CHECK(receivedNacks.empty());
 }
 
@@ -372,6 +501,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error
   BOOST_REQUIRE_EQUAL(receivedData.size(), 1);
   BOOST_CHECK(!receivedData.back().getLocalControlHeader().hasCachingPolicy());
 }
@@ -391,6 +521,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1);
   BOOST_CHECK(receivedInterests.empty());
 }
 
@@ -410,6 +541,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 1);
   BOOST_CHECK(receivedNacks.empty());
 }
 
@@ -461,6 +593,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error
   BOOST_REQUIRE_EQUAL(receivedInterests.size(), 1);
   BOOST_CHECK(!receivedInterests.back().getLocalControlHeader().hasIncomingFaceId());
 }
@@ -478,6 +611,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error
   BOOST_REQUIRE_EQUAL(receivedData.size(), 1);
   BOOST_CHECK(!receivedData.back().getLocalControlHeader().hasIncomingFaceId());
 }
@@ -496,6 +630,7 @@
 
   transport->receivePacket(packet.wireEncode());
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInNetInvalid, 0); // not an error
   BOOST_REQUIRE_EQUAL(receivedNacks.size(), 1);
   BOOST_CHECK(!receivedNacks.back().getLocalControlHeader().hasIncomingFaceId());
 }
@@ -516,6 +651,7 @@
 
   BOOST_CHECK_NO_THROW(transport->receivePacket(packet));
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 1);
   BOOST_CHECK_EQUAL(receivedInterests.size(), 0);
   BOOST_CHECK_EQUAL(receivedData.size(), 0);
   BOOST_CHECK_EQUAL(receivedNacks.size(), 0);
@@ -533,6 +669,7 @@
 
   BOOST_CHECK_NO_THROW(transport->receivePacket(packet));
 
+  BOOST_CHECK_EQUAL(service->getCounters().nInLpInvalid, 1);
   BOOST_CHECK_EQUAL(receivedInterests.size(), 0);
   BOOST_CHECK_EQUAL(receivedData.size(), 0);
   BOOST_CHECK_EQUAL(receivedNacks.size(), 0);