blob: ef590370b5477c7bd3dc64dd9e6383999630e2e3 [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"
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000027#include "fw/face-table.hpp"
Junxiao Shib84e6742016-07-19 13:16:22 +000028#include <ndn-cxx/mgmt/dispatcher.hpp>
29#include <ndn-cxx/util/dummy-client-face.hpp>
30
31#include <thread>
32#include <boost/property_tree/info_parser.hpp>
Yanbiao Li73860e32015-08-19 16:30:16 -070033
34#include "tests/test-common.hpp"
Junxiao Shi221b6fe2016-07-14 18:21:56 +000035#include "tests/identity-management-fixture.hpp"
Yanbiao Li73860e32015-08-19 16:30:16 -070036
Yanbiao Li73860e32015-08-19 16:30:16 -070037namespace nfd {
38namespace tests {
39
Yanbiao Li73860e32015-08-19 16:30:16 -070040BOOST_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")
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000049 : face(getGlobalIoService(), keyChain, {true, true})
Junxiao Shi221b6fe2016-07-14 18:21:56 +000050 , dispatcher(face, keyChain, ndn::security::SigningInfo())
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000051 , authenticator(CommandAuthenticator::create())
52 , manager(faceTable, dispatcher, *authenticator)
Yanbiao Li73860e32015-08-19 16:30:16 -070053 {
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);
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000091 authenticator->setConfigFile(config);
Yanbiao Li73860e32015-08-19 16:30:16 -070092 config.parse(configSection, false, "dummy-config");
93 }
94
95 void
96 closeFaces()
97 {
Junxiao Shib84e6742016-07-19 13:16:22 +000098 std::vector<std::reference_wrapper<Face>> facesToClose;
Junxiao Shi9ddf1b52016-08-22 03:58:55 +000099 std::copy(faceTable.begin(), faceTable.end(), std::back_inserter(facesToClose));
Junxiao Shib84e6742016-07-19 13:16:22 +0000100 for (Face& face : facesToClose) {
101 face.close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700102 }
103 }
104
105public:
Junxiao Shi9ddf1b52016-08-22 03:58:55 +0000106 FaceTable faceTable;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000107 ndn::util::DummyClientFace face;
Yanbiao Li73860e32015-08-19 16:30:16 -0700108 ndn::mgmt::Dispatcher dispatcher;
Junxiao Shi9ddf1b52016-08-22 03:58:55 +0000109 shared_ptr<CommandAuthenticator> authenticator;
Yanbiao Li73860e32015-08-19 16:30:16 -0700110 FaceManager manager;
111};
112
Junxiao Shi9ddf1b52016-08-22 03:58:55 +0000113class FaceManagerFixture : public IdentityManagementTimeFixture
Yanbiao Li73860e32015-08-19 16:30:16 -0700114{
115public:
116 FaceManagerFixture()
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000117 : node1(m_keyChain, "16363")
118 , node2(m_keyChain, "26363")
Yanbiao Li73860e32015-08-19 16:30:16 -0700119 {
Junxiao Shib84e6742016-07-19 13:16:22 +0000120 advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700121 }
122
123 ~FaceManagerFixture()
124 {
Junxiao Shib84e6742016-07-19 13:16:22 +0000125 // Explicitly closing faces is necessary. Otherwise, in a subsequent test case,
126 // incoming packets may be delivered to an old socket from previous test cases.
Yanbiao Li73860e32015-08-19 16:30:16 -0700127 node1.closeFaces();
128 node2.closeFaces();
Junxiao Shib84e6742016-07-19 13:16:22 +0000129 advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700130 }
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());
Junxiao Shib84e6742016-07-19 13:16:22 +0000265 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000266 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700267
268 bool hasCallbackFired = false;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000269 this->node1.face.onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700270 if (!command->getName().isPrefixOf(response.getName())) {
271 return;
272 }
273
274 ControlResponse actual(response.getContent().blockFromValue());
275 ControlResponse expected(CreateResult().getExpected());
276 BOOST_CHECK_EQUAL(expected.getCode(), actual.getCode());
Alexander Afanasyev964d4592015-10-09 13:03:19 -0700277 BOOST_TEST_MESSAGE(actual.getText());
Yanbiao Li73860e32015-08-19 16:30:16 -0700278
279 if (actual.getBody().hasWire()) {
280 ControlParameters expectedParams(FaceType().getParameters());
281 ControlParameters actualParams(actual.getBody());
282
283 BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
284 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
285 }
286 hasCallbackFired = true;
287 });
288
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000289 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000290 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700291
292 BOOST_CHECK(hasCallbackFired);
293}
294
295
296typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
297 // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
298 mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
299 mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;
300
301
302BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFace, T, FaceTransitions, FaceManagerFixture)
303{
304 typedef typename T::first::first FaceType1;
305 typedef typename T::first::second FaceType2;
306 typedef typename T::second FinalFaceType;
307
308 {
309 // create face
310
311 Name commandName("/localhost/nfd/faces");
312 commandName.append("create");
313 commandName.append(FaceType1().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000314 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000315 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700316
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000317 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000318 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700319 }
320
321 //
322 {
323 // re-create face (= change face persistency)
324
325 Name commandName("/localhost/nfd/faces");
326 commandName.append("create");
327 commandName.append(FaceType2().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000328 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000329 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700330
331 bool hasCallbackFired = false;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000332 this->node1.face.onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700333 if (!command->getName().isPrefixOf(response.getName())) {
334 return;
335 }
336
337 ControlResponse actual(response.getContent().blockFromValue());
338 BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
339
340 ControlParameters expectedParams(FinalFaceType().getParameters());
341 ControlParameters actualParams(actual.getBody());
342 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
343
344 hasCallbackFired = true;
345 });
346
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000347 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000348 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700349
350 BOOST_CHECK(hasCallbackFired);
351 }
352}
353
354
355class UdpFace
356{
357public:
358 ControlParameters
359 getParameters()
360 {
361 return ControlParameters()
362 .setUri("udp4://127.0.0.1:16363")
363 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
364 }
365};
366
367
368// Note that the transitions from on-demand TcpFace are intentionally not tested.
369// On-demand TcpFace has a remote endpoint with a randomized port number. Normal face
370// creation operations will not need to create a face toward a remote port not listened by
371// a channel.
372
373typedef mpl::vector<mpl::pair<UdpFace, UdpFacePersistent>,
374 mpl::pair<UdpFace, UdpFacePermanent>> OnDemandFaceTransitions;
375
376// need a slightly different logic to test transitions from OnDemand state
377BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFaceOnDemand, T, OnDemandFaceTransitions, FaceManagerFixture)
378{
379 typedef typename T::first OtherNodeFace;
380 typedef typename T::second FaceType;
381
382 {
383 // create on-demand face
384
385 Name commandName("/localhost/nfd/faces");
386 commandName.append("create");
387 commandName.append(OtherNodeFace().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000388 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000389 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700390
391 ndn::util::signal::ScopedConnection connection =
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000392 this->node2.face.onSendData.connect([this, command] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700393 if (!command->getName().isPrefixOf(response.getName())) {
394 return;
395 }
396
397 ControlResponse controlResponse(response.getContent().blockFromValue());
398 BOOST_REQUIRE_EQUAL(controlResponse.getText(), "OK");
399 BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 200);
400 uint64_t faceId = ControlParameters(controlResponse.getBody()).getFaceId();
Junxiao Shi9ddf1b52016-08-22 03:58:55 +0000401 auto face = this->node2.faceTable.get(static_cast<FaceId>(faceId));
Yanbiao Li73860e32015-08-19 16:30:16 -0700402
403 // to force creation of on-demand face
404 auto dummyInterest = make_shared<Interest>("/hello/world");
405 face->sendInterest(*dummyInterest);
406 });
407
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000408 this->node2.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000409 this->advanceClocks(time::milliseconds(1), 5); // let node2 process command and send Interest
410 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // allow wallclock time for socket IO
411 this->advanceClocks(time::milliseconds(1), 5); // let node1 accept Interest and create on-demand face
Yanbiao Li73860e32015-08-19 16:30:16 -0700412 }
413
414 // make sure there is on-demand face
Yanbiao Li73860e32015-08-19 16:30:16 -0700415 FaceUri onDemandFaceUri(FaceType().getParameters().getUri());
Junxiao Shib84e6742016-07-19 13:16:22 +0000416 const Face* foundFace = nullptr;
417 for (const Face& face : this->node1.faceTable) {
418 if (face.getRemoteUri() == onDemandFaceUri) {
419 foundFace = &face;
Yanbiao Li73860e32015-08-19 16:30:16 -0700420 break;
421 }
422 }
Junxiao Shib84e6742016-07-19 13:16:22 +0000423 BOOST_REQUIRE_MESSAGE(foundFace != nullptr, "on-demand face is not created");
Yanbiao Li73860e32015-08-19 16:30:16 -0700424
425 //
426 {
427 // re-create face (= change face persistency)
428
429 Name commandName("/localhost/nfd/faces");
430 commandName.append("create");
431 commandName.append(FaceType().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000432 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000433 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700434
435 bool hasCallbackFired = false;
Junxiao Shib84e6742016-07-19 13:16:22 +0000436 this->node1.face.onSendData.connect(
437 [this, command, &hasCallbackFired, foundFace] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700438 if (!command->getName().isPrefixOf(response.getName())) {
439 return;
440 }
441
442 ControlResponse actual(response.getContent().blockFromValue());
443 BOOST_REQUIRE_EQUAL(actual.getCode(), 200);
444
445 ControlParameters expectedParams(FaceType().getParameters());
446 ControlParameters actualParams(actual.getBody());
Junxiao Shib84e6742016-07-19 13:16:22 +0000447 BOOST_CHECK_EQUAL(actualParams.getFacePersistency(), expectedParams.getFacePersistency());
448 BOOST_CHECK_EQUAL(actualParams.getFaceId(), foundFace->getId());
449 BOOST_CHECK_EQUAL(foundFace->getPersistency(), expectedParams.getFacePersistency());
Yanbiao Li73860e32015-08-19 16:30:16 -0700450
451 hasCallbackFired = true;
452 });
453
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000454 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000455 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700456
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