face: implement close-on-idle and persistency change for Ethernet unicast

Change-Id: I255024990a72b8cea5a44fa89f515ad91aadba66
Refs: #4011
diff --git a/tests/daemon/face/datagram-transport.t.cpp b/tests/daemon/face/datagram-transport.t.cpp
index 96585ae..535ea43 100644
--- a/tests/daemon/face/datagram-transport.t.cpp
+++ b/tests/daemon/face/datagram-transport.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2017,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -140,14 +140,19 @@
   SKIP_IF_IP_UNAVAILABLE(this->defaultAddr);
   this->initialize(this->defaultAddr);
 
+  this->transport->afterStateChange.connectSingleShot([] (TransportState oldState, TransportState newState) {
+    BOOST_CHECK_EQUAL(oldState, TransportState::UP);
+    BOOST_CHECK_EQUAL(newState, TransportState::CLOSING);
+  });
+
   this->transport->close();
-  BOOST_CHECK_EQUAL(this->transport->getState(), TransportState::CLOSING);
 
   this->transport->afterStateChange.connectSingleShot([this] (TransportState oldState, TransportState newState) {
     BOOST_CHECK_EQUAL(oldState, TransportState::CLOSING);
     BOOST_CHECK_EQUAL(newState, TransportState::CLOSED);
     this->limitedIo.afterOp();
   });
+
   BOOST_REQUIRE_EQUAL(this->limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
 }
 
diff --git a/tests/daemon/face/ethernet-factory.t.cpp b/tests/daemon/face/ethernet-factory.t.cpp
index 953a35f..b83e331 100644
--- a/tests/daemon/face/ethernet-factory.t.cpp
+++ b/tests/daemon/face/ethernet-factory.t.cpp
@@ -36,8 +36,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
-
 BOOST_AUTO_TEST_SUITE(Face)
 BOOST_FIXTURE_TEST_SUITE(TestEthernetFactory, EthernetFixture)
 
diff --git a/tests/daemon/face/ethernet-fixture.hpp b/tests/daemon/face/ethernet-fixture.hpp
index 5e3b612..6705481 100644
--- a/tests/daemon/face/ethernet-fixture.hpp
+++ b/tests/daemon/face/ethernet-fixture.hpp
@@ -30,13 +30,15 @@
 #include "face/multicast-ethernet-transport.hpp"
 #include "face/unicast-ethernet-transport.hpp"
 
