tests: skip IPv6 tests if IPv6 is not available

This commit also renames the getAvailableInterfaceIp() API
to getTestIp(), and improves its expressiveness.

Change-Id: I4b0080fb5e85cd523305ecb14183ef6acb34b5cd
Refs: #3367
diff --git a/tests/daemon/face/get-available-interface-ip.hpp b/tests/daemon/face/get-available-interface-ip.hpp
deleted file mode 100644
index e7088a8..0000000
--- a/tests/daemon/face/get-available-interface-ip.hpp
+++ /dev/null
@@ -1,96 +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_GET_AVAILABLE_INTERFACE_IP_HPP
-#define NFD_TESTS_DAEMON_FACE_GET_AVAILABLE_INTERFACE_IP_HPP
-
-#include "core/network-interface.hpp"
-
-#define SKIP_IF_IP_UNAVAILABLE(address) \
-  do { \
-    if (address.is_unspecified()) { \
-      BOOST_WARN_MESSAGE(false, "skipping assertions that require a valid IP address"); \
-      return; \
-    } \
-  } while (false)
-
-namespace nfd {
-namespace face {
-namespace tests {
-
-/** \brief get a non-local IP address from any available network interface
- *  \tparam A the address type, either boost::asio::ip::address_v4 or boost::asio::ip::address_v6
- *  \param needMulticast true if the address must be chosen from a multicast-capable interface
- *  \return an IP address
- *  \retval default-constructed A, if no address is available
- */
-template<typename A>
-A
-getAvailableInterfaceIp(bool needMulticast = false);
-
-template<>
-inline boost::asio::ip::address_v4
-getAvailableInterfaceIp(bool needMulticast)
-{
-  for (const auto& interface : listNetworkInterfaces()) {
-    if (interface.isUp() &&
-        !interface.isLoopback() &&
-        (!needMulticast || interface.isMulticastCapable())) {
-      for (const auto& address : interface.ipv4Addresses) {
-        if (!address.is_unspecified() &&
-            !address.is_loopback()) {
-          return address;
-        }
-      }
-    }
-  }
-  return {};
-}
-
-template<>
-inline boost::asio::ip::address_v6
-getAvailableInterfaceIp(bool needMulticast)
-{
-  for (const auto& interface : listNetworkInterfaces()) {
-    if (interface.isUp() &&
-        !interface.isLoopback() &&
-        (!needMulticast || interface.isMulticastCapable())) {
-      for (const auto& address : interface.ipv6Addresses) {
-        if (!address.is_unspecified() &&
-            !address.is_link_local() && // see #1428
-            !address.is_loopback()) {
-          return address;
-        }
-      }
-    }
-  }
-  return {};
-}
-
-} // namespace tests
-} // namespace face
-} // namespace nfd
-
-#endif // NFD_TESTS_DAEMON_FACE_GET_AVAILABLE_INTERFACE_IP_HPP
diff --git a/tests/daemon/face/multicast-udp-transport-fixture.hpp b/tests/daemon/face/multicast-udp-transport-fixture.hpp
index 639c828..b8ed524 100644
--- a/tests/daemon/face/multicast-udp-transport-fixture.hpp
+++ b/tests/daemon/face/multicast-udp-transport-fixture.hpp
@@ -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-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -30,7 +30,7 @@
 #include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
