blob: 9a6825eb1d9530418e14ca9e4367f000b011385f [file] [log] [blame]
Eric Newberryb5aa7f52016-09-03 20:36:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Eric Newberry2642cd22017-07-13 21:34:53 -04002/*
Yanbiao Li58ba3f92017-02-15 14:27:18 +00003 * Copyright (c) 2014-2017, Regents of the University of California,
Eric Newberryb5aa7f52016-09-03 20:36:12 -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
Yanbiao Li58ba3f92017-02-15 14:27:18 +000026#include "mgmt/face-manager.hpp"
27#include "face/generic-link-service.hpp"
Eric Newberryb5aa7f52016-09-03 20:36:12 -070028#include "face-manager-command-fixture.hpp"
29#include "nfd-manager-common-fixture.hpp"
Yanbiao Li58ba3f92017-02-15 14:27:18 +000030
Junxiao Shicbc8e942016-09-06 03:17:45 +000031#include <ndn-cxx/lp/tags.hpp>
Eric Newberryb5aa7f52016-09-03 20:36:12 -070032
Yanbiao Li58ba3f92017-02-15 14:27:18 +000033#include <thread>
34
Eric Newberryb5aa7f52016-09-03 20:36:12 -070035namespace nfd {
36namespace tests {
37
38BOOST_AUTO_TEST_SUITE(Mgmt)
39BOOST_AUTO_TEST_SUITE(TestFaceManager)
40
41class FaceManagerUpdateFixture : public FaceManagerCommandFixture
42{
43public:
44 FaceManagerUpdateFixture()
45 : faceId(0)
46 {
47 }
48
49 ~FaceManagerUpdateFixture()
50 {
51 destroyFace();
52 }
53
54 void
55 createFace(const std::string& uri = "tcp4://127.0.0.1:26363",
56 ndn::nfd::FacePersistency persistency = ndn::nfd::FACE_PERSISTENCY_PERSISTENT,
Eric Newberry2642cd22017-07-13 21:34:53 -040057 bool enableLocalFields = false,
58 bool enableReliability = false)
Eric Newberryb5aa7f52016-09-03 20:36:12 -070059 {
60 ControlParameters params;
61 params.setUri(uri);
62 params.setFacePersistency(persistency);
63 params.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, enableLocalFields);
Eric Newberry2642cd22017-07-13 21:34:53 -040064 params.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, enableReliability);
Eric Newberryb5aa7f52016-09-03 20:36:12 -070065
Yanbiao Li58ba3f92017-02-15 14:27:18 +000066 createFace(params);
67 }
68
69 void
70 createFace(const ControlParameters& createParams,
71 bool isForOnDemandFace = false)
72 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000073 Interest req = makeControlCommandRequest("/localhost/nfd/faces/create", createParams);
Eric Newberryb5aa7f52016-09-03 20:36:12 -070074
Yanbiao Li58ba3f92017-02-15 14:27:18 +000075 // if this creation if for on-demand face then create it on node2
76 FaceManagerCommandNode& target = isForOnDemandFace ? this->node2 : this->node1;
77
Eric Newberryb5aa7f52016-09-03 20:36:12 -070078 bool hasCallbackFired = false;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000079 signal::ScopedConnection connection = target.face.onSendData.connect(
Junxiao Shi8a1f1702017-07-03 00:05:08 +000080 [&, req, isForOnDemandFace, this] (const Data& response) {
81 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -070082 return;
83 }
84
85 ControlResponse create(response.getContent().blockFromValue());
86 BOOST_REQUIRE_EQUAL(create.getCode(), 200);
Yanbiao Li58ba3f92017-02-15 14:27:18 +000087 BOOST_REQUIRE(create.getBody().hasWire());
Eric Newberryb5aa7f52016-09-03 20:36:12 -070088
Yanbiao Li58ba3f92017-02-15 14:27:18 +000089 ControlParameters faceParams(create.getBody());
90 BOOST_REQUIRE(faceParams.hasFaceId());
91 this->faceId = faceParams.getFaceId();
Eric Newberryb5aa7f52016-09-03 20:36:12 -070092
93 hasCallbackFired = true;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000094
95 if (isForOnDemandFace) {
96 auto face = target.faceTable.get(static_cast<FaceId>(this->faceId));
97
98 // to force creation of on-demand face
99 face->sendInterest(*make_shared<Interest>("/hello/world"));
100 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700101 });
102
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000103 target.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700104 this->advanceClocks(time::milliseconds(1), 5);
105
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000106 if (isForOnDemandFace) {
107 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // allow wallclock time for socket IO
108 this->advanceClocks(time::milliseconds(1), 5); // let node1 accept Interest and create on-demand face
109 }
110
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700111 BOOST_REQUIRE(hasCallbackFired);
112 }
113
114 void
115 updateFace(const ControlParameters& requestParams,
116 bool isSelfUpdating,
117 const function<void(const ControlResponse& resp)>& checkResp)
118 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000119 Interest req = makeControlCommandRequest("/localhost/nfd/faces/update", requestParams);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700120 if (isSelfUpdating) {
121 // Attach IncomingFaceIdTag to interest
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000122 req.setTag(make_shared<lp::IncomingFaceIdTag>(faceId));
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700123 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700124
125 bool hasCallbackFired = false;
126 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
Davide Pesaventoac238f22017-09-12 15:19:40 -0400127 [req, &hasCallbackFired, &checkResp] (const Data& response) {
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000128 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700129 return;
130 }
131
132 ControlResponse actual(response.getContent().blockFromValue());
133 checkResp(actual);
134
135 hasCallbackFired = true;
136 });
137
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000138 this->node1.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700139 this->advanceClocks(time::milliseconds(1), 5);
140
141 BOOST_CHECK(hasCallbackFired);
142 }
143
144private:
145 void
146 destroyFace()
147 {
148 if (faceId == 0) {
149 return;
150 }
151
152 ControlParameters params;
153 params.setFaceId(faceId);
154
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000155 Interest req = makeControlCommandRequest("/localhost/nfd/faces/destroy", params);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700156
157 bool hasCallbackFired = false;
158 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000159 [this, req, &hasCallbackFired] (const Data& response) {
160 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700161 return;
162 }
163
164 ControlResponse destroy(response.getContent().blockFromValue());
165 BOOST_CHECK_EQUAL(destroy.getCode(), 200);
166
167 faceId = 0;
168 hasCallbackFired = true;
169 });
170
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000171 this->node1.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700172 this->advanceClocks(time::milliseconds(1), 5);
173
174 BOOST_CHECK(hasCallbackFired);
175 }
176
177public:
178 FaceId faceId;
179};
180
181BOOST_FIXTURE_TEST_SUITE(UpdateFace, FaceManagerUpdateFixture)
182
183BOOST_AUTO_TEST_CASE(FaceDoesNotExist)
184{
185 ControlParameters requestParams;
186 requestParams.setFaceId(65535);
187
188 updateFace(requestParams, false, [] (const ControlResponse& actual) {
189 ControlResponse expected(404, "Specified face does not exist");
190 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
191 BOOST_TEST_MESSAGE(actual.getText());
192 });
193}
194
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000195template<bool CAN_CHANGE_PERSISTENCY>
196class UpdatePersistencyDummyTransport : public face::Transport
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700197{
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000198public:
199 UpdatePersistencyDummyTransport()
200 {
201 this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
202 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700203
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000204protected:
205 bool
206 canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const override
207 {
208 return CAN_CHANGE_PERSISTENCY;
209 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700210
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000211 void
212 doClose() override
213 {
214 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700215
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000216private:
217 void
218 doSend(face::Transport::Packet&& packet) override
219 {
220 }
221};
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700222
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000223namespace mpl = boost::mpl;
224
225using UpdatePersistencyTests =
226 mpl::vector<mpl::pair<UpdatePersistencyDummyTransport<true>, CommandSuccess>,
227 mpl::pair<UpdatePersistencyDummyTransport<false>, CommandFailure<409>>>;
228
229BOOST_FIXTURE_TEST_CASE_TEMPLATE(UpdatePersistency, T, UpdatePersistencyTests, FaceManagerUpdateFixture)
230{
231 using TransportType = typename T::first;
232 using ResultType = typename T::second;
233
234 auto face = make_shared<face::Face>(make_unique<face::GenericLinkService>(),
235 make_unique<TransportType>());
236 this->node1.faceTable.add(face);
237
238 auto parameters = ControlParameters()
239 .setFaceId(face->getId())
240 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
241
242 updateFace(parameters, false, [] (const ControlResponse& actual) {
243 BOOST_TEST_MESSAGE(actual.getText());
244 BOOST_CHECK_EQUAL(actual.getCode(), ResultType::getExpected().getCode());
245
246 // the response for either 200 or 409 will have a content body
247 BOOST_REQUIRE(actual.getBody().hasWire());
248
249 ControlParameters resp;
250 resp.wireDecode(actual.getBody());
251 BOOST_CHECK_EQUAL(resp.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700252 });
253}
254
255class TcpLocalFieldsEnable
256{
257public:
258 std::string
259 getUri()
260 {
261 return "tcp4://127.0.0.1:26363";
262 }
263
264 boost::asio::ip::address_v4
265 getIpAddress()
266 {
267 return boost::asio::ip::address_v4::from_string("127.0.0.1");
268 }
269
270 ndn::nfd::FacePersistency
271 getPersistency()
272 {
273 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
274 }
275
276 bool
277 getInitLocalFieldsEnabled()
278 {
279 return false;
280 }
281
282 bool
283 getLocalFieldsEnabled()
284 {
285 return true;
286 }
287
288 bool
289 getLocalFieldsEnabledMask()
290 {
291 return true;
292 }
293
294 bool
295 shouldHaveWire()
296 {
297 return false;
298 }
299};
300
301class TcpLocalFieldsDisable
302{
303public:
304 std::string
305 getUri()
306 {
307 return "tcp4://127.0.0.1:26363";
308 }
309
310 ndn::nfd::FacePersistency
311 getPersistency()
312 {
313 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
314 }
315
316 bool
317 getInitLocalFieldsEnabled()
318 {
319 return true;
320 }
321
322 bool
323 getLocalFieldsEnabled()
324 {
325 return false;
326 }
327
328 bool
329 getLocalFieldsEnabledMask()
330 {
331 return true;
332 }
333
334 bool
335 shouldHaveWire()
336 {
337 return false;
338 }
339};
340
341// UDP faces are non-local by definition
342class UdpLocalFieldsEnable
343{
344public:
345 std::string
346 getUri()
347 {
348 return "udp4://127.0.0.1:26363";
349 }
350
351 ndn::nfd::FacePersistency
352 getPersistency()
353 {
354 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
355 }
356
357 bool
358 getInitLocalFieldsEnabled()
359 {
360 return false;
361 }
362
363 bool
364 getLocalFieldsEnabled()
365 {
366 return true;
367 }
368
369 bool
370 getLocalFieldsEnabledMask()
371 {
372 return true;
373 }
374
375 bool
376 shouldHaveWire()
377 {
378 return true;
379 }
380};
381
382// UDP faces are non-local by definition
383// In this test case, attempt to disable local fields on face with local fields already disabled
384class UdpLocalFieldsDisable
385{
386public:
387 std::string
388 getUri()
389 {
390 return "udp4://127.0.0.1:26363";
391 }
392
393 ndn::nfd::FacePersistency
394 getPersistency()
395 {
396 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
397 }
398
399 bool
400 getInitLocalFieldsEnabled()
401 {
402 return false;
403 }
404
405 bool
406 getLocalFieldsEnabled()
407 {
408 return false;
409 }
410
411 bool
412 getLocalFieldsEnabledMask()
413 {
414 return true;
415 }
416
417 bool
418 shouldHaveWire()
419 {
420 return false;
421 }
422};
423
424// In this test case, set Flags to enable local fields on non-local face, but exclude local fields
425// from Mask. This test case will pass as no action is taken due to the missing Mask bit.
426class UdpLocalFieldsEnableNoMaskBit
427{
428public:
429 std::string
430 getUri()
431 {
432 return "udp4://127.0.0.1:26363";
433 }
434
435 ndn::nfd::FacePersistency
436 getPersistency()
437 {
438 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
439 }
440
441 bool
442 getInitLocalFieldsEnabled()
443 {
444 return false;
445 }
446
447 bool
448 getLocalFieldsEnabled()
449 {
450 return true;
451 }
452
453 bool
454 getLocalFieldsEnabledMask()
455 {
456 return false;
457 }
458
459 bool
460 shouldHaveWire()
461 {
462 return false;
463 }
464};
465
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700466typedef mpl::vector<mpl::pair<TcpLocalFieldsEnable, CommandSuccess>,
467 mpl::pair<TcpLocalFieldsDisable, CommandSuccess>,
468 mpl::pair<UdpLocalFieldsEnable, CommandFailure<409>>,
469 mpl::pair<UdpLocalFieldsDisable, CommandSuccess>,
470 mpl::pair<UdpLocalFieldsEnableNoMaskBit, CommandSuccess>> LocalFieldFaces;
471
472BOOST_AUTO_TEST_CASE_TEMPLATE(UpdateLocalFields, T, LocalFieldFaces)
473{
474 typedef typename T::first TestType;
475 typedef typename T::second ResultType;
476
477 createFace(TestType().getUri(), TestType().getPersistency(), TestType().getInitLocalFieldsEnabled());
478
479 ControlParameters requestParams;
480 requestParams.setFaceId(faceId);
481 requestParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, TestType().getLocalFieldsEnabled());
482 if (!TestType().getLocalFieldsEnabledMask()) {
483 requestParams.unsetFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
484 }
485
486 updateFace(requestParams, false, [] (const ControlResponse& actual) {
487 ControlResponse expected(ResultType().getExpected().getCode(), "");
488 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
489 BOOST_TEST_MESSAGE(actual.getText());
490
491 if (TestType().shouldHaveWire() && actual.getBody().hasWire()) {
492 ControlParameters actualParams(actual.getBody());
493
494 BOOST_CHECK(!actualParams.hasFacePersistency());
495 BOOST_CHECK(actualParams.hasFlags());
496 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
497 BOOST_CHECK(actualParams.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
498 }
499 });
500}
501
502BOOST_AUTO_TEST_CASE(UpdateLocalFieldsEnableDisable)
503{
504 createFace();
505
506 ControlParameters enableParams;
507 enableParams.setFaceId(faceId);
508 enableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
509
510 ControlParameters disableParams;
511 disableParams.setFaceId(faceId);
512 disableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
513
514 updateFace(enableParams, false, [] (const ControlResponse& actual) {
515 ControlResponse expected(200, "OK");
516 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
517 BOOST_TEST_MESSAGE(actual.getText());
518
519 if (actual.getBody().hasWire()) {
520 ControlParameters actualParams(actual.getBody());
521
522 BOOST_CHECK(actualParams.hasFaceId());
523 BOOST_CHECK(actualParams.hasFacePersistency());
524 BOOST_REQUIRE(actualParams.hasFlags());
525 // Check if flags indicate local fields enabled
526 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
527 }
528 else {
529 BOOST_ERROR("Enable: Response does not contain ControlParameters");
530 }
531 });
532
533 updateFace(disableParams, false, [] (const ControlResponse& actual) {
534 ControlResponse expected(200, "OK");
535 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
536 BOOST_TEST_MESSAGE(actual.getText());
537
538 if (actual.getBody().hasWire()) {
539 ControlParameters actualParams(actual.getBody());
540
541 BOOST_CHECK(actualParams.hasFaceId());
542 BOOST_CHECK(actualParams.hasFacePersistency());
543 BOOST_REQUIRE(actualParams.hasFlags());
544 // Check if flags indicate local fields disabled
545 BOOST_CHECK(!actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
546 }
547 else {
548 BOOST_ERROR("Disable: Response does not contain ControlParameters");
549 }
550 });
551}
552
Eric Newberry2642cd22017-07-13 21:34:53 -0400553BOOST_AUTO_TEST_CASE(UpdateReliabilityEnableDisable)
554{
555 createFace("udp4://127.0.0.1:26363");
556
557 ControlParameters enableParams;
558 enableParams.setFaceId(faceId);
559 enableParams.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, true);
560
561 ControlParameters disableParams;
562 disableParams.setFaceId(faceId);
563 disableParams.setFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED, false);
564
565 updateFace(enableParams, false, [] (const ControlResponse& actual) {
566 ControlResponse expected(200, "OK");
567 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
568 BOOST_TEST_MESSAGE(actual.getText());
569
570 if (actual.getBody().hasWire()) {
571 ControlParameters actualParams(actual.getBody());
572
573 BOOST_CHECK(actualParams.hasFaceId());
574 BOOST_CHECK(actualParams.hasFacePersistency());
575 BOOST_REQUIRE(actualParams.hasFlags());
576 // Check if flags indicate reliability enabled
577 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED));
578 }
579 else {
580 BOOST_ERROR("Enable: Response does not contain ControlParameters");
581 }
582 });
583
584 updateFace(disableParams, false, [] (const ControlResponse& actual) {
585 ControlResponse expected(200, "OK");
586 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
587 BOOST_TEST_MESSAGE(actual.getText());
588
589 if (actual.getBody().hasWire()) {
590 ControlParameters actualParams(actual.getBody());
591
592 BOOST_CHECK(actualParams.hasFaceId());
593 BOOST_CHECK(actualParams.hasFacePersistency());
594 BOOST_REQUIRE(actualParams.hasFlags());
595 // Check if flags indicate reliability disabled
596 BOOST_CHECK(!actualParams.getFlagBit(ndn::nfd::BIT_LP_RELIABILITY_ENABLED));
597 }
598 else {
599 BOOST_ERROR("Disable: Response does not contain ControlParameters");
600 }
601 });
602}
603
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700604BOOST_AUTO_TEST_CASE(SelfUpdating)
605{
606 createFace();
607
608 // Send a command that does nothing (will return 200) and does not contain a FaceId
609 ControlParameters sentParams;
610
611 updateFace(sentParams, true, [] (const ControlResponse& actual) {
612 ControlResponse expected(200, "OK");
613 BOOST_REQUIRE_EQUAL(actual.getCode(), expected.getCode());
614 BOOST_TEST_MESSAGE(actual.getText());
615 });
616}
617
618BOOST_AUTO_TEST_SUITE_END() // UpdateFace
619BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
620BOOST_AUTO_TEST_SUITE_END() // Mgmt
621
622} // namespace tests
623} // namespace nfd