Files
NLSR/tests/test-lsdb.cpp
Junxiao Shi 931ca9f576 name-prefix-list: delete unused methods and cleanup tests
Unit tests for NamePrefixList type are deduplicated. This allows
deleting countSources() method and NamePair type, which were used
sparsely in the unit tests and not needed by the rest of the codebase.

refs #4094

Change-Id: Id5a6e6b90f863dfeef2ed71e67a9823d84088a48
2023-08-21 10:14:46 +00:00

469 lines
14 KiB
C++

/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2014-2023, The University of Memphis,
* Regents of the University of California,
* Arizona Board of Regents.
*
* This file is part of NLSR (Named-data Link State Routing).
* See AUTHORS.md for complete list of NLSR authors and contributors.
*
* NLSR 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.
*
* NLSR 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
* NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
*/
#include "lsdb.hpp"
#include "lsa/lsa.hpp"
#include "name-prefix-list.hpp"
#include "tests/io-key-chain-fixture.hpp"
#include "tests/test-common.hpp"
#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
#include <ndn-cxx/security/validator-null.hpp>
#include <ndn-cxx/util/segment-fetcher.hpp>
#include <unistd.h>
namespace nlsr {
namespace test {
class LsdbFixture : public IoKeyChainFixture
{
public:
LsdbFixture()
: face(m_io, m_keyChain, {true, true})
, conf(face, m_keyChain)
, confProcessor(conf)
, lsdb(face, m_keyChain, conf)
{
m_keyChain.createIdentity("/ndn/site/%C1.Router/this-router");
advanceClocks(10_ms);
face.sentInterests.clear();
}
void
isFirstNameLsaEqual(const Lsdb& otherLsdb)
{
auto selfLsaRange = lsdb.getLsdbIterator<NameLsa>();
auto otherLsaRange = otherLsdb.getLsdbIterator<NameLsa>();
if (selfLsaRange.first != selfLsaRange.second && otherLsaRange.first != otherLsaRange.second) {
auto ownLsa = std::static_pointer_cast<NameLsa>(*selfLsaRange.first);
auto otherLsa = std::static_pointer_cast<NameLsa>(*otherLsaRange.first);
BOOST_CHECK_EQUAL(ownLsa->getNpl(), otherLsa->getNpl());
return;
}
BOOST_CHECK(false);
}
void
checkSignalResult(LsdbUpdate updateType,
const std::shared_ptr<Lsa>& lsaPtr,
const std::list<ndn::Name>& namesToAdd,
const std::list<ndn::Name>& namesToRemove)
{
BOOST_CHECK(updateHappened);
BOOST_CHECK_EQUAL(lsaPtrCheck->getOriginRouter(), lsaPtr->getOriginRouter());
BOOST_CHECK_EQUAL(lsaPtrCheck->getType(), lsaPtr->getType());
BOOST_CHECK(updateType == updateTypeCheck);
BOOST_CHECK(namesToAdd == namesToAddCheck);
BOOST_CHECK(namesToRemove == namesToRemoveCheck);
updateHappened = false;
}
void
connectSignal()
{
lsdb.onLsdbModified.connect(
[&] (std::shared_ptr<Lsa> lsa, LsdbUpdate updateType,
const auto& namesToAdd, const auto& namesToRemove) {
lsaPtrCheck = lsa;
updateTypeCheck = updateType;
namesToAddCheck = namesToAdd;
namesToRemoveCheck = namesToRemove;
updateHappened = true;
}
);
}
public:
ndn::DummyClientFace face;
ConfParameter conf;
DummyConfFileProcessor confProcessor;
Lsdb lsdb;
LsdbUpdate updateTypeCheck = LsdbUpdate::INSTALLED;
std::list<ndn::Name> namesToAddCheck;
std::list<ndn::Name> namesToRemoveCheck;
std::shared_ptr<Lsa> lsaPtrCheck = nullptr;
bool updateHappened = false;
};
BOOST_FIXTURE_TEST_SUITE(TestLsdb, LsdbFixture)
BOOST_AUTO_TEST_CASE(LsdbSync)
{
ndn::Name interestName("/ndn/NLSR/LSA/cs/%C1.Router/router2/name");
uint64_t oldSeqNo = 82;
ndn::Name oldInterestName = interestName;
oldInterestName.appendNumber(oldSeqNo);
lsdb.expressInterest(oldInterestName, 0, 0);
advanceClocks(10_ms);
std::vector<ndn::Interest>& interests = face.sentInterests;
BOOST_REQUIRE(interests.size() > 0);
bool didFindInterest = false;
for (const auto& interest : interests) {
didFindInterest = didFindInterest || interest.getName() == oldInterestName;
}
BOOST_CHECK(didFindInterest);
interests.clear();
auto deadline = ndn::time::steady_clock::now() + ndn::time::seconds(LSA_REFRESH_TIME_MAX);
// Simulate an LSA interest timeout
lsdb.onFetchLsaError(ndn::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT, "Timeout",
oldInterestName, 0, deadline, interestName, oldSeqNo);
advanceClocks(10_ms);
BOOST_REQUIRE(interests.size() > 0);
didFindInterest = false;
for (const auto& interest : interests) {
didFindInterest = didFindInterest || interest.getName() == oldInterestName;
}
BOOST_CHECK(didFindInterest);
interests.clear();
uint64_t newSeqNo = 83;
ndn::Name newInterestName = interestName;
newInterestName.appendNumber(newSeqNo);
lsdb.expressInterest(newInterestName, 0, 0);
advanceClocks(10_ms);
BOOST_REQUIRE(interests.size() > 0);
didFindInterest = false;
for (const auto& interest : interests) {
didFindInterest = didFindInterest || interest.getName() == newInterestName;
}
BOOST_CHECK(didFindInterest);
interests.clear();
// Simulate an LSA interest timeout where the sequence number is outdated
lsdb.onFetchLsaError(ndn::SegmentFetcher::ErrorCode::INTEREST_TIMEOUT, "Timeout",
oldInterestName, 0, deadline, interestName, oldSeqNo);
advanceClocks(10_ms);
// Interest should not be expressed for outdated sequence number
BOOST_CHECK_EQUAL(interests.size(), 0);
}
BOOST_AUTO_TEST_CASE(LsdbSegmentedData)
{
// Add a lot of NameLSAs to exceed max packet size
ndn::Name originRouter("/ndn/site/%C1.Router/this-router");
auto nameLsa = lsdb.findLsa<NameLsa>(originRouter);
BOOST_REQUIRE(nameLsa != nullptr);
uint64_t seqNo = nameLsa->getSeqNo();
ndn::Name prefix("/ndn/edu/memphis/netlab/research/nlsr/test/prefix/");
int nPrefixes = 0;
while (nameLsa->wireEncode().size() < ndn::MAX_NDN_PACKET_SIZE) {
nameLsa->addName(ndn::Name(prefix).appendNumber(++nPrefixes));
break;
}
lsdb.installLsa(nameLsa);
// Create another Lsdb and expressInterest
ndn::DummyClientFace face2(m_io, m_keyChain, {true, true});
face.linkTo(face2);
ConfParameter conf2(face2, m_keyChain);
std::string config = R"CONF(
trust-anchor
{
type any
}
)CONF";
conf2.getValidator().load(config, "config-file-from-string");
Lsdb lsdb2(face2, m_keyChain, conf2);
advanceClocks(ndn::time::milliseconds(10), 10);
ndn::Name interestName("/localhop/ndn/nlsr/LSA/site/%C1.Router/this-router/NAME");
interestName.appendNumber(seqNo);
lsdb2.expressInterest(interestName, 0/*= timeout count*/, 0);
advanceClocks(ndn::time::milliseconds(200), 20);
isFirstNameLsaEqual(lsdb2);
}
BOOST_AUTO_TEST_CASE(SegmentLsaData)
{
ndn::Name originRouter("/ndn/site/%C1.Router/this-router");
auto lsa = lsdb.findLsa<NameLsa>(originRouter);
uint64_t seqNo = lsa->getSeqNo();
ndn::Name prefix("/ndn/edu/memphis/netlab/research/nlsr/test/prefix/");
int nPrefixes = 0;
while (lsa->wireEncode().size() < ndn::MAX_NDN_PACKET_SIZE) {
lsa->addName(ndn::Name(prefix).appendNumber(++nPrefixes));
}
lsdb.installLsa(lsa);
ndn::Block expectedDataContent = lsa->wireEncode();
ndn::Name interestName("/localhop/ndn/nlsr/LSA/site/%C1.Router/this-router/NAME/");
interestName.appendNumber(seqNo);
ndn::DummyClientFace face2(m_io, m_keyChain, {true, true});
face.linkTo(face2);
auto fetcher = ndn::SegmentFetcher::start(face2, ndn::Interest(interestName),
ndn::security::getAcceptAllValidator());
fetcher->onComplete.connect([&expectedDataContent] (ndn::ConstBufferPtr bufferPtr) {
ndn::Block block(bufferPtr);
BOOST_CHECK_EQUAL(expectedDataContent, block);
});
advanceClocks(ndn::time::milliseconds(1), 100);
fetcher->stop();
}
BOOST_AUTO_TEST_CASE(ReceiveSegmentedLsaData)
{
ndn::Name router("/ndn/cs/%C1.Router/router1");
uint64_t seqNo = 12;
NamePrefixList prefixList;
NameLsa lsa(router, seqNo, ndn::time::system_clock::now(), prefixList);
ndn::Name prefix("/prefix/");
for (int nPrefixes = 0; nPrefixes < 3; ++nPrefixes) {
lsa.addName(ndn::Name(prefix).appendNumber(nPrefixes));
}
ndn::Name interestName("/localhop/ndn/nlsr/LSA/cs/%C1.Router/router1/NAME/");
interestName.appendNumber(seqNo);
ndn::Block block = lsa.wireEncode();
lsdb.afterFetchLsa(block.getBuffer(), interestName);
auto foundLsa = std::static_pointer_cast<NameLsa>(lsdb.findLsa(lsa.getOriginRouter(), lsa.getType()));
BOOST_REQUIRE(foundLsa != nullptr);
BOOST_CHECK_EQUAL(foundLsa->wireEncode(), lsa.wireEncode());
}
BOOST_AUTO_TEST_CASE(LsdbRemoveAndExists)
{
auto testTimePoint = ndn::time::system_clock::now();
NamePrefixList npl1;
std::string s1 = "name1";
std::string s2 = "name2";
std::string router1 = "/router1/1";
npl1.insert(s1);
npl1.insert(s2);
// For NameLsa lsType is name.
// 12 is seqNo, randomly generated.
// 1800 seconds is the default life time.
NameLsa nlsa1(router1, 12, testTimePoint, npl1);
Lsdb& lsdb1(lsdb);
lsdb1.installLsa(std::make_shared<NameLsa>(nlsa1));
BOOST_CHECK(lsdb1.doesLsaExist(router1, Lsa::Type::NAME));
lsdb1.removeLsa(router1, Lsa::Type::NAME);
BOOST_CHECK_EQUAL(lsdb1.doesLsaExist(router1, Lsa::Type::NAME), false);
}
BOOST_AUTO_TEST_CASE(InstallNameLsa)
{
// Install lsa with name1 and name2
ndn::Name name1("/ndn/name1");
ndn::Name name2("/ndn/name2");
NamePrefixList prefixes;
prefixes.insert(name1);
prefixes.insert(name2);
std::string otherRouter("/ndn/site/%C1.router/other-router");
const auto MAX_TIME = ndn::time::system_clock::time_point::max();
NameLsa lsa(otherRouter, 1, MAX_TIME, prefixes);
lsdb.installLsa(std::make_shared<NameLsa>(lsa));
BOOST_REQUIRE_EQUAL(lsdb.doesLsaExist(otherRouter, Lsa::Type::NAME), true);
NamePrefixList& nameList = std::static_pointer_cast<NameLsa>(lsdb.findLsa(otherRouter, Lsa::Type::NAME))->getNpl();
BOOST_CHECK_EQUAL(nameList, prefixes);
// Add a prefix: name3
ndn::Name name3("/ndn/name3");
prefixes.insert(name3);
NameLsa addLsa(otherRouter, 2, MAX_TIME, prefixes);
lsdb.installLsa(std::make_shared<NameLsa>(addLsa));
// Lsa should include name1, name2, and name3
BOOST_CHECK_EQUAL(nameList, prefixes);
// Remove a prefix: name2
prefixes.erase(name2);
NameLsa removeLsa(otherRouter, 3, MAX_TIME, prefixes);
lsdb.installLsa(std::make_shared<NameLsa>(removeLsa));
// Lsa should include name1 and name3
BOOST_CHECK_EQUAL(nameList, prefixes);
// Add and remove a prefix: add name2, remove name3
prefixes.insert(name2);
prefixes.erase(name3);
NameLsa addAndRemoveLsa(otherRouter, 4, MAX_TIME, prefixes);
lsdb.installLsa(std::make_shared<NameLsa>(addAndRemoveLsa));
// Lsa should include name1 and name2
BOOST_CHECK_EQUAL(nameList, prefixes);
// Install a completely new list of prefixes
ndn::Name name4("/ndn/name4");
ndn::Name name5("/ndn/name5");
NamePrefixList newPrefixes;
newPrefixes.insert(name4);
newPrefixes.insert(name5);
NameLsa newLsa(otherRouter, 5, MAX_TIME, newPrefixes);
lsdb.installLsa(std::make_shared<NameLsa>(newLsa));
// Lsa should include name4 and name5
BOOST_CHECK_EQUAL(nameList, newPrefixes);
}
BOOST_AUTO_TEST_CASE(TestIsLsaNew)
{
ndn::Name originRouter("/ndn/memphis/%C1.Router/other-router");
// Install Name LSA
NamePrefixList nameList;
NameLsa lsa(originRouter, 999, ndn::time::system_clock::time_point::max(), nameList);
lsdb.installLsa(std::make_shared<NameLsa>(lsa));
// Lower NameLSA sequence number
uint64_t lowerSeqNo = 998;
BOOST_CHECK(!lsdb.isLsaNew(originRouter, Lsa::Type::NAME, lowerSeqNo));
// Same NameLSA sequence number
uint64_t sameSeqNo = 999;
BOOST_CHECK(!lsdb.isLsaNew(originRouter, Lsa::Type::NAME, sameSeqNo));
// Higher NameLSA sequence number
uint64_t higherSeqNo = 1000;
BOOST_CHECK(lsdb.isLsaNew(originRouter, Lsa::Type::NAME, higherSeqNo));
}
BOOST_AUTO_TEST_CASE(LsdbSignals)
{
connectSignal();
auto testTimePoint = ndn::time::system_clock::now() + 3600_s;
ndn::Name router2("/router2");
AdjLsa adjLsa(router2, 12, testTimePoint, 2, conf.getAdjacencyList());
std::shared_ptr<Lsa> lsaPtr = std::make_shared<AdjLsa>(adjLsa);
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
adjLsa.setSeqNo(13);
updateHappened = false;
lsaPtr = std::make_shared<AdjLsa>(adjLsa);
lsdb.installLsa(lsaPtr);
BOOST_CHECK(!updateHappened);
Adjacent adj("Neighbor1");
adjLsa.setSeqNo(14);
adjLsa.addAdjacent(adj);
lsaPtr = std::make_shared<AdjLsa>(adjLsa);
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {}, {});
lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::ADJACENCY);
checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
// Name LSA
NamePrefixList npl1{"name1", "name2"};
NameLsa nameLsa(router2, 12, testTimePoint, npl1);
lsaPtr = std::make_shared<NameLsa>(nameLsa);
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
nameLsa.setSeqNo(13);
lsaPtr = std::make_shared<NameLsa>(nameLsa);
lsdb.installLsa(lsaPtr);
BOOST_CHECK(!updateHappened);
NamePrefixList npl2{"name2", "name3"};
NameLsa nameLsa2(router2, 14, testTimePoint, npl2);
lsaPtr = std::make_shared<NameLsa>(nameLsa2);
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {"name3"}, {"name1"});
lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::NAME);
checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
// Coordinate LSA
lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 12, testTimePoint, 2.5, {30}));
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::INSTALLED, lsaPtr, {}, {});
lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 13, testTimePoint, 2.5, {30}));
lsdb.installLsa(lsaPtr);
BOOST_CHECK(!updateHappened);
lsaPtr = std::make_shared<CoordinateLsa>(CoordinateLsa("router1", 14, testTimePoint, 2.5, {40}));
lsdb.installLsa(lsaPtr);
checkSignalResult(LsdbUpdate::UPDATED, lsaPtr, {}, {});
lsdb.removeLsa(lsaPtrCheck->getOriginRouter(), Lsa::Type::COORDINATE);
checkSignalResult(LsdbUpdate::REMOVED, lsaPtr, {}, {});
}
BOOST_AUTO_TEST_SUITE_END() // TestLsdb
} // namespace test
} // namespace nlsr