blob: ede5568ad5d49271739ccb1a38a0e69eac48ef2c [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 Pesaventocf9e1c72019-12-22 17:56:07 -050037#include <boost/concept/assert.hpp>
38
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040039namespace nfd::tests {
Junxiao Shicb766862017-07-07 22:21:04 +000040
Junxiao Shicb766862017-07-07 22:21:04 +000041using ndn::nfd::ControlParameters;
42
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040043/**
44 * \brief Fixture to emulate NFD management.
Junxiao Shicb766862017-07-07 22:21:04 +000045 */
Davide Pesavento21353752020-11-20 00:43:44 -050046class MockNfdMgmtFixture : public IoFixture, public KeyChainFixture
Junxiao Shicb766862017-07-07 22:21:04 +000047{
48protected:
49 MockNfdMgmtFixture()
Davide Pesavento21353752020-11-20 00:43:44 -050050 : face(m_io, m_keyChain,
Davide Pesavento412c9822021-07-02 00:21:05 -040051 {true, false, std::bind(&MockNfdMgmtFixture::processEventsOverride, this, _1)})
Junxiao Shicb766862017-07-07 22:21:04 +000052 {
Davide Pesaventob7703ad2019-03-23 21:12:56 -040053 face.onSendInterest.connect([this] (const Interest& interest) {
54 if (processInterest) {
55 m_io.post([=] { processInterest(interest); });
56 }
Junxiao Shicb766862017-07-07 22:21:04 +000057 });
58 }
59
Junxiao Shicb766862017-07-07 22:21:04 +000060protected: // ControlCommand
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040061 /** \brief Check the Interest is a command with specified prefix.
Junxiao Shicb766862017-07-07 22:21:04 +000062 * \retval nullopt last Interest is not the expected command
63 * \return command parameters
64 */
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040065 static std::optional<ControlParameters>
Junxiao Shicb766862017-07-07 22:21:04 +000066 parseCommand(const Interest& interest, const Name& expectedPrefix)
67 {
68 if (!expectedPrefix.isPrefixOf(interest.getName())) {
Davide Pesaventob7bfcb92022-05-22 23:55:23 -040069 return std::nullopt;
Junxiao Shicb766862017-07-07 22:21:04 +000070 }
71 return ControlParameters(interest.getName().at(expectedPrefix.size()).blockFromValue());
72 }
73
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040074 /** \brief Send successful response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000075 */
76 void
77 succeedCommand(const Interest& interest, const ControlParameters& parameters)
78 {
79 this->sendCommandReply(interest, 200, "OK", parameters.wireEncode());
80 }
81
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040082 /** \brief Send failure response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000083 */
84 void
85 failCommand(const Interest& interest, uint32_t code, const std::string& text)
86 {
87 this->sendCommandReply(interest, {code, text});
88 }
89
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040090 /** \brief Send failure response to a command Interest.
Junxiao Shicb766862017-07-07 22:21:04 +000091 */
92 void
93 failCommand(const Interest& interest, uint32_t code, const std::string& text, const ControlParameters& body)
94 {
95 this->sendCommandReply(interest, code, text, body.wireEncode());
96 }
97
98protected: // StatusDataset
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040099 /** \brief Send an empty dataset in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000100 * \param prefix dataset prefix without version and segment
101 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
102 */
103 void
104 sendEmptyDataset(const Name& prefix)
105 {
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500106 this->sendDatasetReply(prefix, span<uint8_t>{});
Junxiao Shicb766862017-07-07 22:21:04 +0000107 }
108
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400109 /** \brief Send one WireEncodable in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000110 * \param prefix dataset prefix without version and segment
111 * \param payload payload block
112 * \note payload must fit in one Data
113 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
114 */
115 template<typename T>
116 void
117 sendDataset(const Name& prefix, const T& payload)
118 {
119 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
120
121 this->sendDatasetReply(prefix, payload.wireEncode());
122 }
123
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400124 /** \brief Send two WireEncodables in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000125 * \param prefix dataset prefix without version and segment
126 * \param payload1 first vector item
127 * \param payload2 second vector item
128 * \note all payloads must fit in one Data
129 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
130 */
131 template<typename T1, typename T2>
132 void
133 sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
134 {
135 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
136 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
137
138 ndn::encoding::EncodingBuffer buffer;
139 payload2.wireEncode(buffer);
140 payload1.wireEncode(buffer);
141
Davide Pesaventoa599d2a2022-02-16 18:52:43 -0500142 this->sendDatasetReply(prefix, buffer);
Junxiao Shicb766862017-07-07 22:21:04 +0000143 }
144
145private:
146 virtual void
147 processEventsOverride(time::milliseconds timeout)
148 {
Davide Pesavento17057442018-04-20 15:21:31 -0400149 if (timeout <= 0_ms) {
Junxiao Shicb766862017-07-07 22:21:04 +0000150 // give enough time to finish execution
Davide Pesavento17057442018-04-20 15:21:31 -0400151 timeout = 30_s;
Junxiao Shicb766862017-07-07 22:21:04 +0000152 }
Davide Pesavento17057442018-04-20 15:21:31 -0400153 this->advanceClocks(100_ms, timeout);
Junxiao Shicb766862017-07-07 22:21:04 +0000154 }
155
156 void
157 sendCommandReply(const Interest& interest, const ndn::nfd::ControlResponse& resp)
158 {
159 auto data = makeData(interest.getName());
160 data->setContent(resp.wireEncode());
161 face.receive(*data);
162 }
163
164 void
165 sendCommandReply(const Interest& interest, uint32_t code, const std::string& text,
166 const Block& body)
167 {
Davide Pesavento17057442018-04-20 15:21:31 -0400168 this->sendCommandReply(interest, ndn::nfd::ControlResponse(code, text).setBody(body));
Junxiao Shicb766862017-07-07 22:21:04 +0000169 }
170
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400171 /** \brief Send a payload in reply to StatusDataset request.
Junxiao Shicb766862017-07-07 22:21:04 +0000172 * \param name dataset prefix without version and segment
173 * \param contentArgs passed to Data::setContent
174 */
175 template<typename ...ContentArgs>
176 void
177 sendDatasetReply(Name name, ContentArgs&&... contentArgs)
178 {
179 name.appendVersion().appendSegment(0);
180
181 // These warnings assist in debugging when nfdc does not receive StatusDataset.
182 // They usually indicate a misspelled prefix or incorrect timing in the test case.
183 if (face.sentInterests.empty()) {
184 BOOST_WARN_MESSAGE(false, "no Interest expressed");
185 }
186 else {
187 BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
188 "last Interest " << face.sentInterests.back().getName() <<
189 " cannot be satisfied by this Data " << name);
190 }
191
192 auto data = make_shared<Data>(name);
Junxiao Shi73b49802019-05-25 07:52:26 +0000193 data->setFreshnessPeriod(1_s);
Davide Pesavento17057442018-04-20 15:21:31 -0400194 data->setFinalBlock(name[-1]);
Junxiao Shicb766862017-07-07 22:21:04 +0000195 data->setContent(std::forward<ContentArgs>(contentArgs)...);
196 this->signDatasetReply(*data);
197 face.receive(*data);
198 }
199
200 virtual void
201 signDatasetReply(Data& data)
202 {
203 signData(data);
204 }
205
Junxiao Shicb766862017-07-07 22:21:04 +0000206protected:
Davide Pesaventoae430302023-05-11 01:42:46 -0400207 ndn::DummyClientFace face;
Junxiao Shicb766862017-07-07 22:21:04 +0000208 std::function<void(const Interest&)> processInterest;
209};
210
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400211} // namespace nfd::tests
Junxiao Shicb766862017-07-07 22:21:04 +0000212
Davide Pesavento20cafa82022-07-25 01:15:03 -0400213/**
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -0400214 * \brief Require the command in \p interest to have the expected prefix.
Davide Pesavento20cafa82022-07-25 01:15:03 -0400215 * \note This must be used in the `processInterest` lambda, and the Interest must be named `interest`.
216 * \return ControlParameters. The test case will fail if \p interest does not match \p expectedPrefix.
Junxiao Shicb766862017-07-07 22:21:04 +0000217 */
218#define MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix) \
Davide Pesavento20cafa82022-07-25 01:15:03 -0400219 [&interest] { \
Junxiao Shicb766862017-07-07 22:21:04 +0000220 auto params = parseCommand(interest, (expectedPrefix)); \
Davide Pesavento20cafa82022-07-25 01:15:03 -0400221 BOOST_REQUIRE_MESSAGE(params.has_value(), "Interest " << interest.getName() << \
Junxiao Shicb766862017-07-07 22:21:04 +0000222 " does not match command prefix " << (expectedPrefix)); \
223 return *params; \
224 } ()
225
226#endif // NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP