blob: 40dc3baf264e8329b3feaac5372014b5e9de7838 [file] [log] [blame]
Junxiao Shicb766862017-07-07 22:21:04 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento1d12d2f2019-03-22 12:44:14 -04003 * Copyright (c) 2014-2019, 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 Pesaventob7703ad2019-03-23 21:12:56 -040029#include "tests/clock-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 Pesaventob7703ad2019-03-23 21:12:56 -040048class MockNfdMgmtFixture : public ClockFixture, public KeyChainFixture
Junxiao Shicb766862017-07-07 22:21:04 +000049{
50protected:
51 MockNfdMgmtFixture()
Davide Pesaventob7703ad2019-03-23 21:12:56 -040052 : ClockFixture(m_io)
53 , face(m_io, m_keyChain,
Junxiao Shicb766862017-07-07 22:21:04 +000054 {true, false, bind(&MockNfdMgmtFixture::processEventsOverride, this, _1)})
55 {
Davide Pesaventob7703ad2019-03-23 21:12:56 -040056 face.onSendInterest.connect([this] (const Interest& interest) {
57 if (processInterest) {
58 m_io.post([=] { processInterest(interest); });
59 }
Junxiao Shicb766862017-07-07 22:21:04 +000060 });
61 }
62
Junxiao Shicb766862017-07-07 22:21:04 +000063protected: // ControlCommand
64 /** \brief check the Interest is a command with specified prefix
65 * \retval nullopt last Interest is not the expected command
66 * \return command parameters
67 */
Davide Pesavento87fc0f82018-04-11 23:43:51 -040068 static optional<ControlParameters>
Junxiao Shicb766862017-07-07 22:21:04 +000069 parseCommand(const Interest& interest, const Name& expectedPrefix)
70 {
71 if (!expectedPrefix.isPrefixOf(interest.getName())) {
Davide Pesavento87fc0f82018-04-11 23:43:51 -040072 return nullopt;
Junxiao Shicb766862017-07-07 22:21:04 +000073 }
74 return ControlParameters(interest.getName().at(expectedPrefix.size()).blockFromValue());
75 }
76
77 /** \brief send successful response to a command Interest
78 */
79 void
80 succeedCommand(const Interest& interest, const ControlParameters& parameters)
81 {
82 this->sendCommandReply(interest, 200, "OK", parameters.wireEncode());
83 }
84
85 /** \brief send failure response to a command Interest
86 */
87 void
88 failCommand(const Interest& interest, uint32_t code, const std::string& text)
89 {
90 this->sendCommandReply(interest, {code, text});
91 }
92
93 /** \brief send failure response to a command Interest
94 */
95 void
96 failCommand(const Interest& interest, uint32_t code, const std::string& text, const ControlParameters& body)
97 {
98 this->sendCommandReply(interest, code, text, body.wireEncode());
99 }
100
101protected: // StatusDataset
102 /** \brief send an empty dataset in reply to StatusDataset request
103 * \param prefix dataset prefix without version and segment
104 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
105 */
106 void
107 sendEmptyDataset(const Name& prefix)
108 {
109 this->sendDatasetReply(prefix, nullptr, 0);
110 }
111
112 /** \brief send one WireEncodable in reply to StatusDataset request
113 * \param prefix dataset prefix without version and segment
114 * \param payload payload block
115 * \note payload must fit in one Data
116 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
117 */
118 template<typename T>
119 void
120 sendDataset(const Name& prefix, const T& payload)
121 {
122 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
123
124 this->sendDatasetReply(prefix, payload.wireEncode());
125 }
126
127 /** \brief send two WireEncodables in reply to StatusDataset request
128 * \param prefix dataset prefix without version and segment
129 * \param payload1 first vector item
130 * \param payload2 second vector item
131 * \note all payloads must fit in one Data
132 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
133 */
134 template<typename T1, typename T2>
135 void
136 sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
137 {
138 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
139 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
140
141 ndn::encoding::EncodingBuffer buffer;
142 payload2.wireEncode(buffer);
143 payload1.wireEncode(buffer);
144
145 this->sendDatasetReply(prefix, buffer.buf(), buffer.size());
146 }
147
148private:
149 virtual void
150 processEventsOverride(time::milliseconds timeout)
151 {
Davide Pesavento17057442018-04-20 15:21:31 -0400152 if (timeout <= 0_ms) {
Junxiao Shicb766862017-07-07 22:21:04 +0000153 // give enough time to finish execution
Davide Pesavento17057442018-04-20 15:21:31 -0400154 timeout = 30_s;
Junxiao Shicb766862017-07-07 22:21:04 +0000155 }
Davide Pesavento17057442018-04-20 15:21:31 -0400156 this->advanceClocks(100_ms, timeout);
Junxiao Shicb766862017-07-07 22:21:04 +0000157 }
158
159 void
160 sendCommandReply(const Interest& interest, const ndn::nfd::ControlResponse& resp)
161 {
162 auto data = makeData(interest.getName());
163 data->setContent(resp.wireEncode());
164 face.receive(*data);
165 }
166
167 void
168 sendCommandReply(const Interest& interest, uint32_t code, const std::string& text,
169 const Block& body)
170 {
Davide Pesavento17057442018-04-20 15:21:31 -0400171 this->sendCommandReply(interest, ndn::nfd::ControlResponse(code, text).setBody(body));
Junxiao Shicb766862017-07-07 22:21:04 +0000172 }
173
174 /** \brief send a payload in reply to StatusDataset request
175 * \param name dataset prefix without version and segment
176 * \param contentArgs passed to Data::setContent
177 */
178 template<typename ...ContentArgs>
179 void
180 sendDatasetReply(Name name, ContentArgs&&... contentArgs)
181 {
182 name.appendVersion().appendSegment(0);
183
184 // These warnings assist in debugging when nfdc does not receive StatusDataset.
185 // They usually indicate a misspelled prefix or incorrect timing in the test case.
186 if (face.sentInterests.empty()) {
187 BOOST_WARN_MESSAGE(false, "no Interest expressed");
188 }
189 else {
190 BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
191 "last Interest " << face.sentInterests.back().getName() <<
192 " cannot be satisfied by this Data " << name);
193 }
194
195 auto data = make_shared<Data>(name);
Junxiao Shi73b49802019-05-25 07:52:26 +0000196 data->setFreshnessPeriod(1_s);
Davide Pesavento17057442018-04-20 15:21:31 -0400197 data->setFinalBlock(name[-1]);
Junxiao Shicb766862017-07-07 22:21:04 +0000198 data->setContent(std::forward<ContentArgs>(contentArgs)...);
199 this->signDatasetReply(*data);
200 face.receive(*data);
201 }
202
203 virtual void
204 signDatasetReply(Data& data)
205 {
206 signData(data);
207 }
208
Davide Pesaventob7703ad2019-03-23 21:12:56 -0400209private:
210 boost::asio::io_service m_io;
211
Junxiao Shicb766862017-07-07 22:21:04 +0000212protected:
213 ndn::util::DummyClientFace face;
214 std::function<void(const Interest&)> processInterest;
215};
216
217} // namespace tests
218} // namespace tools
219} // namespace nfd
220
221/** \brief require the command in \p interest has expected prefix
222 * \note This must be used in processInterest lambda, and the Interest must be named 'interest'.
223 * \return ControlParameters, or nullopt if \p interest does match \p expectedPrefix
224 */
225#define MOCK_NFD_MGMT_REQUIRE_COMMAND_IS(expectedPrefix) \
226 [interest] { \
227 auto params = parseCommand(interest, (expectedPrefix)); \
228 BOOST_REQUIRE_MESSAGE(params, "Interest " << interest.getName() << \
229 " does not match command prefix " << (expectedPrefix)); \
230 return *params; \
231 } ()
232
233#endif // NFD_TESTS_TOOLS_MOCK_NFD_MGMT_FIXTURE_HPP