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