-#include "test-common.hpp"
+#include "tests/limited-io.hpp"
 
 namespace nfd {
 namespace face {
 namespace tests {
 
-class EthernetFixture : public virtual nfd::tests::BaseFixture
+using namespace nfd::tests;
+
+class EthernetFixture : public virtual BaseFixture
 {
 protected:
   EthernetFixture()
@@ -56,19 +58,19 @@
   }
 
   void
-  initializeUnicast(ethernet::Address remoteAddr = {0x00, 0x00, 0x5e, 0x00, 0x53, 0x5e},
-                    ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT)
+  initializeUnicast(ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
+                    ethernet::Address remoteAddr = {0x00, 0x00, 0x5e, 0x00, 0x53, 0x5e})
   {
     BOOST_ASSERT(netifs.size() > 0);
     localEp = netifs.front().name;
     remoteEp = remoteAddr;
     transport = make_unique<UnicastEthernetTransport>(netifs.front(), remoteEp,
-                                                      persistency, time::seconds(5));
+                                                      persistency, time::seconds(2));
   }
 
   void
-  initializeMulticast(ethernet::Address mcastGroup = {0x01, 0x00, 0x5e, 0x90, 0x10, 0x5e},
-                      ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS)
+  initializeMulticast(ndn::nfd::LinkType linkType = ndn::nfd::LINK_TYPE_MULTI_ACCESS,
+                      ethernet::Address mcastGroup = {0x01, 0x00, 0x5e, 0x90, 0x10, 0x5e})
   {
     BOOST_ASSERT(netifs.size() > 0);
     localEp = netifs.front().name;
@@ -77,6 +79,7 @@
   }
 
 protected:
+  LimitedIo limitedIo;
   unique_ptr<EthernetTransport> transport;
   std::string localEp;
   ethernet::Address remoteEp;
diff --git a/tests/daemon/face/face-system.t.cpp b/tests/daemon/face/face-system.t.cpp
index 8e69441..590c063 100644
--- a/tests/daemon/face/face-system.t.cpp
+++ b/tests/daemon/face/face-system.t.cpp
@@ -32,8 +32,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
-
 BOOST_AUTO_TEST_SUITE(Face)
 BOOST_FIXTURE_TEST_SUITE(TestFaceSystem, FaceSystemFixture)
 
diff --git a/tests/daemon/face/multicast-ethernet-transport.t.cpp b/tests/daemon/face/multicast-ethernet-transport.t.cpp
index ebcbe10..7544adc 100644
--- a/tests/daemon/face/multicast-ethernet-transport.t.cpp
+++ b/tests/daemon/face/multicast-ethernet-transport.t.cpp
@@ -58,9 +58,26 @@
   BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
 }
 
-///\todo #3369 add the equivalent of these test cases from ethernet.t.cpp
-///      as of commit:65caf200924b28748037750449e28bcb548dbc9c
-///      SendPacket, ProcessIncomingPacket
+BOOST_AUTO_TEST_CASE(Close)
+{
+  SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
+  initializeMulticast();
+
+  transport->afterStateChange.connectSingleShot([] (TransportState oldState, TransportState newState) {
+    BOOST_CHECK_EQUAL(oldState, TransportState::UP);
+    BOOST_CHECK_EQUAL(newState, TransportState::CLOSING);
+  });
+
+  transport->close();
+
+  transport->afterStateChange.connectSingleShot([this] (TransportState oldState, TransportState newState) {
+    BOOST_CHECK_EQUAL(oldState, TransportState::CLOSING);
+    BOOST_CHECK_EQUAL(newState, TransportState::CLOSED);
+    limitedIo.afterOp();
+  });
+
+  BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
+}
 
 BOOST_AUTO_TEST_SUITE_END() // TestMulticastEthernetTransport
 BOOST_AUTO_TEST_SUITE_END() // Face
diff --git a/tests/daemon/face/tcp-factory.t.cpp b/tests/daemon/face/tcp-factory.t.cpp
index 7f93d78..a66e46a 100644
--- a/tests/daemon/face/tcp-factory.t.cpp
+++ b/tests/daemon/face/tcp-factory.t.cpp
@@ -33,8 +33,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
-
 BOOST_AUTO_TEST_SUITE(Face)
 BOOST_FIXTURE_TEST_SUITE(TestTcpFactory, BaseFixture)
 
diff --git a/tests/daemon/face/udp-factory.t.cpp b/tests/daemon/face/udp-factory.t.cpp
index 9677abe..d74ba69 100644
--- a/tests/daemon/face/udp-factory.t.cpp
+++ b/tests/daemon/face/udp-factory.t.cpp
@@ -35,8 +35,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
-
 BOOST_AUTO_TEST_SUITE(Face)
 BOOST_FIXTURE_TEST_SUITE(TestUdpFactory, BaseFixture)
 
diff --git a/tests/daemon/face/unicast-ethernet-transport.t.cpp b/tests/daemon/face/unicast-ethernet-transport.t.cpp
index c02fab9..49a0fbb 100644
--- a/tests/daemon/face/unicast-ethernet-transport.t.cpp
+++ b/tests/daemon/face/unicast-ethernet-transport.t.cpp
@@ -53,9 +53,71 @@
   SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
   initializeUnicast();
 
-  BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), false);
+  BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND), true);
   BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERSISTENT), true);
-  BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), false);
+  BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
+}
+
+BOOST_AUTO_TEST_CASE(ExpirationTime)
+{
+  SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
+  initializeUnicast(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+
+  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+
+  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+}
+
+BOOST_AUTO_TEST_CASE(Close)
+{
+  SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
+  initializeUnicast();
+
+  transport->afterStateChange.connectSingleShot([] (TransportState oldState, TransportState newState) {
+    BOOST_CHECK_EQUAL(oldState, TransportState::UP);
+    BOOST_CHECK_EQUAL(newState, TransportState::CLOSING);
+  });
+
+  transport->close();
+
+  transport->afterStateChange.connectSingleShot([this] (TransportState oldState, TransportState newState) {
+    BOOST_CHECK_EQUAL(oldState, TransportState::CLOSING);
+    BOOST_CHECK_EQUAL(newState, TransportState::CLOSED);
+    limitedIo.afterOp();
+  });
+
+  BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
+}
+
+BOOST_AUTO_TEST_CASE(IdleClose)
+{
+  SKIP_IF_ETHERNET_NETIF_COUNT_LT(1);
+  initializeUnicast(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+
+  int nStateChanges = 0;
+  transport->afterStateChange.connect(
+    [this, &nStateChanges] (TransportState oldState, TransportState newState) {
+      switch (nStateChanges) {
+      case 0:
+        BOOST_CHECK_EQUAL(oldState, TransportState::UP);
+        BOOST_CHECK_EQUAL(newState, TransportState::CLOSING);
+        break;
+      case 1:
+        BOOST_CHECK_EQUAL(oldState, TransportState::CLOSING);
+        BOOST_CHECK_EQUAL(newState, TransportState::CLOSED);
+        break;
+      default:
+        BOOST_CHECK(false);
+      }
+      nStateChanges++;
+      limitedIo.afterOp();
+    });
+
+  BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(5)), LimitedIo::EXCEED_OPS);
+  BOOST_CHECK_EQUAL(nStateChanges, 2);
 }
 
 BOOST_AUTO_TEST_SUITE_END() // TestUnicastEthernetTransport
