tests: sync common testing infrastructure with ndn-cxx

Upgrade waf to version 2.0.21

Change-Id: I30615cc49416088e9c5e4d602fd11360c0ed9328
diff --git a/tests/boost-multi-log-formatter.hpp b/tests/boost-multi-log-formatter.hpp
deleted file mode 100644
index ae37416..0000000
--- a/tests/boost-multi-log-formatter.hpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2015 Regents of the University of California.
- *
- * Based on work by Martin Ba (http://stackoverflow.com/a/26718189)
- *
- * This file is distributed under the Boost Software License, Version 1.0.
- * (See http://www.boost.org/LICENSE_1_0.txt)
- */
-
-#ifndef NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP
-#define NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP
-
-#include <boost/version.hpp>
-
-#if BOOST_VERSION >= 105900
-#include <boost/test/unit_test_parameters.hpp>
-#else
-#include <boost/test/detail/unit_test_parameters.hpp>
-#endif // BOOST_VERSION >= 105900
-
-#include <boost/test/unit_test_log_formatter.hpp>
-#include <boost/test/output/compiler_log_formatter.hpp>
-#include <boost/test/output/xml_log_formatter.hpp>
-
-namespace boost {
-namespace unit_test {
-namespace output {
-
-/**
- * @brief Log formatter for Boost.Test that outputs the logging to multiple formatters
- *
- * The log formatter is designed to output to one or multiple formatters at the same time.  For
- * example, one HRF formatter can output to the standard output, while XML formatter output to
- * the file.
- *
- * Usage:
- *
- *     // Call in init_unit_test_suite: (this will override the --log_format parameter)
- *     auto formatter = new boost::unit_test::output::multi_log_formatter; // same as already configured logger
- *
- *     // Prepare and add additional logger(s)
- *     formatter.add(std::make_shared<boost::unit_test::output::xml_log_formatter>(),
- *                   std::make_shared<std::ofstream>("out.xml"));
- *
- *      boost::unit_test::unit_test_log.set_formatter(formatter);
- *
- * @note Calling `boost::unit_test::unit_test_log.set_stream(...)` will change the stream for
- *       the original logger.
- */
-class multi_log_formatter : public unit_test_log_formatter
-{
-public:
-  /**
-   * @brief Create instance of the logger, based on the configured logger instance
-   */
-  multi_log_formatter()
-  {
-    auto format =
-#if BOOST_VERSION > 105900
-      runtime_config::get<output_format>(runtime_config::LOG_FORMAT);
-#else
-      runtime_config::log_format();
-#endif // BOOST_VERSION > 105900
-
-    switch (format) {
-      default:
-#if BOOST_VERSION >= 105900
-      case OF_CLF:
-#else
-      case CLF:
-#endif // BOOST_VERSION >= 105900
-        m_loggers.push_back({std::make_shared<compiler_log_formatter>(), nullptr});
-        break;
-#if BOOST_VERSION >= 105900
-      case OF_XML:
-#else
-      case XML:
-#endif // BOOST_VERSION >= 105900
-        m_loggers.push_back({std::make_shared<xml_log_formatter>(), nullptr});
-        break;
-    }
-  }
-
-  void
-  add(std::shared_ptr<unit_test_log_formatter> formatter, std::shared_ptr<std::ostream> os)
-  {
-    m_loggers.push_back({formatter, os});
-  }
-
-  // Formatter interface
-  void
-  log_start(std::ostream& os, counter_t test_cases_amount)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_start(l.os == nullptr ? os : *l.os, test_cases_amount);
-  }
-
-  void
-  log_finish(std::ostream& os)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_finish(l.os == nullptr ? os : *l.os);
-  }
-
-  void
-  log_build_info(std::ostream& os)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_build_info(l.os == nullptr ? os : *l.os);
-  }
-
-  void
-  test_unit_start(std::ostream& os, const test_unit& tu)
-  {
-    for (auto& l : m_loggers)
-      l.logger->test_unit_start(l.os == nullptr ? os : *l.os, tu);
-  }
-
-  void
-  test_unit_finish(std::ostream& os, const test_unit& tu, unsigned long elapsed)
-  {
-    for (auto& l : m_loggers)
-      l.logger->test_unit_finish(l.os == nullptr ? os : *l.os, tu, elapsed);
-  }
-
-  void
-  test_unit_skipped(std::ostream& os, const test_unit& tu)
-  {
-    for (auto& l : m_loggers)
-      l.logger->test_unit_skipped(l.os == nullptr ? os : *l.os, tu);
-  }
-
-#if BOOST_VERSION >= 105900
-  void
-  log_exception_start(std::ostream& os, const log_checkpoint_data& lcd, const execution_exception& ex)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_exception_start(l.os == nullptr ? os : *l.os, lcd, ex);
-  }
-
-  void
-  log_exception_finish(std::ostream& os)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_exception_finish(l.os == nullptr ? os : *l.os);
-  }
-#else
-  void
-  log_exception(std::ostream& os, const log_checkpoint_data& lcd, const execution_exception& ex)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_exception(l.os == nullptr ? os : *l.os, lcd, ex);
-  }
-#endif // BOOST_VERSION >= 105900
-
-  void
-  log_entry_start(std::ostream& os, const log_entry_data& entry_data, log_entry_types let)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_entry_start(l.os == nullptr ? os : *l.os, entry_data, let);
-  }
-
-  void
-  log_entry_value(std::ostream& os, const_string value)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_entry_value(l.os == nullptr ? os : *l.os, value);
-  }
-
-  void
-  log_entry_finish(std::ostream& os)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_entry_finish(l.os == nullptr ? os : *l.os);
-  }
-
-#if BOOST_VERSION >= 105900
-  void
-  entry_context_start(std::ostream& os, log_level level)
-  {
-    for (auto& l : m_loggers)
-      l.logger->entry_context_start(l.os == nullptr ? os : *l.os, level);
-  }
-
-  void
-  log_entry_context(std::ostream& os, const_string value)
-  {
-    for (auto& l : m_loggers)
-      l.logger->log_entry_context(l.os == nullptr ? os : *l.os, value);
-  }
-
-  void
-  entry_context_finish(std::ostream& os)
-  {
-    for (auto& l : m_loggers)
-      l.logger->entry_context_finish(l.os == nullptr ? os : *l.os);
-  }
-#endif // BOOST_VERSION >= 105900
-
-private:
-  struct LoggerInfo
-  {
-    std::shared_ptr<unit_test_log_formatter> logger;
-    std::shared_ptr<std::ostream> os;
-  };
-  std::vector<LoggerInfo> m_loggers;
-};
-
-} // namespace output
-} // namespace unit_test
-} // namespace boost
-
-#endif // NDN_TESTS_BOOST_MULTI_LOG_FORMATTER_HPP
diff --git a/tests/unit-test-common-fixtures.cpp b/tests/clock-fixture.cpp
similarity index 60%
rename from tests/unit-test-common-fixtures.cpp
rename to tests/clock-fixture.cpp
index f16e027..472e489 100644
--- a/tests/unit-test-common-fixtures.cpp
+++ b/tests/clock-fixture.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016,  Regents of the University of California,
+/*
+ * Copyright (c) 2014-2020,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -24,56 +24,37 @@
  * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "test-common.hpp"
+#include "clock-fixture.hpp"
 
 namespace ndn {
 namespace ndns {
 namespace tests {
 
-BaseFixture::BaseFixture()
+ClockFixture::ClockFixture()
+  : m_steadyClock(make_shared<time::UnitTestSteadyClock>())
+  , m_systemClock(make_shared<time::UnitTestSystemClock>())
 {
+  time::setCustomClocks(m_steadyClock, m_systemClock);
 }
 
-UnitTestTimeFixture::UnitTestTimeFixture()
-  : steadyClock(make_shared<time::UnitTestSteadyClock>())
-  , systemClock(make_shared<time::UnitTestSystemClock>())
-{
-  time::setCustomClocks(steadyClock, systemClock);
-}
-
-UnitTestTimeFixture::~UnitTestTimeFixture()
+ClockFixture::~ClockFixture()
 {
   time::setCustomClocks(nullptr, nullptr);
 }
 
 void
-UnitTestTimeFixture::advanceClocks(const time::nanoseconds& tick, size_t nTicks)
-{
-  this->advanceClocks(tick, tick * nTicks);
-}
-
-void
-UnitTestTimeFixture::advanceClocks(const time::nanoseconds& tick, const time::nanoseconds& total)
+ClockFixture::advanceClocks(time::nanoseconds tick, time::nanoseconds total)
 {
   BOOST_ASSERT(tick > time::nanoseconds::zero());
   BOOST_ASSERT(total >= time::nanoseconds::zero());
 
-  time::nanoseconds remaining = total;
-  while (remaining > time::nanoseconds::zero()) {
-    if (remaining >= tick) {
-      steadyClock->advance(tick);
-      systemClock->advance(tick);
-      remaining -= tick;
-    }
-    else {
-      steadyClock->advance(remaining);
-      systemClock->advance(remaining);
-      remaining = time::nanoseconds::zero();
-    }
+  while (total > time::nanoseconds::zero()) {
+    auto t = std::min(tick, total);
+    m_steadyClock->advance(t);
+    m_systemClock->advance(t);
+    total -= t;
 
-    if (m_io.stopped())
-      m_io.reset();
-    m_io.poll();
+    afterTick();
   }
 }
 
diff --git a/tests/clock-fixture.hpp b/tests/clock-fixture.hpp
new file mode 100644
index 0000000..48a0f73
--- /dev/null
+++ b/tests/clock-fixture.hpp
@@ -0,0 +1,92 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2020,  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 NDNS (Named Data Networking Domain Name Service) and is
+ * based on the code written as part of NFD (Named Data Networking Daemon).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS 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.
+ *
+ * NDNS 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
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNS_TESTS_CLOCK_FIXTURE_HPP
+#define NDNS_TESTS_CLOCK_FIXTURE_HPP
+
+#include <ndn-cxx/util/time-unit-test-clock.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+/** \brief A test fixture that overrides steady clock and system clock.
+ */
+class ClockFixture
+{
+public:
+  virtual
+  ~ClockFixture();
+
+  /** \brief Advance steady and system clocks.
+   *
+   *  Clocks are advanced in increments of \p tick for \p nTicks ticks.
+   *  afterTick() is called after each tick.
+   *
+   *  Exceptions thrown during I/O events are propagated to the caller.
+   *  Clock advancement will stop in the event of an exception.
+   */
+  void
+  advanceClocks(time::nanoseconds tick, size_t nTicks = 1)
+  {
+    advanceClocks(tick, tick * nTicks);
+  }
+
+  /** \brief Advance steady and system clocks.
+   *
+   *  Clocks are advanced in increments of \p tick for \p total time.
+   *  The last increment might be shorter than \p tick.
+   *  afterTick() is called after each tick.
+   *
+   *  Exceptions thrown during I/O events are propagated to the caller.
+   *  Clock advancement will stop in the event of an exception.
+   */
+  void
+  advanceClocks(time::nanoseconds tick, time::nanoseconds total);
+
+protected:
+  ClockFixture();
+
+private:
+  /** \brief Called by advanceClocks() after each clock advancement (tick).
+   *
+   *  The base class implementation is a no-op.
+   */
+  virtual void
+  afterTick()
+  {
+  }
+
+protected:
+  shared_ptr<time::UnitTestSteadyClock> m_steadyClock;
+  shared_ptr<time::UnitTestSystemClock> m_systemClock;
+};
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
+
+#endif // NDNS_TESTS_CLOCK_FIXTURE_HPP
diff --git a/tests/global-configuration-fixture.cpp b/tests/global-configuration.cpp
similarity index 66%
rename from tests/global-configuration-fixture.cpp
rename to tests/global-configuration.cpp
index a8ba286..de38e0e 100644
--- a/tests/global-configuration-fixture.cpp
+++ b/tests/global-configuration.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -17,16 +17,18 @@
  * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
