blob: 82ab19a52236f8a3513c1ac05ec81a3ab6c9889b [file] [log] [blame]
Junxiao Shicb766862017-07-07 22:21:04 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesaventoa599d2a2022-02-16 18:52:43 -05003 * Copyright (c) 2014-2022, 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 Pesaventocf9e1c72019-12-22 17:56:07 -050037#include <boost/concept/assert.hpp>
38
Junxiao Shicb766862017-07-07 22:21:04 +000039namespace nfd {
40namespace tools {
41namespace tests {
42
43using namespace nfd::tests;
44using ndn::nfd::ControlParameters;
45
Davide Pesaventob7703ad2019-03-23 21:12:56 -040046/** \brief Fixture to emulate NFD management.
Junxiao Shicb766862017-07-07 22:21:04 +000047 */
Davide Pesavento21353752020-11-20 00:43:44 -050048class MockNfdMgmtFixture : public IoFixture, public KeyChainFixture
Junxiao Shicb766862017-07-07 22:21:04 +000049{
50protected:
51 MockNfdMgmtFixture()
Davide Pesavento21353752020-11-20 00:43:44 -050052 : face(m_io, m_keyChain,
Davide Pesavento412c9822021-07-02 00:21:05 -040053 {true, false, std::bind(&MockNfdMgmtFixture::processEventsOverride, this, _1)})
Junxiao Shicb766862017-07-07 22:21:04 +000054 {
Davide Pesaventob7703ad2019-03-23 21:12:56 -040055 face.onSendInterest.connect([this] (const Interest& interest) {
56 if (processInterest) {
57 m_io.post([=] { processInterest(interest); });
58 }
Junxiao Shicb766862017-07-07 22:21:04 +000059 });
60 }
61
Junxiao Shicb766862017-07-07 22:21:04 +000062protected: // ControlCommand
63 /** \brief check the Interest is a command with specified prefix
64 * \retval nullopt last Interest is not the expected command
65 * \return command parameters
66 */
Davide Pesavento87fc0f82018-04-11 23:43:51 -040067 static optional<ControlParameters>
Junxiao Shicb766862017-07-07 22:21:04 +000068 parseCommand(const Interest& interest, const Name& expectedPrefix)
69 {
70 if (!expectedPrefix.isPrefixOf(interest.getName())) {
Davide Pesavento87fc0f82018-04-11 23:43:51 -040071 return nullopt;
Junxiao Shicb766862017-07-07 22:21:04 +000072 }
73 return ControlParameters(interest.getName().at(expectedPrefix.size()).blockFromValue());
74 }
75
76 /** \brief send successful response to a command Interest
77 */
78 void
79 succeedCommand(const Interest& interest, const ControlParameters& parameters)
80 {
81 this->sendCommandReply(interest, 200, "OK", parameters.wireEncode());
82 }
83
84 /** \brief send failure response to a command Interest
85 */
86 void
87 failCommand(const Interest& interest, uint32_t code, const std::string& text)
88 {
89 this->sendCommandReply(interest, {code, text});
90 }
91
92 /** \brief send failure response to a command Interest
93 */
94 void
95 failCommand(const Interest& interest, uint32_t code, const std::string& text, const ControlParameters& body)
96 {
97 this->sendCommandReply(interest, code, text, body.wireEncode());
98 }
99
100protected: // StatusDataset
101 /** \brief send an empty dataset in reply to StatusDataset request
102 * \param prefix dataset prefix without version and segment
103 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
104 */
105 void
106 sendEmptyDataset(const Name& prefix)
107 {
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500108 this->sendDatasetReply(prefix, span<uint8_t>{});
Junxiao Shicb766862017-07-07 22:21:04 +0000109 }
110
111 /** \brief send one WireEncodable in reply to StatusDataset request
112 * \param prefix dataset prefix without version and segment
113 * \param payload payload block
114 * \note payload must fit in one Data
115 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
116 */
117 template<typename T>
118 void
119 sendDataset(const Name& prefix, const T& payload)
120 {
121 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
122
123 this->sendDatasetReply(prefix, payload.wireEncode());
124 }
125
126 /** \brief send two WireEncodables in reply to StatusDataset request
127 * \param prefix dataset prefix without version and segment
128 * \param payload1 first vector item
129 * \param payload2 second vector item
130 * \note all payloads must fit in one Data
131 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
132 */
133 template<typename T1, typename T2>
134 void
135 sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
136 {
137 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
138 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
139
140 ndn::encoding::EncodingBuffer buffer;
141 payload2.wireEncode(buffer);
142 payload1.wireEncode(buffer);
143
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500144 this->sendDatasetReply(prefix, buffer);
Junxiao Shicb766862017-07-07 22:21:04 +0000145 }
146
147private:
148 virtual void
149 processEventsOverride(time::milliseconds timeout)
150 {
Davide Pesavento17057442018-04-20 15:21:31 -0400151 if (timeout <= 0_ms) {
Junxiao Shicb766862017-07-07 22:21:04 +0000152 // give enough time to finish execution
Davide Pesavento17057442018-04-20 15:21:31 -0400153 timeout = 30_s;
Junxiao Shicb766862017-07-07 22:21:04 +0000154 }
Davide Pesavento17057442018-04-20 15:21:31 -0400155 this->advanceClocks(100_ms, timeout);
Junxiao Shicb766862017-07-07 22:21:04 +0000156 }
157
158 void
159 sendCommandReply(const Interest& interest, const ndn::nfd::ControlResponse& resp)
160 {
161 auto data = makeData(interest.getName());
162 data->setContent(resp.wireEncode());
163 face.receive(*data);
164 }
165
166 void
167 sendCommandReply(const Interest& interest, uint32_t code, const std::string& text,
168 const Block& body)
169 {
Davide Pesavento17057442018-04-20 15:21:31 -0400170 this->sendCommandReply(interest, ndn::nfd::ControlResponse(code, text).setBody(body));
Junxiao Shicb766862017-07-07 22:21:04 +0000171 }
172
173 /** \brief send a payload in reply to StatusDataset request
174 * \param name dataset prefix without version and segment
175 * \param contentArgs passed to Data::setContent
176 */
177 template<typename ...ContentArgs>
178 void
179 sendDatasetReply(Name name, ContentArgs&&... contentArgs)
180 {
181 name.appendVersion().appendSegment(0);
182
183 // These warnings assist in debugging when nfdc does not receive StatusDataset.
184 // They usually indicate a misspelled prefix or incorrect timing in the test case.
185 if (face.sentInterests.empty()) {
186 BOOST_WARN_MESSAGE(false, "no Interest expressed");
187 }
188 else {
189 BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
190 "last Interest " << face.sentInterests.back().getName() <<
191 " cannot be satisfied by this Data " << name);
192 }
193
194 auto data = make_shared<Data>(name);
Junxiao Shi73b49802019-05-25 07:52:26 +0000195 data->setFreshnessPeriod(1_s);
Davide Pesavento17057442018-04-20 15:21:31 -0400196 data->setFinalBlock(name[-1]);
Junxiao Shicb766862017-07-07 22:21:04 +0000197 data->setContent(std::forward<ContentArgs>(contentArgs)...);
198 this->signDatasetReply(*data);
199 face.receive(*data);
200 }
201
202 virtual void
203 signDatasetReply(Data& data)
204 {
205 signData(data);
206 }
207
Junxiao Shicb766862017-07-07 22:21:04 +0000208protected:
209 ndn::util::DummyClientFace face;
210 std::function<void(const Interest&)> processInterest;
211};
212
213} // namespace tests
214} // namespace tools
215} // namespace nfd
216
217/** \brief require the command in \p interest has expected prefix
218 * \note This must be used in processInterest lambda, and the Interest must be named 'interest'.
219 * \return ControlParameters, or nullopt if \p interest does match \p expectedPrefix
220 */
221#define MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix) \
222 [interest] { \
223 auto params = parseCommand(interest, (expectedPrefix)); \
224 BOOST_REQUIRE_MESSAGE(params, "Interest " << interest.getName() << \
225 " does not match command prefix " << (expectedPrefix)); \
226 return *params; \
227 } ()
228
229#endif // NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP