| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /** |
| * Copyright (c) 2014-2016, 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "rib/auto-prefix-propagator.hpp" |
| |
| #include "tests/test-common.hpp" |
| #include "tests/identity-management-fixture.hpp" |
| #include <ndn-cxx/util/dummy-client-face.hpp> |
| |
| namespace nfd { |
| namespace rib { |
| namespace tests { |
| |
| NFD_LOG_INIT("AutoPrefixPropagatorTest"); |
| |
| const Name TEST_LINK_LOCAL_NFD_PREFIX("/localhop/nfd"); |
| const time::milliseconds TEST_PREFIX_PROPAGATION_TIMEOUT(1000); |
| |
| class AutoPrefixPropagatorFixture : public nfd::tests::IdentityManagementFixture |
| , public nfd::tests::UnitTestTimeFixture |
| { |
| public: |
| AutoPrefixPropagatorFixture() |
| : m_face(ndn::util::makeDummyClientFace(nfd::tests::UnitTestTimeFixture::g_io, {true, true})) |
| , m_controller(*m_face, m_keyChain) |
| , m_propagator(m_controller, m_keyChain, m_rib) |
| , m_requests(m_face->sentInterests) |
| , m_entries(m_propagator.m_propagatedEntries) |
| { |
| m_propagator.enable(); |
| m_propagator.m_controlParameters |
| .setCost(15) |
| .setOrigin(ndn::nfd::ROUTE_ORIGIN_CLIENT)// set origin to client. |
| .setFaceId(0);// the remote hub will take the input face as the faceId. |
| m_propagator.m_commandOptions |
| .setPrefix(TEST_LINK_LOCAL_NFD_PREFIX) |
| .setTimeout(TEST_PREFIX_PROPAGATION_TIMEOUT); |
| } |
| |
| public: // helpers for test |
| bool |
| insertEntryToRib(const Name& name, const uint64_t& faceId = 0) |
| { |
| if (m_rib.find(name) != m_rib.end()) { |
| NFD_LOG_INFO("RIB entry already exists: " << name); |
| return false; |
| } |
| |
| Route route; |
| route.faceId = faceId; |
| m_rib.insert(name, route); |
| advanceClocks(time::milliseconds(1)); |
| |
| return m_rib.find(name) != m_rib.end(); // return whether afterInserEntry will be triggered |
| } |
| |
| bool |
| eraseEntryFromRib(const Name& name) |
| { |
| if (m_rib.find(name) == m_rib.end()) { |
| NFD_LOG_INFO("RIB entry does not exist: " << name); |
| return false; |
| } |
| |
| std::vector<Route> routeList; |
| std::copy(m_rib.find(name)->second->begin(), m_rib.find(name)->second->end(), |
| std::back_inserter(routeList)); |
| for (auto&& route : routeList) { |
| m_rib.erase(name, route); |
| } |
| advanceClocks(time::milliseconds(1)); |
| |
| return m_rib.find(name) == m_rib.end(); // return whether afterEraseEntry will be triggered |
| } |
| |
| void |
| connectToHub() |
| { |
| insertEntryToRib("/localhop/nfd"); |
| } |
| |
| void |
| disconnectFromHub() |
| { |
| eraseEntryFromRib("/localhop/nfd"); |
| } |
| |
| public: // helpers for check |
| enum class CheckRequestResult { |
| OK, |
| OUT_OF_BOUNDARY, |
| INVALID_N_COMPONENTS, |
| WRONG_COMMAND_PREFIX, |
| WRONG_VERB, |
| INVALID_PARAMETERS, |
| WRONG_REGISTERING_PREFIX |
| }; |
| |
| /** |
| * @brief check a request at specified index |
| * |
| * @param idx the index of the specified request in m_requests |
| * @param verb the expected verb of request |
| * @param registeringPrefix the expected registering prefix of request |
| |
| * @retval OK the specified request has a valid name, the right verb, a valid ControlParameters |
| * and the right registering prefix |
| * @retval OUT_OF_BOUNDARY the specified index out of boundary |
| * @retval INVALID_N_COMPONENTS the number of components of the request name is invalid |
| * @retval WRONG_COMMAND_PREFIX the command prefix of the request is wrong |
| * @retval WRONG_VERB the command verb of the request is wrong |
| * @retval INVALID_PARAMETERS no valid parameters can be decoded from the request's name |
| * @retval WRONG_REGISTERING_PREFIX the registering prefix of the request is wrong |
| */ |
| CheckRequestResult |
| checkRequest(size_t idx, const std::string& verb, const Name& registeringPrefix) |
| { |
| Name requestName; |
| try { |
| requestName = m_requests.at(idx).getName(); |
| } |
| catch (const std::out_of_range&) { |
| return CheckRequestResult::OUT_OF_BOUNDARY; |
| } |
| |
| if (requestName.size() < 5) { |
| return CheckRequestResult::INVALID_N_COMPONENTS; |
| } |
| |
| if (requestName.getPrefix(2) != TEST_LINK_LOCAL_NFD_PREFIX) { |
| return CheckRequestResult::WRONG_COMMAND_PREFIX; |
| } |
| |
| if (requestName.get(3) != Name::Component(verb)) { |
| return CheckRequestResult::WRONG_VERB; |
| } |
| |
| ControlParameters parameters; |
| try { |
| parameters.wireDecode(requestName.get(4).blockFromValue()); |
| } |
| catch (const tlv::Error&) { |
| return CheckRequestResult::INVALID_PARAMETERS; |
| } |
| |
| if (parameters.getName() != registeringPrefix) { |
| return CheckRequestResult::WRONG_REGISTERING_PREFIX; |
| } |
| |
| return CheckRequestResult::OK; |
| } |
| |
| protected: |
| shared_ptr<ndn::util::DummyClientFace> m_face; |
| ndn::nfd::Controller m_controller; |
| Rib m_rib; |
| AutoPrefixPropagator m_propagator; |
| std::vector<Interest>& m_requests; // store sent out requests |
| AutoPrefixPropagator::PropagatedEntryList& m_entries; // store propagated entries |
| }; |
| |
| std::ostream& |
| operator<<(std::ostream &os, const AutoPrefixPropagatorFixture::CheckRequestResult& result) |
| { |
| switch (result) { |
| case AutoPrefixPropagatorFixture::CheckRequestResult::OK: |
| os << "OK"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::OUT_OF_BOUNDARY: |
| os << "OUT_OF_BOUNDARY"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_N_COMPONENTS: |
| os << "INVALID_N_COMPONENTS"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_COMMAND_PREFIX: |
| os << "WRONG_COMMAND_PREFIX"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_VERB: |
| os << "WRONG_VERB"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::INVALID_PARAMETERS: |
| os << "INVALID_PARAMETERS"; |
| break; |
| case AutoPrefixPropagatorFixture::CheckRequestResult::WRONG_REGISTERING_PREFIX: |
| os << "WRONG_REGISTERING_PREFIX"; |
| break; |
| default: |
| break; |
| } |
| |
| return os; |
| } |
| |
| BOOST_AUTO_TEST_SUITE(Rib) |
| |
| BOOST_FIXTURE_TEST_SUITE(TestAutoPrefixPropagator, AutoPrefixPropagatorFixture) |
| |
| BOOST_AUTO_TEST_CASE(EnableDisable) |
| { |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| auto testPropagateRevokeBasic = [this] () -> bool { |
| m_propagator.m_propagatedEntries.clear(); |
| |
| if (!insertEntryToRib("/test/A/app")) { |
| return false; |
| } |
| m_entries["/test/A"].succeed(nullptr); |
| if (!eraseEntryFromRib("/test/A/app")) { |
| return false; |
| } |
| return true; |
| }; |
| |
| m_propagator.disable(); |
| BOOST_REQUIRE(testPropagateRevokeBasic()); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_propagator.enable(); |
| BOOST_REQUIRE(testPropagateRevokeBasic()); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 2); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_CASE(LoadConfiguration) |
| { |
| ConfigFile config; |
| config.addSectionHandler("auto_prefix_propagate", |
| bind(&AutoPrefixPropagator::loadConfig, &m_propagator, _1)); |
| |
| const std::string CONFIG_STRING = |
| "auto_prefix_propagate\n" |
| "{\n" |
| " cost 11\n" |
| " timeout 22\n" |
| " refresh_interval 33\n" |
| " base_retry_wait 44\n" |
| " max_retry_wait 55\n" |
| "}"; |
| config.parse(CONFIG_STRING, true, "test-auto-prefix-propagator"); |
| |
| BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getCost(), 11); |
| BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getOrigin(), ndn::nfd::ROUTE_ORIGIN_CLIENT); |
| BOOST_CHECK_EQUAL(m_propagator.m_controlParameters.getFaceId(), 0); |
| |
| BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getPrefix(), TEST_LINK_LOCAL_NFD_PREFIX); |
| BOOST_CHECK_EQUAL(m_propagator.m_commandOptions.getTimeout(), time::milliseconds(22)); |
| |
| BOOST_CHECK_EQUAL(m_propagator.m_refreshInterval, time::seconds(33)); |
| BOOST_CHECK_EQUAL(m_propagator.m_baseRetryWait, time::seconds(44)); |
| BOOST_CHECK_EQUAL(m_propagator.m_maxRetryWait, time::seconds(55)); |
| } |
| |
| BOOST_AUTO_TEST_SUITE(Helpers) |
| |
| BOOST_AUTO_TEST_CASE(GetPrefixPropagationParameters) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(addIdentity("/test/A/B")); |
| BOOST_REQUIRE(addIdentity("/test/C/nrd")); |
| |
| auto parameters1 = m_propagator.getPrefixPropagationParameters("/none/A/B/app"); |
| auto parameters2 = m_propagator.getPrefixPropagationParameters("/test/A/B/app"); |
| auto parameters3 = m_propagator.getPrefixPropagationParameters("/test/C/D/app"); |
| |
| BOOST_CHECK(!parameters1.isValid); |
| |
| BOOST_CHECK(parameters2.isValid); |
| BOOST_CHECK_EQUAL(parameters2.parameters.getName(), "/test/A"); |
| BOOST_CHECK_EQUAL(parameters2.options.getSigningInfo().getSignerName(), "/test/A"); |
| |
| BOOST_CHECK(parameters3.isValid); |
| BOOST_CHECK_EQUAL(parameters3.parameters.getName(), "/test/C"); |
| BOOST_CHECK_EQUAL(parameters3.options.getSigningInfo().getSignerName(), "/test/C/nrd"); |
| } |
| |
| BOOST_AUTO_TEST_CASE(CheckCurrentPropagatedPrefix) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(addIdentity("/test/B/nrd")); |
| BOOST_REQUIRE(addIdentity("/test/A/B")); |
| |
| BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/E")); // does not exist |
| BOOST_CHECK(!m_propagator.doesCurrentPropagatedPrefixWork("/test/A/B")); // has a better option |
| BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/A")); |
| BOOST_CHECK(m_propagator.doesCurrentPropagatedPrefixWork("/test/B")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(RedoPropagation) |
| { |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(addIdentity("/test/B")); |
| BOOST_REQUIRE(addIdentity("/test/B/C")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); |
| BOOST_REQUIRE(insertEntryToRib("/test/B/C/app")); |
| BOOST_REQUIRE(insertEntryToRib("/test/B/D/app")); |
| |
| auto testRedoPropagation = [this] (const Name& signingIdentity) { |
| m_requests.clear(); |
| |
| m_entries[signingIdentity].setSigningIdentity(signingIdentity); |
| |
| auto parameters = m_propagator.m_controlParameters; |
| auto options = m_propagator.m_commandOptions; |
| ndn::security::SigningInfo info(ndn::security::SigningInfo::SIGNER_TYPE_ID, signingIdentity); |
| m_propagator.redoPropagation(m_entries.find(signingIdentity), |
| parameters.setName(signingIdentity), |
| options.setSigningInfo(info), |
| time::seconds(0)); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| testRedoPropagation("/test/A"); // current propagated prefix still works |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| BOOST_CHECK(m_entries.find("test/A") != m_entries.end()); |
| |
| BOOST_CHECK_NO_THROW(m_keyChain.deleteIdentity("/test/B")); |
| testRedoPropagation("/test/B"); // signingIdentity no longer exists |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B/C"), CheckRequestResult::OK); |
| BOOST_CHECK(m_entries.find("/test/B") == m_entries.end()); |
| BOOST_CHECK(m_entries.find("/test/B/C") != m_entries.end()); |
| |
| testRedoPropagation("/test/B"); // no alternative identity |
| BOOST_CHECK(m_requests.empty()); |
| BOOST_CHECK(m_entries.find("/test/B") == m_entries.end()); |
| |
| m_entries["/test/B/C"].succeed(nullptr); |
| testRedoPropagation("/test/B"); // alternative identity has been propagated |
| BOOST_CHECK(m_requests.empty()); |
| BOOST_CHECK(m_entries.find("/test/B") == m_entries.end()); |
| |
| BOOST_REQUIRE(addIdentity("/test/B/")); |
| testRedoPropagation("/test/B/C"); // better option exists: /test/B |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/B"), CheckRequestResult::OK); |
| BOOST_CHECK(m_entries.find("test/B/C") == m_entries.end()); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // Helpers |
| |
| BOOST_AUTO_TEST_SUITE(PropagateRevokeSemantics) |
| |
| BOOST_AUTO_TEST_CASE(Basic) |
| { |
| connectToHub(); // ensure connectivity to the hub |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); // ensure afterInsertEntry signal emitted |
| m_entries["/test/A"].succeed(nullptr); // ensure there is a valid entry inserted |
| BOOST_REQUIRE(eraseEntryFromRib("/test/A/app")); // ensure afterEraseEntry signal emitted |
| |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 2); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(1, "unregister", "/test/A"), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_CASE(LocalPrefix) |
| { |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/localhost/A")); |
| |
| BOOST_REQUIRE(insertEntryToRib("/localhost/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_propagator.m_propagatedEntries["/localhost/A"].succeed(nullptr); |
| BOOST_REQUIRE(eraseEntryFromRib("/localhost/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(InvalidPropagationParameters) |
| { |
| connectToHub(); |
| |
| // no identity can be found |
| BOOST_CHECK(!m_propagator.getPrefixPropagationParameters("/test/A/app").isValid); |
| |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries["/test/A"].succeed(nullptr); |
| BOOST_REQUIRE(eraseEntryFromRib("/test/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(NoHubConnectivity) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries["/test/A"].succeed(nullptr); |
| BOOST_REQUIRE(eraseEntryFromRib("/test/A/app")); |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(ProcessSuspendedEntries) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app1")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); |
| BOOST_CHECK(m_requests.empty()); // no propagation because no hub is connected |
| BOOST_CHECK_EQUAL(m_entries.size(), 1); // /test/A was suspended |
| |
| BOOST_REQUIRE(eraseEntryFromRib("/test/A/app2")); |
| BOOST_CHECK_EQUAL(m_entries.size(), 1); // /test/A was kept for app1 |
| |
| // repeat the scenario that leads to BUG 3362. |
| // ensure there is no improper assertion. |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(PropagatedEntryExists) |
| { |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app1")); |
| |
| m_requests.clear(); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); // /test/A has been propagated by /test/A/app1 |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(PropagatedEntryShouldKeep) |
| { |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app1")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app2")); |
| |
| m_requests.clear(); |
| BOOST_REQUIRE(eraseEntryFromRib("/test/A/app2")); // /test/A should be kept for /test/A/app1 |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(BackOffRetryPolicy) |
| { |
| m_propagator.m_commandOptions.setTimeout(time::milliseconds(1)); |
| m_propagator.m_baseRetryWait = time::seconds(1); |
| m_propagator.m_maxRetryWait = time::seconds(2); |
| |
| connectToHub(); |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); |
| |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| |
| advanceClocks(time::milliseconds(10), time::milliseconds(1050)); // wait for the 1st retry |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 2); |
| BOOST_CHECK_EQUAL(checkRequest(1, "register", "/test/A"), CheckRequestResult::OK); |
| |
| advanceClocks(time::milliseconds(10), time::milliseconds(2050)); // wait for the 2nd retry, 2 times |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 3); |
| BOOST_CHECK_EQUAL(checkRequest(2, "register", "/test/A"), CheckRequestResult::OK); |
| |
| advanceClocks(time::milliseconds(10), time::milliseconds(2050)); // wait for the 3rd retry, reach the upper bound |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 4); |
| BOOST_CHECK_EQUAL(checkRequest(3, "register", "/test/A"), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // PropagateRevokeSemantics |
| |
| BOOST_AUTO_TEST_SUITE(PropagatedEntryStateChanges) |
| |
| BOOST_AUTO_TEST_CASE(AfterRibInsert) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| auto testAfterRibInsert = [this] (const Name& ribEntryPrefix) { |
| m_requests.clear(); |
| m_propagator.m_propagatedEntries.clear(); // ensure entry does not exist |
| |
| auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix); |
| m_propagator.afterRibInsert(propagateParameters.parameters, propagateParameters.options); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| testAfterRibInsert("/test/A/app1"); |
| BOOST_CHECK(m_requests.empty()); // no connectivity now |
| BOOST_CHECK(m_entries.find("/test/A") != m_entries.end()); |
| |
| connectToHub(); |
| testAfterRibInsert("/test/A/app2"); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| BOOST_CHECK(m_entries.find("/test/A") != m_entries.end()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(AfterRibErase) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| auto testAfterRibInsert = [this] (const Name& localUnregPrefix) { |
| m_requests.clear(); |
| |
| auto propagateParameters = m_propagator.getPrefixPropagationParameters(localUnregPrefix); |
| m_propagator.afterRibErase(propagateParameters.parameters.unsetCost(), |
| propagateParameters.options); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| m_entries["/test/A"].succeed(nullptr); |
| testAfterRibInsert("/test/A/app"); |
| BOOST_CHECK(m_requests.empty()); // no connectivity |
| BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased |
| |
| connectToHub(); |
| m_entries["/test/A"].fail(nullptr); |
| testAfterRibInsert("/test/A/app"); |
| BOOST_CHECK(m_requests.empty()); // previous propagation has not succeeded |
| BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased |
| |
| m_entries["/test/A"].succeed(nullptr); |
| testAfterRibInsert("/test/A/app"); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK); |
| BOOST_CHECK(m_entries.find("/test/A") == m_entries.end()); // has been erased |
| } |
| |
| BOOST_AUTO_TEST_CASE(AfterHubConnectDisconnect) |
| { |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| BOOST_REQUIRE(addIdentity("/test/B")); |
| BOOST_REQUIRE(addIdentity("/test/C")); |
| BOOST_REQUIRE(insertEntryToRib("/test/A/app")); |
| BOOST_REQUIRE(insertEntryToRib("/test/B/app")); |
| |
| // recorder the prefixes that will be propagated in order |
| std::vector<Name> propagatedPrefixes; |
| |
| BOOST_CHECK(m_requests.empty()); // no request because there is no connectivity to the hub now |
| BOOST_REQUIRE_EQUAL(m_entries.size(), 2); // valid entries will be kept |
| |
| connectToHub(); // 2 cached entries will be processed |
| for (auto&& entry : m_entries) { |
| propagatedPrefixes.push_back(entry.first); |
| } |
| |
| BOOST_REQUIRE(insertEntryToRib("/test/C/app")); // will be processed directly |
| propagatedPrefixes.push_back("/test/C"); |
| BOOST_REQUIRE_EQUAL(m_entries.size(), 3); |
| |
| BOOST_REQUIRE(m_entries["/test/A"].isPropagating()); |
| BOOST_REQUIRE(m_entries["/test/B"].isPropagating()); |
| BOOST_REQUIRE(m_entries["/test/C"].isPropagating()); |
| |
| disconnectFromHub(); // all 3 entries are initialized |
| BOOST_CHECK(m_entries["/test/A"].isNew()); |
| BOOST_CHECK(m_entries["/test/B"].isNew()); |
| BOOST_CHECK(m_entries["/test/C"].isNew()); |
| |
| connectToHub(); // all 3 entries will be processed |
| for (auto&& entry : m_entries) { |
| propagatedPrefixes.push_back(entry.first); |
| } |
| |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 6); |
| BOOST_REQUIRE_EQUAL(propagatedPrefixes.size(), 6); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", propagatedPrefixes[0]), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(1, "register", propagatedPrefixes[1]), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(2, "register", propagatedPrefixes[2]), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(3, "register", propagatedPrefixes[3]), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(4, "register", propagatedPrefixes[4]), CheckRequestResult::OK); |
| BOOST_CHECK_EQUAL(checkRequest(5, "register", propagatedPrefixes[5]), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_CASE(AfterPropagateSucceed) |
| { |
| bool wasRefreshEventTriggered = false; |
| auto testAfterPropagateSucceed = [&] (const Name& ribEntryPrefix) { |
| m_requests.clear(); |
| wasRefreshEventTriggered = false; |
| |
| auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix); |
| m_propagator.afterPropagateSucceed(propagateParameters.parameters, propagateParameters.options, |
| [&]{ wasRefreshEventTriggered = true; }); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| m_propagator.m_refreshInterval = time::seconds(0); // event will be executed at once |
| m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state |
| |
| testAfterPropagateSucceed("/test/A/app"); // will trigger refresh event |
| BOOST_CHECK(wasRefreshEventTriggered); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state |
| testAfterPropagateSucceed("/test/A/app"); // will call startRevocation |
| BOOST_CHECK(!wasRefreshEventTriggered); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "unregister", "/test/A"), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_CASE(AfterPropagateFail) |
| { |
| bool wasRetryEventTriggered = false; |
| auto testAfterPropagateFail = [&] (const Name& ribEntryPrefix) { |
| m_requests.clear(); |
| wasRetryEventTriggered = false; |
| |
| auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix); |
| m_propagator.afterPropagateFail(400, "test", propagateParameters.parameters, propagateParameters.options, |
| time::seconds(0), [&]{ wasRetryEventTriggered = true; }); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| m_entries["/test/A"].startPropagation(); // set to be in PROPAGATING state |
| |
| testAfterPropagateFail("/test/A/app"); // will trigger retry event |
| BOOST_CHECK(wasRetryEventTriggered); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries.erase(m_entries.find("/test/A")); // set to be in RELEASED state |
| testAfterPropagateFail("/test/A/app"); // will do nothing |
| BOOST_CHECK(!wasRetryEventTriggered); |
| BOOST_CHECK(m_requests.empty()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(AfterRevokeSucceed) |
| { |
| auto testAfterRevokeSucceed = [&] (const Name& ribEntryPrefix) { |
| m_requests.clear(); |
| auto propagateParameters = m_propagator.getPrefixPropagationParameters(ribEntryPrefix); |
| m_propagator.afterRevokeSucceed(propagateParameters.parameters, |
| propagateParameters.options, |
| time::seconds(0)); |
| advanceClocks(time::milliseconds(1)); |
| }; |
| |
| BOOST_REQUIRE(addIdentity("/test/A")); |
| |
| testAfterRevokeSucceed("/test/A/app"); // in RELEASED state |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries["/test/A"].fail(nullptr); // in PROPAGATE_FAIL state |
| testAfterRevokeSucceed("/test/A/app"); |
| BOOST_CHECK(m_requests.empty()); |
| |
| m_entries["/test/A"].succeed(nullptr); // in PROPAGATED state |
| testAfterRevokeSucceed("/test/A/app"); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| |
| m_entries["/test/A"].startPropagation(); // in PROPAGATING state |
| testAfterRevokeSucceed("/test/A/app"); |
| BOOST_REQUIRE_EQUAL(m_requests.size(), 1); |
| BOOST_CHECK_EQUAL(checkRequest(0, "register", "/test/A"), CheckRequestResult::OK); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() // PropagatedEntryStateChanges |
| |
| BOOST_AUTO_TEST_SUITE_END() // TestAutoPrefixPropagator |
| BOOST_AUTO_TEST_SUITE_END() // Rib |
| |
| } // namespace tests |
| } // namespace rib |
| } // namespace nfd |