+
+#include <boost/filesystem.hpp>
+#include <stdlib.h>
 
 namespace ndn {
-namespace ndns {
 namespace tests {
 
-class GlobalConfigurationFixture : boost::noncopyable
+class GlobalConfiguration
 {
 public:
-  GlobalConfigurationFixture()
+  GlobalConfiguration()
   {
     if (getenv("HOME") != nullptr) {
       m_home = getenv("HOME");
@@ -38,25 +40,25 @@
       m_tpm = getenv("NDN_CLIENT_TPM");
     }
 
-    boost::filesystem::path dir(TEST_CONFIG_PATH);
-    dir /= "test-home";
-    setenv("HOME", dir.generic_string().c_str(), 1);
+    auto testHome = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "test-home";
+    setenv("HOME", testHome.c_str(), 1);
+
+    boost::filesystem::create_directories(testHome);
 
     setenv("NDN_CLIENT_PIB", "pib-sqlite3", 1);
     setenv("NDN_CLIENT_TPM", "tpm-file", 1);
-    boost::filesystem::create_directories(dir);
   }
 
-  ~GlobalConfigurationFixture()
+  ~GlobalConfiguration() noexcept
   {
     if (!m_home.empty()) {
-      setenv("HOME", m_home.c_str(), 1);
+      setenv("HOME", m_home.data(), 1);
     }
     if (!m_pib.empty()) {
-      setenv("NDN_CLIENT_PIB", m_home.c_str(), 1);
+      setenv("NDN_CLIENT_PIB", m_home.data(), 1);
     }
     if (!m_tpm.empty()) {
-      setenv("NDN_CLIENT_TPM", m_home.c_str(), 1);
+      setenv("NDN_CLIENT_TPM", m_home.data(), 1);
     }
   }
 
@@ -66,11 +68,13 @@
   std::string m_tpm;
 };
 
-BOOST_GLOBAL_FIXTURE(GlobalConfigurationFixture)
-#if (BOOST_VERSION >= 105900)
-;
-#endif // BOOST_VERSION >= 105900
+#if BOOST_VERSION >= 106500
+BOOST_TEST_GLOBAL_CONFIGURATION(GlobalConfiguration);
+#elif BOOST_VERSION >= 105900
+BOOST_GLOBAL_FIXTURE(GlobalConfiguration);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalConfiguration)
+#endif
 
 } // namespace tests
-} // namespace ndns
 } // namespace ndn
