blob: 521be9bac3156d317e5d7010eeddc2e5fd1c4e99 [file] [log] [blame]
/* -*- 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