485 lines
14 KiB
C++
485 lines
14 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2013-2023 Regents of the University of California.
|
|
*
|
|
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
|
*
|
|
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* ndn-cxx library 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received copies of the GNU General Public License and GNU Lesser
|
|
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
|
*/
|
|
|
|
#include "ndn-cxx/mgmt/nfd/status-dataset.hpp"
|
|
#include "ndn-cxx/mgmt/nfd/controller.hpp"
|
|
|
|
#include "tests/test-common.hpp"
|
|
#include "tests/unit/mgmt/nfd/controller-fixture.hpp"
|
|
|
|
namespace ndn {
|
|
namespace nfd {
|
|
namespace tests {
|
|
|
|
using namespace ndn::tests;
|
|
|
|
BOOST_AUTO_TEST_SUITE(Mgmt)
|
|
BOOST_AUTO_TEST_SUITE(Nfd)
|
|
|
|
class ControllerStatusDatasetFixture : public ControllerFixture
|
|
{
|
|
protected:
|
|
/** \brief Send one WireEncodable as Data reply.
|
|
* \param prefix dataset prefix without version and segment
|
|
* \param payload payload block
|
|
* \note payload must fit in one Data
|
|
*/
|
|
template<typename T>
|
|
void
|
|
sendDataset(const Name& prefix, const T& payload)
|
|
{
|
|
auto data = this->prepareDatasetReply(prefix);
|
|
data->setContent(payload.wireEncode());
|
|
face.receive(*signData(data));
|
|
}
|
|
|
|
/** \brief Send two WireEncodables as Data reply.
|
|
* \param prefix dataset prefix without version and segment
|
|
* \param payload1 first vector item
|
|
* \param payload2 second vector item
|
|
* \note all payloads must fit in one Data
|
|
*/
|
|
template<typename T1, typename T2>
|
|
void
|
|
sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
|
|
{
|
|
// The test suite allows up to two items, and put them in the same Data packet,
|
|
// because this test suite focuses on Controller::fetch<StatusDataset>,
|
|
// and is not intended to cover SegmentFetcher behavior.
|
|
|
|
EncodingBuffer buffer;
|
|
payload2.wireEncode(buffer);
|
|
payload1.wireEncode(buffer);
|
|
|
|
auto data = this->prepareDatasetReply(prefix);
|
|
data->setContent(buffer);
|
|
face.receive(*signData(data));
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<Data>
|
|
prepareDatasetReply(const Name& prefix)
|
|
{
|
|
Name name = prefix;
|
|
name.appendVersion().appendSegment(0);
|
|
|
|
// These warnings assist in debugging a `hasResult` check failure.
|
|
// They usually indicate a misspelled prefix or incorrect timing in the test case.
|
|
if (face.sentInterests.size() < 1) {
|
|
BOOST_WARN_MESSAGE(false, "no Interest expressed");
|
|
}
|
|
else {
|
|
BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
|
|
"last Interest " << face.sentInterests.back().getName() <<
|
|
" cannot be satisfied by this Data " << name);
|
|
}
|
|
|
|
auto data = std::make_shared<Data>(name);
|
|
data->setFreshnessPeriod(1_s);
|
|
data->setFinalBlock(name[-1]);
|
|
return data;
|
|
}
|
|
};
|
|
|
|
BOOST_FIXTURE_TEST_SUITE(TestStatusDataset, ControllerStatusDatasetFixture)
|
|
|
|
BOOST_AUTO_TEST_SUITE(Failures)
|
|
|
|
BOOST_AUTO_TEST_CASE(Timeout)
|
|
{
|
|
CommandOptions options;
|
|
options.setTimeout(3000_ms);
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback,
|
|
options);
|
|
this->advanceClocks(500_ms);
|
|
BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1);
|
|
|
|
this->advanceClocks(500_ms, 6);
|
|
BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0);
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_TIMEOUT);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DataHasNoSegment)
|
|
{
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
auto data = makeData("/localhost/nfd/faces/list/%FD%00");
|
|
data->setFreshnessPeriod(1_s);
|
|
face.receive(*data);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ValidationFailure)
|
|
{
|
|
this->setValidationResult(false);
|
|
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
FaceStatus payload;
|
|
payload.setFaceId(5744);
|
|
this->sendDataset("/localhost/nfd/faces/list", payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_VALIDATION);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(Nack)
|
|
{
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
|
|
face.receive(lp::Nack(face.sentInterests.back()));
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_NACK);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ParseError1)
|
|
{
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
Name payload; // Name is not valid FaceStatus
|
|
this->sendDataset("/localhost/nfd/faces/list", payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ParseError2)
|
|
{
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
FaceStatus payload1;
|
|
payload1.setFaceId(10930);
|
|
Name payload2; // Name is not valid FaceStatus
|
|
this->sendDataset("/localhost/nfd/faces/list", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(failCodes.size(), 1);
|
|
BOOST_CHECK_EQUAL(failCodes.back(), Controller::ERROR_SERVER);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // Failures
|
|
|
|
BOOST_AUTO_TEST_SUITE(NoCallback)
|
|
|
|
BOOST_AUTO_TEST_CASE(Success)
|
|
{
|
|
controller.fetch<FaceDataset>(
|
|
nullptr,
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 1);
|
|
|
|
FaceStatus payload;
|
|
payload.setFaceId(2577);
|
|
this->sendDataset("/localhost/nfd/faces/list", payload);
|
|
BOOST_CHECK_NO_THROW(this->advanceClocks(500_ms));
|
|
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
BOOST_CHECK_EQUAL(controller.m_fetchers.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(Failure)
|
|
{
|
|
CommandOptions options;
|
|
options.setTimeout(3000_ms);
|
|
controller.fetch<FaceDataset>(
|
|
[] (auto&&) { BOOST_FAIL("fetchDataset should not succeed"); },
|
|
nullptr,
|
|
options);
|
|
BOOST_CHECK_NO_THROW(this->advanceClocks(500_ms, 7));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // NoCallback
|
|
|
|
BOOST_AUTO_TEST_SUITE(Datasets)
|
|
|
|
BOOST_AUTO_TEST_CASE(StatusGeneral)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<ForwarderGeneralStatusDataset>(
|
|
[&hasResult] (const ForwarderStatus& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.getNfdVersion(), "0.4.2");
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
ForwarderStatus payload;
|
|
payload.setNfdVersion("0.4.2");
|
|
this->sendDataset("/localhost/nfd/status/general", payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FaceList)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<FaceDataset>(
|
|
[&hasResult] (const std::vector<FaceStatus>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 2);
|
|
BOOST_CHECK_EQUAL(result.front().getFaceId(), 24485);
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
FaceStatus payload1;
|
|
payload1.setFaceId(24485);
|
|
FaceStatus payload2;
|
|
payload2.setFaceId(12987);
|
|
this->sendDataset("/localhost/nfd/faces/list", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FaceQuery)
|
|
{
|
|
FaceQueryFilter filter;
|
|
filter.setUriScheme("udp4");
|
|
bool hasResult = false;
|
|
controller.fetch<FaceQueryDataset>(
|
|
filter,
|
|
[&hasResult] (const std::vector<FaceStatus>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 1);
|
|
BOOST_CHECK_EQUAL(result.front().getFaceId(), 8795);
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
Name prefix("/localhost/nfd/faces/query");
|
|
prefix.append(filter.wireEncode());
|
|
FaceStatus payload;
|
|
payload.setFaceId(8795);
|
|
this->sendDataset(prefix, payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FaceQueryWithOptions)
|
|
{
|
|
FaceQueryFilter filter;
|
|
filter.setUriScheme("udp4");
|
|
CommandOptions options;
|
|
options.setTimeout(3000_ms);
|
|
bool hasResult = false;
|
|
controller.fetch<FaceQueryDataset>(
|
|
filter,
|
|
[&hasResult] (const std::vector<FaceStatus>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 1);
|
|
BOOST_CHECK_EQUAL(result.front().getFaceId(), 14022);
|
|
},
|
|
datasetFailCallback,
|
|
options);
|
|
this->advanceClocks(500_ms);
|
|
|
|
Name prefix("/localhost/nfd/faces/query");
|
|
prefix.append(filter.wireEncode());
|
|
FaceStatus payload;
|
|
payload.setFaceId(14022);
|
|
this->sendDataset(prefix, payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FaceChannels)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<ChannelDataset>(
|
|
[&hasResult] (const std::vector<ChannelStatus>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 2);
|
|
BOOST_CHECK_EQUAL(result.front().getLocalUri(), "tcp4://192.0.2.1:6363");
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
ChannelStatus payload1;
|
|
payload1.setLocalUri("tcp4://192.0.2.1:6363");
|
|
ChannelStatus payload2;
|
|
payload2.setLocalUri("udp4://192.0.2.1:6363");
|
|
this->sendDataset("/localhost/nfd/faces/channels", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(FibList)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<FibDataset>(
|
|
[&hasResult] (const std::vector<FibEntry>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 2);
|
|
BOOST_CHECK_EQUAL(result.front().getPrefix(), "/wYs7fzYcfG");
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
FibEntry payload1;
|
|
payload1.setPrefix("/wYs7fzYcfG");
|
|
FibEntry payload2;
|
|
payload2.setPrefix("/LKvmnzY5S");
|
|
this->sendDataset("/localhost/nfd/fib/list", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(CsInfo)
|
|
{
|
|
using ndn::nfd::CsInfo;
|
|
|
|
bool hasResult = false;
|
|
controller.fetch<CsInfoDataset>(
|
|
[&hasResult] (const CsInfo& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.getNHits(), 4539);
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
CsInfo payload;
|
|
payload.setNHits(4539);
|
|
this->sendDataset("/localhost/nfd/cs/info", payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(StrategyChoiceList)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<StrategyChoiceDataset>(
|
|
[&hasResult] (const std::vector<StrategyChoice>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 2);
|
|
BOOST_CHECK_EQUAL(result.front().getName(), "/8MLz6N3B");
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
StrategyChoice payload1;
|
|
payload1.setName("/8MLz6N3B");
|
|
StrategyChoice payload2;
|
|
payload2.setName("/svqcBu0YwU");
|
|
this->sendDataset("/localhost/nfd/strategy-choice/list", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(RibList)
|
|
{
|
|
bool hasResult = false;
|
|
controller.fetch<RibDataset>(
|
|
[&hasResult] (const std::vector<RibEntry>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 2);
|
|
BOOST_CHECK_EQUAL(result.front().getName(), "/zXxBth97ee");
|
|
},
|
|
datasetFailCallback);
|
|
this->advanceClocks(500_ms);
|
|
|
|
RibEntry payload1;
|
|
payload1.setName("/zXxBth97ee");
|
|
RibEntry payload2;
|
|
payload2.setName("/rJ8CvUpr4G");
|
|
this->sendDataset("/localhost/nfd/rib/list", payload1, payload2);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(RibListWithOptions)
|
|
{
|
|
CommandOptions options;
|
|
options.setPrefix("/localhop/nfd");
|
|
bool hasResult = false;
|
|
controller.fetch<RibDataset>(
|
|
[&hasResult] (const std::vector<RibEntry>& result) {
|
|
hasResult = true;
|
|
BOOST_CHECK_EQUAL(result.size(), 1);
|
|
BOOST_CHECK_EQUAL(result.front().getName(), "/e6L5K4ascd");
|
|
},
|
|
datasetFailCallback,
|
|
options);
|
|
this->advanceClocks(500_ms);
|
|
|
|
RibEntry payload;
|
|
payload.setName("/e6L5K4ascd");
|
|
this->sendDataset("/localhop/nfd/rib/list", payload);
|
|
this->advanceClocks(500_ms);
|
|
|
|
BOOST_CHECK(hasResult);
|
|
BOOST_CHECK_EQUAL(failCodes.size(), 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // Datasets
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // TestStatusDataset
|
|
BOOST_AUTO_TEST_SUITE_END() // Nfd
|
|
BOOST_AUTO_TEST_SUITE_END() // Mgmt
|
|
|
|
} // namespace tests
|
|
} // namespace nfd
|
|
} // namespace ndn
|