-#include "get-available-interface-ip.hpp"
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 
 namespace nfd {
@@ -47,7 +47,7 @@
   MulticastUdpTransportFixture()
     : transport(nullptr)
     , multicastEp(ip::address::from_string("230.15.19.47"), 7070)
-    , defaultAddr(getAvailableInterfaceIp<ip::address_v4>(true))
+    , defaultAddr(getTestIp<ip::address_v4>(LoopbackAddress::No, MulticastInterface::Yes))
     , receivedPackets(nullptr)
     , remoteSockRx(g_io)
     , remoteSockTx(g_io)
diff --git a/tests/daemon/face/tcp-channel.t.cpp b/tests/daemon/face/tcp-channel.t.cpp
index 040dc45..f829aa2 100644
--- a/tests/daemon/face/tcp-channel.t.cpp
+++ b/tests/daemon/face/tcp-channel.t.cpp
@@ -25,6 +25,7 @@
 
 #include "face/tcp-channel.hpp"
 
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 #include "tests/test-common.hpp"
 
@@ -39,13 +40,13 @@
 namespace ip = boost::asio::ip;
 
 typedef boost::mpl::vector<ip::address_v4,
-                           ip::address_v6> AddressTypes;
+                           ip::address_v6> AddressFamilies;
 
 class TcpChannelFixture : public BaseFixture
 {
 protected:
   TcpChannelFixture()
-    : nextPort(7050)
+    : m_nextPort(7050)
   {
   }
 
@@ -53,7 +54,7 @@
   makeChannel(const ip::address& addr, uint16_t port = 0)
   {
     if (port == 0)
-      port = nextPort++;
+      port = m_nextPort++;
 
     return make_unique<TcpChannel>(tcp::Endpoint(addr, port));
   }
@@ -100,12 +101,12 @@
   std::vector<shared_ptr<Face>> clientFaces;
 
 private:
-  uint16_t nextPort;
+  uint16_t m_nextPort;
 };
 
 BOOST_FIXTURE_TEST_SUITE(TestTcpChannel, TcpChannelFixture)
 
-BOOST_AUTO_TEST_CASE_TEMPLATE(Uri, A, AddressTypes)
+BOOST_AUTO_TEST_CASE_TEMPLATE(Uri, A, AddressFamilies)
 {
   tcp::Endpoint ep(A::loopback(), 7050);
   auto channel = makeChannel(ep.address(), ep.port());
@@ -125,9 +126,11 @@
   BOOST_CHECK_EQUAL(channel->isListening(), true);
 }
 
-BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleAccepts, A, AddressTypes)
+BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleAccepts, A, AddressFamilies)
 {
-  this->listen(A::loopback());
+  auto address = getTestIp<A>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->listen(address);
 
   BOOST_CHECK_EQUAL(listenerChannel->isListening(), true);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
@@ -173,11 +176,14 @@
   BOOST_CHECK_EQUAL(clientFaces.at(2), clientFaces.at(3));
 }
 
