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