/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2014-2019, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, * Washington University in St. Louis, * Beijing Institute of Technology, * The University of Memphis. * * This file is part of NFD (Named Data Networking Forwarding Daemon). * See AUTHORS.md for complete list of NFD authors and contributors. * * NFD 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. * * NFD 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 * NFD, e.g., in COPYING.md file. If not, see . */ #include "table/strategy-choice.hpp" #include "tests/test-common.hpp" #include "tests/daemon/global-io-fixture.hpp" #include "tests/daemon/fw/dummy-strategy.hpp" namespace nfd { namespace tests { class StrategyChoiceFixture : public GlobalIoFixture { protected: StrategyChoiceFixture() : sc(forwarder.getStrategyChoice()) , strategyNameP("/strategy-choice-P/%FD%00") , strategyNameQ("/strategy-choice-Q/%FD%00") { DummyStrategy::registerAs(strategyNameP); DummyStrategy::registerAs(strategyNameQ); } /** \brief insert StrategyChoice entry at \p prefix for \p instanceName * \return constructed instance name */ Name insertAndGet(const Name& prefix, const Name& instanceName) { BOOST_REQUIRE(sc.insert(prefix, instanceName)); bool isFound; Name foundName; std::tie(isFound, foundName) = sc.get(prefix); BOOST_REQUIRE(isFound); return foundName; } /** \brief determine whether the effective strategy type at \p prefix is \p S * \tparam S expected strategy type */ template bool isStrategyType(const Name& prefix) { auto& effectiveStrategy = sc.findEffectiveStrategy(prefix); return dynamic_cast(&effectiveStrategy) != nullptr; } template Name findInstanceName(const Q& query) { return sc.findEffectiveStrategy(query).getInstanceName(); } protected: Forwarder forwarder; StrategyChoice& sc; const Name strategyNameP; const Name strategyNameQ; }; BOOST_AUTO_TEST_SUITE(Table) BOOST_FIXTURE_TEST_SUITE(TestStrategyChoice, StrategyChoiceFixture) BOOST_AUTO_TEST_CASE(Versioning) { const Name strategyNameV("/strategy-choice-V"); const Name strategyNameV0("/strategy-choice-V/%FD%00"); const Name strategyNameV1("/strategy-choice-V/%FD%01"); const Name strategyNameV2("/strategy-choice-V/%FD%02"); const Name strategyNameV3("/strategy-choice-V/%FD%03"); const Name strategyNameV4("/strategy-choice-V/%FD%04"); const Name strategyNameV5("/strategy-choice-V/%FD%05"); VersionedDummyStrategy<1>::registerAs(strategyNameV1); VersionedDummyStrategy<3>::registerAs(strategyNameV3); VersionedDummyStrategy<4>::registerAs(strategyNameV4); // unversioned: choose latest version BOOST_CHECK_EQUAL(this->insertAndGet("/A", strategyNameV), strategyNameV4); BOOST_CHECK(this->isStrategyType>("/A")); // exact version: choose same version BOOST_CHECK_EQUAL(this->insertAndGet("/B", strategyNameV1), strategyNameV1); BOOST_CHECK(this->isStrategyType>("/B")); BOOST_CHECK_EQUAL(this->insertAndGet("/C", strategyNameV3), strategyNameV3); BOOST_CHECK(this->isStrategyType>("/C")); BOOST_CHECK_EQUAL(this->insertAndGet("/D", strategyNameV4), strategyNameV4); BOOST_CHECK(this->isStrategyType>("/D")); // lower version: choose next higher version BOOST_CHECK_EQUAL(this->insertAndGet("/E", strategyNameV0), strategyNameV0); BOOST_CHECK(this->isStrategyType>("/E")); BOOST_CHECK_EQUAL(this->insertAndGet("/F", strategyNameV2), strategyNameV2); BOOST_CHECK(this->isStrategyType>("/F")); // higher version: failure StrategyChoice::InsertResult res5 = sc.insert("/G", strategyNameV5); BOOST_CHECK(!res5); BOOST_CHECK(!res5.isRegistered()); } BOOST_AUTO_TEST_CASE(Parameters) { // no parameters BOOST_CHECK_EQUAL(this->insertAndGet("/A", strategyNameP), strategyNameP); // one parameter Name oneParamName = Name(strategyNameP).append("param"); BOOST_CHECK_EQUAL(this->insertAndGet("/B", oneParamName), oneParamName); // two parameters Name twoParamName = Name(strategyNameP).append("x").append("y"); BOOST_CHECK_EQUAL(this->insertAndGet("/C", twoParamName), twoParamName); // parameter without version is disallowed Name oneParamUnversioned = strategyNameP.getPrefix(-1).append("param"); BOOST_CHECK(!sc.insert("/D", oneParamUnversioned)); } BOOST_AUTO_TEST_CASE(InsertLongName) { Name n1; while (n1.size() < NameTree::getMaxDepth()) { n1.append("A"); } Name n2 = n1; while (n2.size() < NameTree::getMaxDepth() * 2) { n2.append("B"); } BOOST_CHECK(sc.insert(n1, strategyNameP)); BOOST_CHECK(!sc.insert(n2, strategyNameP)); } BOOST_AUTO_TEST_CASE(Get) { BOOST_CHECK(sc.insert("/", strategyNameP)); // { '/'=>P } auto getRoot = sc.get("/"); BOOST_CHECK_EQUAL(getRoot.first, true); BOOST_CHECK_EQUAL(getRoot.second, strategyNameP); auto getA = sc.get("/A"); BOOST_CHECK_EQUAL(getA.first, false); } BOOST_AUTO_TEST_CASE(FindEffectiveStrategy) { const Name strategyNameZ("/strategy-choice-Z/%FD%00"); // unregistered strategyName BOOST_CHECK(sc.insert("/", strategyNameP)); // { '/'=>P } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameP); BOOST_CHECK(sc.insert("/A/B", strategyNameP)); // { '/'=>P, '/A/B'=>P } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameP); // same entry, same instance BOOST_CHECK_EQUAL(&sc.findEffectiveStrategy("/"), &sc.findEffectiveStrategy("/A")); // different entries, distinct instances BOOST_CHECK_NE(&sc.findEffectiveStrategy("/"), &sc.findEffectiveStrategy("/A/B")); sc.erase("/A"); // no effect // { '/'=>P, '/A/B'=>P } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameP); BOOST_CHECK(sc.insert("/A", strategyNameQ)); // { '/'=>P, '/A/B'=>P, '/A'=>Q } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameQ); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameP); sc.erase("/A/B"); // { '/'=>P, '/A'=>Q } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameQ); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameQ); BOOST_CHECK(!sc.insert("/", strategyNameZ)); // non existent strategy BOOST_CHECK(sc.insert("/", strategyNameQ)); BOOST_CHECK(sc.insert("/A", strategyNameP)); // { '/'=>Q, '/A'=>P } BOOST_CHECK_EQUAL(this->findInstanceName("/"), strategyNameQ); BOOST_CHECK_EQUAL(this->findInstanceName("/A"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/A/B"), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName("/D"), strategyNameQ); } BOOST_AUTO_TEST_CASE(FindEffectiveStrategyWithPitEntry) { shared_ptr dataABC = makeData("/A/B/C"); Name fullName = dataABC->getFullName(); BOOST_CHECK(sc.insert("/A", strategyNameP)); BOOST_CHECK(sc.insert(fullName, strategyNameQ)); Pit& pit = forwarder.getPit(); shared_ptr interestAB = makeInterest("/A/B"); shared_ptr pitAB = pit.insert(*interestAB).first; shared_ptr interestFull = makeInterest(fullName); shared_ptr pitFull = pit.insert(*interestFull).first; BOOST_CHECK_EQUAL(this->findInstanceName(*pitAB), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName(*pitFull), strategyNameQ); } BOOST_AUTO_TEST_CASE(FindEffectiveStrategyWithMeasurementsEntry) { BOOST_CHECK(sc.insert("/A", strategyNameP)); BOOST_CHECK(sc.insert("/A/B/C", strategyNameQ)); Measurements& measurements = forwarder.getMeasurements(); measurements::Entry& mAB = measurements.get("/A/B"); measurements::Entry& mABCD = measurements.get("/A/B/C/D"); BOOST_CHECK_EQUAL(this->findInstanceName(mAB), strategyNameP); BOOST_CHECK_EQUAL(this->findInstanceName(mABCD), strategyNameQ); } BOOST_AUTO_TEST_CASE(Erase) { NameTree& nameTree = forwarder.getNameTree(); sc.insert("/", strategyNameP); size_t nNameTreeEntriesBefore = nameTree.size(); sc.insert("/A/B", strategyNameQ); sc.erase("/A/B"); BOOST_CHECK_EQUAL(nameTree.size(), nNameTreeEntriesBefore); } BOOST_AUTO_TEST_CASE(Enumerate) { sc.insert("/", strategyNameP); sc.insert("/A/B", strategyNameQ); sc.insert("/A/B/C", strategyNameP); sc.insert("/D", strategyNameP); sc.insert("/E", strategyNameQ); BOOST_CHECK_EQUAL(sc.size(), 5); std::map map; // namespace=>strategyName for (StrategyChoice::const_iterator it = sc.begin(); it != sc.end(); ++it) { map[it->getPrefix()] = it->getStrategyInstanceName(); } BOOST_CHECK_EQUAL(map.at("/"), strategyNameP); BOOST_CHECK_EQUAL(map.at("/A/B"), strategyNameQ); BOOST_CHECK_EQUAL(map.at("/A/B/C"), strategyNameP); BOOST_CHECK_EQUAL(map.at("/D"), strategyNameP); BOOST_CHECK_EQUAL(map.at("/E"), strategyNameQ); BOOST_CHECK_EQUAL(map.size(), 5); } class PStrategyInfo : public fw::StrategyInfo { public: static constexpr int getTypeId() { return 10; } }; BOOST_AUTO_TEST_CASE(ClearStrategyInfo) { Measurements& measurements = forwarder.getMeasurements(); BOOST_CHECK(sc.insert("/", strategyNameP)); // { '/'=>P } measurements.get("/").insertStrategyInfo(); measurements.get("/A").insertStrategyInfo(); measurements.get("/A/B").insertStrategyInfo(); measurements.get("/A/C").insertStrategyInfo(); BOOST_CHECK(sc.insert("/A/B", strategyNameP)); // { '/'=>P, '/A/B'=>P } BOOST_CHECK(measurements.get("/").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A/B").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A/C").getStrategyInfo() != nullptr); BOOST_CHECK(sc.insert("/A", strategyNameQ)); // { '/'=>P, '/A/B'=>P, '/A'=>Q } BOOST_CHECK(measurements.get("/").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A").getStrategyInfo() == nullptr); BOOST_CHECK(measurements.get("/A/B").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A/C").getStrategyInfo() == nullptr); sc.erase("/A/B"); // { '/'=>P, '/A'=>Q } BOOST_CHECK(measurements.get("/").getStrategyInfo() != nullptr); BOOST_CHECK(measurements.get("/A").getStrategyInfo() == nullptr); BOOST_CHECK(measurements.get("/A/B").getStrategyInfo() == nullptr); BOOST_CHECK(measurements.get("/A/C").getStrategyInfo() == nullptr); } BOOST_AUTO_TEST_SUITE_END() // TestStrategyChoice BOOST_AUTO_TEST_SUITE_END() // Table } // namespace tests } // namespace nfd