-BOOST_AUTO_TEST_CASE_TEMPLATE(ConnectTimeout, A, AddressTypes)
+BOOST_AUTO_TEST_CASE_TEMPLATE(ConnectTimeout, A, AddressFamilies)
 {
-  auto channel = makeChannel(A());
+  auto address = getTestIp<A>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  // do not listen
 
-  channel->connect(tcp::Endpoint(A::loopback(), 7040),
+  auto channel = makeChannel(A());
+  channel->connect(tcp::Endpoint(address, 7040),
     [this] (const shared_ptr<Face>&) {
       BOOST_FAIL("Connect succeeded when it should have failed");
       this->limitedIo.afterOp();
@@ -192,11 +198,13 @@
   BOOST_CHECK_EQUAL(channel->size(), 0);
 }
 
-BOOST_AUTO_TEST_CASE(FaceClosure)
+BOOST_AUTO_TEST_CASE_TEMPLATE(FaceClosure, A, AddressFamilies)
 {
-  this->listen(ip::address_v4::loopback());
+  auto address = getTestIp<A>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->listen(address);
 
-  auto clientChannel = makeChannel(ip::address_v4());
+  auto clientChannel = makeChannel(A());
   this->connect(*clientChannel);
 
   BOOST_CHECK(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS);
diff --git a/tests/daemon/face/tcp-transport-fixture.hpp b/tests/daemon/face/tcp-transport-fixture.hpp
index e68eff9..97b195f 100644
--- a/tests/daemon/face/tcp-transport-fixture.hpp
+++ b/tests/daemon/face/tcp-transport-fixture.hpp
@@ -30,6 +30,7 @@
 #include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 
 namespace nfd {
diff --git a/tests/daemon/face/tcp-transport.t.cpp b/tests/daemon/face/tcp-transport.t.cpp
index 4871e3c..fd0d7ae 100644
--- a/tests/daemon/face/tcp-transport.t.cpp
+++ b/tests/daemon/face/tcp-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-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -23,7 +23,6 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "get-available-interface-ip.hpp"
 #include "transport-test-common.hpp"
 
 #include "tcp-transport-fixture.hpp"
@@ -37,7 +36,9 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv4)
 {
-  initialize();
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address);
 
   checkStaticPropertiesInitialized(*transport);
 
@@ -51,7 +52,9 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv6)
 {
-  initialize(ip::address_v6::loopback());
+  auto address = getTestIp<ip::address_v6>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address);
 
   checkStaticPropertiesInitialized(*transport);
 
@@ -65,7 +68,7 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv4)
 {
-  auto address = getAvailableInterfaceIp<ip::address_v4>();
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::No);
   SKIP_IF_IP_UNAVAILABLE(address);
   initialize(address);
 
@@ -83,7 +86,7 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv6)
 {
-  auto address = getAvailableInterfaceIp<ip::address_v6>();
+  auto address = getTestIp<ip::address_v6>(LoopbackAddress::No);
   SKIP_IF_IP_UNAVAILABLE(address);
   initialize(address);
 
diff --git a/tests/daemon/face/test-ip.cpp b/tests/daemon/face/test-ip.cpp
new file mode 100644
index 0000000..a4cda7d
--- /dev/null
+++ b/tests/daemon/face/test-ip.cpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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 "test-ip.hpp"
+
+#include "core/network-interface.hpp"
+
+namespace nfd {
+namespace tests {
+namespace {
+
+template<typename E>
+bool
+matchTristate(E e, bool b)
+{
+  return (e == E::DontCare) ||
+         (e == E::Yes && b) ||
+         (e == E::No && !b);
+}
+
+} // unnamed namespace
+
+template<>
+boost::asio::ip::address_v4
+getTestIp(LoopbackAddress loopback, MulticastInterface mcast)
+{
+  for (const auto& interface : listNetworkInterfaces()) {
+    if (interface.isUp() &&
+        matchTristate(loopback, interface.isLoopback()) &&
+        matchTristate(mcast, interface.isMulticastCapable())) {
+      for (const auto& address : interface.ipv4Addresses) {
+        if (!address.is_unspecified() &&
+            matchTristate(loopback, address.is_loopback())) {
+          return address;
+        }
+      }
+    }
+  }
+  return {};
+}
+
+template<>
+boost::asio::ip::address_v6
+getTestIp(LoopbackAddress loopback, MulticastInterface mcast)
+{
+  for (const auto& interface : listNetworkInterfaces()) {
+    if (interface.isUp() &&
+        matchTristate(loopback, interface.isLoopback()) &&
+        matchTristate(mcast, interface.isMulticastCapable())) {
+      for (const auto& address : interface.ipv6Addresses) {
+        if (!address.is_unspecified() &&
+            !address.is_link_local() && // see #1428
+            matchTristate(loopback, address.is_loopback())) {
+          return address;
+        }
+      }
+    }
+  }
+  return {};
+}
+
+} // namespace tests
+} // namespace nfd
diff --git a/tests/daemon/face/test-ip.hpp b/tests/daemon/face/test-ip.hpp
new file mode 100644
index 0000000..2aa6203
--- /dev/null
+++ b/tests/daemon/face/test-ip.hpp
@@ -0,0 +1,80 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014-2016,  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_TEST_IP_HPP
+#define NFD_TESTS_DAEMON_FACE_TEST_IP_HPP
+
+#include <boost/asio/ip/address_v4.hpp>
+#include <boost/asio/ip/address_v6.hpp>
+
+#define SKIP_IF_IP_UNAVAILABLE(address) \
+  do { \
+    if ((address).is_unspecified()) { \
+      BOOST_WARN_MESSAGE(false, "skipping assertions that require a valid IP address"); \
+      return; \
+    } \
+  } while (false)
+
+namespace nfd {
+namespace tests {
+
+enum class LoopbackAddress {
+  No,
+  Yes,
+  DontCare,
+  Default = Yes
+};
+
+enum class MulticastInterface {
+  No,
+  Yes,
+  DontCare,
+  Default = DontCare
+};
+
+/** \brief get an IP address for test purposes from any available network interface
+ *  \tparam A the address type, either boost::asio::ip::address_v4 or boost::asio::ip::address_v6
+ *  \param loopback specifies if the address can, must, or must not be a loopback address
+ *  \param mcast specifies if the address can, must, or must not be chosen from a multicast-capable interface
+ *  \return an IP address
+ *  \retval default-constructed A, if no appropriate address is available
+ */
+template<typename A>
+A
+getTestIp(LoopbackAddress loopback = LoopbackAddress::Default,
+          MulticastInterface mcast = MulticastInterface::Default);
+
+template<>
+boost::asio::ip::address_v4
+getTestIp(LoopbackAddress loopback, MulticastInterface mcast);
+
+template<>
+boost::asio::ip::address_v6
+getTestIp(LoopbackAddress loopback, MulticastInterface mcast);
+
+} // namespace tests
+} // namespace nfd
+
+#endif // NFD_TESTS_DAEMON_FACE_TEST_IP_HPP
diff --git a/tests/daemon/face/udp-channel.t.cpp b/tests/daemon/face/udp-channel.t.cpp
index 8fccab1..d945012 100644
--- a/tests/daemon/face/udp-channel.t.cpp
+++ b/tests/daemon/face/udp-channel.t.cpp
@@ -26,6 +26,7 @@
 #include "face/udp-channel.hpp"
 #include "face/transport.hpp"
 
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 #include "tests/test-common.hpp"
 
@@ -40,7 +41,7 @@
 namespace ip = boost::asio::ip;
 
 typedef boost::mpl::vector<ip::address_v4,
-                           ip::address_v6> AddressTypes;
+                           ip::address_v6> AddressFamilies;
 
 class UdpChannelFixture : public BaseFixture
 {
@@ -108,7 +109,7 @@
 
 BOOST_FIXTURE_TEST_SUITE(TestUdpChannel, UdpChannelFixture)
 
-BOOST_AUTO_TEST_CASE_TEMPLATE(Uri, A, AddressTypes)
+BOOST_AUTO_TEST_CASE_TEMPLATE(Uri, A, AddressFamilies)
 {
   udp::Endpoint ep(A::loopback(), 7050);
   auto channel = makeChannel(ep.address(), ep.port());
@@ -128,9 +129,11 @@
   BOOST_CHECK_EQUAL(channel->isListening(), true);
 }
 
-BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleAccepts, A, AddressTypes)
+BOOST_AUTO_TEST_CASE_TEMPLATE(MultipleAccepts, A, AddressFamilies)
 {
-  this->listen(A::loopback());
+  auto address = getTestIp<A>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->listen(address);
 
   BOOST_CHECK_EQUAL(listenerChannel->isListening(), true);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
@@ -178,11 +181,13 @@
   BOOST_CHECK_EQUAL(clientFaces.at(2), clientFaces.at(3));
 }
 
-BOOST_AUTO_TEST_CASE(FaceClosure)
+BOOST_AUTO_TEST_CASE_TEMPLATE(FaceClosure, A, AddressFamilies)
 {
-  this->listen(ip::address_v4::loopback());
+  auto address = getTestIp<A>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->listen(address);
 
-  auto clientChannel = makeChannel(ip::address_v4());
+  auto clientChannel = makeChannel(A());
   this->connect(*clientChannel);
 
   BOOST_CHECK(limitedIo.run(2, time::seconds(1)) == LimitedIo::EXCEED_OPS);
diff --git a/tests/daemon/face/udp-factory.t.cpp b/tests/daemon/face/udp-factory.t.cpp
index fac01af..be7a73b 100644
--- a/tests/daemon/face/udp-factory.t.cpp
+++ b/tests/daemon/face/udp-factory.t.cpp
@@ -92,15 +92,13 @@
 
 BOOST_AUTO_TEST_CASE(CreateMulticastFace)
 {
-  using boost::asio::ip::udp;
-
   UdpFactory factory;
 
   auto multicastFace1  = factory.createMulticastFace("127.0.0.1", "224.0.0.1", "20070");
   auto multicastFace1a = factory.createMulticastFace("127.0.0.1", "224.0.0.1", "20070");
   BOOST_CHECK_EQUAL(multicastFace1, multicastFace1a);
 
-  // createMulticastFace with a local endpoint that has already been allocated for a UDP unicast channel
+  // createMulticastFace with a local endpoint that is already used by a channel
   auto channel = factory.createChannel("127.0.0.1", "20071");
   BOOST_CHECK_EXCEPTION(factory.createMulticastFace("127.0.0.1", "224.0.0.1", "20071"), UdpFactory::Error,
                         [] (const UdpFactory::Error& e) {
@@ -109,8 +107,8 @@
                                         "endpoint is already allocated for a UDP unicast channel") == 0;
                         });
 
-  // createMulticastFace with a local endpoint that has already been allocated
-  // for a UDP multicast face on a different multicast group
+  // createMulticastFace with a local endpoint that is already
+  // used by a multicast face on a different multicast group
   BOOST_CHECK_EXCEPTION(factory.createMulticastFace("127.0.0.1", "224.0.0.42", "20070"), UdpFactory::Error,
                         [] (const UdpFactory::Error& e) {
                           return strcmp(e.what(),
@@ -136,8 +134,8 @@
                         });
 
   // createMulticastFace with different local and remote port numbers
-  udp::endpoint localEndpoint(boost::asio::ip::address_v4::loopback(), 20074);
-  udp::endpoint multicastEndpoint(boost::asio::ip::address::from_string("224.0.0.1"), 20075);
+  udp::Endpoint localEndpoint(boost::asio::ip::address_v4::loopback(), 20074);
+  udp::Endpoint multicastEndpoint(boost::asio::ip::address::from_string("224.0.0.1"), 20075);
   BOOST_CHECK_EXCEPTION(factory.createMulticastFace(localEndpoint, multicastEndpoint), UdpFactory::Error,
                         [] (const UdpFactory::Error& e) {
                           return strcmp(e.what(),
diff --git a/tests/daemon/face/unicast-udp-transport-fixture.hpp b/tests/daemon/face/unicast-udp-transport-fixture.hpp
index 01698cb..74de35d 100644
--- a/tests/daemon/face/unicast-udp-transport-fixture.hpp
+++ b/tests/daemon/face/unicast-udp-transport-fixture.hpp
@@ -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-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -30,6 +30,7 @@
 #include "face/face.hpp"
 
 #include "dummy-receive-link-service.hpp"
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 
 namespace nfd {
@@ -46,7 +47,7 @@
   UnicastUdpTransportFixture()
     : transport(nullptr)
     , remoteSocket(g_io)
-    , defaultAddr(ip::address_v4::loopback())
+    , defaultAddr(getTestIp<ip::address_v4>())
     , receivedPackets(nullptr)
   {
   }
diff --git a/tests/daemon/face/unicast-udp-transport.t.cpp b/tests/daemon/face/unicast-udp-transport.t.cpp
index fb5469d..d45b116 100644
--- a/tests/daemon/face/unicast-udp-transport.t.cpp
+++ b/tests/daemon/face/unicast-udp-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-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -23,7 +23,6 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "get-available-interface-ip.hpp"
 #include "transport-test-common.hpp"
 
 #include "unicast-udp-transport-fixture.hpp"
@@ -37,7 +36,9 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv4)
 {
-  initialize();
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address);
 
   checkStaticPropertiesInitialized(*transport);
 
@@ -51,7 +52,9 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv6)
 {
-  initialize(ip::address_v6::loopback());
+  auto address = getTestIp<ip::address_v6>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address);
 
   checkStaticPropertiesInitialized(*transport);
 
@@ -65,7 +68,7 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv4)
 {
-  auto address = getAvailableInterfaceIp<ip::address_v4>();
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::No);
   SKIP_IF_IP_UNAVAILABLE(address);
   initialize(address);
 
@@ -83,7 +86,7 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv6)
 {
-  auto address = getAvailableInterfaceIp<ip::address_v6>();
+  auto address = getTestIp<ip::address_v6>(LoopbackAddress::No);
   SKIP_IF_IP_UNAVAILABLE(address);
   initialize(address);
 
@@ -101,7 +104,10 @@
 
 BOOST_AUTO_TEST_CASE(IdleClose)
 {
-  initialize(ip::address_v4::loopback(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
+  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;
@@ -134,7 +140,9 @@
 
 BOOST_AUTO_TEST_CASE_TEMPLATE(RemoteClose, Persistency, RemoteClosePersistencies)
 {
-  initialize(ip::address_v4::loopback(), Persistency::value);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address, Persistency::value);
 
   transport->afterStateChange.connectSingleShot([this] (TransportState oldState, TransportState newState) {
     BOOST_CHECK_EQUAL(oldState, TransportState::UP);
@@ -158,7 +166,9 @@
 
 BOOST_AUTO_TEST_CASE(RemoteClosePermanent)
 {
-  initialize(ip::address_v4::loopback(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  initialize(address, ndn::nfd::FACE_PERSISTENCY_PERMANENT);
 
   remoteSocket.close();
 
@@ -198,9 +208,11 @@
 
 BOOST_AUTO_TEST_CASE(ChangePersistencyNoExpirationTime)
 {
-  initialize(ip::address_v4::loopback(), ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
-  BOOST_CHECK_NE(transport->getExpirationTime(), time::steady_clock::TimePoint::max());
+  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());
 }
diff --git a/tests/daemon/face/websocket-channel.t.cpp b/tests/daemon/face/websocket-channel.t.cpp
index afa3629..2474300 100644
--- a/tests/daemon/face/websocket-channel.t.cpp
+++ b/tests/daemon/face/websocket-channel.t.cpp
@@ -26,6 +26,7 @@
 #include "face/websocket-channel.hpp"
 #include "face/websocket-transport.hpp"
 
+#include "test-ip.hpp"
 #include "tests/limited-io.hpp"
 #include "tests/test-common.hpp"
 
@@ -176,7 +177,7 @@
 {
   websocket::Endpoint ep(ip::address_v4::loopback(), 20070);
   auto channel = makeChannel(ep.address(), ep.port());
-  BOOST_CHECK_EQUAL(channel->getUri(), FaceUri("ws://127.0.0.1:20070"));
+  BOOST_CHECK_EQUAL(channel->getUri(), FaceUri(ep, "ws"));
 }
 
 BOOST_AUTO_TEST_CASE(Listen)
@@ -194,21 +195,25 @@
 
 BOOST_AUTO_TEST_CASE(MultipleAccepts)
 {
-  listen(ip::address_v4::loopback());
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->listen(address);
 
   BOOST_CHECK_EQUAL(listenerChannel->isListening(), true);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
 
   websocket::Client client1;
-  clientConnect(client1);
+  this->clientConnect(client1);
+
   BOOST_CHECK_EQUAL(limitedIo.run(2, // listenerOnFaceCreated, clientHandleOpen
                     time::seconds(1)), LimitedIo::EXCEED_OPS);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 1);
 
   websocket::Client client2;
   websocket::Client client3;
-  clientConnect(client2);
-  clientConnect(client3);
+  this->clientConnect(client2);
+  this->clientConnect(client3);
+
   BOOST_CHECK_EQUAL(limitedIo.run(4, // 2 listenerOnFaceCreated, 2 clientHandleOpen
                     time::seconds(1)), LimitedIo::EXCEED_OPS);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 3);
@@ -221,7 +226,9 @@
 
 BOOST_AUTO_TEST_CASE(Send)
 {
-  initialize(ip::address_v4::loopback());
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address);
   auto transport = listenerFaces.front()->getTransport();
 
   Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
@@ -247,7 +254,9 @@
 
 BOOST_AUTO_TEST_CASE(Receive)
 {
-  initialize(ip::address_v4::loopback());
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address);
 
   // use network-layer packets here, otherwise GenericLinkService
   // won't recognize the packet type and will discard it
@@ -269,7 +278,9 @@
 
 BOOST_AUTO_TEST_CASE(FaceClosure)
 {
-  initialize(ip::address_v4::loopback());
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address);
 
   listenerFaces.front()->close();
   BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
@@ -277,7 +288,9 @@
 
 BOOST_AUTO_TEST_CASE(RemoteClose)
 {
-  initialize(ip::address_v4::loopback());
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address);
 
   client.close(clientHandle, websocketpp::close::status::going_away, "");
   BOOST_CHECK_EQUAL(limitedIo.run(1, // faceClosedSignal
@@ -288,7 +301,9 @@
 BOOST_AUTO_TEST_CASE(SetPingInterval)
 {
   auto pingInterval = time::milliseconds(300);
-  initialize(ip::address_v4::loopback(), pingInterval, time::milliseconds(1000));
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address, pingInterval, time::milliseconds(1000));
 
   BOOST_CHECK_EQUAL(limitedIo.run(2, // clientHandlePing
                     time::seconds(1)), LimitedIo::EXCEED_OPS);
@@ -298,9 +313,11 @@
 
 BOOST_AUTO_TEST_CASE(SetPongTimeOut)
 {
-  initialize(ip::address_v4::loopback(), time::milliseconds(500), time::milliseconds(300));
-
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->initialize(address, time::milliseconds(500), time::milliseconds(300));
   clientShouldPong = false;
+
   BOOST_CHECK_EQUAL(limitedIo.run(2, // clientHandlePing, faceClosedSignal
                     time::seconds(2)), LimitedIo::EXCEED_OPS);
   BOOST_CHECK_EQUAL(listenerChannel->size(), 0);
diff --git a/tests/daemon/face/websocket-transport.t.cpp b/tests/daemon/face/websocket-transport.t.cpp
index 6a028ad..8dbd717 100644
--- a/tests/daemon/face/websocket-transport.t.cpp
+++ b/tests/daemon/face/websocket-transport.t.cpp
@@ -25,10 +25,10 @@
 
 #include "face/websocket-transport.hpp"
 #include "face/face.hpp"
-#include "dummy-receive-link-service.hpp"
-#include "get-available-interface-ip.hpp"
-#include "transport-test-common.hpp"
 
+#include "dummy-receive-link-service.hpp"
+#include "test-ip.hpp"
+#include "transport-test-common.hpp"
 #include "tests/limited-io.hpp"
 
 namespace nfd {
@@ -92,7 +92,7 @@
 
     websocketpp::lib::error_code ec;
     websocket::Client::connection_ptr con = client.get_connection(uri, ec);
-    BOOST_REQUIRE(!ec);
+    BOOST_REQUIRE_EQUAL(ec, websocketpp::lib::error_code());
 
     client.connect(con);
   }
@@ -214,8 +214,10 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesLocalIpv4)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::Yes);
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
+
   checkStaticPropertiesInitialized(*transport);
 
   BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("ws://127.0.0.1:20070"));
@@ -230,11 +232,10 @@
 
 BOOST_AUTO_TEST_CASE(StaticPropertiesNonLocalIpv4)
 {
-  auto address = getAvailableInterfaceIp<ip::address_v4>();
+  auto address = getTestIp<ip::address_v4>(LoopbackAddress::No);
   SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
-  ip::tcp::endpoint ep(address, 20070);
-  this->endToEndInitialize(ep);
   checkStaticPropertiesInitialized(*transport);
 
   BOOST_CHECK_EQUAL(transport->getLocalUri(), FaceUri("ws://" + address.to_string() + ":20070"));
@@ -249,8 +250,10 @@
 
 BOOST_AUTO_TEST_CASE(PingPong)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep, time::milliseconds(500), time::milliseconds(300));
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070),
+                           time::milliseconds(500), time::milliseconds(300));
 
   BOOST_CHECK_EQUAL(limitedIo.run(2, // clientHandlePing, serverHandlePong
                     time::milliseconds(1500)), LimitedIo::EXCEED_OPS);
@@ -272,8 +275,9 @@
 
 BOOST_AUTO_TEST_CASE(Send)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
   Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
   transport->send(Transport::Packet(Block(pkt1)));
@@ -298,8 +302,9 @@
 
 BOOST_AUTO_TEST_CASE(ReceiveNormal)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
   Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
   client.send(clientHdl, pkt1.wire(), pkt1.size(), websocketpp::frame::opcode::binary);
@@ -319,8 +324,9 @@
 
 BOOST_AUTO_TEST_CASE(ReceiveMalformed)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
   Block pkt1 = ndn::encoding::makeStringBlock(300, "hello");
   client.send(clientHdl, pkt1.wire(), pkt1.size() - 1, // truncated
@@ -344,8 +350,9 @@
 
 BOOST_AUTO_TEST_CASE(Close)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
   int nStateChanges = 0;
   transport->afterStateChange.connect(
@@ -371,8 +378,9 @@
 
 BOOST_AUTO_TEST_CASE(RemoteClose)
 {
-  ip::tcp::endpoint ep(ip::address_v4::loopback(), 20070);
-  this->endToEndInitialize(ep);
+  auto address = getTestIp<ip::address_v4>();
+  SKIP_IF_IP_UNAVAILABLE(address);
+  this->endToEndInitialize(ip::tcp::endpoint(address, 20070));
 
   int nStateChanges = 0;
   transport->afterStateChange.connect(