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
469 lines
14 KiB
C++
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
|