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