diff --git a/tests/identity-management-fixture.cpp b/tests/identity-management-fixture.cpp
deleted file mode 100644
index 8215b75..0000000
--- a/tests/identity-management-fixture.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2020, Regents of the University of California.
- *
- * This file is part of NDNS (Named Data Networking Domain Name Service).
- * See AUTHORS.md for complete list of NDNS authors and contributors.
- *
- * NDNS 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.
- *
- * NDNS 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
- * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "identity-management-fixture.hpp"
-
-#include <ndn-cxx/util/io.hpp>
-#include <ndn-cxx/security/additional-description.hpp>
-
-#include <boost/filesystem.hpp>
-
-namespace ndn {
-namespace ndns {
-namespace tests {
-
-IdentityManagementBaseFixture::~IdentityManagementBaseFixture()
-{
-  boost::system::error_code ec;
-  for (const auto& certFile : m_certFiles) {
-    boost::filesystem::remove(certFile, ec); // ignore error
-  }
-}
-
-bool
-IdentityManagementBaseFixture::saveCertToFile(const Data& obj, const std::string& filename)
-{
-  m_certFiles.insert(filename);
-  try {
-    io::save(obj, filename);
-    return true;
-  }
-  catch (const io::Error&) {
-    return false;
-  }
-}
-
-IdentityManagementFixture::IdentityManagementFixture()
-  : m_keyChain("pib-memory:", "tpm-memory:")
-{
-}
-
-security::Identity
-IdentityManagementFixture::addIdentity(const Name& identityName, const KeyParams& params)
-{
-  auto identity = m_keyChain.createIdentity(identityName, params);
-  m_identities.insert(identityName);
-  return identity;
-}
-
-bool
-IdentityManagementFixture::saveIdentityCertificate(const security::Identity& identity,
-                                                     const std::string& filename)
-{
-  try {
-    auto cert = identity.getDefaultKey().getDefaultCertificate();
-    return saveCertToFile(cert, filename);
-  }
-  catch (const security::Pib::Error&) {
-    return false;
-  }
-}
-
-security::Identity
-IdentityManagementFixture::addSubCertificate(const Name& subIdentityName,
-                                               const security::Identity& issuer, const KeyParams& params)
-{
-  auto subIdentity = addIdentity(subIdentityName, params);
-
-  security::Certificate request = subIdentity.getDefaultKey().getDefaultCertificate();
-
-  request.setName(request.getKeyName().append("parent").appendVersion());
-
-  SignatureInfo info;
-  info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(7300)));
-
-  security::AdditionalDescription description;
-  description.set("type", "sub-certificate");
-  info.addCustomTlv(description.wireEncode());
-
-  m_keyChain.sign(request, signingByIdentity(issuer).setSignatureInfo(info));
-  m_keyChain.setDefaultCertificate(subIdentity.getDefaultKey(), request);
-
-  return subIdentity;
-}
-
-security::Certificate
-IdentityManagementFixture::addCertificate(const security::Key& key, const std::string& issuer)
-{
-  Name certificateName = key.getName();
-  certificateName
-    .append(issuer)
-    .appendVersion();
-  security::Certificate certificate;
-  certificate.setName(certificateName);
-
-  // set metainfo
-  certificate.setContentType(tlv::ContentType_Key);
-  certificate.setFreshnessPeriod(time::hours(1));
-
-  // set content
-  certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size());
-
-  // set signature-info
-  SignatureInfo info;
-  info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
-                                                  time::system_clock::now() + time::days(10)));
-
-  m_keyChain.sign(certificate, signingByKey(key).setSignatureInfo(info));
-  return certificate;
-}
-
-} // namespace tests
-} // namespace ndns
-} // namespace ndn
diff --git a/tests/identity-management-fixture.hpp b/tests/identity-management-fixture.hpp
deleted file mode 100644
index 5b4aff3..0000000
--- a/tests/identity-management-fixture.hpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2020, Regents of the University of California.
- *
- * This file is part of NDNS (Named Data Networking Domain Name Service).
- * See AUTHORS.md for complete list of NDNS authors and contributors.
- *
- * NDNS 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.
- *
- * NDNS 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
- * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
-#define NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
-
-#include "boost-test.hpp"
-#include "test-home-fixture.hpp"
-
-#include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/security/signing-helpers.hpp>
-
-#include <vector>
-
-namespace ndn {
-namespace ndns {
-namespace tests {
-
-class IdentityManagementBaseFixture : public TestHomeFixture<DefaultPibDir>
-{
-public:
-  ~IdentityManagementBaseFixture();
-
-  bool
-  saveCertToFile(const Data& obj, const std::string& filename);
-
-protected:
-  std::set<Name> m_identities;
-  std::set<std::string> m_certFiles;
-};
-
-/**
- * @brief A test suite level fixture to help with identity management
- *
- * Test cases in the suite can use this fixture to create identities.  Identities,
- * certificates, and saved certificates are automatically removed during test teardown.
- */
-class IdentityManagementFixture : public IdentityManagementBaseFixture
-{
-public:
-  IdentityManagementFixture();
-
-  /**
-   * @brief Add identity @p identityName
-   * @return name of the created self-signed certificate
-   */
-  security::Identity
-  addIdentity(const Name& identityName, const KeyParams& params = security::KeyChain::getDefaultKeyParams());
-
-  /**
-   *  @brief Save identity certificate to a file
-   *  @param identity identity
-   *  @param filename file name, should be writable
-   *  @return whether successful
-   */
-  bool
-  saveIdentityCertificate(const security::Identity& identity, const std::string& filename);
-
-  /**
-   * @brief Issue a certificate for \p subIdentityName signed by \p issuer
-   *
-   *  If identity does not exist, it is created.
-   *  A new key is generated as the default key for identity.
-   *  A default certificate for the key is signed by the issuer using its default certificate.
-   *
-   *  @return the sub identity
-   */
-  security::Identity
-  addSubCertificate(const Name& subIdentityName, const security::Identity& issuer,
-                    const KeyParams& params = security::KeyChain::getDefaultKeyParams());
-
-  /**
-   * @brief Add a self-signed certificate to @p key with issuer ID @p issuer
-   */
-  security::Certificate
-  addCertificate(const security::Key& key, const std::string& issuer);
-
-protected:
-  security::KeyChain m_keyChain;
-};
-
-} // namespace tests
-} // namespace ndns
-} // namespace ndn
-
-#endif // NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
diff --git a/tests/io-fixture.hpp b/tests/io-fixture.hpp
new file mode 100644
index 0000000..1917e6e
--- /dev/null
+++ b/tests/io-fixture.hpp
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2020,  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 NDNS (Named Data Networking Domain Name Service) and is
+ * based on the code written as part of NFD (Named Data Networking Daemon).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS 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.
+ *
+ * NDNS 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
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNS_TESTS_IO_FIXTURE_HPP
+#define NDNS_TESTS_IO_FIXTURE_HPP
+
+#include "clock-fixture.hpp"
+
+#include <boost/asio/io_service.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+class IoFixture : public ClockFixture
+{
+private:
+  void
+  afterTick() final
+  {
+    if (m_io.stopped()) {
+#if BOOST_VERSION >= 106600
+      m_io.restart();
+#else
+      m_io.reset();
+#endif
+    }
+    m_io.poll();
+  }
+
+protected:
+  boost::asio::io_service m_io;
+};
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
+
+#endif // NDNS_TESTS_IO_FIXTURE_HPP
diff --git a/tests/key-chain-fixture.cpp b/tests/key-chain-fixture.cpp
new file mode 100644
index 0000000..c374fa3
--- /dev/null
+++ b/tests/key-chain-fixture.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS 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.
+ *
+ * NDNS 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
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "key-chain-fixture.hpp"
+
+#include <ndn-cxx/util/io.hpp>
+
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+using namespace ndn::security;
+
+KeyChainFixture::KeyChainFixture()
+  : m_keyChain("pib-memory:", "tpm-memory:")
+{
+}
+
+KeyChainFixture::~KeyChainFixture()
+{
+  boost::system::error_code ec;
+  for (const auto& certFile : m_certFiles) {
+    boost::filesystem::remove(certFile, ec); // ignore error
+  }
+}
+
+Certificate
+KeyChainFixture::makeCert(const Key& key, const std::string& issuer, const Key& signingKey)
+{
+  Certificate cert;
+  cert.setName(Name(key.getName())
+               .append(issuer)
+               .appendVersion());
+
+  // set metainfo
+  cert.setContentType(tlv::ContentType_Key);
+  cert.setFreshnessPeriod(1_h);
+
+  // set content
+  cert.setContent(key.getPublicKey().data(), key.getPublicKey().size());
+
+  // set signature info
+  ndn::SignatureInfo info;
+  auto now = time::system_clock::now();
+  info.setValidityPeriod(ValidityPeriod(now - 30_days, now + 30_days));
+
+  m_keyChain.sign(cert, signingByKey(signingKey ? signingKey : key).setSignatureInfo(info));
+  return cert;
+}
+
+bool
+KeyChainFixture::saveCert(const Data& cert, const std::string& filename)
+{
+  m_certFiles.push_back(filename);
+  try {
+    ndn::io::save(cert, filename);
+    return true;
+  }
+  catch (const ndn::io::Error&) {
+    return false;
+  }
+}
+
+bool
+KeyChainFixture::saveIdentityCert(const Identity& identity, const std::string& filename)
+{
+  Certificate cert;
+  try {
+    cert = identity.getDefaultKey().getDefaultCertificate();
+  }
+  catch (const Pib::Error&) {
+    return false;
+  }
+
+  return saveCert(cert, filename);
+}
+
+bool
+KeyChainFixture::saveIdentityCert(const Name& identityName, const std::string& filename,
+                                  bool allowCreate)
+{
+  Identity id;
+  try {
+    id = m_keyChain.getPib().getIdentity(identityName);
+  }
+  catch (const Pib::Error&) {
+    if (allowCreate) {
+      id = m_keyChain.createIdentity(identityName);
+    }
+  }
+
+  if (!id) {
+    return false;
+  }
+
+  return saveIdentityCert(id, filename);
+}
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
diff --git a/tests/key-chain-fixture.hpp b/tests/key-chain-fixture.hpp
new file mode 100644
index 0000000..003149d
--- /dev/null
+++ b/tests/key-chain-fixture.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of NDNS (Named Data Networking Domain Name Service).
+ * See AUTHORS.md for complete list of NDNS authors and contributors.
+ *
+ * NDNS 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.
+ *
+ * NDNS 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
+ * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NDNS_TESTS_KEY_CHAIN_FIXTURE_HPP
+#define NDNS_TESTS_KEY_CHAIN_FIXTURE_HPP
+
+#include "test-home-fixture.hpp"
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+/**
+ * @brief A fixture providing an in-memory KeyChain.
+ *
+ * Test cases can use this fixture to create identities. Identities, certificates, and
+ * saved certificates are automatically removed during test teardown.
+ */
+class KeyChainFixture : public TestHomeFixture<DefaultPibDir>
+{
+protected:
+  using Certificate = ndn::security::Certificate;
+  using Identity    = ndn::security::Identity;
+  using Key         = ndn::security::Key;
+
+public:
+  /**
+   * @brief Creates and returns a certificate for a given key
+   * @param key The key for which to make a certificate
+   * @param issuer The IssuerId to include in the certificate name
+   * @param signingKey The key with which to sign the certificate; if not provided, the
+   *                   certificate will be self-signed
+   */
+  Certificate
+  makeCert(const Key& key, const std::string& issuer, const Key& signingKey = Key());
+
+  /**
+   * @brief Saves an NDN certificate to a file
+   * @return true if successful, false otherwise
+   */
+  bool
+  saveCert(const Data& cert, const std::string& filename);
+
+  /**
+   * @brief Saves the default certificate of @p identity to a file
+   * @return true if successful, false otherwise
+   */
+  bool
+  saveIdentityCert(const Identity& identity, const std::string& filename);
+
+  /**
+   * @brief Saves the default certificate of the identity named @p identityName to a file
+   * @param identityName Name of the identity
+   * @param filename File name, must be writable
+   * @param allowCreate If true, create the identity if it does not exist
+   * @return true if successful, false otherwise
+   */
+  bool
+  saveIdentityCert(const Name& identityName, const std::string& filename,
+                   bool allowCreate = false);
+
+protected:
+  KeyChainFixture();
+
+  ~KeyChainFixture();
+
+protected:
+  ndn::KeyChain m_keyChain;
+
+private:
+  std::vector<std::string> m_certFiles;
+};
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn
+
+#endif // NDNS_TESTS_KEY_CHAIN_FIXTURE_HPP
diff --git a/tests/main.cpp b/tests/main.cpp
index fc8f99a..3a1bd40 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -24,92 +24,5 @@
  * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#define BOOST_TEST_MODULE NDNS Unit Tests
