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