blob: 6379003dd1afe27f8cc50583cec573e8844382f6 [file] [log] [blame]
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shic542f632017-07-18 14:20:32 +00002/*
Davide Pesaventocb385e32024-12-27 15:22:02 -05003 * Copyright (c) 2013-2025 Regents of the University of California.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07004 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07005 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07006 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070010 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070011 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070014 *
Alexander Afanasyev80b68e12015-09-17 17:01:04 -070015 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070020 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/mgmt/dispatcher.hpp"
Davide Pesaventocb385e32024-12-27 15:22:02 -050023#include "ndn-cxx/mgmt/nfd/control-command.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/util/dummy-client-face.hpp"
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070025
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050026#include "tests/test-common.hpp"
27#include "tests/unit/io-key-chain-fixture.hpp"
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070028
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040029namespace ndn::tests {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070030
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040031using namespace ndn::mgmt;
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070032
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050033class DispatcherFixture : public IoKeyChainFixture
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070034{
Davide Pesavento54dfc4a2024-12-26 17:30:41 -050035protected:
36 DummyClientFace face{m_io, m_keyChain, {true, true}};
37 Dispatcher dispatcher{face, m_keyChain};
38 InMemoryStorageFifo& storage{dispatcher.m_storage};
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070039};
40
Davide Pesavento0e13ed32024-12-28 15:01:25 -050041class VoidParameters : public ControlParametersBase
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070042{
43public:
44 explicit
45 VoidParameters(const Block& wire)
46 {
47 wireDecode(wire);
48 }
49
Junxiao Shid97c9532017-04-27 16:17:04 +000050 Block
Davide Pesaventoaa82eb62016-04-22 19:08:40 +020051 wireEncode() const final
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070052 {
53 return Block(128);
54 }
55
Junxiao Shid97c9532017-04-27 16:17:04 +000056 void
Davide Pesaventoaa82eb62016-04-22 19:08:40 +020057 wireDecode(const Block& wire) final
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070058 {
59 if (wire.type() != 128)
Davide Pesavento923ba442019-02-12 22:00:38 -050060 NDN_THROW(tlv::Error("Expecting TLV type 128"));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070061 }
62};
63
64static Authorization
65makeTestAuthorization()
66{
Davide Pesavento0e13ed32024-12-28 15:01:25 -050067 return [] (const Name&, const Interest& interest, const ControlParametersBase*,
Davide Pesavento3c34ec12021-03-28 21:50:06 -040068 AcceptContinuation accept, RejectContinuation reject) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070069 if (interest.getName()[-1] == name::Component("valid")) {
70 accept("");
71 }
72 else {
73 if (interest.getName()[-1] == name::Component("silent")) {
74 reject(RejectReply::SILENT);
75 }
76 else {
77 reject(RejectReply::STATUS403);
78 }
79 }
80 };
81}
82
Junxiao Shid97c9532017-04-27 16:17:04 +000083BOOST_AUTO_TEST_SUITE(Mgmt)
84BOOST_FIXTURE_TEST_SUITE(TestDispatcher, DispatcherFixture)
85
86BOOST_AUTO_TEST_CASE(Basic)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070087{
Davide Pesaventocb385e32024-12-27 15:22:02 -050088 auto nop = [] (auto&&...) {};
89 auto tautology = [] (auto&&...) { return true; };
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070090
Davide Pesaventocb385e32024-12-27 15:22:02 -050091 BOOST_CHECK_NO_THROW(dispatcher
92 .addControlCommand<VoidParameters>("test/1", makeAcceptAllAuthorization(),
93 tautology, nop));
94 BOOST_CHECK_NO_THROW(dispatcher
95 .addControlCommand<VoidParameters>("test/2", makeAcceptAllAuthorization(),
96 tautology, nop));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070097 BOOST_CHECK_THROW(dispatcher
Davide Pesaventocb385e32024-12-27 15:22:02 -050098 .addControlCommand<VoidParameters>("test", makeAcceptAllAuthorization(),
99 tautology, nop),
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700100 std::out_of_range);
101
Davide Pesaventocb385e32024-12-27 15:22:02 -0500102 BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/1", makeAcceptAllAuthorization(), nop));
103 BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/2", makeAcceptAllAuthorization(), nop));
104 BOOST_CHECK_THROW(dispatcher.addStatusDataset("status", makeAcceptAllAuthorization(), nop),
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700105 std::out_of_range);
106
107 BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/1"));
108 BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/2"));
109 BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream"), std::out_of_range);
110
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700111 BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/1"));
112 BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/2"));
113 BOOST_CHECK_THROW(dispatcher.addTopPrefix("/root"), std::out_of_range);
114
115 BOOST_CHECK_THROW(dispatcher
Davide Pesaventocb385e32024-12-27 15:22:02 -0500116 .addControlCommand<VoidParameters>("test/3", makeAcceptAllAuthorization(),
117 tautology, nop),
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700118 std::domain_error);
119
Davide Pesaventocb385e32024-12-27 15:22:02 -0500120 BOOST_CHECK_THROW(dispatcher.addStatusDataset("status/3", makeAcceptAllAuthorization(), nop),
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700121 std::domain_error);
122
123 BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream/3"), std::domain_error);
124}
125
Junxiao Shid97c9532017-04-27 16:17:04 +0000126BOOST_AUTO_TEST_CASE(AddRemoveTopPrefix)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700127{
128 std::map<std::string, size_t> nCallbackCalled;
129 dispatcher
130 .addControlCommand<VoidParameters>("test/1", makeAcceptAllAuthorization(),
Davide Pesaventocb385e32024-12-27 15:22:02 -0500131 [] (auto&&...) { return true; },
132 [&nCallbackCalled] (auto&&...) { ++nCallbackCalled["test/1"]; });
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700133
134 dispatcher
135 .addControlCommand<VoidParameters>("test/2", makeAcceptAllAuthorization(),
Davide Pesaventocb385e32024-12-27 15:22:02 -0500136 [] (auto&&...) { return true; },
137 [&nCallbackCalled] (auto&&...) { ++nCallbackCalled["test/2"]; });
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700138
Junxiao Shi85d90832016-08-04 03:19:46 +0000139 face.receive(*makeInterest("/root/1/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500140 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700141 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 0);
142 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0);
143
144 dispatcher.addTopPrefix("/root/1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500145 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700146
Junxiao Shi85d90832016-08-04 03:19:46 +0000147 face.receive(*makeInterest("/root/1/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500148 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700149 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
150 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0);
151
Junxiao Shi85d90832016-08-04 03:19:46 +0000152 face.receive(*makeInterest("/root/1/test/2/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500153 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700154 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
155 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1);
156
Junxiao Shi85d90832016-08-04 03:19:46 +0000157 face.receive(*makeInterest("/root/2/test/1/%80%00"));
158 face.receive(*makeInterest("/root/2/test/2/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500159 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700160 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
161 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1);
162
163 dispatcher.addTopPrefix("/root/2");
Davide Pesavento0f830802018-01-16 23:58:58 -0500164 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700165
Junxiao Shi85d90832016-08-04 03:19:46 +0000166 face.receive(*makeInterest("/root/1/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500167 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700168 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 2);
169
Junxiao Shi85d90832016-08-04 03:19:46 +0000170 face.receive(*makeInterest("/root/2/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500171 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700172 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3);
173
174 dispatcher.removeTopPrefix("/root/1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500175 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700176
Junxiao Shi85d90832016-08-04 03:19:46 +0000177 face.receive(*makeInterest("/root/1/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500178 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700179 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3);
180
Junxiao Shi85d90832016-08-04 03:19:46 +0000181 face.receive(*makeInterest("/root/2/test/1/%80%00"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500182 advanceClocks(1_ms);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700183 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 4);
184}
185
Davide Pesaventocb385e32024-12-27 15:22:02 -0500186BOOST_AUTO_TEST_CASE(ControlCommandOld,
187 * ut::description("test old-style ControlCommand registration"))
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700188{
189 size_t nCallbackCalled = 0;
Davide Pesaventocb385e32024-12-27 15:22:02 -0500190 auto handler = [&nCallbackCalled] (auto&&...) { ++nCallbackCalled; };
191 dispatcher.addControlCommand<VoidParameters>("test", makeTestAuthorization(),
192 [] (auto&&...) { return true; }, std::move(handler));
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700193
194 dispatcher.addTopPrefix("/root");
Davide Pesavento0f830802018-01-16 23:58:58 -0500195 advanceClocks(1_ms);
Davide Pesaventocb385e32024-12-27 15:22:02 -0500196 BOOST_REQUIRE_EQUAL(face.sentData.size(), 0);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700197
Junxiao Shi85d90832016-08-04 03:19:46 +0000198 face.receive(*makeInterest("/root/test/%80%00")); // returns 403
199 face.receive(*makeInterest("/root/test/%80%00/invalid")); // returns 403
200 face.receive(*makeInterest("/root/test/%80%00/silent")); // silently ignored
201 face.receive(*makeInterest("/root/test/.../invalid")); // silently ignored (wrong format)
202 face.receive(*makeInterest("/root/test/.../valid")); // silently ignored (wrong format)
Davide Pesavento0f830802018-01-16 23:58:58 -0500203 advanceClocks(1_ms, 20);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700204 BOOST_CHECK_EQUAL(nCallbackCalled, 0);
Davide Pesaventocb385e32024-12-27 15:22:02 -0500205 BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700206
Junxiao Shi72c0c642018-04-20 15:41:09 +0000207 BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800208 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000209 BOOST_CHECK_EQUAL(face.sentData[1].getContentType(), tlv::ContentType_Blob);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800210 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700211
Junxiao Shi85d90832016-08-04 03:19:46 +0000212 face.receive(*makeInterest("/root/test/%80%00/valid"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500213 advanceClocks(1_ms, 10);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700214 BOOST_CHECK_EQUAL(nCallbackCalled, 1);
215}
216
Davide Pesaventocb385e32024-12-27 15:22:02 -0500217BOOST_AUTO_TEST_CASE(ControlCommandNew,
218 * ut::description("test new-style ControlCommand registration"))
219{
220 size_t nHandlerCalled = 0;
221 auto handler = [&nHandlerCalled] (auto&&...) { ++nHandlerCalled; };
222
223 // test addControlCommand()
224 dispatcher.addControlCommand<nfd::FaceCreateCommand>(makeAcceptAllAuthorization(), handler);
225 dispatcher.addControlCommand<nfd::FaceUpdateCommand>(makeAcceptAllAuthorization(), handler);
226 dispatcher.addControlCommand<nfd::FaceDestroyCommand>(makeAcceptAllAuthorization(), handler);
227 dispatcher.addControlCommand<nfd::FibAddNextHopCommand>(makeAcceptAllAuthorization(), handler);
228 dispatcher.addControlCommand<nfd::FibRemoveNextHopCommand>(makeAcceptAllAuthorization(), handler);
229 dispatcher.addControlCommand<nfd::CsConfigCommand>(makeAcceptAllAuthorization(), handler);
230 dispatcher.addControlCommand<nfd::CsEraseCommand>(makeAcceptAllAuthorization(), handler);
231 dispatcher.addControlCommand<nfd::StrategyChoiceSetCommand>(makeAcceptAllAuthorization(), handler);
232 dispatcher.addControlCommand<nfd::StrategyChoiceUnsetCommand>(makeAcceptAllAuthorization(), handler);
233 dispatcher.addControlCommand<nfd::RibRegisterCommand>(makeAcceptAllAuthorization(), handler);
234 dispatcher.addControlCommand<nfd::RibUnregisterCommand>(makeAcceptAllAuthorization(), handler);
jaczhi82d8ed02025-01-07 15:51:02 -0800235 dispatcher.addControlCommand<nfd::RibAnnounceCommand>(makeAcceptAllAuthorization(), handler);
Davide Pesaventocb385e32024-12-27 15:22:02 -0500236
237 BOOST_CHECK_THROW(dispatcher.addControlCommand<nfd::CsConfigCommand>(makeAcceptAllAuthorization(),
238 [] (auto&&...) {}),
239 std::out_of_range);
240
241 dispatcher.addTopPrefix("/root");
242 advanceClocks(1_ms);
243 BOOST_REQUIRE_EQUAL(face.sentData.size(), 0);
244
245 BOOST_CHECK_THROW(dispatcher.addControlCommand<nfd::CsConfigCommand>(makeAcceptAllAuthorization(),
246 [] (auto&&...) {}),
247 std::domain_error);
248
249 // we pick FaceDestroyCommand as an example for the following tests
250
251 // malformed request (missing ControlParameters) => silently ignored
252 auto baseName = Name("/root").append(nfd::FaceDestroyCommand::getName());
253 auto interest = makeInterest(baseName);
254 face.receive(*interest);
255 advanceClocks(1_ms);
256 BOOST_CHECK_EQUAL(nHandlerCalled, 0);
257 BOOST_CHECK_EQUAL(face.sentData.size(), 0);
258
259 // ControlParameters present but invalid (missing required field) => reply with error 400
260 nfd::ControlParameters params;
261 interest->setName(Name(baseName).append(params.wireEncode()));
262 face.receive(*interest);
263 advanceClocks(1_ms);
264 BOOST_CHECK_EQUAL(nHandlerCalled, 0);
265 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
266 BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob);
267 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 400);
268
269 // valid request
270 params.setFaceId(42);
271 interest->setName(Name(baseName).append(params.wireEncode()));
272 face.receive(*interest);
273 advanceClocks(1_ms);
274 BOOST_CHECK_EQUAL(nHandlerCalled, 1);
275 BOOST_CHECK_EQUAL(face.sentData.size(), 1);
276}
277
278BOOST_AUTO_TEST_CASE(ControlCommandResponse)
279{
280 auto handler = [] (const Name& prefix, const Interest& interest,
Davide Pesavento0e13ed32024-12-28 15:01:25 -0500281 const ControlParametersBase&, const CommandContinuation& done) {
Davide Pesaventocb385e32024-12-27 15:22:02 -0500282 BOOST_CHECK_EQUAL(prefix, "/root");
283 BOOST_CHECK_EQUAL(interest.getName().getPrefix(3),
284 Name("/root").append(nfd::CsConfigCommand::getName()));
285 done(ControlResponse(42, "the answer"));
286 };
287
288 // use CsConfigCommand as an example
289 dispatcher.addControlCommand<nfd::CsConfigCommand>(makeAcceptAllAuthorization(), handler);
290 dispatcher.addTopPrefix("/root");
291 advanceClocks(1_ms);
292 BOOST_REQUIRE_EQUAL(face.sentData.size(), 0);
293
294 nfd::ControlParameters params;
295 auto interest = makeInterest(Name("/root")
296 .append(nfd::CsConfigCommand::getName())
297 .append(params.wireEncode()));
298 face.receive(*interest);
299 advanceClocks(1_ms, 10);
300
301 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
302 BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob);
303 ControlResponse resp(face.sentData[0].getContent().blockFromValue());
304 BOOST_CHECK_EQUAL(resp.getCode(), 42);
305 BOOST_CHECK_EQUAL(resp.getText(), "the answer");
306}
307
Davide Pesavento0e13ed32024-12-28 15:01:25 -0500308class StatefulParameters : public ControlParametersBase
Junxiao Shid97c9532017-04-27 16:17:04 +0000309{
310public:
311 explicit
312 StatefulParameters(const Block& wire)
313 {
314 wireDecode(wire);
315 }
316
317 Block
318 wireEncode() const final
319 {
Davide Pesaventofbea4fc2022-02-08 07:26:04 -0500320 return {};
Junxiao Shid97c9532017-04-27 16:17:04 +0000321 }
322
323 void
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400324 wireDecode(const Block&) final
Junxiao Shid97c9532017-04-27 16:17:04 +0000325 {
326 m_state = EXPECTED_STATE;
327 }
328
329 bool
330 check() const
331 {
332 return m_state == EXPECTED_STATE;
333 }
334
335private:
336 static constexpr int EXPECTED_STATE = 12602;
337 int m_state = 0;
338};
339
Davide Pesavento0c526032024-01-31 21:14:01 -0500340BOOST_AUTO_TEST_CASE(ControlCommandAsyncAuthorization,
341 * ut::description("test for bug #4059"))
Junxiao Shid97c9532017-04-27 16:17:04 +0000342{
343 AcceptContinuation authorizationAccept;
Davide Pesavento0e13ed32024-12-28 15:01:25 -0500344 auto authorization = [&authorizationAccept] (const Name&, const Interest&, const ControlParametersBase*,
Davide Pesavento54dfc4a2024-12-26 17:30:41 -0500345 AcceptContinuation accept, RejectContinuation) {
346 authorizationAccept = std::move(accept);
347 };
Junxiao Shid97c9532017-04-27 16:17:04 +0000348
Davide Pesavento0e13ed32024-12-28 15:01:25 -0500349 auto validateParameters = [] (const ControlParametersBase& params) {
Davide Pesavento54dfc4a2024-12-26 17:30:41 -0500350 return dynamic_cast<const StatefulParameters&>(params).check();
351 };
Junxiao Shid97c9532017-04-27 16:17:04 +0000352
353 size_t nCallbackCalled = 0;
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400354 dispatcher.addControlCommand<StatefulParameters>("test", authorization, validateParameters,
Davide Pesaventocb385e32024-12-27 15:22:02 -0500355 [&nCallbackCalled] (auto&&...) { ++nCallbackCalled; });
Junxiao Shid97c9532017-04-27 16:17:04 +0000356
357 dispatcher.addTopPrefix("/root");
Davide Pesavento0f830802018-01-16 23:58:58 -0500358 advanceClocks(1_ms);
Junxiao Shid97c9532017-04-27 16:17:04 +0000359
360 face.receive(*makeInterest("/root/test/%80%00"));
361 BOOST_CHECK_EQUAL(nCallbackCalled, 0);
362 BOOST_REQUIRE(authorizationAccept != nullptr);
363
Davide Pesavento0f830802018-01-16 23:58:58 -0500364 advanceClocks(1_ms);
Junxiao Shid97c9532017-04-27 16:17:04 +0000365 authorizationAccept("");
Davide Pesavento0f830802018-01-16 23:58:58 -0500366 advanceClocks(1_ms);
Junxiao Shid97c9532017-04-27 16:17:04 +0000367 BOOST_CHECK_EQUAL(nCallbackCalled, 1);
368}
369
370BOOST_AUTO_TEST_CASE(StatusDataset)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700371{
Davide Pesaventofbea4fc2022-02-08 07:26:04 -0500372 const Block smallBlock({0x81, 0x01, 0x01});
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400373 const Block largeBlock = [] {
374 Block b(129, std::make_shared<const Buffer>(3000));
375 b.encode();
376 return b;
377 }();
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700378
379 dispatcher.addStatusDataset("test/small",
380 makeTestAuthorization(),
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400381 [&smallBlock] (const Name&, const Interest&,
Davide Pesaventob10024c2017-09-22 01:36:44 -0400382 StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700383 context.append(smallBlock);
384 context.append(smallBlock);
385 context.append(smallBlock);
386 context.end();
387 });
388
389 dispatcher.addStatusDataset("test/large",
390 makeTestAuthorization(),
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400391 [&largeBlock] (const Name&, const Interest&,
Davide Pesaventob10024c2017-09-22 01:36:44 -0400392 StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700393 context.append(largeBlock);
394 context.append(largeBlock);
395 context.append(largeBlock);
396 context.end();
397 });
398
399 dispatcher.addStatusDataset("test/reject",
400 makeTestAuthorization(),
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400401 [] (const Name&, const Interest&, StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700402 context.reject();
403 });
404
405 dispatcher.addTopPrefix("/root");
Davide Pesavento0f830802018-01-16 23:58:58 -0500406 advanceClocks(1_ms);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800407 face.sentData.clear();
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700408
Junxiao Shi85d90832016-08-04 03:19:46 +0000409 face.receive(*makeInterest("/root/test/small/%80%00")); // returns 403
410 face.receive(*makeInterest("/root/test/small/%80%00/invalid")); // returns 403
411 face.receive(*makeInterest("/root/test/small/%80%00/silent")); // silently ignored
Davide Pesavento0f830802018-01-16 23:58:58 -0500412 advanceClocks(1_ms, 20);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700413
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400414 BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000415 BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Blob);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800416 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000417 BOOST_CHECK_EQUAL(face.sentData[1].getContentType(), tlv::ContentType_Blob);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800418 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700419
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800420 face.sentData.clear();
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800421
Junxiao Shib55e5d32018-07-18 13:32:00 -0600422 auto interestSmall = *makeInterest("/root/test/small/valid", true);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800423 face.receive(interestSmall);
Davide Pesavento0f830802018-01-16 23:58:58 -0500424 advanceClocks(1_ms, 10);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800425
426 // one data packet is generated and sent to both places
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400427 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800428 BOOST_CHECK_EQUAL(storage.size(), 1);
429
430 auto fetchedData = storage.find(interestSmall);
431 BOOST_REQUIRE(fetchedData != nullptr);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000432 BOOST_CHECK_EQUAL(face.sentData[0].wireEncode(), fetchedData->wireEncode());
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700433
Junxiao Shi85d90832016-08-04 03:19:46 +0000434 face.receive(*makeInterest(Name("/root/test/small/valid").appendVersion(10))); // should be ignored
435 face.receive(*makeInterest(Name("/root/test/small/valid").appendSegment(20))); // should be ignored
Davide Pesavento0f830802018-01-16 23:58:58 -0500436 advanceClocks(1_ms, 10);
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400437 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800438 BOOST_CHECK_EQUAL(storage.size(), 1);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700439
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800440 Block content = face.sentData[0].getContent();
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700441 BOOST_CHECK_NO_THROW(content.parse());
442
Junxiao Shi72c0c642018-04-20 15:41:09 +0000443 BOOST_REQUIRE_EQUAL(content.elements().size(), 3);
444 BOOST_CHECK_EQUAL(content.elements()[0], smallBlock);
445 BOOST_CHECK_EQUAL(content.elements()[1], smallBlock);
446 BOOST_CHECK_EQUAL(content.elements()[2], smallBlock);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700447
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800448 storage.erase("/", true); // clear the storage
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800449 face.sentData.clear();
Junxiao Shi85d90832016-08-04 03:19:46 +0000450 face.receive(*makeInterest("/root/test/large/valid"));
Davide Pesavento0f830802018-01-16 23:58:58 -0500451 advanceClocks(1_ms, 10);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700452
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800453 // two data packets are generated, the first one will be sent to both places
454 // while the second one will only be inserted into the in-memory storage
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400455 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
456 BOOST_REQUIRE_EQUAL(storage.size(), 2);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800457
458 // segment0 should be sent through the face
459 const auto& component = face.sentData[0].getName().at(-1);
460 BOOST_CHECK(component.isSegment());
461 BOOST_CHECK_EQUAL(component.toSegment(), 0);
462
463 std::vector<Data> dataInStorage;
464 std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage));
465
466 // the Data sent through the face should be the same as the first Data in the storage
467 BOOST_CHECK_EQUAL(face.sentData[0].getName(), dataInStorage[0].getName());
Junxiao Shi72c0c642018-04-20 15:41:09 +0000468 BOOST_CHECK_EQUAL(face.sentData[0].getContent(), dataInStorage[0].getContent());
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800469
470 content = [&dataInStorage] () -> Block {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700471 EncodingBuffer encoder;
Davide Pesavento258d51a2022-02-27 21:26:28 -0500472 size_t valueLength = encoder.prependBytes(dataInStorage[1].getContent().value_bytes());
473 valueLength += encoder.prependBytes(dataInStorage[0].getContent().value_bytes());
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700474 encoder.prependVarNumber(valueLength);
475 encoder.prependVarNumber(tlv::Content);
476 return encoder.block();
477 }();
478
479 BOOST_CHECK_NO_THROW(content.parse());
Junxiao Shi72c0c642018-04-20 15:41:09 +0000480 BOOST_REQUIRE_EQUAL(content.elements().size(), 3);
481 BOOST_CHECK_EQUAL(content.elements()[0], largeBlock);
482 BOOST_CHECK_EQUAL(content.elements()[1], largeBlock);
483 BOOST_CHECK_EQUAL(content.elements()[2], largeBlock);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700484
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800485 storage.erase("/", true);// clear the storage
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800486 face.sentData.clear();
Junxiao Shi85d90832016-08-04 03:19:46 +0000487 face.receive(*makeInterest("/root/test/reject/%80%00/valid")); // returns nack
Davide Pesavento0f830802018-01-16 23:58:58 -0500488 advanceClocks(1_ms);
Davide Pesavento3c34ec12021-03-28 21:50:06 -0400489
490 BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
Junxiao Shi72c0c642018-04-20 15:41:09 +0000491 BOOST_CHECK_EQUAL(face.sentData[0].getContentType(), tlv::ContentType_Nack);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800492 BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 400);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800493 BOOST_CHECK_EQUAL(storage.size(), 0); // the nack packet will not be inserted into the in-memory storage
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700494}
495
Junxiao Shid97c9532017-04-27 16:17:04 +0000496BOOST_AUTO_TEST_CASE(NotificationStream)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700497{
Davide Pesaventofbea4fc2022-02-08 07:26:04 -0500498 const Block block({0x82, 0x01, 0x02});
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700499 auto post = dispatcher.addNotificationStream("test");
500
501 post(block);
Davide Pesavento0f830802018-01-16 23:58:58 -0500502 advanceClocks(1_ms);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800503 BOOST_CHECK_EQUAL(face.sentData.size(), 0);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700504
505 dispatcher.addTopPrefix("/root");
Davide Pesavento0f830802018-01-16 23:58:58 -0500506 advanceClocks(1_ms);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800507 face.sentData.clear();
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700508
509 post(block);
Davide Pesavento0f830802018-01-16 23:58:58 -0500510 advanceClocks(1_ms);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800511 BOOST_CHECK_EQUAL(face.sentData.size(), 1);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800512 BOOST_CHECK_EQUAL(storage.size(), 1);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700513
514 post(block);
515 post(block);
516 post(block);
Davide Pesavento0f830802018-01-16 23:58:58 -0500517 advanceClocks(1_ms, 10);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700518
Junxiao Shi72c0c642018-04-20 15:41:09 +0000519 BOOST_REQUIRE_EQUAL(face.sentData.size(), 4);
Eric Newberryc25e4632021-02-11 10:48:11 -0800520 BOOST_CHECK_EQUAL(face.sentData[0].getName(), "/root/test/seq=0");
521 BOOST_CHECK_EQUAL(face.sentData[1].getName(), "/root/test/seq=1");
522 BOOST_CHECK_EQUAL(face.sentData[2].getName(), "/root/test/seq=2");
523 BOOST_CHECK_EQUAL(face.sentData[3].getName(), "/root/test/seq=3");
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700524
Junxiao Shi72c0c642018-04-20 15:41:09 +0000525 BOOST_CHECK_EQUAL(face.sentData[0].getContent().blockFromValue(), block);
526 BOOST_CHECK_EQUAL(face.sentData[1].getContent().blockFromValue(), block);
527 BOOST_CHECK_EQUAL(face.sentData[2].getContent().blockFromValue(), block);
528 BOOST_CHECK_EQUAL(face.sentData[3].getContent().blockFromValue(), block);
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800529
530 // each version of notification will be sent to both places
531 std::vector<Data> dataInStorage;
532 std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage));
Junxiao Shi72c0c642018-04-20 15:41:09 +0000533 BOOST_REQUIRE_EQUAL(dataInStorage.size(), 4);
Eric Newberryc25e4632021-02-11 10:48:11 -0800534 BOOST_CHECK_EQUAL(dataInStorage[0].getName(), "/root/test/seq=0");
535 BOOST_CHECK_EQUAL(dataInStorage[1].getName(), "/root/test/seq=1");
536 BOOST_CHECK_EQUAL(dataInStorage[2].getName(), "/root/test/seq=2");
537 BOOST_CHECK_EQUAL(dataInStorage[3].getName(), "/root/test/seq=3");
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800538
Junxiao Shi72c0c642018-04-20 15:41:09 +0000539 BOOST_CHECK_EQUAL(dataInStorage[0].getContent().blockFromValue(), block);
540 BOOST_CHECK_EQUAL(dataInStorage[1].getContent().blockFromValue(), block);
541 BOOST_CHECK_EQUAL(dataInStorage[2].getContent().blockFromValue(), block);
542 BOOST_CHECK_EQUAL(dataInStorage[3].getContent().blockFromValue(), block);
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700543}
544
Yanbiao Li4b4f7542016-03-11 02:04:43 +0800545BOOST_AUTO_TEST_SUITE_END() // TestDispatcher
546BOOST_AUTO_TEST_SUITE_END() // Mgmt
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700547
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400548} // namespace ndn::tests