tests: sync common testing infrastructure with ndn-cxx

Upgrade waf to version 2.0.21

Change-Id: I30615cc49416088e9c5e4d602fd11360c0ed9328
diff --git a/tests/unit/mgmt/management-tool.t.cpp b/tests/unit/mgmt/management-tool.t.cpp
new file mode 100644
index 0000000..2ac878a
--- /dev/null
+++ b/tests/unit/mgmt/management-tool.t.cpp
@@ -0,0 +1,1082 @@
+/* -*- 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 "mgmt/management-tool.hpp"
+#include "daemon/rrset-factory.hpp"
+#include "util/cert-helper.hpp"
+#include "ndns-enum.hpp"
+#include "ndns-label.hpp"
+#include "ndns-tlv.hpp"
+
+#include "boost-test.hpp"
+#include "key-chain-fixture.hpp"
+
+#include <random>
+
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/range/adaptors.hpp>
+#if BOOST_VERSION >= 105900
+#include <boost/test/tools/output_test_stream.hpp>
+#else
+#include <boost/test/output_test_stream.hpp>
+#endif
+
+#include <ndn-cxx/security/transform.hpp>
+#include <ndn-cxx/util/io.hpp>
+#include <ndn-cxx/util/regex.hpp>
+
+namespace ndn {
+namespace ndns {
+namespace tests {
+
+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
+ */
+static void
+copyDir(const boost::filesystem::path& source, const boost::filesystem::path& destination)
+{
+  namespace fs = boost::filesystem;
+
+  fs::create_directory(destination);
+  for (fs::directory_iterator file(source); file != fs::directory_iterator(); ++file) {
+    fs::path current(file->path());
+    if (is_directory(current)) {
+      copyDir(current, destination / current.filename());
+    }
+    else {
+      copy_file(current, destination / current.filename());
+    }
+  }
+}
+
+class TestHome : boost::noncopyable
+{
+public:
+  TestHome()
+  {
+    if (std::getenv("HOME"))
+      m_origHome = std::getenv("HOME");
+
+    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.data(), 1);
+    else
+      unsetenv("HOME");
+  }
+
+protected:
+  std::string m_origHome;
+};
+
+class ManagementToolFixture : public TestHome, public KeyChainFixture
+{
+public:
+  class Error : public std::runtime_error
+  {
+  public:
+    using std::runtime_error::runtime_error;
+  };
+
+  class PreviousStateCleaner
+  {
+  public:
+    PreviousStateCleaner()
+    {
+      boost::filesystem::remove(TEST_DATABASE);
+      boost::filesystem::remove_all(TEST_CERTDIR);
+    }
+  };
+
+  ManagementToolFixture()
+    : m_tool(TEST_DATABASE.string().c_str(), m_keyChain)
+    , m_dbMgr(TEST_DATABASE.string().c_str())
+  {
+    boost::filesystem::create_directory(TEST_CERTDIR);
+    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");
+    m_keyChain.addCertificate(ksk, kskCert);
+    rootKsk = kskCert.getName();
+
+    Key dsk = m_keyChain.createKey(root);
+    // replace rootDsk's default cert with ksk-signing cert
+    m_keyChain.deleteCertificate(dsk, dsk.getDefaultCertificate().getName());
+    Certificate dskCert = CertHelper::createCertificate(m_keyChain, dsk, ksk, "CERT");
+    m_keyChain.addCertificate(dsk, dskCert);
+    rootDsk = dskCert.getName();
+
+    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");
+    m_keyChain.addCertificate(otherKskKey, otherKskCert);
+    otherKsk  = otherKskCert.getName();
+
+    // replace rootDsk's default cert with ksk-signing cert
+    Key otherDskKey = m_keyChain.createKey(other);
+    m_keyChain.deleteCertificate(otherDskKey, otherDskKey.getDefaultCertificate().getName());
+    Certificate otherDskCert = CertHelper::createCertificate(m_keyChain, otherDskKey, otherKskKey, "CERT");
+    m_keyChain.addCertificate(otherDskKey, otherDskCert);
+    otherDsk = otherDskCert.getName();
+
+    Certificate rootDkeyCert = CertHelper::createCertificate(m_keyChain, otherDskKey, otherKskKey, "CERT");
+    m_keyChain.addCertificate(otherDskKey, rootDkeyCert);
+    rootDkey = rootDkeyCert.getName();
+  }
+
+  ~ManagementToolFixture()
+  {
+  }
+
+  std::vector<Certificate>
+  getCerts(const Name& zoneName)
+  {
+    Zone zone(zoneName);
+    std::vector<Certificate> certs;
+    std::map<std::string, Block> zoneInfo = m_dbMgr.getZoneInfo(zone);
+    // ksk are always the first key
+    certs.push_back(Certificate(zoneInfo["ksk"]));
+    certs.push_back(Certificate(zoneInfo["dsk"]));
+    return certs;
+  }
+
+  Rrset
+  findRrSet(Zone& zone, const Name& label, const name::Component& type)
+  {
+    Rrset rrset(&zone);
+    rrset.setLabel(label);
+    rrset.setType(type);
+
+    if (!m_dbMgr.find(rrset))
+      BOOST_THROW_EXCEPTION(Error("Record not found"));
+    else
+      return rrset;
+  }
+
+  Name
+  getLabel(const Zone& zone, const Name& fullName)
+  {
+    size_t zoneNameSize = zone.getName().size();
+    return fullName.getSubName(zoneNameSize + 1, fullName.size() - zoneNameSize - 3);
+  }
+
+  Certificate
+  findCertFromIdentity(const Name& identityName, const Name& certName)
+  {
+    Certificate rtn;
+    Identity identity = CertHelper::getIdentity(m_keyChain, identityName);
+    for (const auto& key : identity.getKeys()) {
+      for (const auto& cert : key.getCertificates()) {
+        if (cert.getName() == certName) {
+          rtn = cert;
+          return rtn;
+        }
+      }
+    }
+    BOOST_THROW_EXCEPTION(Error("Certificate not found in keyChain"));
+    return rtn;
+  }
+
+  Certificate
+  findCertFromDb(Zone& zone, const Name& fullName)
+  {
+    Rrset rrset = findRrSet(zone, getLabel(zone, fullName), label::CERT_RR_TYPE);
+    Certificate cert;
+    cert.wireDecode(rrset.getData());
+    return cert;
+  }
+
+  Certificate
+  findDkeyFromDb(const Name& zoneName)
+  {
+    Zone zone(zoneName);
+    std::map<std::string, Block> zoneInfo = m_dbMgr.getZoneInfo(zone);
+    return Certificate(zoneInfo["dkey"]);
+  }
+
+  Response
+  findResponse(Zone& zone, const Name& label, const name::Component& type)
+  {
+    Rrset rrset = findRrSet(zone, label, type);
+    Data data(rrset.getData());
+    Response resp;
+    resp.fromData(zone.getName(), data);
+    return resp;
+  }
+
+public:
+  PreviousStateCleaner cleaner; // must be first variable
+  ndns::ManagementTool m_tool;
+  ndns::DbMgr m_dbMgr;
+
+  // Names of pre-created certificates
+  // Uncomment and run InitPreconfiguredKeys test case and then update names in the
+  // constructor.
+  Name rootKsk;
+  Name rootDsk;
+  Name otherKsk;
+  Name otherDsk;
+  Name rootDkey;
+};
+
+BOOST_FIXTURE_TEST_SUITE(ManagementTool, ManagementToolFixture)
+
+// BOOST_FIXTURE_TEST_CASE(InitPreconfiguredKeys, ManagementToolFixture)
+// {
+//   using time::seconds;
+
+//   auto generateCerts = [this] (const Name& zone, const Name& parentCert = Name()) -> Name {
+//     // to re-generate certificates, uncomment and then update rootKsk/rootDsk names
+//     Name kskName = m_keyChain.generateRsaKeyPair(zone, true);
+//     auto kskCert = m_keyChain
+//       .prepareUnsignedIdentityCertificate(kskName, zone, time::fromUnixTimestamp(seconds(0)),
+//                                           time::fromUnixTimestamp(seconds(2147483648)), {});
+//     if (parentCert.empty()) {
+//       m_keyChain.selfSign(*kskCert);
+//     }
+//     else {
+//       m_keyChain.sign(*kskCert, parentCert);
+//     }
+//     m_keyChain.addCertificate(*kskCert);
+
+//     Name dskName = m_keyChain.generateRsaKeyPair(zone, false);
+//     auto dskCert = m_keyChain
+//       .prepareUnsignedIdentityCertificate(dskName, zone, time::fromUnixTimestamp(seconds(0)),
+//                                           time::fromUnixTimestamp(seconds(2147483648)), {});
+//     m_keyChain.sign(*dskCert, kskCert->getName());
+//     m_keyChain.addCertificate(*dskCert);
+
+//     return dskCert->getName();
+//   };
+
+//   Name rootDsk = generateCerts(ROOT_ZONE);
+//   generateCerts("/ndns-test", rootDsk);
+
+//   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;
+// }
+
+BOOST_AUTO_TEST_CASE(SqliteLabelOrder)
+{
+  // the correctness of our DoE design rely on the ordering of SQLite
+  // this unit test make sure that our label::isSmallerInLabelOrder
+  // is the same as the ordering of BLOB in SQLite
+
+  std::random_device seed;
+  std::mt19937 gen(seed());
+
+  auto genRandomString = [&] (int length) -> std::string {
+    std::string charset =
+    "0123456789"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz";
+    std::uniform_int_distribution<size_t> dist(0, charset.size() - 1);
+
+    std::string str(length, 0);
+    std::generate_n(str.begin(), length, [&] { return charset[dist(gen)];} );
+    return str;
+  };
+
+  auto genRandomLabel = [&]() -> Name {
+    std::uniform_int_distribution<size_t> numberOfLabelsDist(1, 5);
+    std::uniform_int_distribution<size_t> labelSizeDist(1, 10);
+    Name nm;
+    size_t length = numberOfLabelsDist(gen);
+    for (size_t i = 0; i < length; i++) {
+      nm.append(genRandomString(labelSizeDist(gen)));
+    }
+    return nm;
+  };
+
+  const size_t NGENERATED_LABELS = 10;
+
+  Zone zone = m_tool.createZone("/net/ndnsim", "/net");
+  RrsetFactory rrsetFactory(TEST_DATABASE.string(), zone.getName(),
+                            m_keyChain, DEFAULT_CERT);
+  rrsetFactory.checkZoneKey();
+  std::vector<Rrset> rrsets;
+  std::vector<Name> names;
+  for (size_t i = 0; i < NGENERATED_LABELS; i++) {
+    Name randomLabel = genRandomLabel();
+    Rrset randomTxt = rrsetFactory.generateTxtRrset(randomLabel,
+                                                    VERSION_USE_UNIX_TIMESTAMP,
+                                                    DEFAULT_CACHE_TTL,
+                                                    {});
+
+    rrsets.push_back(randomTxt);
+    m_dbMgr.insert(randomTxt);
+    names.push_back(randomLabel);
+  }
+
+  std::sort(rrsets.begin(), rrsets.end());
+
+  using boost::adaptors::filtered;
+  using boost::adaptors::transformed;
+
+  std::vector<Rrset> rrsetsFromDb = m_dbMgr.findRrsets(zone);
+  auto fromDbFiltered = rrsetsFromDb | filtered([] (const Rrset& rrset) {
+      return rrset.getType() == label::TXT_RR_TYPE;
+    });
+
+  auto extractLabel = [] (const Rrset& rr) {
+    return rr.getLabel();
+  };
+  auto expected = rrsets | transformed(extractLabel);
+  auto actual = fromDbFiltered | transformed(extractLabel);
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(),
+                                actual.begin(), actual.end());
+}
+
+BOOST_AUTO_TEST_CASE(CreateDeleteRootFixture)
+{
+  // creating root_zone need a rootDkey
+  BOOST_CHECK_THROW(m_tool.createZone(ROOT_ZONE, ROOT_ZONE,
+                                      time::seconds(4600),
+                                      time::seconds(4600),
+                                      rootKsk, rootDsk), ndns::ManagementTool::Error);
+
+  m_tool.createZone(ROOT_ZONE, ROOT_ZONE,
+                    time::seconds(4600),
+                    time::seconds(4600),
+                    rootKsk, rootDsk, rootDkey);
+
+  Zone zone(ROOT_ZONE);
+  Name zoneIdentityName = Name(ROOT_ZONE).append("NDNS");
+  BOOST_REQUIRE_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_REQUIRE_NO_THROW(findCertFromDb(zone, rootDsk));
+  BOOST_CHECK_EQUAL(findCertFromDb(zone, rootDsk).getName(), rootDsk);
+  BOOST_CHECK_EQUAL(findCertFromDb(zone, rootKsk).getName(), rootKsk);
+  BOOST_CHECK_EQUAL(findDkeyFromDb(ROOT_ZONE).getName(), rootDkey);
+
+  BOOST_CHECK_EQUAL(findCertFromIdentity(zoneIdentityName, rootDsk).getName(), rootDsk);
+  BOOST_CHECK_EQUAL(findCertFromIdentity(zoneIdentityName, rootKsk).getName(), rootKsk);
+
+  BOOST_CHECK_NO_THROW(m_tool.deleteZone(ROOT_ZONE));
+  BOOST_CHECK_EQUAL(m_dbMgr.find(zone), false);
+}
+
+BOOST_AUTO_TEST_CASE(CreateDeleteChildFixture)
+{
+  Name parentZoneName("/ndns-test");
+  Name zoneName = Name(parentZoneName).append("child-zone");
+
+  Zone zone1(zoneName);
+  Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
+  BOOST_REQUIRE_EQUAL(m_dbMgr.find(zone1), false);
+
+  // will generate keys automatically
+  m_tool.createZone(zoneName, parentZoneName);
+  BOOST_CHECK_EQUAL(CertHelper::doesIdentityExist(m_keyChain, zoneIdentityName), true);
+
+  std::vector<Certificate>&& certs = getCerts(zoneName);
+  BOOST_REQUIRE_EQUAL(certs.size(), 2);
+
+  const Name& ksk = certs[0].getName();
+  const Name& dsk = certs[1].getName();
+
+  Zone zone(zoneName);
+  BOOST_REQUIRE_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_REQUIRE_NO_THROW(findCertFromDb(zone, dsk));
+  BOOST_CHECK_EQUAL(findCertFromDb(zone, dsk).getName(), dsk);
+  BOOST_CHECK_EQUAL(findCertFromDb(zone, ksk).getName(), ksk);
+
+  BOOST_CHECK_EQUAL(findCertFromIdentity(zoneIdentityName, dsk), findCertFromDb(zone, dsk));
+  BOOST_CHECK_EQUAL(findCertFromIdentity(zoneIdentityName, ksk), findCertFromDb(zone, ksk));
+
+  BOOST_CHECK_NO_THROW(m_tool.deleteZone(zoneName));
+
+  BOOST_CHECK_THROW(m_tool.deleteZone(zoneName), ndns::ManagementTool::Error);
+  BOOST_CHECK_THROW(m_tool.deleteZone("/non/existing/zone"), ndns::ManagementTool::Error);
+}
+
+BOOST_AUTO_TEST_CASE(CreateZoneWithFixture)
+{
+  Name parentZoneName("/ndns-test");
+  Name zoneName = Name(parentZoneName).append("child-zone");
+  Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
+
+  m_tool.createZone(zoneName, parentZoneName, time::seconds(4200), time::days(30));
+  BOOST_CHECK_EQUAL(CertHelper::doesIdentityExist(m_keyChain, zoneIdentityName), true);
+
+  std::vector<Certificate>&& certs = getCerts(zoneName);
+  BOOST_REQUIRE_EQUAL(certs.size(), 2);
+
+  const Name& dsk = certs[1].getName();
+
+  // Check zone ttl
+  Zone zone(zoneName);
+  BOOST_REQUIRE_EQUAL(m_dbMgr.find(zone), true);
+  BOOST_CHECK_EQUAL(zone.getTtl(), time::seconds(4200));
+
+  // check dkey name
+  Name dkeyName = Name(parentZoneName).append("NDNS").append(zoneName.getSubName(parentZoneName.size()));
+  Certificate dkey = findDkeyFromDb(zoneName);
+  BOOST_CHECK(dkeyName.isPrefixOf(dkey.getName()));
+
+  // TODO: check signing hierarchy
+
+  // Check dsk rrset ttl
+  Rrset rrset;
+  BOOST_REQUIRE_NO_THROW(rrset = findRrSet(zone, getLabel(zone, dsk), label::CERT_RR_TYPE));
+  BOOST_CHECK_EQUAL(rrset.getTtl(), time::seconds(4200));
+
+  // Check certificate freshnessPeriod and validity
+  Certificate cert = CertHelper::getCertificate(m_keyChain, zoneIdentityName, dsk);
+  time::system_clock::TimePoint beg,end;
+  std::tie(beg, end) = cert.getValidityPeriod().getPeriod();
+
+  BOOST_REQUIRE_NO_THROW(cert = findCertFromDb(zone, dsk));
+  BOOST_CHECK_EQUAL(cert.getFreshnessPeriod(), time::seconds(4200));
+  BOOST_CHECK_EQUAL(end - beg, time::days(30));
+  m_tool.deleteZone(zoneName);
+}
+
+BOOST_AUTO_TEST_CASE(ZoneCreatePreconditions)
+{
+  BOOST_CHECK_NO_THROW(m_tool.createZone("/net/ndnsim", "/net"));
+  BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net"), ndns::ManagementTool::Error);
+
+  std::vector<Certificate>&& certs = getCerts("/net/ndnsim");
+  BOOST_REQUIRE_EQUAL(certs.size(), 2);
+
+  const Name& ksk = certs[0].getName();
+  const Name& dsk = certs[1].getName();
+
+  m_tool.deleteZone("/net/ndnsim");
+  // identity will still exist after the zone is deleted
+
+  BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net/ndnsim"), ndns::ManagementTool::Error);
+
+  BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/com"), ndns::ManagementTool::Error);
+
+  BOOST_CHECK_NO_THROW(m_tool.createZone("/net/ndnsim", "/",
+                                         time::seconds(1), time::days(1), ksk, dsk));
+  BOOST_CHECK_EQUAL(getCerts("/net/ndnsim").size(), 2);
+  m_tool.deleteZone("/net/ndnsim");
+
+  BOOST_CHECK_NO_THROW(m_tool.createZone("/net/ndnsim", "/",
+                                         time::seconds(1), time::days(1), Name(), dsk));
+
+  m_tool.deleteZone("/net/ndnsim");
+
+  BOOST_CHECK_NO_THROW(m_tool.createZone("/net/ndnsim", "/",
+                                         time::seconds(1), time::days(1), ksk, Name()));
+  m_tool.deleteZone("/net/ndnsim");
+
+  BOOST_CHECK_THROW(m_tool.createZone("/net/ndnsim", "/net",
+                                      time::seconds(1), time::days(1), "/com/ndnsim"),
+                                      ndns::ManagementTool::Error);
+
+  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 = 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 = 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 = 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",
+                                      time::seconds(1), time::days(1), cert.getName()),
+                    ndns::ManagementTool::Error);
+
+  // for root zone special case (requires a valid DKEY to be specified)
+  BOOST_CHECK_THROW(m_tool.createZone("/", "/"), ndns::ManagementTool::Error);
+
+  BOOST_CHECK_NO_THROW(m_tool.createZone("/", "/", time::seconds(1), time::days(1),
+                                         DEFAULT_CERT, DEFAULT_CERT, rootDkey));
+}
+
+class OutputTester
+{
+public:
+  OutputTester()
+    : savedBuf(std::clog.rdbuf())
+  {
+    std::cout.rdbuf(buffer.rdbuf());
+  }
+
+  ~OutputTester()
+  {
+    std::cout.rdbuf(savedBuf);
+  }
+
+public:
+  std::stringstream buffer;
+  std::streambuf* savedBuf;
+};
+
+// BOOST_AUTO_TEST_CASE(ExportCertificate)
+// {
+//   std::string outputFile = TEST_CERTDIR.string() + "/ss.cert";
+
+//   BOOST_REQUIRE_THROW(m_tool.exportCertificate("/random/name", outputFile),
+//                       ndns::ManagementTool::Error);
+
+//   BOOST_REQUIRE_EQUAL(boost::filesystem::exists(outputFile), false);
+//   // doesn't check the zone, export from KeyChain directly
+//   BOOST_CHECK_NO_THROW(m_tool.exportCertificate(otherDsk, outputFile));
+//   BOOST_REQUIRE_EQUAL(boost::filesystem::exists(outputFile), true);
+
+//   std::string dskValue =
+//     "Bv0C3Ac3CAluZG5zLXRlc3QIA0tFWQgRZHNrLTE0MTY5NzQwMDY2NTkIB0lELUNF\n"
+//     "UlQICf0AAAFJ6jt6DhQDGAECFf0BYTCCAV0wIhgPMTk3MDAxMDEwMDAwMDBaGA8y\n"
+//     "MDM4MDExOTAzMTQwOFowEzARBgNVBCkTCi9uZG5zLXRlc3QwggEgMA0GCSqGSIb3\n"
+//     "DQEBAQUAA4IBDQAwggEIAoIBAQDIFUL7Fz8mmxxIT8l3FtWm+CuH9+iQ0Uj/a30P\n"
+//     "mKe4gWvtxzhb4vIngYbXGv2iUzHswdqYlTVeDdW6eOFKMvyY5p5eVtLqDFZ7EEK0\n"
+//     "0rpTh648HjCSz+Awgp2nbiYAAVvhP6YF+NxGBH412uPI7kLY6ozypsNmYP+K4SYT\n"
+//     "oY9ee4xLSjqzXfLMyP1h8OHcN/aNmccRJlyYblCmCDbZPnzu3ttHHwdrYQLeFvb0\n"
+//     "B5grCAQoPHwkfxkEnzQBA/fbUdvKNdayEkuibPLlIlmj2cBtk5iVk8JCSibP3Zlz\n"
+//     "36Sks1DAO+1EvCRnjoH5vYmkpMUBFue+6A40IQG4brM2CiIRAgERFjMbAQEcLgcs\n"
+//     "CAluZG5zLXRlc3QIA0tFWQgRa3NrLTE0MTY5NzQwMDY1NzcIB0lELUNFUlQX/QEA\n"
+//     "GP2bQqp/7rfb8tShwDbXihWrPojwEFqlfwLibK9aM1RxwpHVqbtRsPYmuWc87LaU\n"
+//     "OztPOZinHGL80ypFC+wYadVGnE8MPdTkUYUik7mbHDEsYWADoyGMVhoZv+OTJ/5m\n"
+//     "MUh/kR1FMiqtZcIQtLB3cdCeGlZBl9wm2SvhMKVUym3RsQO46RpnmsEQcCfWMBZg\n"
+//     "u5U6mhYIpiQPZ/sYyZ9zXstwsIfaF1p0V+1dW5y99PZJXIegVKhkGGU0ibjYoJy7\n"
+//     "6uUjqBBDX8KMdt6n/Zy1/pGG1eOchMyV0JZ8+MJxWuiTEh5PJeYMFHTV/BVp8aPy\n"
+//     "8UNqhMpjAZwW6pdvOZADVg==\n";
+
+//   {
+//     std::ifstream ifs(outputFile.c_str());
+//     std::string actualValue((std::istreambuf_iterator<char>(ifs)),
+//                             std::istreambuf_iterator<char>());
+//     BOOST_CHECK_EQUAL(actualValue, dskValue);
+//   }
+//   boost::filesystem::remove(outputFile);
+
+//   // doesn't check the zone, export from KeyChain directly
+//   BOOST_CHECK_NO_THROW(m_tool.exportCertificate(otherKsk, outputFile));
+//   boost::filesystem::remove(outputFile);
+
+//   Name zoneName("/ndns-test");
+//   m_tool.createZone(zoneName, ROOT_ZONE, time::seconds(4200), time::days(30),
+//                     otherKsk, otherDsk);
+
+//   m_keyChain.deleteCertificate(otherKsk);
+//   m_keyChain.deleteCertificate(otherDsk);
+
+//   // retrieve cert from the zone
+//   BOOST_CHECK_NO_THROW(m_tool.exportCertificate(otherDsk, outputFile));
+//   {
+//     std::ifstream ifs(outputFile.c_str());
+//     std::string actualValue((std::istreambuf_iterator<char>(ifs)),
+//                             std::istreambuf_iterator<char>());
+//     BOOST_CHECK_EQUAL(actualValue, dskValue);
+//   }
+//   boost::filesystem::remove(outputFile);
+
+//   BOOST_REQUIRE_THROW(m_tool.exportCertificate(otherKsk, outputFile),
+//                       ndns::ManagementTool::Error);
+
+//   // output to std::cout
+//   std::string acutalOutput;
+//   {
+//     OutputTester tester;
+//     m_tool.exportCertificate(otherDsk, "-");
+//     acutalOutput = tester.buffer.str();
+//   }
+//   BOOST_CHECK_EQUAL(acutalOutput, dskValue);
+// }
+
+BOOST_AUTO_TEST_CASE(AddRrset)
+{
+  Name zoneName("/ndns-test");
+  Zone zone(zoneName);
+
+  time::seconds ttl1(4200);
+  time::seconds ttl2(4500);
+  m_tool.createZone(zoneName, ROOT_ZONE, ttl1);
+
+  RrsetFactory rf(TEST_DATABASE, zoneName, m_keyChain, DEFAULT_CERT);
+  rf.checkZoneKey();
+  Rrset rrset1 = rf.generateNsRrset("/l1", 7654, ttl2, DelegationList());
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrset(rrset1));
+  Rrset rrset2 = findRrSet(zone, "/l1", label::NS_RR_TYPE);
+  BOOST_CHECK_EQUAL(rrset1, rrset2);
+}
+
+BOOST_AUTO_TEST_CASE(AddMultiLevelLabelRrset)
+{
+  Name zoneName("/ndns-test");
+  Zone zone(zoneName);
+
+  time::seconds ttl(4200);
+  m_tool.createZone(zoneName, ROOT_ZONE, ttl);
+
+  RrsetFactory rf(TEST_DATABASE, zoneName, m_keyChain, DEFAULT_CERT);
+  rf.checkZoneKey();
+
+  auto checkRrset = [&zone, &zoneName, this](Name label,
+                                             name::Component type,
+                                             NdnsContentType contentType) -> void {
+    Rrset rr1 = findRrSet(zone, label, type);
+    BOOST_CHECK_EQUAL(Data(rr1.getData()).getContentType(), contentType);
+    Response response1;
+    response1.fromData(zoneName, Data(rr1.getData()));
+    BOOST_CHECK_EQUAL(response1.getRrLabel(), label);
+  };
+
+  Name labelName("/l1/l2/l3");
+
+  Rrset rrset1 = rf.generateNsRrset(labelName, 7654, ttl, DelegationList());
+
+  //add NS NDNS_AUTH and check user-defined ttl
+  BOOST_CHECK_NO_THROW(m_tool.addMultiLevelLabelRrset(rrset1, rf, ttl));
+  Rrset rrset2 = findRrSet(zone, labelName, label::NS_RR_TYPE);
+  BOOST_CHECK_EQUAL(rrset1, rrset2);
+
+  checkRrset("/l1", label::NS_RR_TYPE, ndns::NDNS_AUTH);
+  checkRrset("/l1/l2", label::NS_RR_TYPE, ndns::NDNS_AUTH);
+
+  // insert a same-name rrset with TXT type
+  Rrset txtRr = rf.generateTxtRrset("/l1/l2/l3", 7654, ttl, std::vector<std::string>());
+  BOOST_CHECK_NO_THROW(m_tool.addMultiLevelLabelRrset(txtRr, rf, ttl));
+
+  checkRrset("/l1", label::NS_RR_TYPE, ndns::NDNS_AUTH);
+  checkRrset("/l1/l2", label::NS_RR_TYPE, ndns::NDNS_AUTH);
+  checkRrset("/l1/l2/l3", label::TXT_RR_TYPE, ndns::NDNS_RESP);
+  // check that there is no confliction
+  checkRrset("/l1/l2/l3", label::NS_RR_TYPE, ndns::NDNS_LINK);
+
+  // insert a shorter NS, when there are longer NS or TXT
+  Rrset shorterNs = rf.generateNsRrset("/l1/l2", 7654, ttl, DelegationList());
+  BOOST_CHECK_THROW(m_tool.addMultiLevelLabelRrset(shorterNs, rf, ttl),
+                    ndns::ManagementTool::Error);
+
+  // insert a longer NS, when there is already a shorter NS
+  Rrset longerNs = rf.generateNsRrset("/l1/l2/l3/l4", 7654, ttl, DelegationList());
+  BOOST_CHECK_THROW(m_tool.addMultiLevelLabelRrset(longerNs, rf, ttl),
+                    ndns::ManagementTool::Error);
+
+  // insert a smaller TXT, when there are longer NS and TXT
+  Rrset shorterTxt = rf.generateTxtRrset("/l1/l2", 7654, ttl, std::vector<std::string>());
+  BOOST_CHECK_NO_THROW(m_tool.addMultiLevelLabelRrset(shorterTxt, rf, ttl));
+
+  // insert a smaller NS, when there is long TXT
+  Rrset longTxt = rf.generateTxtRrset("/k1/k2/k3", 7654, ttl, std::vector<std::string>());
+  Rrset smallerNs = rf.generateNsRrset("/k1/k2", 7654, ttl, DelegationList());
+  BOOST_CHECK_NO_THROW(m_tool.addMultiLevelLabelRrset(longTxt, rf, ttl));
+  BOOST_CHECK_THROW(m_tool.addMultiLevelLabelRrset(smallerNs, rf, ttl),
+                    ndns::ManagementTool::Error);
+
+  // inserting a longer TXT, when there is shoter TXT
+  Rrset longerTxt = rf.generateTxtRrset("/k1/k2/k3/k4", 7654, ttl, std::vector<std::string>());
+  BOOST_CHECK_NO_THROW(m_tool.addMultiLevelLabelRrset(longerTxt, rf, ttl));
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetDskCertPreConditon)
+{
+  // check pre-condition
+  Name zoneName("/ndns-test");
+
+  // Check: throw if zone not exist
+  std::string certPath = TEST_CERTDIR.string();
+  BOOST_CHECK_THROW(m_tool.addRrsetFromFile(zoneName, certPath), ndns::ManagementTool::Error);
+
+  m_tool.createZone(zoneName, ROOT_ZONE);
+
+  // Check: throw if certificate does not match
+  BOOST_CHECK_THROW(m_tool.addRrsetFromFile(zoneName, certPath), ndns::ManagementTool::Error);
+
+  std::string rightCertPath = TEST_CERTDIR.string() + "/ss.cert";
+  std::vector<Certificate>&& certs = getCerts(zoneName);
+  const Name& ksk = certs[0].getName();
+  m_tool.exportCertificate(ksk, rightCertPath);
+
+  // Check: throw if it's a duplicated certificate
+  BOOST_CHECK_THROW(m_tool.addRrsetFromFile(zoneName, rightCertPath), ndns::ManagementTool::Error);
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetDskCert)
+{
+  Name parentZoneName("/ndns-test");
+  Name zoneName("/ndns-test/child-zone");
+  Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
+
+  m_tool.createZone(parentZoneName, ROOT_ZONE, time::seconds(1), time::days(1), otherKsk, otherDsk);
+  m_tool.createZone(zoneName, parentZoneName);
+
+  Zone zone(zoneName);
+  Zone parentZone(parentZoneName);
+
+  Certificate dkey(findDkeyFromDb(zone.getName()));
+  std::string output = TEST_CERTDIR.string() + "/ss.cert";
+  ndn::io::save(dkey, output);
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrsetFromFile(parentZoneName, output));
+  // Check if child zone's d-key could be inserted correctly
+  BOOST_CHECK_NO_THROW(findRrSet(parentZone, getLabel(parentZone, dkey.getName()), label::CERT_RR_TYPE));
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetDskCertUserProvidedCert)
+{
+  //check using user provided certificate
+  Name parentZoneName("/ndns-test");
+  Name parentZoneIdentityName = Name(parentZoneName).append(label::NDNS_ITERATIVE_QUERY);
+  Name zoneName("/ndns-test/child-zone");
+  Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
+
+  // Name dskName = m_keyChain.generateRsaKeyPair(parentZoneName, false);
+  Identity id = CertHelper::getIdentity(m_keyChain, parentZoneIdentityName);
+  Key dsk = m_keyChain.createKey(id);
+  Certificate dskCert = dsk.getDefaultCertificate();
+
+  // check addRrsetFromFile1
+  m_tool.createZone(parentZoneName, ROOT_ZONE, time::seconds(1), time::days(1), otherKsk, otherDsk);
+  m_tool.createZone(zoneName, parentZoneName);
+
+  Certificate dkey(findDkeyFromDb(zoneName));
+  std::string output = TEST_CERTDIR.string() + "/ss.cert";
+  ndn::io::save(dkey, output);
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrsetFromFile(parentZoneName, output, time::seconds(4600),
+                                               dskCert.getName()));
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetDskCertInvalidOutput)
+{
+  //check invalid output
+  Name parentZoneName("/ndns-test");
+  Name zoneName = Name(parentZoneName).append("child-zone");
+  m_tool.createZone(zoneName, parentZoneName);
+
+  Name content = "invalid data packet";
+  std::string output = TEST_CERTDIR.string() + "/ss.cert";
+  ndn::io::save(content, output);
+
+  BOOST_CHECK_THROW(m_tool.addRrsetFromFile(zoneName, output), ndns::ManagementTool::Error);
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetVersionControl)
+{
+  //check version control
+  time::seconds ttl(4200);
+  Name parentZoneName("/ndns-test");
+  Name zoneName = Name(parentZoneName).append("child-zone");
+  m_tool.createZone(zoneName, parentZoneName);
+
+  Name label("/label");
+  uint64_t version = 110;
+
+  RrsetFactory rf(TEST_DATABASE, zoneName, m_keyChain, DEFAULT_CERT);
+  rf.checkZoneKey();
+
+  Rrset rrset1 = rf.generateTxtRrset(label, version, ttl, {});
+
+  m_tool.addRrset(rrset1);
+  // throw error when adding duplicated rrset with the same version
+  BOOST_CHECK_THROW(m_tool.addRrset(rrset1),
+                    ndns::ManagementTool::Error);
+  version--;
+  Rrset rrset2 = rf.generateTxtRrset(label, version, ttl, {});
+  // throw error when adding duplicated rrset with older version
+  BOOST_CHECK_THROW(m_tool.addRrset(rrset2),
+                    ndns::ManagementTool::Error);
+
+  version++;
+  version++;
+  Rrset rrset3 = rf.generateTxtRrset(label, version, ttl, {});
+  BOOST_CHECK_NO_THROW(m_tool.addRrset(rrset3));
+
+  Zone zone(zoneName);
+  m_dbMgr.find(zone);
+  Rrset rrset;
+  rrset.setZone(&zone);
+  rrset.setLabel(label);
+  rrset.setType(label::TXT_RR_TYPE);
+  m_dbMgr.find(rrset);
+
+  BOOST_CHECK_EQUAL(rrset.getVersion(), name::Component::fromVersion(version));
+}
+
+BOOST_AUTO_TEST_CASE(AddRrSetDskCertFormat)
+{
+  //check input with different formats
+  Name parentZoneName("/ndns-test");
+  Name zoneName = Name(parentZoneName).append("child-zone");
+  Zone parentZone(parentZoneName);
+
+  m_tool.createZone(parentZoneName, ROOT_ZONE, time::seconds(1), time::days(1), otherKsk, otherDsk);
+  m_tool.createZone(zoneName, parentZoneName);
+
+  Certificate cert(findDkeyFromDb(zoneName));
+  std::string output = TEST_CERTDIR.string() + "/a.cert";
+
+  Name parentZoneIdentityName = Name(parentZoneName).append(label::NDNS_ITERATIVE_QUERY);
+
+  // base64
+  ndn::io::save(cert, output, ndn::io::BASE64);
+  BOOST_CHECK_NO_THROW(
+    m_tool.addRrsetFromFile(parentZoneName, output, DEFAULT_CACHE_TTL, DEFAULT_CERT, ndn::io::BASE64));
+  m_tool.removeRrSet(parentZoneName, getLabel(parentZone, cert.getName()), label::CERT_RR_TYPE);
+
+  // raw
+  ndn::io::save(cert, output, ndn::io::NO_ENCODING);
+  BOOST_CHECK_NO_THROW(
+    m_tool.addRrsetFromFile(parentZoneName, output, DEFAULT_CACHE_TTL, DEFAULT_CERT, ndn::io::NO_ENCODING));
+  m_tool.removeRrSet(parentZoneName, getLabel(parentZone, cert.getName()), label::CERT_RR_TYPE);
+
+  // hex
+  ndn::io::save(cert, output, ndn::io::HEX);
+  BOOST_CHECK_NO_THROW(
+    m_tool.addRrsetFromFile(parentZoneName, output, DEFAULT_CACHE_TTL, DEFAULT_CERT, ndn::io::HEX));
+  m_tool.removeRrSet(parentZoneName, getLabel(parentZone, cert.getName()), label::CERT_RR_TYPE);
+
+  // incorrect encoding input
+  ndn::io::save(cert, output, ndn::io::HEX);
+  BOOST_CHECK_THROW(
+    m_tool.addRrsetFromFile(parentZoneName, output, DEFAULT_CACHE_TTL, DEFAULT_CERT,
+                            static_cast<ndn::io::IoEncoding>(127)),
+    ndns::ManagementTool::Error);
+}
+
+BOOST_AUTO_TEST_CASE(ListAllZones)
+{
+  m_tool.createZone(ROOT_ZONE, ROOT_ZONE, time::seconds(1), time::days(1), rootKsk, rootDsk, rootDkey);
+  m_tool.createZone("/ndns-test", ROOT_ZONE, time::seconds(10), time::days(1), otherKsk, otherDsk);
+
+  Name rootDskName = CertHelper::getCertificate(m_keyChain, "/NDNS/", rootDsk).getKeyName();
+  Name otherDskName = CertHelper::getCertificate(m_keyChain, "/ndns-test/NDNS/", otherDsk).getKeyName();
+
+  std::string expectedValue =
+  "/           ; default-ttl=1 default-key=" + rootDskName.toUri() +  " "
+  "default-certificate=" + rootDsk.toUri() + "\n"
+  "/ndns-test  ; default-ttl=10 default-key=" + otherDskName.toUri() +  " "
+  "default-certificate=" + otherDsk.toUri() + "\n";
+
+  output_test_stream testOutput;
+  m_tool.listAllZones(testOutput);
+  BOOST_CHECK(testOutput.is_equal(expectedValue));
+}
+
+// Test need to fix values of keys, otherwise it produces different values every time
+
+// BOOST_AUTO_TEST_CASE(ListZone)
+// {
+//   m_tool.createZone("/ndns-test", ROOT_ZONE, time::seconds(10), time::days(1), otherKsk, otherDsk);
+
+//   RrsetFactory rf(TEST_DATABASE, "/ndns-test", m_keyChain, DEFAULT_CERT);
+//   rf.checkZoneKey();
+
+//   // Add NS with NDNS_RESP
+//   Delegation del;
+//   del.preference = 10;
+//   del.name = Name("/get/link");
+//   DelegationList ds = {del};
+//   Rrset rrset1 = rf.generateNsRrset("/label1", 100, DEFAULT_RR_TTL, ds);
+//   m_tool.addRrset(rrset1);
+
+//   // Add NS with NDNS_AUTH
+//   Rrset rrset2 = rf.generateAuthRrset("/label2", 100000, DEFAULT_RR_TTL);
+//   m_tool.addRrset(rrset2);
+
+//   // Add TXT from file
+//   std::string output = TEST_CERTDIR.string() + "/a.rrset";
+//   Response re1;
+//   re1.setZone("/ndns-test");
+//   re1.setQueryType(label::NDNS_ITERATIVE_QUERY);
+//   re1.setRrLabel("/label2");
+//   re1.setRrType(label::TXT_RR_TYPE);
+//   re1.setContentType(NDNS_RESP);
+//   re1.setVersion(name::Component::fromVersion(654321));
+//   re1.addRr("First RR");
+//   re1.addRr("Second RR");
+//   re1.addRr("Last RR");
+//   shared_ptr<Data> data1 = re1.toData();
+//   m_keyChain.sign(*data1, security::signingByCertificate(otherDsk));
+//   ndn::io::save(*data1, output);
+//   m_tool.addRrsetFromFile("/ndns-test", output);
+
+//   // Add TXT in normal way
+//   Rrset rrset3 = rf.generateTxtRrset("/label3", 3333, DEFAULT_RR_TTL, {"Hello", "World"});
+//   m_tool.addRrset(rrset3);
+
+//   m_tool.listZone("/ndns-test", std::cout, true);
+
+//   output_test_stream testOutput;
+//   m_tool.listZone("/ndns-test", testOutput, true);
+
+//   std::string expectedValue =
+//     R"VALUE(; Zone /ndns-test
+
+// ; rrset=/ type=DOE version=%FD%00%00%01b%26e%AE%99 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /                                 3600  DOE   Bw0IBmxhYmVsMwgDVFhU
+// /                                 3600  DOE   BxUIA0tFWQgIEgV0kDpqdkEIBENFUlQ=
+
+// /KEY/%12%05t%90%3AjvA             10    CERT  ; content-type=KEY version=%FD%00%00%01b%26e%AEY signed-by=/ndns-test/NDNS/KEY/%8D%1Dj%1E%BE%B0%2A%E4
+// Certificate name:
+//   /ndns-test/NDNS/KEY/%12%05t%90%3AjvA/CERT/%FD%00%00%01b%26e%AEY
+// Validity:
+//   NotBefore: 20180314T212340
+//   NotAfter: 20180324T212340
+// Public key bits:
+//   MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA
+//   AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////
+//   ///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd
+//   NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5
+//   RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA
+//   //////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABHU62fbCa6KR7G1iyMr6/NtF
+//   5oHrAdzttIgh5pk1VS1YcFO1zhpUnpJS43FlduYHVBLrXwYS6tZ15Ge/D3uy1f4=
+// Signature Information:
+//   Signature Type: SignatureSha256WithEcdsa
+//   Key Locator: Name=/ndns-test/NDNS/KEY/%8D%1Dj%1E%BE%B0%2A%E4
+
+// ; rrset=/KEY/%12%05t%90%3AjvA/CERT type=DOE version=%FD%00%00%01b%26e%AE%91 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /KEY/%12%05t%90%3AjvA/CERT        3600  DOE   BxUIA0tFWQgIEgV0kDpqdkEIBENFUlQ=
+// /KEY/%12%05t%90%3AjvA/CERT        3600  DOE   BxUIA0tFWQgIjR1qHr6wKuQIBENFUlQ=
+
+// /KEY/%8D%1Dj%1E%BE%B0%2A%E4       10    CERT  ; content-type=KEY version=%FD%00%00%01b%26e%AEX signed-by=/ndns-test/NDNS/KEY/%8D%1Dj%1E%BE%B0%2A%E4
+// Certificate name:
+//   /ndns-test/NDNS/KEY/%8D%1Dj%1E%BE%B0%2A%E4/CERT/%FD%00%00%01b%26e%AEX
+// Validity:
+//   NotBefore: 20180314T212340
+//   NotAfter: 20180324T212340
+// Public key bits:
+//   MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA
+//   AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////
+//   ///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd
+//   NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5
+//   RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA
+//   //////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABMRVD/FUfCQVvjcwQLe9k1aS
+//   5pZ/xmFndOHn1+a0OYVzxCV1JcxL1eojcij42tCP5mtocrj9DjYyFBv4Atg1RZE=
+// Signature Information:
+//   Signature Type: SignatureSha256WithEcdsa
+//   Key Locator: Self-Signed Name=/ndns-test/NDNS/KEY/%8D%1Dj%1E%BE%B0%2A%E4
+
+// ; rrset=/KEY/%8D%1Dj%1E%BE%B0%2A%E4/CERT type=DOE version=%FD%00%00%01b%26e%AE%93 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /KEY/%8D%1Dj%1E%BE%B0%2A%E4/CERT  3600  DOE   BxUIA0tFWQgIjR1qHr6wKuQIBENFUlQ=
+// /KEY/%8D%1Dj%1E%BE%B0%2A%E4/CERT  3600  DOE   BwwIBmxhYmVsMQgCTlM=
+
+// ; rrset=/label1 type=NS version=%FDd signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label1                           10    NS    10
+
+// ; rrset=/label1/NS type=DOE version=%FD%00%00%01b%26e%AE%94 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label1/NS                        3600  DOE   BwwIBmxhYmVsMQgCTlM=
+// /label1/NS                        3600  DOE   BwwIBmxhYmVsMggCTlM=
+
+// ; rrset=/label2 type=NS version=%FD%00%01%86%A0 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label2                           10    NS    NDNS-Auth
+
+// ; rrset=/label2 type=TXT version=%FD%00%09%FB%F1 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label2                           10    TXT   First RR
+// /label2                           10    TXT   Second RR
+// /label2                           10    TXT   Last RR
+
+// ; rrset=/label2/NS type=DOE version=%FD%00%00%01b%26e%AE%96 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label2/NS                        3600  DOE   BwwIBmxhYmVsMggCTlM=
+// /label2/NS                        3600  DOE   Bw0IBmxhYmVsMggDVFhU
+
+// ; rrset=/label2/TXT type=DOE version=%FD%00%00%01b%26e%AE%97 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label2/TXT                       3600  DOE   Bw0IBmxhYmVsMggDVFhU
+// /label2/TXT                       3600  DOE   Bw0IBmxhYmVsMwgDVFhU
+
+// ; rrset=/label3 type=TXT version=%FD%0D%05 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label3                           10    TXT   Hello
+// /label3                           10    TXT   World
+
+// ; rrset=/label3/TXT type=DOE version=%FD%00%00%01b%26e%AE%98 signed-by=/ndns-test/NDNS/KEY/%12%05t%90%3AjvA
+// /label3/TXT                       3600  DOE   Bw0IBmxhYmVsMwgDVFhU
+// /label3/TXT                       3600  DOE   BxUIA0tFWQgIEgV0kDpqdkEIBENFUlQ=
+
+// )VALUE";
+
+//   BOOST_CHECK(testOutput.is_equal(expectedValue));
+// }
+
+BOOST_FIXTURE_TEST_CASE(GetRrSet, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+  m_tool.createZone(zoneName, ROOT_ZONE, time::seconds(1), time::days(1), otherKsk, otherDsk);
+  RrsetFactory rf(TEST_DATABASE, zoneName, m_keyChain, DEFAULT_CERT);
+  rf.checkZoneKey();
+  Rrset rrset1 = rf.generateTxtRrset("/label", 100, DEFAULT_RR_TTL, {"Value1", "Value2"});
+
+  m_tool.addRrset(rrset1);
+
+  std::stringstream os;
+
+  using security::transform::base64Encode;
+  using security::transform::streamSink;
+  using security::transform::bufferSource;
+
+  bufferSource(rrset1.getData().wire(), rrset1.getData().size()) >> base64Encode() >> streamSink(os);
+
+  std::string expectedValue = os.str();
+
+  output_test_stream testOutput;
+  m_tool.getRrSet(zoneName, "/label",label::TXT_RR_TYPE, testOutput);
+  BOOST_CHECK(testOutput.is_equal(expectedValue));
+}
+
+BOOST_FIXTURE_TEST_CASE(RemoveRrSet, ManagementToolFixture)
+{
+  Name zoneName("/ndns-test");
+
+  m_tool.createZone(zoneName, ROOT_ZONE);
+  RrsetFactory rf(TEST_DATABASE, zoneName, m_keyChain, DEFAULT_CERT);
+  rf.checkZoneKey();
+
+  Rrset rrset1 = rf.generateTxtRrset("/label", 100, DEFAULT_RR_TTL, {});
+
+  BOOST_CHECK_NO_THROW(m_tool.addRrset(rrset1));
+
+  Zone zone(zoneName);
+  BOOST_CHECK_NO_THROW(findRrSet(zone, "/label", label::TXT_RR_TYPE));
+
+  BOOST_CHECK_NO_THROW(m_tool.removeRrSet(zoneName, "/label", label::NS_RR_TYPE));
+
+  BOOST_CHECK_THROW(findRrSet(zone, "/label", label::NS_RR_TYPE), Error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndns
+} // namespace ndn