diff --git a/tests/daemon/face/unicast-udp-transport.t.cpp b/tests/daemon/face/unicast-udp-transport.t.cpp
index 98d99ac..c73e5e6 100644
--- a/tests/daemon/face/unicast-udp-transport.t.cpp
+++ b/tests/daemon/face/unicast-udp-transport.t.cpp
@@ -113,16 +113,28 @@
   BOOST_CHECK_EQUAL(transport->canChangePersistencyTo(ndn::nfd::FACE_PERSISTENCY_PERMANENT), true);
 }
 
+BOOST_AUTO_TEST_CASE(ExpirationTime)
+{
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+
+  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
+  BOOST_CHECK_EQUAL(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+
+  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+}
+
 BOOST_AUTO_TEST_CASE(IdleClose)
 {
   auto address = getTestIp<ip::address_v4>();
   SKIP_IF_IP_UNAVAILABLE(address);
   initialize(address, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
 
-  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
-
   int nStateChanges = 0;
-  this->transport->afterStateChange.connect(
+  transport->afterStateChange.connect(
     [this, &nStateChanges] (TransportState oldState, TransportState newState) {
       switch (nStateChanges) {
       case 0:
@@ -137,17 +149,16 @@
         BOOST_CHECK(false);
       }
       nStateChanges++;
-      this->limitedIo.afterOp();
+      limitedIo.afterOp();
     });
 
-  BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(10)), LimitedIo::EXCEED_OPS);
-
+  BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(8)), LimitedIo::EXCEED_OPS);
   BOOST_CHECK_EQUAL(nStateChanges, 2);
 }
 
-typedef std::integral_constant<ndn::nfd::FacePersistency, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND> OnDemand;
-typedef std::integral_constant<ndn::nfd::FacePersistency, ndn::nfd::FACE_PERSISTENCY_PERSISTENT> Persistent;
-typedef boost::mpl::vector<OnDemand, Persistent> RemoteClosePersistencies;
+using OnDemand = std::integral_constant<ndn::nfd::FacePersistency, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND>;
+using Persistent = std::integral_constant<ndn::nfd::FacePersistency, ndn::nfd::FACE_PERSISTENCY_PERSISTENT>;
+using RemoteClosePersistencies = boost::mpl::vector<OnDemand, Persistent>;
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(RemoteClose, Persistency, RemoteClosePersistencies)
 {
@@ -201,7 +212,7 @@
   remoteSocket.async_receive(boost::asio::buffer(readBuf),
     [this] (const boost::system::error_code& error, size_t) {
       BOOST_REQUIRE_EQUAL(error, boost::system::errc::success);
-      this->limitedIo.afterOp();
+      limitedIo.afterOp();
     });
   BOOST_REQUIRE_EQUAL(limitedIo.run(1, time::seconds(1)), LimitedIo::EXCEED_OPS);
 
@@ -217,17 +228,6 @@
   BOOST_CHECK_EQUAL(transport->getState(), TransportState::UP);
 }
 
-BOOST_AUTO_TEST_CASE(ChangePersistencyNoExpirationTime)
-{
-  auto address = getTestIp<ip::address_v4>();
-  SKIP_IF_IP_UNAVAILABLE(address);
-  initialize(address, ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-
-  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
-  transport->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
-  BOOST_CHECK_EQUAL(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
-}
-
 BOOST_AUTO_TEST_SUITE_END() // TestUnicastUdpTransport
 BOOST_AUTO_TEST_SUITE_END() // Face
 
diff --git a/tests/daemon/face/unix-stream-factory.t.cpp b/tests/daemon/face/unix-stream-factory.t.cpp
index 7cdd741..dc5b5ac 100644
--- a/tests/daemon/face/unix-stream-factory.t.cpp
+++ b/tests/daemon/face/unix-stream-factory.t.cpp
@@ -33,8 +33,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
-
 #define CHANNEL_PATH1 "unix-stream-test.1.sock"
 #define CHANNEL_PATH2 "unix-stream-test.2.sock"
 
diff --git a/tests/daemon/face/websocket-factory.t.cpp b/tests/daemon/face/websocket-factory.t.cpp
index 95fd7d8..5243c97 100644
--- a/tests/daemon/face/websocket-factory.t.cpp
+++ b/tests/daemon/face/websocket-factory.t.cpp
@@ -33,7 +33,6 @@
 namespace face {
 namespace tests {
 
-using namespace nfd::tests;
 namespace ip = boost::asio::ip;
 
 BOOST_AUTO_TEST_SUITE(Face)