blob: 4d55849f25220e0973769cec2f4e94177d7f6a32 [file] [log] [blame]
Junxiao Shi1f481fa2017-01-26 15:14:43 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2017, Regents of the University of California,
4 * 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_NFDC_MOCK_NFD_MGMT_FIXTURE_HPP
27#define NFD_TESTS_TOOLS_NFDC_MOCK_NFD_MGMT_FIXTURE_HPP
28
29#include <ndn-cxx/util/dummy-client-face.hpp>
30
31#include "tests/test-common.hpp"
32#include "tests/identity-management-fixture.hpp"
33
34namespace nfd {
35namespace tools {
36namespace nfdc {
37namespace tests {
38
39using namespace nfd::tests;
Junxiao Shi1d7fef52017-02-02 05:33:14 +000040using ndn::nfd::ControlParameters;
Junxiao Shi1f481fa2017-01-26 15:14:43 +000041
42/** \brief fixture to emulate NFD management
43 */
44class MockNfdMgmtFixture : public IdentityManagementTimeFixture
45{
46protected:
47 MockNfdMgmtFixture()
48 : face(g_io, m_keyChain,
49 {true, false, bind(&MockNfdMgmtFixture::processEventsOverride, this, _1)})
50 {
51 face.onSendInterest.connect([=] (const Interest& interest) {
52 g_io.post([=] {
53 if (processInterest != nullptr) {
54 processInterest(interest);
55 }
56 });
57 });
58 }
59
Junxiao Shi1d7fef52017-02-02 05:33:14 +000060protected: // ControlCommand
61 /** \brief check the last Interest is a command with specified prefix
62 * \retval nullopt last Interest is not the expected command
63 * \return command parameters
64 */
65 ndn::optional<ControlParameters>
66 getCommand(const Name& expectedPrefix)
67 {
68 if (face.sentInterests.empty() ||
69 !expectedPrefix.isPrefixOf(face.sentInterests.back().getName())) {
70 return ndn::nullopt;
71 }
72 return ControlParameters(face.sentInterests.back().getName()
73 .at(expectedPrefix.size()).blockFromValue());
74 }
75
76 /** \brief respond to the last command
77 * \pre last Interest is a command
78 */
79 void
80 succeedCommand(const ControlParameters& parameters)
81 {
82 ndn::nfd::ControlResponse resp(200, "OK");
83 resp.setBody(parameters.wireEncode());
84 this->sendCommandReply(resp);
85 }
86
87 /** \brief respond to the last command
88 * \pre last Interest is a command
89 */
90 void
91 failCommand(uint32_t code, const std::string& text)
92 {
93 this->sendCommandReply({code, text});
94 }
95
96protected: // StatusDataset
Junxiao Shi1f481fa2017-01-26 15:14:43 +000097 /** \brief send an empty dataset in reply to StatusDataset request
98 * \param prefix dataset prefix without version and segment
99 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
100 */
101 void
102 sendEmptyDataset(const Name& prefix)
103 {
104 this->sendDatasetReply(prefix, nullptr, 0);
105 }
106
107 /** \brief send one WireEncodable in reply to StatusDataset request
108 * \param prefix dataset prefix without version and segment
109 * \param payload payload block
110 * \note payload must fit in one Data
111 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
112 */
113 template<typename T>
114 void
115 sendDataset(const Name& prefix, const T& payload)
116 {
117 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T>));
118
119 this->sendDatasetReply(prefix, payload.wireEncode());
120 }
121
122 /** \brief send two WireEncodables in reply to StatusDataset request
123 * \param prefix dataset prefix without version and segment
124 * \param payload1 first vector item
125 * \param payload2 second vector item
126 * \note all payloads must fit in one Data
127 * \pre Interest for dataset has been expressed, sendDataset has not been invoked
128 */
129 template<typename T1, typename T2>
130 void
131 sendDataset(const Name& prefix, const T1& payload1, const T2& payload2)
132 {
133 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T1>));
134 BOOST_CONCEPT_ASSERT((ndn::WireEncodable<T2>));
135
136 ndn::encoding::EncodingBuffer buffer;
137 payload2.wireEncode(buffer);
138 payload1.wireEncode(buffer);
139
140 this->sendDatasetReply(prefix, buffer.buf(), buffer.size());
141 }
142
143private:
144 virtual void
145 processEventsOverride(time::milliseconds timeout)
146 {
147 if (timeout <= time::milliseconds::zero()) {
148 // give enough time to finish execution
149 timeout = time::seconds(30);
150 }
151 this->advanceClocks(time::milliseconds(100), timeout);
152 }
153
Junxiao Shi1d7fef52017-02-02 05:33:14 +0000154 void
155 sendCommandReply(const ndn::nfd::ControlResponse& resp)
156 {
157 auto data = makeData(face.sentInterests.back().getName());
158 data->setContent(resp.wireEncode());
159 face.receive(*data);
160 }
161
Junxiao Shi1f481fa2017-01-26 15:14:43 +0000162 /** \brief send a payload in reply to StatusDataset request
163 * \param name dataset prefix without version and segment
164 * \param contentArgs passed to Data::setContent
165 */
166 template<typename ...ContentArgs>
167 void
168 sendDatasetReply(Name name, ContentArgs&&... contentArgs)
169 {
170 name.appendVersion().appendSegment(0);
171
172 // These warnings assist in debugging when nfdc does not receive StatusDataset.
173 // They usually indicate a misspelled prefix or incorrect timing in the test case.
174 if (face.sentInterests.empty()) {
175 BOOST_WARN_MESSAGE(false, "no Interest expressed");
176 }
177 else {
178 BOOST_WARN_MESSAGE(face.sentInterests.back().getName().isPrefixOf(name),
179 "last Interest " << face.sentInterests.back().getName() <<
180 " cannot be satisfied by this Data " << name);
181 }
182
183 auto data = make_shared<Data>(name);
184 data->setFinalBlockId(name[-1]);
185 data->setContent(std::forward<ContentArgs>(contentArgs)...);
186 this->signDatasetReply(*data);
187 face.receive(*data);
188 }
189
190 virtual void
191 signDatasetReply(Data& data)
192 {
193 signData(data);
194 }
195
196protected:
197 ndn::util::DummyClientFace face;
198 std::function<void(const Interest&)> processInterest;
199};
200
201} // namespace tests
202} // namespace nfdc
203} // namespace tools
204} // namespace nfd
205
Junxiao Shi1d7fef52017-02-02 05:33:14 +0000206#define MOCK_NFD_MGMT_REQUIRE_LAST_COMMAND_IS(expectedPrefix) \
207 [this] { \
208 BOOST_REQUIRE_MESSAGE(!face.sentInterests.empty(), "no Interest expressed"); \
209 auto params = this->getCommand(expectedPrefix); \
210 BOOST_REQUIRE_MESSAGE(params, "last Interest " << face.sentInterests.back().getName() << \
211 " does not match command prefix " << expectedPrefix); \
212 return *params; \
213 } ()
214
Junxiao Shi1f481fa2017-01-26 15:14:43 +0000215#endif // NFD_TESTS_TOOLS_NFDC_MOCK_NFD_MGMT_FIXTURE_HPP