/* -*- 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 . */ #include "statistics.hpp" #include "hello-protocol.hpp" #include "lsdb.hpp" #include "nlsr.hpp" #include "tests/io-key-chain-fixture.hpp" #include "tests/test-common.hpp" #include namespace nlsr { namespace test { class StatisticsFixture : public IoKeyChainFixture { public: StatisticsFixture() : face(m_io, m_keyChain) , conf(face, m_keyChain) , confProcessor(conf) , nlsr(face, m_keyChain, conf) , lsdb(nlsr.m_lsdb) , hello(nlsr.m_helloProtocol) , collector(nlsr.m_statsCollector) { // Otherwise code coverage node fails with default 60 seconds lifetime conf.setSyncInterestLifetime(1000); m_keyChain.createIdentity(conf.getRouterPrefix()); this->advanceClocks(ndn::time::milliseconds(1), 10); face.sentInterests.clear(); } /*! * \brief Checks if lsa interest was received and data for interest was sent * * \param interestPrefix is an interest name prefix * \param lsaType indicates whether the lsa is a name, adjacency, or coordinate * \param seqNo sequence number that will be appended to an interest name * \param receivedInterestType is the specific Statisitcs::PacketType interest that is received * \param sentDataType is the Statistics::PacketType data being sent upon interest process * * This is a general function that can be used for all three types of lsa. Calling processInterest() * from lsdb will cause the statsCollector to increment the incoming interest type and increment the * outgoing data type. */ void receiveInterestAndCheckSentStats(const std::string& interestPrefix, const std::string& lsaType, uint32_t seqNo, Statistics::PacketType receivedInterestType, Statistics::PacketType sentDataType) { size_t rcvBefore = collector.getStatistics().get(receivedInterestType); size_t sentBefore = collector.getStatistics().get(sentDataType); ndn::Name interestName = ndn::Name(ndn::Name(interestPrefix + lsaType).appendNumber(seqNo)); lsdb.processInterest(ndn::Name(), ndn::Interest(interestName)); this->advanceClocks(ndn::time::milliseconds(1), 10); BOOST_CHECK_EQUAL(collector.getStatistics().get(receivedInterestType), rcvBefore + 1); BOOST_CHECK_EQUAL(collector.getStatistics().get(sentDataType), sentBefore + 1); } /*! * \brief Checks if statistics update after an lsa interest is sent * * \param prefix is an interest prefix * \param lsaType indicates whether the lsa is a name, adjacency, or coordinate * \param seqNo is the sequence number * \param statsType is a statistical PacketType * * The function is called to initiate an expressInterest call in lsdb and to check if the * expected statistical packetType was incremented. */ void sendInterestAndCheckStats(const std::string& prefix, const std::string& lsaType, uint32_t seqNo, Statistics::PacketType statsType) { size_t sentBefore = collector.getStatistics().get(statsType); lsdb.expressInterest(ndn::Name(prefix + lsaType).appendNumber(seqNo), 0, 0, ndn::time::steady_clock::time_point::min()); this->advanceClocks(ndn::time::milliseconds(1), 10); BOOST_CHECK_EQUAL(collector.getStatistics().get(statsType), sentBefore + 1); } public: ndn::DummyClientFace face; ConfParameter conf; DummyConfFileProcessor confProcessor; Nlsr nlsr; Lsdb& lsdb; HelloProtocol& hello; StatsCollector& collector; }; BOOST_FIXTURE_TEST_SUITE(TestStatistics, StatisticsFixture) // A statistical PacketType is directly incremented (without signals). BOOST_AUTO_TEST_CASE(StatsIncrement) { Statistics stats; BOOST_CHECK_EQUAL(stats.get(Statistics::PacketType::SENT_HELLO_INTEREST), 0); stats.increment(Statistics::PacketType::SENT_HELLO_INTEREST); BOOST_CHECK_EQUAL(stats.get(Statistics::PacketType::SENT_HELLO_INTEREST), 1); } /* * After a PacketType has been incremented, the resetAll() function is called, which sets all * statistical packetType counts to 0 */ BOOST_AUTO_TEST_CASE(StatsReset) { Statistics stats; stats.increment(Statistics::PacketType::SENT_HELLO_INTEREST); stats.resetAll(); BOOST_CHECK_EQUAL(stats.get(Statistics::PacketType::SENT_HELLO_INTEREST), 0); } /* * This tests hello interests and hello data statistical collection by constructing an adjacency lsa * and calling functions that trigger the sending and receiving hello of interests/data. */ BOOST_AUTO_TEST_CASE(SendHelloInterest) { Adjacent other("/ndn/router/other", ndn::FaceUri("udp4://other"), 25, Adjacent::STATUS_INACTIVE, 0, 0); // This router's Adjacency LSA conf.getAdjacencyList().insert(other); ndn::Name otherName(other.getName()); otherName.append("NLSR"); otherName.append("INFO"); otherName.append(ndn::tlv::GenericNameComponent, conf.getRouterPrefix().wireEncode()); hello.expressInterest(otherName, 1); this->advanceClocks(ndn::time::milliseconds(1), 10); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::SENT_HELLO_INTEREST), 1); ndn::Name thisName(conf.getRouterPrefix()); thisName.append("NLSR"); thisName.append("INFO"); thisName.append(ndn::tlv::GenericNameComponent, other.getName().wireEncode()); ndn::Interest interest(thisName); hello.processInterest(ndn::Name(), interest); this->advanceClocks(ndn::time::milliseconds(1), 10); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_HELLO_INTEREST), 1); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::SENT_HELLO_DATA), 1); // Receive Hello Data ndn::Name dataName = otherName; ndn::Data data(dataName); hello.onContentValidated(data); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_HELLO_DATA), 1); } /* * An interest is sent for each lsa type (name, adjacency, coordinate). The respective statistics are * totaled and checked. */ BOOST_AUTO_TEST_CASE(LsdbSendLsaInterest) { const std::string interestPrefix("/localhop/ndn/nlsr/LSA/site/%C1.Router/router/"); uint32_t seqNo = 1; // Adjacency LSA sendInterestAndCheckStats(interestPrefix, boost::lexical_cast(Lsa::Type::ADJACENCY), seqNo, Statistics::PacketType::SENT_ADJ_LSA_INTEREST); // Coordinate LSA sendInterestAndCheckStats(interestPrefix, boost::lexical_cast(Lsa::Type::COORDINATE), seqNo, Statistics::PacketType::SENT_COORD_LSA_INTEREST); // Name LSA sendInterestAndCheckStats(interestPrefix, boost::lexical_cast(Lsa::Type::NAME), seqNo, Statistics::PacketType::SENT_NAME_LSA_INTEREST); // 3 total lsa interests were sent BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::SENT_LSA_INTEREST), 3); } /* * Tests the statistics collected upon processing incoming lsa * interests and respective outgoing data. This process will trigger * both an increment for received lsa interest and sent lsa data. * * /sa receiveInterestAndCheckSentStats */ BOOST_AUTO_TEST_CASE(LsdbReceiveInterestSendData) { // Adjacency LSA lsdb.buildAndInstallOwnAdjLsa(); auto adjLsa = lsdb.findLsa(conf.getRouterPrefix()); uint32_t seqNo = adjLsa->getSeqNo(); Adjacent adjacency("adjacency"); adjacency.setStatus(Adjacent::STATUS_ACTIVE); adjLsa->addAdjacent(adjacency); lsdb.installLsa(adjLsa); const std::string interestPrefix("/localhop/ndn/nlsr/LSA/site/%C1.Router/this-router/"); // Receive Adjacency LSA Interest receiveInterestAndCheckSentStats(interestPrefix, boost::lexical_cast(Lsa::Type::ADJACENCY), seqNo, Statistics::PacketType::RCV_ADJ_LSA_INTEREST, Statistics::PacketType::SENT_ADJ_LSA_DATA); // Name LSA auto nameLsa = std::static_pointer_cast(lsdb.findLsa(conf.getRouterPrefix(), Lsa::Type::NAME)); BOOST_ASSERT(nameLsa != nullptr); seqNo = nameLsa->getSeqNo(); nameLsa->addName(ndn::Name("/ndn/name")); lsdb.installLsa(nameLsa); // Receive Name LSA Interest receiveInterestAndCheckSentStats(interestPrefix, boost::lexical_cast(Lsa::Type::NAME), seqNo, Statistics::PacketType::RCV_NAME_LSA_INTEREST, Statistics::PacketType::SENT_NAME_LSA_DATA); // // Coordinate LSA lsdb.buildAndInstallOwnCoordinateLsa(); ndn::Name coorLsaKey = conf.getRouterPrefix(); coorLsaKey.append(boost::lexical_cast(Lsa::Type::COORDINATE)); auto coorLsa = lsdb.findLsa(conf.getRouterPrefix()); seqNo = coorLsa->getSeqNo(); coorLsa->setCorTheta({20.0, 30.0}); lsdb.installLsa(coorLsa); // Receive Adjacency LSA Interest receiveInterestAndCheckSentStats(interestPrefix, boost::lexical_cast(Lsa::Type::COORDINATE), seqNo, Statistics::PacketType::RCV_COORD_LSA_INTEREST, Statistics::PacketType::SENT_COORD_LSA_DATA); // 3 different lsa type interests should be received BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_LSA_INTEREST), 3); // data should have been sent 3x, once per lsa type BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::SENT_LSA_DATA), 3); } /* * Data for each lsa type (name, adjacency, coordinate) is sent to the lsdb and statistics are * checked to verify the respective statistical PacketType has been received. */ BOOST_AUTO_TEST_CASE(LsdbReceiveData) { ndn::Name routerName("/ndn/cs/%C1.Router/router1"); uint32_t seqNo = 1; const auto MAX_TIME = ndn::time::system_clock::time_point::max(); // adjacency lsa ndn::Name adjInterest("/localhop/ndn/nlsr/LSA/cs/%C1.Router/router1/ADJACENCY/"); adjInterest.appendNumber(seqNo); AdjLsa aLsa(routerName, seqNo, MAX_TIME, 1, conf.getAdjacencyList()); lsdb.installLsa(std::make_shared(aLsa)); lsdb.afterFetchLsa(aLsa.wireEncode().getBuffer(), adjInterest); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_ADJ_LSA_DATA), 1); // coordinate lsa ndn::Name coordInterest("/localhop/ndn/nlsr/LSA/cs/%C1.Router/router1/COORDINATE/"); coordInterest.appendNumber(seqNo); std::vector angles = {20.0, 30.0}; CoordinateLsa cLsa(routerName, seqNo, MAX_TIME, 2.5, angles); lsdb.installLsa(std::make_shared(cLsa)); lsdb.afterFetchLsa(cLsa.wireEncode().getBuffer(), coordInterest); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_COORD_LSA_DATA), 1); // name lsa ndn::Name interestName("/localhop/ndn/nlsr/LSA/cs/%C1.Router/router1/NAME/"); interestName.appendNumber(seqNo); NameLsa nlsa(routerName, seqNo, MAX_TIME, conf.getNamePrefixList()); lsdb.installLsa(std::make_shared(nlsa)); lsdb.afterFetchLsa(nlsa.wireEncode().getBuffer(), interestName); BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_NAME_LSA_DATA), 1); // 3 lsa data types should be received BOOST_CHECK_EQUAL(collector.getStatistics().get(Statistics::PacketType::RCV_LSA_DATA), 3); } BOOST_AUTO_TEST_SUITE_END() } // namespace test } // namespace nlsr