blob: 7c8e32c43d843e2ad7867482e7d28b1ba23c2727 [file] [log] [blame]
/* -*- 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 <http://www.gnu.org/licenses/>.
*/
#include "nfdc/status-report.hpp"
#include "status-fixture.hpp"
namespace nfd {
namespace tools {
namespace nfdc {
namespace tests {
const std::string STATUS_XML = stripXmlSpaces(R"XML(
<?xml version="1.0"?>
<nfdStatus xmlns="ndn:/localhost/nfd/status/1">
<module1/>
<module2/>
</nfdStatus>
)XML");
const std::string STATUS_TEXT = std::string(R"TEXT(
module1
module2
)TEXT").substr(1);
class DummyModule : public Module
{
public:
DummyModule(const std::string& moduleName, boost::asio::io_service& io)
: m_moduleName(moduleName)
, m_scheduler(io)
, m_res(0)
, m_delay(time::milliseconds(1))
{
}
/** \brief cause fetchStatus to succeed or fail
* \param res zero to succeed, non-zero to fail with specific code
* \param delay duration from fetchStatus invocation to succeed or fail; must be positive
*/
void
setResult(uint32_t res, time::nanoseconds delay)
{
BOOST_ASSERT(delay > time::nanoseconds::zero());
m_res = res;
m_delay = delay;
}
void
fetchStatus(Controller&,
const std::function<void()>& onSuccess,
const Controller::DatasetFailCallback& onFailure,
const CommandOptions&) final
{
++nFetchStatusCalls;
m_scheduler.schedule(m_delay, [=] {
if (m_res == 0) {
onSuccess();
}
else {
onFailure(m_res, m_moduleName + " fails with code " + to_string(m_res));
}
});
}
void
formatStatusXml(std::ostream& os) const final
{
os << '<' << m_moduleName << "/>";
}
void
formatStatusText(std::ostream& os) const final
{
os << m_moduleName << '\n';
}
public:
int nFetchStatusCalls = 0;
private:
std::string m_moduleName;
Scheduler m_scheduler;
uint32_t m_res;
time::nanoseconds m_delay;
};
class StatusReportTester : public StatusReport
{
private:
void
processEvents(Face&) override
{
processEventsFunc();
}
public:
std::function<void()> processEventsFunc;
};
class StatusReportModulesFixture : public ClockFixture, public KeyChainFixture
{
protected:
StatusReportModulesFixture()
: ClockFixture(m_io)
, face(m_io, m_keyChain)
, controller(face, m_keyChain, validator)
, res(0)
{
}
DummyModule&
addModule(const std::string& moduleName)
{
report.sections.push_back(make_unique<DummyModule>(moduleName, m_io));
return static_cast<DummyModule&>(*report.sections.back());
}
void
collect(time::nanoseconds tick, size_t nTicks)
{
report.processEventsFunc = [=] {
this->advanceClocks(tick, nTicks);
};
res = report.collect(face, m_keyChain, validator, CommandOptions());
if (res == 0) {
statusXml.str("");
report.formatXml(statusXml);
statusText.str("");
report.formatText(statusText);
}
}
private:
boost::asio::io_service m_io;
protected:
ndn::util::DummyClientFace face;
ValidatorNull validator;
Controller controller;
StatusReportTester report;
uint32_t res;
output_test_stream statusXml;
output_test_stream statusText;
};
BOOST_AUTO_TEST_SUITE(Nfdc)
BOOST_FIXTURE_TEST_SUITE(TestStatusReport, StatusReportModulesFixture)
BOOST_AUTO_TEST_CASE(Normal)
{
DummyModule& m1 = addModule("module1");
m1.setResult(0, time::milliseconds(10));
DummyModule& m2 = addModule("module2");
m2.setResult(0, time::milliseconds(20));
this->collect(time::milliseconds(5), 6);
BOOST_CHECK_EQUAL(m1.nFetchStatusCalls, 1);
BOOST_CHECK_EQUAL(m2.nFetchStatusCalls, 1);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK(statusXml.is_equal(STATUS_XML));
BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
}
BOOST_AUTO_TEST_CASE(Reorder)
{
DummyModule& m1 = addModule("module1");
m1.setResult(0, time::milliseconds(20));
DummyModule& m2 = addModule("module2");
m2.setResult(0, time::milliseconds(10)); // module2 completes earlier than module1
this->collect(time::milliseconds(5), 6);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK(statusXml.is_equal(STATUS_XML)); // output is still in order
BOOST_CHECK(statusText.is_equal(STATUS_TEXT));
}
BOOST_AUTO_TEST_CASE(Error)
{
DummyModule& m1 = addModule("module1");
m1.setResult(0, time::milliseconds(20));
DummyModule& m2 = addModule("module2");
m2.setResult(500, time::milliseconds(10));
this->collect(time::milliseconds(5), 6);
BOOST_CHECK_EQUAL(res, 1000500);
}
BOOST_AUTO_TEST_SUITE_END() // TestStatusReport
BOOST_AUTO_TEST_SUITE_END() // Nfdc
} // namespace tests
} // namespace nfdc
} // namespace tools
} // namespace nfd