blob: eed9846ef4ecdad7447f0b54810dbfbf28c299a3 [file] [log] [blame]
Junxiao Shicb766862017-07-07 22:21:04 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesaventoae430302023-05-11 01:42:46 -04003 * Copyright (c) 2014-2023, Regents of the University of California,
Junxiao Shicb766862017-07-07 22:21:04 +00004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26#ifndef NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP
27#define NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP
28
Davide Pesavento21353752020-11-20 00:43:44 -050029#include "tests/io-fixture.hpp"
Davide Pesavento1d12d2f2019-03-22 12:44:14 -040030#include "tests/key-chain-fixture.hpp"
Davide Pesaventob7703ad2019-03-23 21:12:56 -040031#include "tests/test-common.hpp"
Junxiao Shicb766862017-07-07 22:21:04 +000032
Davide Pesavento17057442018-04-20 15:21:31 -040033#include <ndn-cxx/mgmt/nfd/control-parameters.hpp>
34#include <ndn-cxx/mgmt/nfd/control-response.hpp>
Alexander Afanasyev847de402017-09-21 18:57:30 -040035#include <ndn-cxx/util/dummy-client-face.hpp>
36
Davide Pesavento5d642632023-10-03 00:36:08 -040037#include <boost/asio/defer.hpp>
Davide Pesaventocf9e1c72019-12-22 17:56:07 -050038#include <boost/concept/assert.hpp>
39
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040040namespace nfd::tests {
Junxiao Shicb766862017-07-07 22:21:04 +000041
Junxiao Shicb766862017-07-07 22:21:04 +000042using ndn::nfd::ControlParameters;
43
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040044/**
45 * \brief Fixture to emulate NFD management.
Junxiao Shicb766862017-07-07 22:21:04 +000046 */
Davide Pesavento21353752020-11-20 00:43:44 -050047class MockNfdMgmtFixture : public IoFixture, public KeyChainFixture
Junxiao Shicb766862017-07-07 22:21:04 +000048{
49protected:
50 MockNfdMgmtFixture()
Davide Pesavento21353752020-11-20 00:43:44 -050051 : face(m_io, m_keyChain,
Davide Pesavento412c9822021-07-02 00:21:05 -040052 {true, false, std::bind(&MockNfdMgmtFixture::processEventsOverride, this, _1)})
Junxiao Shicb766862017-07-07 22:21:04 +000053 {
Davide Pesaventob7703ad2019-03-23 21:12:56 -040054 face.onSendInterest.connect([this] (const Interest& interest) {
55 if (processInterest) {
Davide Pesavento5d642632023-10-03 00:36:08 -040056 boost::asio::defer(m_io, [=] { processInterest(interest); });
Davide Pesaventob7703ad2019-03-23 21:12:56 -040057 }
Junxiao Shicb766862017-07-07 22:21:04 +000058 });
59 }
60
Junxiao Shicb766862017-07-07 22:21:04 +000061protected: // ControlCommand
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040062 /** \brief Check the Interest is a command with specified prefix.
Junxiao Shicb766862017-07-07 22:21:04 +000063 * \retval nullopt last Interest is not the expected command
64 * \return command parameters
65 */
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040066 static std::optional<ControlParameters>
Junxiao Shicb766862017-07-07 22:21:04 +000067 parseCommand(const Interest& interest, const Name& expectedPrefix)
68 {
69 if (!expectedPrefix.isPrefixOf(interest.getName())) {
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040070 return std::nullopt;
Junxiao Shicb766862017-07-07 22:21:04 +000071 }
72 return ControlParameters(interest.getName().at(expectedPrefix.size()).blockFromValue());
73 }
74
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040075 /** \brief Send successful response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000076 */
77 void
78 succeedCommand(const Interest& interest, const ControlParameters& parameters)
79 {
80 this->sendCommandReply(interest, 200, "OK", parameters.wireEncode());
81 }
82
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040083 /** \brief Send failure response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000084 */
85 void
86 failCommand(const Interest& interest, uint32_t code, const std::string& text)
87 {
88 this->sendCommandReply(interest, {code, text});
89 }
90
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040091 /** \brief Send failure response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000092 */
93 void
94 failCommand(const Interest& interest, uint32_t code, const std::string& text, const ControlParameters& body)
95 {
96 this->sendCommandReply(interest, code, text, body.wireEncode());
97 }
98
99protected: // StatusDataset
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400100 /** \brief Send an empty dataset in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000101 * \param prefix dataset prefix without version and segment
102 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
103 */
104 void
105 sendEmptyDataset(const Name& prefix)
106 {
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500107 this->sendDatasetReply(prefix, span<uint8_t>{});
Junxiao Shicb766862017-07-07 22:21:04 +0000108 }
109
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400110 /** \brief Send one WireEncodable in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000111 * \param prefix dataset prefix without version and segment
112 * \param payload payload block
113 * \note payload must fit in one Data
114 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
115 */
116 template<typename T>
117 void
118 sendDataset(const Name& prefix, const T& payload)
119 {
120 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
121
122 this->sendDatasetReply(prefix, payload.wireEncode());
123 }
124
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400125 /** \brief Send two WireEncodables in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000126 * \param prefix dataset prefix without version and segment
127 * \param payload1 first vector item
128 * \param payload2 second vector item
129 * \note all payloads must fit in one Data
130 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
131 */
132 template<typename T1, typename T2>
133 void
134 sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
135 {
136 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
137 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
138
139 ndn::encoding::EncodingBuffer buffer;
140 payload2.wireEncode(buffer);
141 payload1.wireEncode(buffer);
142
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500143 this->sendDatasetReply(prefix, buffer);
Junxiao Shicb766862017-07-07 22:21:04 +0000144 }
145
146private:
147 virtual void
148 processEventsOverride(time::milliseconds timeout)
149 {
Davide Pesavento17057442018-04-20 15:21:31 -0400150 if (timeout <= 0_ms) {
Junxiao Shicb766862017-07-07 22:21:04 +0000151 // give enough time to finish execution
Davide Pesavento17057442018-04-20 15:21:31 -0400152 timeout = 30_s;
Junxiao Shicb766862017-07-07 22:21:04 +0000153 }
Davide Pesavento17057442018-04-20 15:21:31 -0400154 this->advanceClocks(100_ms, timeout);
Junxiao Shicb766862017-07-07 22:21:04 +0000155 }
156
157 void
158 sendCommandReply(const Interest& interest, const ndn::nfd::ControlResponse& resp)
159 {
160 auto data = makeData(interest.getName());
161 data->setContent(resp.wireEncode());
162 face.receive(*data);
163 }
164
165 void
166 sendCommandReply(const Interest& interest, uint32_t code, const std::string& text,
167 const Block& body)
168 {
Davide Pesavento17057442018-04-20 15:21:31 -0400169 this->sendCommandReply(interest, ndn::nfd::ControlResponse(code, text).setBody(body));
Junxiao Shicb766862017-07-07 22:21:04 +0000170 }
171
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400172 /** \brief Send a payload in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000173 * \param name dataset prefix without version and segment
174 * \param contentArgs passed to Data::setContent
175 */
176 template<typename ...ContentArgs>
177 void
178 sendDatasetReply(Name name, ContentArgs&&... contentArgs)
179 {
180 name.appendVersion().appendSegment(0);
181
182 // These warnings assist in debugging when nfdc does not receive StatusDataset.
183 // They usually indicate a misspelled prefix or incorrect timing in the test case.
184 if (face.sentInterests.empty()) {
185 BOOST_WARN_MESSAGE(false, "no Interest expressed");
186 }
187 else {
188 BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
189 "last Interest " << face.sentInterests.back().getName() <<
190 " cannot be satisfied by this Data " << name);
191 }
192
193 auto data = make_shared<Data>(name);
Junxiao Shi73b49802019-05-25 07:52:26 +0000194 data->setFreshnessPeriod(1_s);
Davide Pesavento17057442018-04-20 15:21:31 -0400195 data->setFinalBlock(name[-1]);
Junxiao Shicb766862017-07-07 22:21:04 +0000196 data->setContent(std::forward<ContentArgs>(contentArgs)...);
197 this->signDatasetReply(*data);
198 face.receive(*data);
199 }
200
201 virtual void
202 signDatasetReply(Data& data)
203 {
204 signData(data);
205 }
206
Junxiao Shicb766862017-07-07 22:21:04 +0000207protected:
Davide Pesaventoae430302023-05-11 01:42:46 -0400208 ndn::DummyClientFace face;
Junxiao Shicb766862017-07-07 22:21:04 +0000209 std::function<void(const Interest&)> processInterest;
210};
211
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400212} // namespace nfd::tests
Junxiao Shicb766862017-07-07 22:21:04 +0000213
Davide Pesavento20cafa82022-07-25 01:15:03 -0400214/**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400215 * \brief Require the command in \p interest to have the expected prefix.
Davide Pesavento20cafa82022-07-25 01:15:03 -0400216 * \note This must be used in the `processInterest` lambda, and the Interest must be named `interest`.
217 * \return ControlParameters. The test case will fail if \p interest does not match \p expectedPrefix.
Junxiao Shicb766862017-07-07 22:21:04 +0000218 */
219#define MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix) \
Davide Pesavento20cafa82022-07-25 01:15:03 -0400220 [&interest] { \
Junxiao Shicb766862017-07-07 22:21:04 +0000221 auto params = parseCommand(interest, (expectedPrefix)); \
Davide Pesavento20cafa82022-07-25 01:15:03 -0400222 BOOST_REQUIRE_MESSAGE(params.has_value(), "Interest " << interest.getName() << \
Junxiao Shicb766862017-07-07 22:21:04 +0000223 " does not match command prefix " << (expectedPrefix)); \
224 return *params; \
225 } ()
226
227#endif // NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP