blob: 2fbcd4fc4184e63047ef462cea14fb2b1b591fab [file] [log] [blame]
Yanbiao Li8ee37ed2015-05-19 12:44:04 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev80b68e12015-09-17 17:01:04 -07003 * Copyright (c) 2013-2015 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
22#include "mgmt/dispatcher.hpp"
23#include "management/nfd-control-parameters.hpp"
24#include "util/dummy-client-face.hpp"
25
26#include "boost-test.hpp"
27#include "identity-management-fixture.hpp"
28#include "unit-tests/unit-test-time-fixture.hpp"
29#include "unit-tests/make-interest-data.hpp"
30
31namespace ndn {
32namespace mgmt {
33namespace tests {
34
35using namespace ndn::tests;
36
Junxiao Shif65a3362015-09-06 20:54:54 -070037BOOST_AUTO_TEST_SUITE(Mgmt)
38BOOST_AUTO_TEST_SUITE(TestDispatcher)
Yanbiao Li8ee37ed2015-05-19 12:44:04 -070039
40class DispatcherFixture : public UnitTestTimeFixture
41 , public security::IdentityManagementFixture
42{
43public:
44 DispatcherFixture()
45 : face(util::makeDummyClientFace(io, {true, true}))
46 , dispatcher(*face, m_keyChain, security::SigningInfo())
47 {
48 }
49
50public:
51 shared_ptr<util::DummyClientFace> face;
52 mgmt::Dispatcher dispatcher;
53};
54
55class VoidParameters : public mgmt::ControlParameters
56{
57public:
58 explicit
59 VoidParameters(const Block& wire)
60 {
61 wireDecode(wire);
62 }
63
64 virtual Block
65 wireEncode() const NDN_CXX_DECL_FINAL
66 {
67 return Block(128);
68 }
69
70 virtual void
71 wireDecode(const Block& wire) NDN_CXX_DECL_FINAL
72 {
73 if (wire.type() != 128)
74 throw tlv::Error("Expecting TLV type 128");
75 }
76};
77
78static Authorization
79makeTestAuthorization()
80{
81 return [] (const Name& prefix,
82 const Interest& interest,
83 const ControlParameters* params,
84 AcceptContinuation accept,
85 RejectContinuation reject) {
86 if (interest.getName()[-1] == name::Component("valid")) {
87 accept("");
88 }
89 else {
90 if (interest.getName()[-1] == name::Component("silent")) {
91 reject(RejectReply::SILENT);
92 }
93 else {
94 reject(RejectReply::STATUS403);
95 }
96 }
97 };
98}
99
100BOOST_FIXTURE_TEST_CASE(BasicUsageSemantics, DispatcherFixture)
101{
102 BOOST_CHECK_NO_THROW(dispatcher
103 .addControlCommand<VoidParameters>("test/1", makeAcceptAllAuthorization(),
104 bind([] { return true; }),
105 bind([]{})));
106 BOOST_CHECK_NO_THROW(dispatcher
107 .addControlCommand<VoidParameters>("test/2", makeAcceptAllAuthorization(),
108 bind([] { return true; }),
109 bind([]{})));
110
111 BOOST_CHECK_THROW(dispatcher
112 .addControlCommand<VoidParameters>("test", makeAcceptAllAuthorization(),
113 bind([] { return true; }),
114 bind([]{})),
115 std::out_of_range);
116
117 BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/1",
118 makeAcceptAllAuthorization(), bind([]{})));
119 BOOST_CHECK_NO_THROW(dispatcher.addStatusDataset("status/2",
120 makeAcceptAllAuthorization(), bind([]{})));
121 BOOST_CHECK_THROW(dispatcher.addStatusDataset("status",
122 makeAcceptAllAuthorization(), bind([]{})),
123 std::out_of_range);
124
125 BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/1"));
126 BOOST_CHECK_NO_THROW(dispatcher.addNotificationStream("stream/2"));
127 BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream"), std::out_of_range);
128
129
130 BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/1"));
131 BOOST_CHECK_NO_THROW(dispatcher.addTopPrefix("/root/2"));
132 BOOST_CHECK_THROW(dispatcher.addTopPrefix("/root"), std::out_of_range);
133
134 BOOST_CHECK_THROW(dispatcher
135 .addControlCommand<VoidParameters>("test/3", makeAcceptAllAuthorization(),
136 bind([] { return true; }),
137 bind([]{})),
138 std::domain_error);
139
140 BOOST_CHECK_THROW(dispatcher.addStatusDataset("status/3",
141 makeAcceptAllAuthorization(), bind([]{})),
142 std::domain_error);
143
144 BOOST_CHECK_THROW(dispatcher.addNotificationStream("stream/3"), std::domain_error);
145}
146
147BOOST_FIXTURE_TEST_CASE(AddRemoveTopPrefix, DispatcherFixture)
148{
149 std::map<std::string, size_t> nCallbackCalled;
150 dispatcher
151 .addControlCommand<VoidParameters>("test/1", makeAcceptAllAuthorization(),
152 bind([] { return true; }),
153 bind([&nCallbackCalled] { ++nCallbackCalled["test/1"]; }));
154
155 dispatcher
156 .addControlCommand<VoidParameters>("test/2", makeAcceptAllAuthorization(),
157 bind([] { return true; }),
158 bind([&nCallbackCalled] { ++nCallbackCalled["test/2"]; }));
159
160 face->receive(*util::makeInterest("/root/1/test/1/%80%00"));
161 advanceClocks(time::milliseconds(1));
162 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 0);
163 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0);
164
165 dispatcher.addTopPrefix("/root/1");
166 advanceClocks(time::milliseconds(1));
167
168 face->receive(*util::makeInterest("/root/1/test/1/%80%00"));
169 advanceClocks(time::milliseconds(1));
170 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
171 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 0);
172
173 face->receive(*util::makeInterest("/root/1/test/2/%80%00"));
174 advanceClocks(time::milliseconds(1));
175 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
176 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1);
177
178 face->receive(*util::makeInterest("/root/2/test/1/%80%00"));
179 face->receive(*util::makeInterest("/root/2/test/2/%80%00"));
180 advanceClocks(time::milliseconds(1));
181 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 1);
182 BOOST_CHECK_EQUAL(nCallbackCalled["test/2"], 1);
183
184 dispatcher.addTopPrefix("/root/2");
185 advanceClocks(time::milliseconds(1));
186
187 face->receive(*util::makeInterest("/root/1/test/1/%80%00"));
188 advanceClocks(time::milliseconds(1));
189 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 2);
190
191 face->receive(*util::makeInterest("/root/2/test/1/%80%00"));
192 advanceClocks(time::milliseconds(1));
193 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3);
194
195 dispatcher.removeTopPrefix("/root/1");
196 advanceClocks(time::milliseconds(1));
197
198 face->receive(*util::makeInterest("/root/1/test/1/%80%00"));
199 advanceClocks(time::milliseconds(1));
200 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 3);
201
202 face->receive(*util::makeInterest("/root/2/test/1/%80%00"));
203 advanceClocks(time::milliseconds(1));
204 BOOST_CHECK_EQUAL(nCallbackCalled["test/1"], 4);
205}
206
207BOOST_FIXTURE_TEST_CASE(ControlCommand, DispatcherFixture)
208{
209 size_t nCallbackCalled = 0;
210 dispatcher
211 .addControlCommand<VoidParameters>("test",
212 makeTestAuthorization(),
213 bind([] { return true; }),
214 bind([&nCallbackCalled] { ++nCallbackCalled; }));
215
216 dispatcher.addTopPrefix("/root");
217 advanceClocks(time::milliseconds(1));
218 face->sentDatas.clear();
219
220 face->receive(*util::makeInterest("/root/test/%80%00")); // returns 403
221 face->receive(*util::makeInterest("/root/test/%80%00/invalid")); // returns 403
222 face->receive(*util::makeInterest("/root/test/%80%00/silent")); // silently ignored
223 face->receive(*util::makeInterest("/root/test/.../invalid")); // silently ignored (wrong format)
224 face->receive(*util::makeInterest("/root/test/.../valid")); // silently ignored (wrong format)
225 advanceClocks(time::milliseconds(1), 20);
226 BOOST_CHECK_EQUAL(nCallbackCalled, 0);
227 BOOST_CHECK_EQUAL(face->sentDatas.size(), 2);
228
229 BOOST_CHECK(face->sentDatas[0].getContentType() == tlv::ContentType_Blob);
230 BOOST_CHECK_EQUAL(ControlResponse(face->sentDatas[0].getContent().blockFromValue()).getCode(), 403);
231 BOOST_CHECK(face->sentDatas[1].getContentType() == tlv::ContentType_Blob);
232 BOOST_CHECK_EQUAL(ControlResponse(face->sentDatas[1].getContent().blockFromValue()).getCode(), 403);
233
234 face->receive(*util::makeInterest("/root/test/%80%00/valid"));
235 advanceClocks(time::milliseconds(1), 10);
236 BOOST_CHECK_EQUAL(nCallbackCalled, 1);
237}
238
239BOOST_FIXTURE_TEST_CASE(StatusDataset, DispatcherFixture)
240{
241 static Block smallBlock("\x81\x01\0x01", 3);
242 static Block largeBlock = [] () -> Block {
243 EncodingBuffer encoder;
244 for (size_t i = 0; i < 2500; ++i) {
245 encoder.prependByte(1);
246 }
247 encoder.prependVarNumber(2500);
248 encoder.prependVarNumber(129);
249 return encoder.block();
250 }();
251
252 dispatcher.addStatusDataset("test/small",
253 makeTestAuthorization(),
254 [] (const Name& prefix, const Interest& interest,
Junxiao Shif65a3362015-09-06 20:54:54 -0700255 StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700256 context.append(smallBlock);
257 context.append(smallBlock);
258 context.append(smallBlock);
259 context.end();
260 });
261
262 dispatcher.addStatusDataset("test/large",
263 makeTestAuthorization(),
264 [] (const Name& prefix, const Interest& interest,
Junxiao Shif65a3362015-09-06 20:54:54 -0700265 StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700266 context.append(largeBlock);
267 context.append(largeBlock);
268 context.append(largeBlock);
269 context.end();
270 });
271
272 dispatcher.addStatusDataset("test/reject",
273 makeTestAuthorization(),
274 [] (const Name& prefix, const Interest& interest,
Junxiao Shif65a3362015-09-06 20:54:54 -0700275 StatusDatasetContext& context) {
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700276 context.reject();
277 });
278
279 dispatcher.addTopPrefix("/root");
280 advanceClocks(time::milliseconds(1));
281 face->sentDatas.clear();
282
283 face->receive(*util::makeInterest("/root/test/small/%80%00")); // returns 403
284 face->receive(*util::makeInterest("/root/test/small/%80%00/invalid")); // returns 403
285 face->receive(*util::makeInterest("/root/test/small/%80%00/silent")); // silently ignored
286 advanceClocks(time::milliseconds(1), 20);
287 BOOST_CHECK_EQUAL(face->sentDatas.size(), 2);
288
289 BOOST_CHECK(face->sentDatas[0].getContentType() == tlv::ContentType_Blob);
290 BOOST_CHECK_EQUAL(ControlResponse(face->sentDatas[0].getContent().blockFromValue()).getCode(), 403);
291 BOOST_CHECK(face->sentDatas[1].getContentType() == tlv::ContentType_Blob);
292 BOOST_CHECK_EQUAL(ControlResponse(face->sentDatas[1].getContent().blockFromValue()).getCode(), 403);
293
294 face->sentDatas.clear();
295 face->receive(*util::makeInterest("/root/test/small/valid"));
296 advanceClocks(time::milliseconds(1), 10);
297 BOOST_CHECK_EQUAL(face->sentDatas.size(), 1);
298
299 face->receive(*util::makeInterest(Name("/root/test/small/valid").appendVersion(10))); // should be ignored
300 face->receive(*util::makeInterest(Name("/root/test/small/valid").appendSegment(20))); // should be ignored
301 advanceClocks(time::milliseconds(1), 10);
302 BOOST_CHECK_EQUAL(face->sentDatas.size(), 1);
303
304 Block content = face->sentDatas[0].getContent();
305 BOOST_CHECK_NO_THROW(content.parse());
306
307 BOOST_CHECK_EQUAL(content.elements().size(), 3);
308 BOOST_CHECK(content.elements()[0] == smallBlock);
309 BOOST_CHECK(content.elements()[1] == smallBlock);
310 BOOST_CHECK(content.elements()[2] == smallBlock);
311
312 face->sentDatas.clear();
313 face->receive(*util::makeInterest("/root/test/large/valid"));
314 advanceClocks(time::milliseconds(1), 10);
315 BOOST_CHECK_EQUAL(face->sentDatas.size(), 2);
316
317 const auto& datas = face->sentDatas;
318 content = [&datas] () -> Block {
319 EncodingBuffer encoder;
320 size_t valueLength = encoder.prependByteArray(datas[1].getContent().value(),
321 datas[1].getContent().value_size());
322 valueLength += encoder.prependByteArray(datas[0].getContent().value(),
323 datas[0].getContent().value_size());
324 encoder.prependVarNumber(valueLength);
325 encoder.prependVarNumber(tlv::Content);
326 return encoder.block();
327 }();
328
329 BOOST_CHECK_NO_THROW(content.parse());
330
331 BOOST_CHECK_EQUAL(content.elements().size(), 3);
332 BOOST_CHECK(content.elements()[0] == largeBlock);
333 BOOST_CHECK(content.elements()[1] == largeBlock);
334 BOOST_CHECK(content.elements()[2] == largeBlock);
335
336 face->sentDatas.clear();
337 face->receive(*util::makeInterest("/root/test/reject/%80%00/valid")); // returns nack
338 advanceClocks(time::milliseconds(1));
339 BOOST_CHECK_EQUAL(face->sentDatas.size(), 1);
340 BOOST_CHECK(face->sentDatas[0].getContentType() == tlv::ContentType_Nack);
341 BOOST_CHECK_EQUAL(ControlResponse(face->sentDatas[0].getContent().blockFromValue()).getCode(), 400);
342}
343
344BOOST_FIXTURE_TEST_CASE(NotificationStream, DispatcherFixture)
345{
346 static Block block("\x82\x01\x02", 3);
347
348 auto post = dispatcher.addNotificationStream("test");
349
350 post(block);
351 advanceClocks(time::milliseconds(1));
352 BOOST_CHECK_EQUAL(face->sentDatas.size(), 0);
353
354 dispatcher.addTopPrefix("/root");
355 advanceClocks(time::milliseconds(1));
356 face->sentDatas.clear();
357
358 post(block);
359 advanceClocks(time::milliseconds(1));
360 BOOST_CHECK_EQUAL(face->sentDatas.size(), 1);
361
362 post(block);
363 post(block);
364 post(block);
365 advanceClocks(time::milliseconds(1), 10);
366
367 BOOST_CHECK_EQUAL(face->sentDatas.size(), 4);
368 BOOST_CHECK_EQUAL(face->sentDatas[0].getName(), "/root/test/%FE%00");
369 BOOST_CHECK_EQUAL(face->sentDatas[1].getName(), "/root/test/%FE%01");
370 BOOST_CHECK_EQUAL(face->sentDatas[2].getName(), "/root/test/%FE%02");
371 BOOST_CHECK_EQUAL(face->sentDatas[3].getName(), "/root/test/%FE%03");
372
373 BOOST_CHECK(face->sentDatas[0].getContent().blockFromValue() == block);
374 BOOST_CHECK(face->sentDatas[1].getContent().blockFromValue() == block);
375 BOOST_CHECK(face->sentDatas[2].getContent().blockFromValue() == block);
376 BOOST_CHECK(face->sentDatas[3].getContent().blockFromValue() == block);
377}
378
379BOOST_AUTO_TEST_SUITE_END()
Junxiao Shif65a3362015-09-06 20:54:54 -0700380BOOST_AUTO_TEST_SUITE_END()
Yanbiao Li8ee37ed2015-05-19 12:44:04 -0700381
382} // namespace tests
383} // namespace mgmt
384} // namespace ndn