-
-#include <boost/version.hpp>
-
-#if BOOST_VERSION >= 106200
-// Boost.Test v3.3 (Boost 1.62) natively supports multi-logger output
+#define BOOST_TEST_MODULE NDNS
 #include "boost-test.hpp"
-#else
-#define BOOST_TEST_ALTERNATIVE_INIT_API
-#define BOOST_TEST_NO_MAIN
-#include "boost-test.hpp"
-#include "boost-multi-log-formatter.hpp"
-
-#include <boost/program_options/options_description.hpp>
-#include <boost/program_options/variables_map.hpp>
-#include <boost/program_options/parsers.hpp>
-
-#include <fstream>
-#include <iostream>
-
-static bool
-init_tests()
-{
-  init_unit_test();
-
-  namespace po = boost::program_options;
-  namespace ut = boost::unit_test;
-
-  po::options_description extraOptions;
-  std::string logger;
-  std::string outputFile = "-";
-  extraOptions.add_options()
-    ("log_format2", po::value<std::string>(&logger), "Type of second log formatter: HRF or XML")
-    ("log_sink2", po::value<std::string>(&outputFile)->default_value(outputFile), "Second log sink, - for stdout")
-    ;
-  po::variables_map vm;
-  try {
-    po::store(po::command_line_parser(ut::framework::master_test_suite().argc,
-                                      ut::framework::master_test_suite().argv)
-                .options(extraOptions)
-                .run(),
-              vm);
-    po::notify(vm);
-  }
-  catch (const std::exception& e) {
-    std::cerr << "ERROR: " << e.what() << "\n"
-              << extraOptions << std::endl;
-    return false;
-  }
-
-  if (vm.count("log_format2") == 0) {
-    // second logger is not configured
-    return true;
-  }
-
-  std::shared_ptr<ut::unit_test_log_formatter> formatter;
-  if (logger == "XML") {
-    formatter = std::make_shared<ut::output::xml_log_formatter>();
-  }
-  else if (logger == "HRF") {
-    formatter = std::make_shared<ut::output::compiler_log_formatter>();
-  }
-  else {
-    std::cerr << "ERROR: only HRF or XML log formatter can be specified" << std::endl;
-    return false;
-  }
-
-  std::shared_ptr<std::ostream> output;
-  if (outputFile == "-") {
-    output = std::shared_ptr<std::ostream>(&std::cout, std::bind([]{}));
-  }
-  else {
-    output = std::make_shared<std::ofstream>(outputFile.c_str());
-  }
-
-  auto multiFormatter = new ut::output::multi_log_formatter;
-  multiFormatter->add(formatter, output);
-  ut::unit_test_log.set_formatter(multiFormatter);
-
-  return true;
-}
-
-int
-main(int argc, char* argv[])
-{
-  return ::boost::unit_test::unit_test_main(&init_tests, argc, argv);
-}
-
-#endif // BOOST_VERSION >= 106200
diff --git a/tests/test-common.cpp b/tests/test-common.cpp
deleted file mode 100644
index edafcb4..0000000
--- a/tests/test-common.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2017, Regents of the University of California.
- *
- * This file is part of NDNS (Named Data Networking Domain Name Service).
- * See AUTHORS.md for complete list of NDNS authors and contributors.
- *
- * NDNS 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.
- *
- * NDNS 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
- * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "test-common.hpp"
-
-#include <ndn-cxx/security/signature-sha256-with-rsa.hpp>
-
-namespace ndn {
-namespace ndns {
-namespace tests {
-
-shared_ptr<Interest>
-makeInterest(const Name& name, uint32_t nonce)
-{
-  auto interest = make_shared<Interest>(name);
-  if (nonce != 0) {
-    interest->setNonce(nonce);
-  }
-  return interest;
-}
-
-shared_ptr<Data>
-makeData(const Name& name)
-{
-  auto data = make_shared<Data>(name);
-  return signData(data);
-}
-
-Data&
-signData(Data& data)
-{
-  ndn::SignatureSha256WithRsa fakeSignature;
-  fakeSignature.setValue(ndn::encoding::makeEmptyBlock(tlv::SignatureValue));
-  data.setSignature(fakeSignature);
-  data.wireEncode();
-
-  return data;
-}
-
-lp::Nack
-makeNack(const Name& name, uint32_t nonce, lp::NackReason reason)
-{
-  Interest interest(name);
-  interest.setNonce(nonce);
-  lp::Nack nack(std::move(interest));
-  nack.setReason(reason);
-  return nack;
-}
-
-} // namespace tests
-} // namespace ndns
-} // namespace ndn
diff --git a/tests/test-common.hpp b/tests/test-common.hpp
deleted file mode 100644
index 0746b83..0000000
--- a/tests/test-common.hpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/*
- * Copyright (c) 2014-2020, Regents of the University of California.
- *
- * This file is part of NDNS (Named Data Networking Domain Name Service).
- * See AUTHORS.md for complete list of NDNS authors and contributors.
- *
- * NDNS 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.
- *
- * NDNS 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
- * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NDNS_TESTS_TEST_COMMON_HPP
-#define NDNS_TESTS_TEST_COMMON_HPP
-
-#include "logger.hpp"
-#include "boost-test.hpp"
-#include "unit-test-common-fixtures.hpp"
-#include "identity-management-fixture.hpp"
-
-#include <ndn-cxx/name.hpp>
-#include <ndn-cxx/data.hpp>
-#include <ndn-cxx/interest.hpp>
-#include <ndn-cxx/link.hpp>
-#include <ndn-cxx/lp/nack.hpp>
-#include <ndn-cxx/util/dummy-client-face.hpp>
-#include <ndn-cxx/security/signing-helpers.hpp>
-
-#include <boost/version.hpp>
-#include <boost/asio.hpp>
-#include <boost/filesystem.hpp>
-
-#include <fstream>
-
-namespace ndn {
-namespace ndns {
-namespace tests {
-
-using ndn::security::KeyChain;
-using ndn::security::Identity;
-using ndn::security::pib::Key;
-using ndn::security::Certificate;
-
-/** \brief create an Interest
- *  \param name Interest name
- *  \param nonce if non-zero, set Nonce to this value
- *               (useful for creating Nack with same Nonce)
- */
-shared_ptr<Interest>
-makeInterest(const Name& name, uint32_t nonce = 0);
-
-/** \brief create a Data with fake signature
- *  \note Data may be modified afterwards without losing the fake signature.
- *        If a real signature is desired, sign again with KeyChain.
- */
-shared_ptr<Data>
-makeData(const Name& name);
-
-/** \brief add a fake signature to Data
- */
-Data&
-signData(Data& data);
-
-/** \brief add a fake signature to Data
- */
-inline shared_ptr<Data>
-signData(shared_ptr<Data> data)
-{
-  signData(*data);
-  return data;
-}
-
-/** \brief create a Nack
- *  \param name Interest name
- *  \param nonce Interest nonce
- *  \param reason Nack reason
- */
-lp::Nack
-makeNack(const Name& name, uint32_t nonce, lp::NackReason reason);
-
-/** \brief replace a name component
- *  \param[inout] name name
- *  \param index name component index
- *  \param a arguments to name::Component constructor
- */
-template<typename...A>
-void
-setNameComponent(Name& name, ssize_t index, const A& ...a)
-{
-  Name name2 = name.getPrefix(index);
-  name2.append(name::Component(a...));
-  name2.append(name.getSubName(name2.size()));
-  name = name2;
-}
-
-template<typename Packet, typename...A>
-void
-setNameComponent(Packet& packet, ssize_t index, const A& ...a)
-{
-  Name name = packet.getName();
-  setNameComponent(name, index, a...);
-  packet.setName(name);
-}
-
-} // namespace tests
-} // namespace ndns
-} // namespace ndn
-
-#endif // NDNS_TESTS_TEST_COMMON_HPP
diff --git a/tests/test-home-fixture.hpp b/tests/test-home-fixture.hpp
index 08d2158..17e9abf 100644
--- a/tests/test-home-fixture.hpp
+++ b/tests/test-home-fixture.hpp
@@ -20,11 +20,12 @@
 #ifndef NDNS_TESTS_TEST_HOME_FIXTURE_HPP
 #define NDNS_TESTS_TEST_HOME_FIXTURE_HPP
 
