blob: b827c85cec1a4e6467679ed36337add68c519ac2 [file] [log] [blame]
Yanbiao Li73860e32015-08-19 16:30:16 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Weiwei Liuf5aee942016-03-19 07:00:42 +00003 * Copyright (c) 2014-2016, Regents of the University of California,
Yanbiao Li73860e32015-08-19 16:30:16 -07004 * 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/face-manager.hpp"
27#include "fw/forwarder.hpp"
28
29#include "tests/test-common.hpp"
30
31#include <ndn-cxx/mgmt/dispatcher.hpp>
32#include <ndn-cxx/util/dummy-client-face.hpp>
33
34#include <boost/property_tree/info_parser.hpp>
35
36namespace nfd {
37namespace tests {
38
39
40BOOST_AUTO_TEST_SUITE(Mgmt)
41BOOST_AUTO_TEST_SUITE(TestFaceManager)
42
43BOOST_FIXTURE_TEST_SUITE(CreateFace, BaseFixture)
44
45class FaceManagerNode
46{
47public:
48 FaceManagerNode(ndn::KeyChain& keyChain, const std::string& port = "6363")
49 : face(ndn::util::makeDummyClientFace(getGlobalIoService(), {true, true}))
50 , dispatcher(*face, keyChain, ndn::security::SigningInfo())
51 , manager(forwarder.getFaceTable(), dispatcher, validator)
52 {
53 dispatcher.addTopPrefix("/localhost/nfd");
54
55 std::string basicConfig =
56 "face_system\n"
57 "{\n"
58 " tcp\n"
59 " {\n"
60 " port " + port + "\n"
61 " }\n"
62 " udp\n"
63 " {\n"
64 " port " + port + "\n"
Weiwei Liuf5aee942016-03-19 07:00:42 +000065 " mcast no\n"
66 " }\n"
67 " ether\n"
68 " {\n"
69 " mcast no\n"
Yanbiao Li73860e32015-08-19 16:30:16 -070070 " }\n"
71 "}\n"
72 "authorizations\n"
73 "{\n"
74 " authorize\n"
75 " {\n"
76 " certfile any\n"
77 " privileges\n"
78 " {\n"
79 " faces\n"
80 " }\n"
81 " }\n"
82 "}\n"
83 "\n";
84 std::istringstream input(basicConfig);
85 nfd::ConfigSection configSection;
86 boost::property_tree::read_info(input, configSection);
87
88 ConfigFile config;
89 manager.setConfigFile(config);
90 validator.setConfigFile(config);
91 config.parse(configSection, false, "dummy-config");
92 }
93
94 void
95 closeFaces()
96 {
97 std::vector<shared_ptr<Face>> facesToClose;
98 std::copy(forwarder.getFaceTable().begin(), forwarder.getFaceTable().end(),
99 std::back_inserter(facesToClose));
100 for (auto face : facesToClose) {
101 face->close();
102 }
103 }
104
105public:
106 Forwarder forwarder;
107 shared_ptr<ndn::util::DummyClientFace> face;
108 ndn::mgmt::Dispatcher dispatcher;
109 CommandValidator validator;
110 FaceManager manager;
111};
112
113class FaceManagerFixture : public UnitTestTimeFixture
114{
115public:
116 FaceManagerFixture()
117 : node1(keyChain, "16363")
118 , node2(keyChain, "26363")
119 {
120 advanceClocks(time::milliseconds(1), 100);
121 }
122
123 ~FaceManagerFixture()
124 {
125 node1.closeFaces();
126 node2.closeFaces();
127 advanceClocks(time::milliseconds(1), 100);
128 }
129
130public:
131 ndn::KeyChain keyChain;
132 FaceManagerNode node1; // used to test FaceManager
133 FaceManagerNode node2; // acts as a remote endpoint
134};
135
136class TcpFaceOnDemand
137{
138public:
139 ControlParameters
140 getParameters()
141 {
142 return ControlParameters()
143 .setUri("tcp4://127.0.0.1:26363")
144 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
145 }
146};
147
148class TcpFacePersistent
149{
150public:
151 ControlParameters
152 getParameters()
153 {
154 return ControlParameters()
155 .setUri("tcp4://127.0.0.1:26363")
156 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
157 }
158};
159
160class TcpFacePermanent
161{
162public:
163 ControlParameters
164 getParameters()
165 {
166 return ControlParameters()
167 .setUri("tcp4://127.0.0.1:26363")
168 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
169 }
170};
171
172class UdpFaceOnDemand
173{
174public:
175 ControlParameters
176 getParameters()
177 {
178 return ControlParameters()
179 .setUri("udp4://127.0.0.1:26363")
180 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
181 }
182};
183
184class UdpFaceCannotConnect // face that will cause afterCreateFaceFailure to be invoked
185{
186public:
187 ControlParameters
188 getParameters()
189 {
190 return ControlParameters()
191 .setUri("udp4://0.0.0.0:16363"); // cannot connect to self
192 }
193};
194
195
196class UdpFacePersistent
197{
198public:
199 ControlParameters
200 getParameters()
201 {
202 return ControlParameters()
203 .setUri("udp4://127.0.0.1:26363")
204 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
205 }
206};
207
208class UdpFacePermanent
209{
210public:
211 ControlParameters
212 getParameters()
213 {
214 return ControlParameters()
215 .setUri("udp4://127.0.0.1:26363")
216 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
217 }
218};
219
220class Success
221{
222public:
223 ControlResponse
224 getExpected()
225 {
226 return ControlResponse()
227 .setCode(200)
228 .setText("OK");
229 }
230};
231
232template<int CODE>
233class Failure
234{
235public:
236 ControlResponse
237 getExpected()
238 {
239 return ControlResponse()
240 .setCode(CODE)
241 .setText("Error"); // error description should not be checked
242 }
243};
244
245namespace mpl = boost::mpl;
246
247// pairs of CreateCommand and Success status
248typedef mpl::vector<mpl::pair<TcpFaceOnDemand, Failure<500>>,
249 mpl::pair<TcpFacePersistent, Success>,
250 mpl::pair<TcpFacePermanent, Failure<500>>,
251 mpl::pair<UdpFaceOnDemand, Failure<500>>,
252 mpl::pair<UdpFacePersistent, Success>,
253 mpl::pair<UdpFacePermanent, Success>,
254 mpl::pair<UdpFaceCannotConnect, Failure<408>>> Faces;
255
256BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerFixture)
257{
258 typedef typename T::first FaceType;
259 typedef typename T::second CreateResult;
260
261 Name commandName("/localhost/nfd/faces");
262 commandName.append("create");
263 commandName.append(FaceType().getParameters().wireEncode());
264
265 shared_ptr<Interest> command(make_shared<Interest>(commandName));
266 this->keyChain.sign(*command);
267
268 bool hasCallbackFired = false;
269 this->node1.face->onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
270 // std::cout << response << std::endl;
271 if (!command->getName().isPrefixOf(response.getName())) {
272 return;
273 }
274
275 ControlResponse actual(response.getContent().blockFromValue());
276 ControlResponse expected(CreateResult().getExpected());
277 BOOST_CHECK_EQUAL(expected.getCode(), actual.getCode());
Alexander Afanasyev964d4592015-10-09 13:03:19 -0700278 BOOST_TEST_MESSAGE(actual.getText());
Yanbiao Li73860e32015-08-19 16:30:16 -0700279
280 if (actual.getBody().hasWire()) {
281 ControlParameters expectedParams(FaceType().getParameters());
282 ControlParameters actualParams(actual.getBody());
283
284 BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
285 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
286 }
287 hasCallbackFired = true;
288 });
289
290 this->node1.face->receive(*command);
291 this->advanceClocks(time::milliseconds(1), 100);
292
293 BOOST_CHECK(hasCallbackFired);
294}
295
296
297typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
298 // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
299 mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
300 mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;
301
302
303BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFace, T, FaceTransitions, FaceManagerFixture)
304{
305 typedef typename T::first::first FaceType1;
306 typedef typename T::first::second FaceType2;
307 typedef typename T::second FinalFaceType;
308
309 {
310 // create face
311
312 Name commandName("/localhost/nfd/faces");
313 commandName.append("create");
314 commandName.append(FaceType1().getParameters().wireEncode());
315
316 shared_ptr<Interest> command(make_shared<Interest>(commandName));
317 this->keyChain.sign(*command);
318
319 this->node1.face->receive(*command);
320 this->advanceClocks(time::milliseconds(1), 10);
321 }
322
323 //
324 {
325 // re-create face (= change face persistency)
326
327 Name commandName("/localhost/nfd/faces");
328 commandName.append("create");
329 commandName.append(FaceType2().getParameters().wireEncode());
330
331 shared_ptr<Interest> command(make_shared<Interest>(commandName));
332 this->keyChain.sign(*command);
333
334 bool hasCallbackFired = false;
335 this->node1.face->onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
336 if (!command->getName().isPrefixOf(response.getName())) {
337 return;
338 }
339
340 ControlResponse actual(response.getContent().blockFromValue());
341 BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
342
343 ControlParameters expectedParams(FinalFaceType().getParameters());
344 ControlParameters actualParams(actual.getBody());
345 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
346
347 hasCallbackFired = true;
348 });
349
350 this->node1.face->receive(*command);
351 this->advanceClocks(time::milliseconds(1), 10);
352
353 BOOST_CHECK(hasCallbackFired);
354 }
355}
356
357
358class UdpFace
359{
360public:
361 ControlParameters
362 getParameters()
363 {
364 return ControlParameters()
365 .setUri("udp4://127.0.0.1:16363")
366 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
367 }
368};
369
370
371// Note that the transitions from on-demand TcpFace are intentionally not tested.
372// On-demand TcpFace has a remote endpoint with a randomized port number. Normal face
373// creation operations will not need to create a face toward a remote port not listened by
374// a channel.
375
376typedef mpl::vector<mpl::pair<UdpFace, UdpFacePersistent>,
377 mpl::pair<UdpFace, UdpFacePermanent>> OnDemandFaceTransitions;
378
379// need a slightly different logic to test transitions from OnDemand state
380BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFaceOnDemand, T, OnDemandFaceTransitions, FaceManagerFixture)
381{
382 typedef typename T::first OtherNodeFace;
383 typedef typename T::second FaceType;
384
385 {
386 // create on-demand face
387
388 Name commandName("/localhost/nfd/faces");
389 commandName.append("create");
390 commandName.append(OtherNodeFace().getParameters().wireEncode());
391
392 shared_ptr<Interest> command(make_shared<Interest>(commandName));
393 this->keyChain.sign(*command);
394
395 ndn::util::signal::ScopedConnection connection =
396 this->node2.face->onSendData.connect([this, command] (const Data& response) {
397 if (!command->getName().isPrefixOf(response.getName())) {
398 return;
399 }
400
401 ControlResponse controlResponse(response.getContent().blockFromValue());
402 BOOST_REQUIRE_EQUAL(controlResponse.getText(), "OK");
403 BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 200);
404 uint64_t faceId = ControlParameters(controlResponse.getBody()).getFaceId();
405 auto face = this->node2.forwarder.getFace(static_cast<FaceId>(faceId));
406
407 // to force creation of on-demand face
408 auto dummyInterest = make_shared<Interest>("/hello/world");
409 face->sendInterest(*dummyInterest);
410 });
411
412 this->node2.face->receive(*command);
413 this->advanceClocks(time::milliseconds(1), 10);
414 }
415
416 // make sure there is on-demand face
417 bool onDemandFaceFound = false;
418 FaceUri onDemandFaceUri(FaceType().getParameters().getUri());
419 for (auto face : this->node1.forwarder.getFaceTable()) {
420 if (face->getRemoteUri() == onDemandFaceUri) {
421 onDemandFaceFound = true;
422 break;
423 }
424 }
425 BOOST_REQUIRE(onDemandFaceFound);
426
427 //
428 {
429 // re-create face (= change face persistency)
430
431 Name commandName("/localhost/nfd/faces");
432 commandName.append("create");
433 commandName.append(FaceType().getParameters().wireEncode());
434
435 shared_ptr<Interest> command(make_shared<Interest>(commandName));
436 this->keyChain.sign(*command);
437
438 bool hasCallbackFired = false;
439 this->node1.face->onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
440 if (!command->getName().isPrefixOf(response.getName())) {
441 return;
442 }
443
444 ControlResponse actual(response.getContent().blockFromValue());
445 BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
446
447 ControlParameters expectedParams(FaceType().getParameters());
448 ControlParameters actualParams(actual.getBody());
449 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
450
451 hasCallbackFired = true;
452 });
453
454 this->node1.face->receive(*command);
455 this->advanceClocks(time::milliseconds(1), 10);
456
457 BOOST_CHECK(hasCallbackFired);
458 }
459}
460
461BOOST_AUTO_TEST_SUITE_END() // CreateFace
462BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
463BOOST_AUTO_TEST_SUITE_END() // Mgmt
464
Weiwei Liuf5aee942016-03-19 07:00:42 +0000465} // namespace tests
466} // namespace nfd