blob: 8c67b3ae0147fc119424e76272a7c9e0b745368e [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"
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 Shib84e6742016-07-19 13:16:22 +000049 : faceTable(forwarder.getFaceTable())
50 , face(getGlobalIoService(), keyChain, {true, true})
Junxiao Shi221b6fe2016-07-14 18:21:56 +000051 , dispatcher(face, keyChain, ndn::security::SigningInfo())
Junxiao Shib84e6742016-07-19 13:16:22 +000052 , manager(faceTable, dispatcher, validator)
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);
91 validator.setConfigFile(config);
92 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;
Yanbiao Li73860e32015-08-19 16:30:16 -070099 std::copy(forwarder.getFaceTable().begin(), forwarder.getFaceTable().end(),
100 std::back_inserter(facesToClose));
Junxiao Shib84e6742016-07-19 13:16:22 +0000101 for (Face& face : facesToClose) {
102 face.close();
Yanbiao Li73860e32015-08-19 16:30:16 -0700103 }
104 }
105
106public:
107 Forwarder forwarder;
Junxiao Shib84e6742016-07-19 13:16:22 +0000108 FaceTable& faceTable;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000109 ndn::util::DummyClientFace face;
Yanbiao Li73860e32015-08-19 16:30:16 -0700110 ndn::mgmt::Dispatcher dispatcher;
111 CommandValidator validator;
112 FaceManager manager;
113};
114
115class FaceManagerFixture : public UnitTestTimeFixture
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000116 , public IdentityManagementFixture
Yanbiao Li73860e32015-08-19 16:30:16 -0700117{
118public:
119 FaceManagerFixture()
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000120 : node1(m_keyChain, "16363")
121 , node2(m_keyChain, "26363")
Yanbiao Li73860e32015-08-19 16:30:16 -0700122 {
Junxiao Shib84e6742016-07-19 13:16:22 +0000123 advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700124 }
125
126 ~FaceManagerFixture()
127 {
Junxiao Shib84e6742016-07-19 13:16:22 +0000128 // Explicitly closing faces is necessary. Otherwise, in a subsequent test case,
129 // incoming packets may be delivered to an old socket from previous test cases.
Yanbiao Li73860e32015-08-19 16:30:16 -0700130 node1.closeFaces();
131 node2.closeFaces();
Junxiao Shib84e6742016-07-19 13:16:22 +0000132 advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700133 }
134
135public:
Yanbiao Li73860e32015-08-19 16:30:16 -0700136 FaceManagerNode node1; // used to test FaceManager
137 FaceManagerNode node2; // acts as a remote endpoint
138};
139
140class TcpFaceOnDemand
141{
142public:
143 ControlParameters
144 getParameters()
145 {
146 return ControlParameters()
147 .setUri("tcp4://127.0.0.1:26363")
148 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
149 }
150};
151
152class TcpFacePersistent
153{
154public:
155 ControlParameters
156 getParameters()
157 {
158 return ControlParameters()
159 .setUri("tcp4://127.0.0.1:26363")
160 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
161 }
162};
163
164class TcpFacePermanent
165{
166public:
167 ControlParameters
168 getParameters()
169 {
170 return ControlParameters()
171 .setUri("tcp4://127.0.0.1:26363")
172 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
173 }
174};
175
176class UdpFaceOnDemand
177{
178public:
179 ControlParameters
180 getParameters()
181 {
182 return ControlParameters()
183 .setUri("udp4://127.0.0.1:26363")
184 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_ON_DEMAND);
185 }
186};
187
188class UdpFaceCannotConnect // face that will cause afterCreateFaceFailure to be invoked
189{
190public:
191 ControlParameters
192 getParameters()
193 {
194 return ControlParameters()
195 .setUri("udp4://0.0.0.0:16363"); // cannot connect to self
196 }
197};
198
199
200class UdpFacePersistent
201{
202public:
203 ControlParameters
204 getParameters()
205 {
206 return ControlParameters()
207 .setUri("udp4://127.0.0.1:26363")
208 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
209 }
210};
211
212class UdpFacePermanent
213{
214public:
215 ControlParameters
216 getParameters()
217 {
218 return ControlParameters()
219 .setUri("udp4://127.0.0.1:26363")
220 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
221 }
222};
223
224class Success
225{
226public:
227 ControlResponse
228 getExpected()
229 {
230 return ControlResponse()
231 .setCode(200)
232 .setText("OK");
233 }
234};
235
236template<int CODE>
237class Failure
238{
239public:
240 ControlResponse
241 getExpected()
242 {
243 return ControlResponse()
244 .setCode(CODE)
245 .setText("Error"); // error description should not be checked
246 }
247};
248
249namespace mpl = boost::mpl;
250
251// pairs of CreateCommand and Success status
252typedef mpl::vector<mpl::pair<TcpFaceOnDemand, Failure<500>>,
253 mpl::pair<TcpFacePersistent, Success>,
254 mpl::pair<TcpFacePermanent, Failure<500>>,
255 mpl::pair<UdpFaceOnDemand, Failure<500>>,
256 mpl::pair<UdpFacePersistent, Success>,
257 mpl::pair<UdpFacePermanent, Success>,
258 mpl::pair<UdpFaceCannotConnect, Failure<408>>> Faces;
259
260BOOST_FIXTURE_TEST_CASE_TEMPLATE(NewFace, T, Faces, FaceManagerFixture)
261{
262 typedef typename T::first FaceType;
263 typedef typename T::second CreateResult;
264
265 Name commandName("/localhost/nfd/faces");
266 commandName.append("create");
267 commandName.append(FaceType().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000268 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000269 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700270
271 bool hasCallbackFired = false;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000272 this->node1.face.onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700273 if (!command->getName().isPrefixOf(response.getName())) {
274 return;
275 }
276
277 ControlResponse actual(response.getContent().blockFromValue());
278 ControlResponse expected(CreateResult().getExpected());
279 BOOST_CHECK_EQUAL(expected.getCode(), actual.getCode());
Alexander Afanasyev964d4592015-10-09 13:03:19 -0700280 BOOST_TEST_MESSAGE(actual.getText());
Yanbiao Li73860e32015-08-19 16:30:16 -0700281
282 if (actual.getBody().hasWire()) {
283 ControlParameters expectedParams(FaceType().getParameters());
284 ControlParameters actualParams(actual.getBody());
285
286 BOOST_CHECK_EQUAL(expectedParams.getUri(), actualParams.getUri());
287 BOOST_CHECK_EQUAL(expectedParams.getFacePersistency(), actualParams.getFacePersistency());
288 }
289 hasCallbackFired = true;
290 });
291
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000292 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000293 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700294
295 BOOST_CHECK(hasCallbackFired);
296}
297
298
299typedef mpl::vector<// mpl::pair<mpl::pair<TcpFacePersistent, TcpFacePermanent>, TcpFacePermanent>, // no need to check now
300 // mpl::pair<mpl::pair<TcpFacePermanent, TcpFacePersistent>, TcpFacePermanent>, // no need to check now
301 mpl::pair<mpl::pair<UdpFacePersistent, UdpFacePermanent>, UdpFacePermanent>,
302 mpl::pair<mpl::pair<UdpFacePermanent, UdpFacePersistent>, UdpFacePermanent>> FaceTransitions;
303
304
305BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExistingFace, T, FaceTransitions, FaceManagerFixture)
306{
307 typedef typename T::first::first FaceType1;
308 typedef typename T::first::second FaceType2;
309 typedef typename T::second FinalFaceType;
310
311 {
312 // create face
313
314 Name commandName("/localhost/nfd/faces");
315 commandName.append("create");
316 commandName.append(FaceType1().getParameters().wireEncode());
Junxiao Shib84e6742016-07-19 13:16:22 +0000317 auto command = makeInterest(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);
Junxiao Shib84e6742016-07-19 13:16:22 +0000321 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700322 }
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());
Junxiao Shib84e6742016-07-19 13:16:22 +0000331 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000332 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700333
334 bool hasCallbackFired = false;
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000335 this->node1.face.onSendData.connect([this, command, &hasCallbackFired] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700336 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
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000350 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000351 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700352
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());
Junxiao Shib84e6742016-07-19 13:16:22 +0000391 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000392 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700393
394 ndn::util::signal::ScopedConnection connection =
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000395 this->node2.face.onSendData.connect([this, command] (const Data& response) {
Yanbiao Li73860e32015-08-19 16:30:16 -0700396 if (!command->getName().isPrefixOf(response.getName())) {
397 return;
398 }
399
400 ControlResponse controlResponse(response.getContent().blockFromValue());
401 BOOST_REQUIRE_EQUAL(controlResponse.getText(), "OK");
402 BOOST_REQUIRE_EQUAL(controlResponse.getCode(), 200);
403 uint64_t faceId = ControlParameters(controlResponse.getBody()).getFaceId();
404 auto face = this->node2.forwarder.getFace(static_cast<FaceId>(faceId));
405
406 // to force creation of on-demand face
407 auto dummyInterest = make_shared<Interest>("/hello/world");
408 face->sendInterest(*dummyInterest);
409 });
410
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000411 this->node2.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000412 this->advanceClocks(time::milliseconds(1), 5); // let node2 process command and send Interest
413 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // allow wallclock time for socket IO
414 this->advanceClocks(time::milliseconds(1), 5); // let node1 accept Interest and create on-demand face
Yanbiao Li73860e32015-08-19 16:30:16 -0700415 }
416
417 // make sure there is on-demand face
Yanbiao Li73860e32015-08-19 16:30:16 -0700418 FaceUri onDemandFaceUri(FaceType().getParameters().getUri());
Junxiao Shib84e6742016-07-19 13:16:22 +0000419 const Face* foundFace = nullptr;
420 for (const Face& face : this->node1.faceTable) {
421 if (face.getRemoteUri() == onDemandFaceUri) {
422 foundFace = &face;
Yanbiao Li73860e32015-08-19 16:30:16 -0700423 break;
424 }
425 }
Junxiao Shib84e6742016-07-19 13:16:22 +0000426 BOOST_REQUIRE_MESSAGE(foundFace != nullptr, "on-demand face is not created");
Yanbiao Li73860e32015-08-19 16:30:16 -0700427
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());
Junxiao Shib84e6742016-07-19 13:16:22 +0000435 auto command = makeInterest(commandName);
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000436 m_keyChain.sign(*command);
Yanbiao Li73860e32015-08-19 16:30:16 -0700437
438 bool hasCallbackFired = false;
Junxiao Shib84e6742016-07-19 13:16:22 +0000439 this->node1.face.onSendData.connect(
440 [this, command, &hasCallbackFired, foundFace] (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());
Junxiao Shib84e6742016-07-19 13:16:22 +0000450 BOOST_CHECK_EQUAL(actualParams.getFacePersistency(), expectedParams.getFacePersistency());
451 BOOST_CHECK_EQUAL(actualParams.getFaceId(), foundFace->getId());
452 BOOST_CHECK_EQUAL(foundFace->getPersistency(), expectedParams.getFacePersistency());
Yanbiao Li73860e32015-08-19 16:30:16 -0700453
454 hasCallbackFired = true;
455 });
456
Junxiao Shi221b6fe2016-07-14 18:21:56 +0000457 this->node1.face.receive(*command);
Junxiao Shib84e6742016-07-19 13:16:22 +0000458 this->advanceClocks(time::milliseconds(1), 5);
Yanbiao Li73860e32015-08-19 16:30:16 -0700459
460 BOOST_CHECK(hasCallbackFired);
461 }
462}
463
464BOOST_AUTO_TEST_SUITE_END() // CreateFace
465BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
466BOOST_AUTO_TEST_SUITE_END() // Mgmt
467
Weiwei Liuf5aee942016-03-19 07:00:42 +0000468} // namespace tests
469} // namespace nfd