-#include "boost-test.hpp"
-
-#include <boost/filesystem.hpp>
-#include <boost/algorithm/string.hpp>
+#include <cstdlib>
 #include <fstream>
+#include <initializer_list>
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/filesystem.hpp>
 
 namespace ndn {
 namespace ndns {
@@ -43,11 +44,11 @@
   PibDirFixture()
     : m_pibDir(Path().PATH)
   {
-    if (getenv("NDN_CLIENT_PIB") != nullptr) {
-      m_oldPib = getenv("NDN_CLIENT_PIB");
+    if (std::getenv("NDN_CLIENT_PIB") != nullptr) {
+      m_oldPib = std::getenv("NDN_CLIENT_PIB");
     }
-    if (getenv("NDN_CLIENT_TPM") != nullptr) {
-      m_oldTpm = getenv("NDN_CLIENT_TPM");
+    if (std::getenv("NDN_CLIENT_TPM") != nullptr) {
+      m_oldTpm = std::getenv("NDN_CLIENT_TPM");
     }
 
     /// @todo Consider change to an in-memory PIB/TPM
@@ -58,14 +59,14 @@
   ~PibDirFixture()
   {
     if (!m_oldPib.empty()) {
-      setenv("NDN_CLIENT_PIB", m_oldPib.c_str(), true);
+      setenv("NDN_CLIENT_PIB", m_oldPib.data(), true);
     }
     else {
       unsetenv("NDN_CLIENT_PIB");
     }
 
     if (!m_oldTpm.empty()) {
-      setenv("NDN_CLIENT_TPM", m_oldTpm.c_str(), true);
+      setenv("NDN_CLIENT_TPM", m_oldTpm.data(), true);
     }
     else {
       unsetenv("NDN_CLIENT_TPM");
@@ -91,7 +92,7 @@
 public:
   TestHomeFixture()
   {
-    setenv("TEST_HOME", this->m_pibDir.c_str(), true);
+    setenv("TEST_HOME", this->m_pibDir.data(), true);
   }
 
   ~TestHomeFixture()
@@ -100,7 +101,7 @@
   }
 
   void
-  createClientConf(std::initializer_list<std::string> lines)
+  createClientConf(std::initializer_list<std::string> lines) const
   {
     boost::filesystem::create_directories(boost::filesystem::path(this->m_pibDir) / ".ndn");
     std::ofstream of((boost::filesystem::path(this->m_pibDir) / ".ndn" / "client.conf").c_str());
diff --git a/tests/unit-test-common-fixtures.hpp b/tests/unit-test-common-fixtures.hpp
deleted file mode 100644
index 9e1c9ac..0000000
--- a/tests/unit-test-common-fixtures.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2017,  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 NDNS (Named Data Networking Domain Name Service) and is
- * based on the code written as part of NFD (Named Data Networking Daemon).
- * See AUTHORS.md for complete list of NDNS authors and contributors.
- *
- * NDNS 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.
- *
- * NDNS 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
- * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef NDNS_TESTS_UNIT_TEST_COMMON_FIXTURES_HPP
-#define NDNS_TESTS_UNIT_TEST_COMMON_FIXTURES_HPP
-
-#include "boost-test.hpp"
-
-#include <boost/asio.hpp>
-#include <ndn-cxx/util/time-unit-test-clock.hpp>
-
-namespace ndn {
-namespace ndns {
-namespace tests {
-
-/** \brief base test fixture
- *
- *  Every test case should be based on this fixture,
- *  to have per test case io_service initialization.
- */
-class BaseFixture
-{
-protected:
-  BaseFixture();
-
-protected:
-  /** \brief reference to global io_service
-   */
-  boost::asio::io_service m_io;
-};
-
-/** \brief a base test fixture that overrides steady clock and system clock
- */
-class UnitTestTimeFixture : public virtual BaseFixture
-{
-protected:
-  UnitTestTimeFixture();
-
-  ~UnitTestTimeFixture();
-
-  /** \brief advance steady and system clocks
-   *
-   *  Clocks are advanced in increments of \p tick for \p nTicks ticks.
-   *  After each tick, global io_service is polled to process pending I/O events.
-   *
-   *  Exceptions thrown during I/O events are propagated to the caller.
-   *  Clock advancing would stop in case of an exception.
-   */
-  void
-  advanceClocks(const time::nanoseconds& tick, size_t nTicks = 1);
-
-  /** \brief advance steady and system clocks
-   *
-   *  Clocks are advanced in increments of \p tick for \p total time.
-   *  The last increment might be shorter than \p tick.
-   *  After each tick, global io_service is polled to process pending I/O events.
-   *
-   *  Exceptions thrown during I/O events are propagated to the caller.
-   *  Clock advancing would stop in case of an exception.
-   */
-  void
-  advanceClocks(const time::nanoseconds& tick, const time::nanoseconds& total);
-
-protected:
-  shared_ptr<time::UnitTestSteadyClock> steadyClock;
-  shared_ptr<time::UnitTestSystemClock> systemClock;
-
-  friend class LimitedIo;
-};
-
-} // namespace tests
-} // namespace ndns
-} // namespace ndn
-
-#endif // NDNS_TESTS_UNIT_TEST_COMMON_FIXTURES_HPP
diff --git a/tests/unit/clients/iterative-query-controller.cpp b/tests/unit/clients/iterative-query-controller.t.cpp
similarity index 97%
rename from tests/unit/clients/iterative-query-controller.cpp
rename to tests/unit/clients/iterative-query-controller.t.cpp
index 46d11d4..6478156 100644
--- a/tests/unit/clients/iterative-query-controller.cpp
+++ b/tests/unit/clients/iterative-query-controller.t.cpp
@@ -20,9 +20,11 @@
 #include "clients/iterative-query-controller.hpp"
 #include "daemon/name-server.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
 #include "unit/database-test-data.hpp"
 
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
 namespace ndn {
 namespace ndns {
 namespace tests {
@@ -128,7 +130,6 @@
       }
     }
   }
-
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/unit/clients/query.cpp b/tests/unit/clients/query.t.cpp
similarity index 91%
rename from tests/unit/clients/query.cpp
rename to tests/unit/clients/query.t.cpp
index f7ed478..e4da482 100644
--- a/tests/unit/clients/query.cpp
+++ b/tests/unit/clients/query.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -19,10 +19,10 @@
 
 #include "clients/query.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
+#include "key-chain-fixture.hpp"
 
 #include <boost/lexical_cast.hpp>
-#include <string>
 
 namespace ndn {
 namespace ndns {
@@ -30,9 +30,9 @@
 
 BOOST_AUTO_TEST_SUITE(Query)
 
-BOOST_FIXTURE_TEST_CASE(TestCase, IdentityManagementFixture)
+BOOST_FIXTURE_TEST_CASE(TestCase, KeyChainFixture)
 {
-  security::Identity certIdentity = addIdentity("/cert/name");
+  auto certIdentity = m_keyChain.createIdentity("/cert/name");
   Name zone("/net");
   name::Component qType = ndns::label::NDNS_ITERATIVE_QUERY;
   ndns::Query q(zone, qType);
@@ -77,7 +77,7 @@
   BOOST_CHECK_EQUAL(q5.fromInterest(zone, interest), true);
   BOOST_CHECK_EQUAL(q4, q5);
   BOOST_CHECK_NE(q2, q4);
- }
+}
 
 BOOST_AUTO_TEST_SUITE_END()
 
diff --git a/tests/unit/clients/response.cpp b/tests/unit/clients/response.t.cpp
similarity index 93%
rename from tests/unit/clients/response.cpp
rename to tests/unit/clients/response.t.cpp
index 88941c8..97a6fe0 100644
--- a/tests/unit/clients/response.cpp
+++ b/tests/unit/clients/response.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016, Regents of the University of California.
+/*
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -19,13 +19,14 @@
 
 #include "clients/response.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
+#include "key-chain-fixture.hpp"
 
 namespace ndn {
 namespace ndns {
 namespace tests {
 
-BOOST_FIXTURE_TEST_SUITE(Response, IdentityManagementFixture)
+BOOST_FIXTURE_TEST_SUITE(Response, KeyChainFixture)
 
 BOOST_AUTO_TEST_CASE(Basic)
 {
diff --git a/tests/unit/daemon/db-mgr.cpp b/tests/unit/daemon/db-mgr.t.cpp
similarity index 96%
rename from tests/unit/daemon/db-mgr.cpp
rename to tests/unit/daemon/db-mgr.t.cpp
index ffa38b8..0b69330 100644
--- a/tests/unit/daemon/db-mgr.cpp
+++ b/tests/unit/daemon/db-mgr.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -18,9 +18,12 @@
  */
 
 #include "daemon/db-mgr.hpp"
-#include "test-common.hpp"
+#include "logger.hpp"
+
+#include "boost-test.hpp"
 
 #include <algorithm>
+#include <boost/filesystem.hpp>
 
 namespace ndn {
 namespace ndns {
@@ -30,7 +33,7 @@
 
 BOOST_AUTO_TEST_SUITE(DbMgr)
 
-static const boost::filesystem::path TEST_DATABASE2 = TEST_CONFIG_PATH "/" "test-ndns.db";
+const auto TEST_DATABASE2 = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "test-ndns.db";
 
 class DbMgrFixture
 {
@@ -43,16 +46,14 @@
   ~DbMgrFixture()
   {
     session.close();
-    boost::filesystem::remove(TEST_DATABASE2);
     NDNS_LOG_INFO("remove database " << TEST_DATABASE2);
+    boost::filesystem::remove(TEST_DATABASE2);
   }
 
 public:
   ndns::DbMgr session;
 };
 
-
-
 BOOST_FIXTURE_TEST_CASE(Zones, DbMgrFixture)
 {
   Zone zone1;
diff --git a/tests/unit/daemon/name-server.cpp b/tests/unit/daemon/name-server.t.cpp
similarity index 98%
rename from tests/unit/daemon/name-server.cpp
rename to tests/unit/daemon/name-server.t.cpp
index cf31a8f..4ad5a11 100644
--- a/tests/unit/daemon/name-server.cpp
+++ b/tests/unit/daemon/name-server.t.cpp
@@ -18,13 +18,16 @@
  */
 
 #include "daemon/name-server.hpp"
-#include "daemon/db-mgr.hpp"
-#include "clients/response.hpp"
-#include "clients/query.hpp"
 
-#include "test-common.hpp"
+#include "clients/query.hpp"
+#include "clients/response.hpp"
+#include "daemon/db-mgr.hpp"
+#include "logger.hpp"
+
+#include "boost-test.hpp"
 #include "unit/database-test-data.hpp"
 
+#include <ndn-cxx/util/dummy-client-face.hpp>
 #include <ndn-cxx/util/regex.hpp>
 
 namespace ndn {
diff --git a/tests/unit/daemon/rrset-factory.cpp b/tests/unit/daemon/rrset-factory.t.cpp
similarity index 89%
rename from tests/unit/daemon/rrset-factory.cpp
rename to tests/unit/daemon/rrset-factory.t.cpp
index 39c9286..6f2eb69 100644
--- a/tests/unit/daemon/rrset-factory.cpp
+++ b/tests/unit/daemon/rrset-factory.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -18,11 +18,13 @@
  */
 
 #include "daemon/rrset-factory.hpp"
-
-#include "test-common.hpp"
 #include "mgmt/management-tool.hpp"
 
+#include "boost-test.hpp"
+#include "key-chain-fixture.hpp"
+
 #include <boost/lexical_cast.hpp>
+
 #include <ndn-cxx/security/verification-helpers.hpp>
 
 namespace ndn {
@@ -31,15 +33,16 @@
 
 NDNS_LOG_INIT(RrsetFactoryTest);
 
-class RrsetFactoryFixture : public IdentityManagementFixture
+const auto TEST_DATABASE2 = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "test-ndns.db";
+const auto TEST_CERT = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "anchors" / "root.cert";
+
+class RrsetFactoryFixture : public KeyChainFixture
 {
 public:
   RrsetFactoryFixture()
-    : TEST_DATABASE2(TEST_CONFIG_PATH "/" "test-ndns.db"),
-      TEST_IDENTITY_NAME("/rrest/factory"),
-      TEST_CERT(TEST_CONFIG_PATH "/" "anchors/root.cert"),
-      m_session(TEST_DATABASE2.string()),
-      m_zoneName(TEST_IDENTITY_NAME)
+    : TEST_IDENTITY_NAME("/rrest/factory")
+    , m_session(TEST_DATABASE2.string())
+    , m_zoneName(TEST_IDENTITY_NAME)
   {
     Zone zone1;
     zone1.setName(m_zoneName);
@@ -48,12 +51,12 @@
 
     Name identityName = Name(TEST_IDENTITY_NAME).append("NDNS");
 
-    m_identity = this->addIdentity(identityName);
+    m_identity = m_keyChain.createIdentity(identityName);
     m_cert = m_identity.getDefaultKey().getDefaultCertificate();
     m_certName = m_cert.getName();
-    saveIdentityCertificate(m_identity, TEST_CERT.string());
+    saveIdentityCert(m_identity, TEST_CERT.string());
 
-    NDNS_LOG_INFO("save test root cert " << m_certName << " to: " << TEST_CERT.string());
+    NDNS_LOG_INFO("save test root cert " << m_certName << " to: " << TEST_CERT);
     BOOST_CHECK_GT(m_certName.size(), 0);
     NDNS_LOG_TRACE("test certName: " << m_certName);
   }
@@ -61,15 +64,13 @@
   ~RrsetFactoryFixture()
   {
     m_session.close();
-    boost::filesystem::remove(TEST_DATABASE2);
     NDNS_LOG_INFO("remove database " << TEST_DATABASE2);
+    boost::filesystem::remove(TEST_DATABASE2);
     boost::filesystem::remove(TEST_CERT);
   }
 
 public:
-  const boost::filesystem::path TEST_DATABASE2;
   const Name TEST_IDENTITY_NAME;
-  const boost::filesystem::path TEST_CERT;
   ndns::DbMgr m_session;
   Name m_zoneName;
   Name m_certName;
diff --git a/tests/unit/daemon/rrset.cpp b/tests/unit/daemon/rrset.t.cpp
similarity index 99%
rename from tests/unit/daemon/rrset.cpp
rename to tests/unit/daemon/rrset.t.cpp
index f9e2704..eb9f035 100644
--- a/tests/unit/daemon/rrset.cpp
+++ b/tests/unit/daemon/rrset.t.cpp
@@ -19,7 +19,7 @@
 
 #include "daemon/rrset.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
 
 #if BOOST_VERSION >= 105900
 #include <boost/test/tools/output_test_stream.hpp>
diff --git a/tests/unit/daemon/zone.cpp b/tests/unit/daemon/zone.t.cpp
similarity index 98%
rename from tests/unit/daemon/zone.cpp
rename to tests/unit/daemon/zone.t.cpp
index 09bc781..ed57285 100644
--- a/tests/unit/daemon/zone.cpp
+++ b/tests/unit/daemon/zone.t.cpp
@@ -19,7 +19,7 @@
 
 #include "daemon/zone.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
 
 #if BOOST_VERSION >= 105900
 #include <boost/test/tools/output_test_stream.hpp>
diff --git a/tests/unit/database-test-data.cpp b/tests/unit/database-test-data.cpp
index 2aef965..d4808d6 100644
--- a/tests/unit/database-test-data.cpp
+++ b/tests/unit/database-test-data.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2018, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -19,27 +19,28 @@
 
 #include "database-test-data.hpp"
 #include "daemon/rrset-factory.hpp"
-#include "util/cert-helper.hpp"
 #include "mgmt/management-tool.hpp"
+#include "util/cert-helper.hpp"
+
 #include <ndn-cxx/security/verification-helpers.hpp>
 
+namespace fs = boost::filesystem;
+
 namespace ndn {
 namespace ndns {
 namespace tests {
 
 NDNS_LOG_INIT(TestFakeData);
 
-const boost::filesystem::path DbTestData::TEST_DATABASE = TEST_CONFIG_PATH "/" "test-ndns.db";
+const fs::path DbTestData::TEST_DATABASE = fs::path(UNIT_TESTS_TMPDIR) / "test-ndns.db";
 const Name DbTestData::TEST_IDENTITY_NAME("/test19");
-const boost::filesystem::path DbTestData::TEST_CERT =
-  TEST_CONFIG_PATH "/" "anchors/root.cert";
-const boost::filesystem::path DbTestData::TEST_DKEY_CERT =
-  TEST_CONFIG_PATH "/" "dkey.cert";
+const fs::path DbTestData::TEST_CERT = fs::path(UNIT_TESTS_TMPDIR) / "anchors" / "root.cert";
+const fs::path DbTestData::TEST_DKEY_CERT = fs::path(UNIT_TESTS_TMPDIR) / "dkey.cert";
 
 DbTestData::PreviousStateCleaner::PreviousStateCleaner()
 {
-  boost::filesystem::remove(TEST_DATABASE);
-  boost::filesystem::remove(TEST_CERT);
+  fs::remove(TEST_DATABASE);
+  fs::remove(TEST_CERT);
 }
 
 DbTestData::DbTestData()
@@ -50,20 +51,16 @@
 {
   NDNS_LOG_TRACE("start creating test data");
 
-  ndns::NdnsValidatorBuilder::VALIDATOR_CONF_FILE = TEST_CONFIG_PATH "/" "validator.conf";
+  NdnsValidatorBuilder::VALIDATOR_CONF_FILE = (fs::path(UNIT_TESTS_TMPDIR) / "validator.conf").string();
 
   ManagementTool tool(TEST_DATABASE.string(), m_keyChain);
   // this is how DKEY is added to parent zone in real world.
-  auto addDkeyCertToParent = [&tool](Zone& dkeyFrom, Zone& dkeyTo)->void{
+  auto addDkeyCertToParent = [&tool] (Zone& dkeyFrom, Zone& dkeyTo) {
     Certificate dkeyCert;
     dkeyCert = tool.getZoneDkey(dkeyFrom);
-    ndn::io::save(dkeyCert, TEST_DKEY_CERT.string());
-    tool.addRrsetFromFile(dkeyTo.getName(),
-                          TEST_DKEY_CERT.string(),
-                          DEFAULT_RR_TTL,
-                          DEFAULT_CERT,
-                          ndn::io::BASE64,
-                          true);
+    io::save(dkeyCert, TEST_DKEY_CERT.string());
+    tool.addRrsetFromFile(dkeyTo.getName(), TEST_DKEY_CERT.string(),
+                          DEFAULT_RR_TTL, DEFAULT_CERT, io::BASE64, true);
   };
 
   Name testName(m_testName);
@@ -85,16 +82,15 @@
   m_certName = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, identityName);
   m_cert = CertHelper::getCertificate(m_keyChain, identityName, m_certName);
 
-  ndn::io::save(m_cert, TEST_CERT.string());
+  io::save(m_cert, TEST_CERT.string());
   NDNS_LOG_INFO("save test root cert " << m_certName << " to: " << TEST_CERT.string());
 
-  BOOST_CHECK_GT(m_certName.size(), 0);
+  BOOST_ASSERT(m_certName.size() > 0);
   NDNS_LOG_TRACE("test certName: " << m_certName);
 
   int certificateIndex = 0;
-  function<void(const Name&,Zone&,const name::Component&)> addQueryRrset =
-    [this, &certificateIndex] (const Name& label, Zone& zone,
-                               const name::Component& type) {
+  auto addQueryRrset = [this, &certificateIndex] (const Name& label, Zone& zone,
+                                                  const name::Component& type) {
     const time::seconds ttl(3000 + 100 * certificateIndex);
     const name::Component version = name::Component::fromVersion(100 + 1000 * certificateIndex);
     name::Component qType(label::NDNS_ITERATIVE_QUERY);
@@ -140,7 +136,7 @@
                   m_keyChain, m_certName);
   rf.onlyCheckZone();
   if (type == label::NS_RR_TYPE) {
-    ndn::DelegationList ds;
+    DelegationList ds;
     ds.insert(1, "xx");
     rrset = rf.generateNsRrset(label, version.toVersion(), ttl, ds);
     if (contentType != NDNS_AUTH) {
@@ -157,8 +153,7 @@
                                  m_cert);
   }
 
-  shared_ptr<Data> data = make_shared<Data>(rrset.getData());
-
+  auto data = make_shared<Data>(rrset.getData());
   security::verifySignature(*data, m_cert);
 
   ManagementTool tool(TEST_DATABASE.string(), m_keyChain);
diff --git a/tests/unit/database-test-data.hpp b/tests/unit/database-test-data.hpp
index f1ff278..a7a9668 100644
--- a/tests/unit/database-test-data.hpp
+++ b/tests/unit/database-test-data.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2014-2017, Regents of the University of California.
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -25,13 +25,14 @@
 #include "clients/query.hpp"
 #include "validator/validator.hpp"
 
-#include "test-common.hpp"
+#include "io-fixture.hpp"
+#include "key-chain-fixture.hpp"
 
 namespace ndn {
 namespace ndns {
 namespace tests {
 
-class DbTestData : public IdentityManagementFixture, public UnitTestTimeFixture
+class DbTestData : public IoFixture, public KeyChainFixture
 {
 public:
   static const boost::filesystem::path TEST_DATABASE;
@@ -41,7 +42,7 @@
 
   DbTestData();
 
-  ~DbTestData();
+  ~DbTestData() override;
 
 private:
   void
diff --git a/tests/unit/mgmt/management-tool.cpp b/tests/unit/mgmt/management-tool.t.cpp
similarity index 96%
rename from tests/unit/mgmt/management-tool.cpp
rename to tests/unit/mgmt/management-tool.t.cpp
index a8a47cc..2ac878a 100644
--- a/tests/unit/mgmt/management-tool.cpp
+++ b/tests/unit/mgmt/management-tool.t.cpp
@@ -23,7 +23,9 @@
 #include "ndns-enum.hpp"
 #include "ndns-label.hpp"
 #include "ndns-tlv.hpp"
-#include "test-common.hpp"
+
+#include "boost-test.hpp"
+#include "key-chain-fixture.hpp"
 
 #include <random>
 
@@ -39,22 +41,22 @@
 #include <ndn-cxx/util/io.hpp>
 #include <ndn-cxx/util/regex.hpp>
 
-using boost::test_tools::output_test_stream;
-
 namespace ndn {
 namespace ndns {
 namespace tests {
 
-static const boost::filesystem::path TEST_DATABASE = TEST_CONFIG_PATH "/management_tool.db";
-static const boost::filesystem::path TEST_CERTDIR = TEST_CONFIG_PATH "/management_tool_certs";
-static const Name FAKE_ROOT("/fake-root/123456789");
+using boost::test_tools::output_test_stream;
+
+const auto TEST_DATABASE = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "management_tool.db";
+const auto TEST_CERTDIR = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "management_tool_certs";
+const Name FAKE_ROOT("/fake-root/123456789");
 
 /**
  * @brief Recursive copy a directory using Boost Filesystem
  *
  * Based on from http://stackoverflow.com/q/8593608/2150331
  */
-void
+static void
 copyDir(const boost::filesystem::path& source, const boost::filesystem::path& destination)
 {
   namespace fs = boost::filesystem;
@@ -79,16 +81,17 @@
     if (std::getenv("HOME"))
       m_origHome = std::getenv("HOME");
 
-    setenv("HOME", TEST_CONFIG_PATH "/tests/unit/mgmt/", 1);
-    boost::filesystem::remove_all(TEST_CONFIG_PATH "/tests/unit/mgmt/");
-    boost::filesystem::create_directories(TEST_CONFIG_PATH "/tests/unit/mgmt");
-    copyDir("tests/unit/mgmt/.ndn", TEST_CONFIG_PATH "/tests/unit/mgmt/.ndn");
+    auto p = boost::filesystem::path(UNIT_TESTS_TMPDIR) / "tests" / "unit" / "mgmt";
+    setenv("HOME", p.c_str(), 1);
+    boost::filesystem::remove_all(p);
+    boost::filesystem::create_directories(p);
+    copyDir("tests/unit/mgmt/.ndn", p / ".ndn");
   }
 
   ~TestHome()
   {
     if (!m_origHome.empty())
-      setenv("HOME", m_origHome.c_str(), 1);
+      setenv("HOME", m_origHome.data(), 1);
     else
       unsetenv("HOME");
   }
@@ -97,18 +100,13 @@
   std::string m_origHome;
 };
 
-
-class ManagementToolFixture : public TestHome, public IdentityManagementFixture
+class ManagementToolFixture : public TestHome, public KeyChainFixture
 {
 public:
   class Error : public std::runtime_error
   {
   public:
-    explicit
-    Error(const std::string& what)
-      : std::runtime_error(what)
-    {
-    }
+    using std::runtime_error::runtime_error;
   };
 
   class PreviousStateCleaner
@@ -126,7 +124,7 @@
     , m_dbMgr(TEST_DATABASE.string().c_str())
   {
     boost::filesystem::create_directory(TEST_CERTDIR);
-    Identity root = addIdentity("NDNS");
+    Identity root = m_keyChain.createIdentity("NDNS");
     Key ksk = root.getDefaultKey();
     m_keyChain.deleteCertificate(ksk, ksk.getDefaultCertificate().getName());
     Certificate kskCert = CertHelper::createCertificate(m_keyChain, ksk, ksk, "CERT");
@@ -140,7 +138,7 @@
     m_keyChain.addCertificate(dsk, dskCert);
     rootDsk = dskCert.getName();
 
-    Identity other = addIdentity("/ndns-test/NDNS");
+    Identity other = m_keyChain.createIdentity("/ndns-test/NDNS");
     Key otherKskKey = other.getDefaultKey();
     m_keyChain.deleteCertificate(otherKskKey, otherKskKey.getDefaultCertificate().getName());
     Certificate otherKskCert = CertHelper::createCertificate(m_keyChain, otherKskKey, otherKskKey, "CERT");
@@ -287,7 +285,7 @@
 //   Name rootDsk = generateCerts(ROOT_ZONE);
 //   generateCerts("/ndns-test", rootDsk);
 
-//   copyDir(TEST_CONFIG_PATH "/tests/unit/mgmt/.ndn", "/tmp/.ndn");
+//   copyDir(UNIT_TESTS_TMPDIR "/tests/unit/mgmt/.ndn", "/tmp/.ndn");
 //   std::cout << "Manually copy contents of /tmp/.ndn into tests/unit/mgmt/.ndn" << std::endl;
 // }
 
@@ -503,25 +501,25 @@
                                       time::seconds(1), time::days(1), "/com/ndnsim"),
                                       ndns::ManagementTool::Error);
 
-  Identity id = addIdentity("/net/ndnsim/NDNS");
+  Identity id = m_keyChain.createIdentity("/net/ndnsim/NDNS");
   Certificate cert = id.getDefaultKey().getDefaultCertificate();
   BOOST_CHECK_NO_THROW(m_tool.createZone("/net/ndnsim", "/net",
                                          time::seconds(1), time::days(1), cert.getName()));
 
-  id = addIdentity("/com/ndnsim/NDNS");
+  id = m_keyChain.createIdentity("/com/ndnsim/NDNS");
   cert = id.getDefaultKey().getDefaultCertificate();
 
   BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net",
                                       time::seconds(1), time::days(1), cert.getName()),
                     ndns::ManagementTool::Error);
 
-  id = addIdentity("/net/ndnsim/www/NDNS");
+  id = m_keyChain.createIdentity("/net/ndnsim/www/NDNS");
   cert = id.getDefaultKey().getDefaultCertificate();
   BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net",
                                       time::seconds(1), time::days(1), cert.getName()),
                     ndns::ManagementTool::Error);
 
-  id = addIdentity("/net/ndnsim/NDNS");
+  id = m_keyChain.createIdentity("/net/ndnsim/NDNS");
   cert = id.getDefaultKey().getDefaultCertificate();
   m_keyChain.deleteCertificate(id.getDefaultKey(), cert.getName());
   BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net",
diff --git a/tests/unit/ndns-label.cpp b/tests/unit/ndns-label.t.cpp
similarity index 94%
rename from tests/unit/ndns-label.cpp
rename to tests/unit/ndns-label.t.cpp
index cfd650c..90c7ee1 100644
--- a/tests/unit/ndns-label.cpp
+++ b/tests/unit/ndns-label.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2016, Regents of the University of California.
+/*
+ * Copyright (c) 2014-2020, Regents of the University of California.
  *
  * This file is part of NDNS (Named Data Networking Domain Name Service).
  * See AUTHORS.md for complete list of NDNS authors and contributors.
@@ -19,7 +19,9 @@
 
 #include "ndns-label.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
+
+#include <ndn-cxx/data.hpp>
 
 namespace ndn {
 namespace ndns {
diff --git a/tests/unit/validator/certificate-fetcher-ndns-app-cert.cpp b/tests/unit/validator/certificate-fetcher-ndns-app-cert.t.cpp
similarity index 93%
rename from tests/unit/validator/certificate-fetcher-ndns-app-cert.cpp
rename to tests/unit/validator/certificate-fetcher-ndns-app-cert.t.cpp
index d425832..ae41eeb 100644
--- a/tests/unit/validator/certificate-fetcher-ndns-app-cert.cpp
+++ b/tests/unit/validator/certificate-fetcher-ndns-app-cert.t.cpp
@@ -17,18 +17,20 @@
  * NDNS, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include "validator/validator.hpp"
 #include "validator/certificate-fetcher-ndns-appcert.hpp"
+
 #include "ndns-label.hpp"
-#include "util/cert-helper.hpp"
 #include "daemon/name-server.hpp"
 #include "daemon/rrset-factory.hpp"
 #include "mgmt/management-tool.hpp"
+#include "util/cert-helper.hpp"
+#include "validator/validator.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
 #include "unit/database-test-data.hpp"
 
 #include <ndn-cxx/security/validation-policy-simple-hierarchy.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
 
 namespace ndn {
 namespace ndns {
@@ -39,7 +41,7 @@
 static unique_ptr<security::Validator>
 makeValidatorAppCert(Face& face)
 {
-  return make_unique<security::Validator>(make_unique<::ndn::security::ValidationPolicySimpleHierarchy>(),
+  return make_unique<security::Validator>(make_unique<security::ValidationPolicySimpleHierarchy>(),
                                           make_unique<CertificateFetcherAppCert>(face));
 }
 
@@ -54,7 +56,7 @@
     buildAppCertAndData();
 
     auto serverValidator = NdnsValidatorBuilder::create(m_validatorFace, 10, 0,
-                                                        TEST_CONFIG_PATH "/validator.conf");
+                                                        UNIT_TESTS_TMPDIR "/validator.conf");
     // initialize all servers
     auto addServer = [this, &serverValidator] (const Name& zoneName) {
       m_serverFaces.push_back(make_unique<util::DummyClientFace>(m_io, m_keyChain,
@@ -81,7 +83,7 @@
   buildAppCertAndData()
   {
     // create NDNS-stored certificate and the signed data
-    Identity ndnsimIdentity = addIdentity(m_ndnsimName);
+    Identity ndnsimIdentity = m_keyChain.createIdentity(m_ndnsimName);
     Key randomKey = m_keyChain.createKey(ndnsimIdentity);
     Certificate ndnsStoredAppCert = randomKey.getDefaultCertificate();
     RrsetFactory rf(TEST_DATABASE.string(), m_ndnsimName, m_keyChain,
diff --git a/tests/unit/validator/validator.cpp b/tests/unit/validator/validator.t.cpp
similarity index 97%
rename from tests/unit/validator/validator.cpp
rename to tests/unit/validator/validator.t.cpp
index 2948ae3..0161125 100644
--- a/tests/unit/validator/validator.cpp
+++ b/tests/unit/validator/validator.t.cpp
@@ -19,12 +19,14 @@
 
 #include "validator/validator.hpp"
 #include "ndns-label.hpp"
-#include "util/cert-helper.hpp"
 #include "daemon/name-server.hpp"
+#include "util/cert-helper.hpp"
 
-#include "test-common.hpp"
+#include "boost-test.hpp"
 #include "unit/database-test-data.hpp"
 
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
 namespace ndn {
 namespace ndns {
 namespace tests {
@@ -37,7 +39,7 @@
   ValidatorTestFixture()
     : m_validatorFace(m_io, m_keyChain, {true, true})
     , m_validator(NdnsValidatorBuilder::create(m_validatorFace, 500, 0,
-                                               TEST_CONFIG_PATH "/validator.conf"))
+                                               UNIT_TESTS_TMPDIR "/validator.conf"))
   {
     // generate a random cert
     // check how does name-server test do
diff --git a/tests/wscript b/tests/wscript
index 6249874..a0b5c2e 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -1,19 +1,17 @@
 # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
 top = '..'
 
 def build(bld):
-    if not bld.env['WITH_TESTS']:
+    if not bld.env.WITH_TESTS:
         return
 
-    tmp_folder = bld.bldnode.make_node('tmp-files')
-    config_path = 'TEST_CONFIG_PATH="%s"' % tmp_folder
-    tmp_folder.make_node('anchors').mkdir()
+    tmpdir = bld.bldnode.make_node('tmp-files')
+    tmpdir.make_node('anchors').mkdir()
 
     bld(features='subst',
         name='test-validator-conf',
         source='../validator.conf.sample.in',
-        target=tmp_folder.make_node('validator.conf'),
+        target=tmpdir.make_node('validator.conf'),
         ANCHORPATH='\"anchors/root.cert\"')
 
     bld.objects(
@@ -21,11 +19,12 @@
         source='main.cpp',
         use='ndns-objects')
 
+    tmpdir_define = 'UNIT_TESTS_TMPDIR="%s"' % tmpdir
     bld.program(
         target='../unit-tests',
         name='unit-tests',
         source=bld.path.ant_glob('**/*.cpp', excl=['main.cpp']),
         use='ndns-objects unit-tests-main',
-        includes='../src .',
-        install_path=None,
-        defines=[config_path])
+        includes='.',
+        defines=[tmpdir_define],
+        install_path=None)