add logger

Change-Id: If41d6d94086ec9fffb954a52e1529ccfad7f42fe
diff --git a/tests/core/logger.t.cpp b/tests/core/logger.t.cpp
new file mode 100644
index 0000000..521be9b
--- /dev/null
+++ b/tests/core/logger.t.cpp
@@ -0,0 +1,335 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California
+ *
+ * This file is part of NSL (NDN Signature Logger).
+ * See AUTHORS.md for complete list of NSL authors and contributors.
+ *
+ * NSL 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.
+ *
+ * NSL 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
+ * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of nsl authors and contributors.
+ */
+
+#include "logger.hpp"
+#include "identity-fixture.hpp"
+#include "db-fixture.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include <ndn-cxx/util/io.hpp>
+
+#include "boost-test.hpp"
+
+namespace nsl {
+namespace tests {
+
+class LoggerFixture : public IdentityFixture
+                    , public DbFixture
+{
+public:
+  LoggerFixture()
+    : face1(ndn::util::makeDummyClientFace(io, {true, true}))
+    , face2(ndn::util::makeDummyClientFace(io, {true, true}))
+    , readInterestOffset1(0)
+    , readDataOffset1(0)
+    , readInterestOffset2(0)
+    , readDataOffset2(0)
+  {
+  }
+
+  ~LoggerFixture()
+  {
+  }
+
+  bool
+  passPacket()
+  {
+    bool hasPassed = false;
+
+    checkFace(face1->sentInterests, readInterestOffset1, *face2, hasPassed);
+    checkFace(face1->sentDatas, readDataOffset1, *face2, hasPassed);
+    checkFace(face2->sentInterests, readInterestOffset2, *face1, hasPassed);
+    checkFace(face2->sentDatas, readDataOffset2, *face1, hasPassed);
+
+    return hasPassed;
+  }
+
+  template<typename Packet>
+  void
+  checkFace(std::vector<Packet>& receivedPackets,
+            size_t& readPacketOffset,
+            ndn::util::DummyClientFace& receiver,
+            bool& hasPassed)
+  {
+    while (receivedPackets.size() > readPacketOffset) {
+      receiver.receive(receivedPackets[readPacketOffset]);
+      readPacketOffset++;
+      hasPassed = true;
+    }
+  }
+
+  void
+  clear()
+  {
+    face1->sentDatas.clear();
+    face1->sentInterests.clear();
+    face2->sentDatas.clear();
+    face2->sentInterests.clear();
+
+    readInterestOffset1 = 0;
+    readDataOffset1 = 0;
+    readInterestOffset2 = 0;
+    readDataOffset2 = 0;
+  }
+
+public:
+  shared_ptr<ndn::util::DummyClientFace> face1;
+  shared_ptr<ndn::util::DummyClientFace> face2;
+
+  size_t readInterestOffset1;
+  size_t readDataOffset1;
+  size_t readInterestOffset2;
+  size_t readDataOffset2;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestLogger, LoggerFixture)
+
+const std::string CONFIG =
+  "logger-name /test/logger                             \n"
+  "policy                                               \n"
+  "{                                                    \n"
+  "  rule                                               \n"
+  "  {                                                  \n"
+  "    id \"Simple Rule\"                               \n"
+  "    for data                                         \n"
+  "    checker                                          \n"
+  "    {                                                \n"
+  "      type customized                                \n"
+  "      sig-type rsa-sha256                            \n"
+  "      key-locator                                    \n"
+  "      {                                              \n"
+  "        type name                                    \n"
+  "        hyper-relation                               \n"
+  "        {                                            \n"
+  "          k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+  "          k-expand \\\\1\\\\2                        \n"
+  "          h-relation is-strict-prefix-of             \n"
+  "          p-regex ^(<>*)$                            \n"
+  "          p-expand \\\\1                             \n"
+  "        }                                            \n"
+  "      }                                              \n"
+  "    }                                                \n"
+  "  }                                                  \n"
+  "}                                                    \n"
+  "validator                                            \n"
+  "{                                                    \n"
+  "  rule                                               \n"
+  "  {                                                  \n"
+  "    id \"Request Rule\"                              \n"
+  "    for interest                                     \n"
+  "    filter                                           \n"
+  "    {                                                \n"
+  "      type name                                      \n"
+  "      name /test/logger/log                          \n"
+  "      relation is-strict-prefix-of                   \n"
+  "    }                                                \n"
+  "    checker                                          \n"
+  "    {                                                \n"
+  "      type customized                                \n"
+  "      sig-type rsa-sha256                            \n"
+  "      key-locator                                    \n"
+  "      {                                              \n"
+  "        type name                                    \n"
+  "        regex ^[^<KEY>]*<KEY><>*<><ID-CERT>$         \n"
+  "      }                                              \n"
+  "    }                                                \n"
+  "  }                                                  \n"
+  "  rule                                               \n"
+  "  {                                                  \n"
+  "    id \"Simple Rule\"                               \n"
+  "    for data                                         \n"
+  "    checker                                          \n"
+  "    {                                                \n"
+  "      type customized                                \n"
+  "      sig-type rsa-sha256                            \n"
+  "      key-locator                                    \n"
+  "      {                                              \n"
+  "        type name                                    \n"
+  "        hyper-relation                               \n"
+  "        {                                            \n"
+  "          k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
+  "          k-expand \\\\1\\\\2                        \n"
+  "          h-relation is-strict-prefix-of             \n"
+  "          p-regex ^(<>*)$                            \n"
+  "          p-expand \\\\1                             \n"
+  "        }                                            \n"
+  "      }                                              \n"
+  "    }                                                \n"
+  "  }                                                  \n"
+  "  trust-anchor                                       \n"
+  "  {                                                  \n"
+  "    type file                                        \n"
+  "    file-name \"trust-anchor.cert\"                  \n"
+  "  }                                                  \n"
+  "}                                                    \n";
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  namespace fs = boost::filesystem;
+
+  fs::create_directory(fs::path(TEST_LOGGER_PATH));
+
+  fs::path configPath = fs::path(TEST_LOGGER_PATH) / "logger-test.conf";
+  std::ofstream os(configPath.c_str());
+  os << CONFIG;
+  os.close();
+
+  Name root("/ndn");
+  addIdentity(root);
+  auto rootCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(root));
+  fs::path certPath = fs::path(TEST_LOGGER_PATH) / "trust-anchor.cert";
+  ndn::io::save(*rootCert, certPath.string());
+
+  Logger logger(*face1, configPath.string());
+
+  BOOST_CHECK_EQUAL(logger.getLoggerName(), Name("/test/logger"));
+  BOOST_CHECK_EQUAL(logger.getTreePrefix(), Name("/test/logger/tree"));
+  BOOST_CHECK_EQUAL(logger.getLeafPrefix(), Name("/test/logger/leaf"));
+  BOOST_CHECK_EQUAL(logger.getLogPrefix(), Name("/test/logger/log"));
+
+  advanceClocks(time::milliseconds(2), 100);
+
+  Timestamp rootTs = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
+  NonNegativeInteger rootSeqNo = logger.addSelfSignedCert(*rootCert, rootTs);
+  BOOST_CHECK_EQUAL(rootSeqNo, 0);
+
+  Name leafInterestName("/test/logger/leaf");
+  leafInterestName.appendNumber(0);
+  auto leafInterest = make_shared<Interest>(leafInterestName);
+
+  face1->receive(*leafInterest);
+  advanceClocks(time::milliseconds(2), 100);
+
+  BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+  BOOST_CHECK(leafInterestName.isPrefixOf(face1->sentDatas[0].getName()));
+
+  face1->sentDatas.clear();
+
+  Name treeInterestName("/test/logger/tree");
+  treeInterestName.appendNumber(0);
+  treeInterestName.appendNumber(0);
+  auto treeInterest = make_shared<Interest>(treeInterestName);
+
+  face1->receive(*treeInterest);
+  advanceClocks(time::milliseconds(2), 100);
+
+  BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+  BOOST_CHECK(treeInterestName.isPrefixOf(face1->sentDatas[0].getName()));
+
+  face1->sentDatas.clear();
+
+  Name tld("/ndn/tld");
+  Name tldKeyName = m_keyChain.generateRsaKeyPair(tld);
+  std::vector<ndn::CertificateSubjectDescription> subjectDescription;
+  auto tldCert =
+    m_keyChain.prepareUnsignedIdentityCertificate(tldKeyName, root,
+                                                  time::system_clock::now(),
+                                                  time::system_clock::now() + time::days(1),
+                                                  subjectDescription);
+  m_keyChain.signByIdentity(*tldCert, root);
+  m_keyChain.addCertificate(*tldCert);
+
+  face2->setInterestFilter(tldCert->getName().getPrefix(-1),
+    [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*tldCert); },
+    ndn::RegisterPrefixSuccessCallback(),
+    [] (const Name&, const std::string&) {});
+  advanceClocks(time::milliseconds(2), 100);
+  clear();
+
+  Name logInterestName("/test/logger/log");
+  logInterestName.append(tldCert->getFullName().wireEncode());
+  logInterestName.appendNumber(0);
+  auto logInterest = make_shared<Interest>(logInterestName);
+  m_keyChain.sign(*logInterest, tldCert->getName());
+
+  face1->receive(*logInterest);
+  do {
+    advanceClocks(time::milliseconds(2), 100);
+  } while (passPacket());
+  clear();
+
+  BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 2);
+  auto leafResult1 = logger.getDb().getLeaf(1);
+  BOOST_CHECK(leafResult1.first != nullptr);
+  BOOST_CHECK(leafResult1.second != nullptr);
+
+
+
+  Name leafInterestName2("/test/logger/leaf");
+  leafInterestName2.appendNumber(1);
+  auto leafInterest2 = make_shared<Interest>(leafInterestName2);
+
+  face1->receive(*leafInterest2);
+  advanceClocks(time::milliseconds(2), 100);
+
+  BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+  BOOST_CHECK(leafInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
+  clear();
+
+
+
+  Name treeInterestName2("/test/logger/tree");
+  treeInterestName2.appendNumber(1);
+  treeInterestName2.appendNumber(0);
+  auto treeInterest2 = make_shared<Interest>(treeInterestName2);
+
+  face1->receive(*treeInterest2);
+  advanceClocks(time::milliseconds(2), 100);
+
+  BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
+  BOOST_CHECK(treeInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
+  clear();
+
+
+  auto data = make_shared<Data>(Name("/ndn/tld/data"));
+  m_keyChain.sign(*data, tldCert->getName());
+
+  face2->setInterestFilter(data->getName(),
+    [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*data); },
+    ndn::RegisterPrefixSuccessCallback(),
+    [] (const Name&, const std::string&) {});
+  advanceClocks(time::milliseconds(2), 100);
+  clear();
+
+  Name logInterestName2("/test/logger/log");
+  logInterestName2.append(data->getFullName().wireEncode());
+  logInterestName2.appendNumber(1);
+  auto logInterest2 = make_shared<Interest>(logInterestName2);
+  m_keyChain.sign(*logInterest2, tldCert->getName());
+
+  face1->receive(*logInterest2);
+  do {
+    advanceClocks(time::milliseconds(2), 100);
+  } while (passPacket());
+  clear();
+
+  BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 3);
+  auto leafResult2 = logger.getDb().getLeaf(2);
+  BOOST_CHECK(leafResult2.first != nullptr);
+  BOOST_CHECK(leafResult2.second == nullptr);
+
+
+  fs::remove_all(fs::path(TEST_LOGGER_PATH));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace nsl