blob: 67576226223fe933cb2eba455bd6cfad45bcaa69 [file] [log] [blame]
Eric Newberryb5aa7f52016-09-03 20:36:12 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
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,
57 bool enableLocalFields = false)
58 {
59 ControlParameters params;
60 params.setUri(uri);
61 params.setFacePersistency(persistency);
62 params.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, enableLocalFields);
63
Yanbiao Li58ba3f92017-02-15 14:27:18 +000064 createFace(params);
65 }
66
67 void
68 createFace(const ControlParameters& createParams,
69 bool isForOnDemandFace = false)
70 {
Eric Newberryb5aa7f52016-09-03 20:36:12 -070071 Name commandName("/localhost/nfd/faces/create");
Yanbiao Li58ba3f92017-02-15 14:27:18 +000072 commandName.append(createParams.wireEncode());
Eric Newberryb5aa7f52016-09-03 20:36:12 -070073 auto command = makeInterest(commandName);
74 m_keyChain.sign(*command);
75
Yanbiao Li58ba3f92017-02-15 14:27:18 +000076 // if this creation if for on-demand face then create it on node2
77 FaceManagerCommandNode& target = isForOnDemandFace ? this->node2 : this->node1;
78
Eric Newberryb5aa7f52016-09-03 20:36:12 -070079 bool hasCallbackFired = false;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000080 signal::ScopedConnection connection = target.face.onSendData.connect(
81 [&, command, isForOnDemandFace, this] (const Data& response) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -070082 if (!command->getName().isPrefixOf(response.getName())) {
83 return;
84 }
85
86 ControlResponse create(response.getContent().blockFromValue());
87 BOOST_REQUIRE_EQUAL(create.getCode(), 200);
Yanbiao Li58ba3f92017-02-15 14:27:18 +000088 BOOST_REQUIRE(create.getBody().hasWire());
Eric Newberryb5aa7f52016-09-03 20:36:12 -070089
Yanbiao Li58ba3f92017-02-15 14:27:18 +000090 ControlParameters faceParams(create.getBody());
91 BOOST_REQUIRE(faceParams.hasFaceId());
92 this->faceId = faceParams.getFaceId();
Eric Newberryb5aa7f52016-09-03 20:36:12 -070093
94 hasCallbackFired = true;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000095
96 if (isForOnDemandFace) {
97 auto face = target.faceTable.get(static_cast<FaceId>(this->faceId));
98
99 // to force creation of on-demand face
100 face->sendInterest(*make_shared<Interest>("/hello/world"));
101 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700102 });
103
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000104 target.face.receive(*command);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700105 this->advanceClocks(time::milliseconds(1), 5);
106
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000107 if (isForOnDemandFace) {
108 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // allow wallclock time for socket IO
109 this->advanceClocks(time::milliseconds(1), 5); // let node1 accept Interest and create on-demand face
110 }
111
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700112 BOOST_REQUIRE(hasCallbackFired);
113 }
114
115 void
116 updateFace(const ControlParameters& requestParams,
117 bool isSelfUpdating,
118 const function<void(const ControlResponse& resp)>& checkResp)
119 {
120 Name commandName("/localhost/nfd/faces/update");
121 commandName.append(requestParams.wireEncode());
122 auto command = makeInterest(commandName);
123 if (isSelfUpdating) {
124 // Attach IncomingFaceIdTag to interest
125 command->setTag(make_shared<lp::IncomingFaceIdTag>(faceId));
126 }
127 m_keyChain.sign(*command);
128
129 bool hasCallbackFired = false;
130 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
131 [this, command, &hasCallbackFired, &checkResp] (const Data& response) {
132 if (!command->getName().isPrefixOf(response.getName())) {
133 return;
134 }
135
136 ControlResponse actual(response.getContent().blockFromValue());
137 checkResp(actual);
138
139 hasCallbackFired = true;
140 });
141
142 this->node1.face.receive(*command);
143 this->advanceClocks(time::milliseconds(1), 5);
144
145 BOOST_CHECK(hasCallbackFired);
146 }
147
148private:
149 void
150 destroyFace()
151 {
152 if (faceId == 0) {
153 return;
154 }
155
156 ControlParameters params;
157 params.setFaceId(faceId);
158
159 Name commandName("/localhost/nfd/faces/destroy");
160 commandName.append(params.wireEncode());
161 auto command = makeInterest(commandName);
162 m_keyChain.sign(*command);
163
164 bool hasCallbackFired = false;
165 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
166 [this, command, &hasCallbackFired] (const Data& response) {
167 if (!command->getName().isPrefixOf(response.getName())) {
168 return;
169 }
170
171 ControlResponse destroy(response.getContent().blockFromValue());
172 BOOST_CHECK_EQUAL(destroy.getCode(), 200);
173
174 faceId = 0;
175 hasCallbackFired = true;
176 });
177
178 this->node1.face.receive(*command);
179 this->advanceClocks(time::milliseconds(1), 5);
180
181 BOOST_CHECK(hasCallbackFired);
182 }
183
184public:
185 FaceId faceId;
186};
187
188BOOST_FIXTURE_TEST_SUITE(UpdateFace, FaceManagerUpdateFixture)
189
190BOOST_AUTO_TEST_CASE(FaceDoesNotExist)
191{
192 ControlParameters requestParams;
193 requestParams.setFaceId(65535);
194
195 updateFace(requestParams, false, [] (const ControlResponse& actual) {
196 ControlResponse expected(404, "Specified face does not exist");
197 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
198 BOOST_TEST_MESSAGE(actual.getText());
199 });
200}
201
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000202template<bool CAN_CHANGE_PERSISTENCY>
203class UpdatePersistencyDummyTransport : public face::Transport
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700204{
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000205public:
206 UpdatePersistencyDummyTransport()
207 {
208 this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
209 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700210
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000211protected:
212 bool
213 canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const override
214 {
215 return CAN_CHANGE_PERSISTENCY;
216 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700217
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000218 void
219 doClose() override
220 {
221 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700222
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000223private:
224 void
225 doSend(face::Transport::Packet&& packet) override
226 {
227 }
228};
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700229
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000230namespace mpl = boost::mpl;
231
232using UpdatePersistencyTests =
233 mpl::vector<mpl::pair<UpdatePersistencyDummyTransport<true>, CommandSuccess>,
234 mpl::pair<UpdatePersistencyDummyTransport<false>, CommandFailure<409>>>;
235
236BOOST_FIXTURE_TEST_CASE_TEMPLATE(UpdatePersistency, T, UpdatePersistencyTests, FaceManagerUpdateFixture)
237{
238 using TransportType = typename T::first;
239 using ResultType = typename T::second;
240
241 auto face = make_shared<face::Face>(make_unique<face::GenericLinkService>(),
242 make_unique<TransportType>());
243 this->node1.faceTable.add(face);
244
245 auto parameters = ControlParameters()
246 .setFaceId(face->getId())
247 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
248
249 updateFace(parameters, false, [] (const ControlResponse& actual) {
250 BOOST_TEST_MESSAGE(actual.getText());
251 BOOST_CHECK_EQUAL(actual.getCode(), ResultType::getExpected().getCode());
252
253 // the response for either 200 or 409 will have a content body
254 BOOST_REQUIRE(actual.getBody().hasWire());
255
256 ControlParameters resp;
257 resp.wireDecode(actual.getBody());
258 BOOST_CHECK_EQUAL(resp.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700259 });
260}
261
262class TcpLocalFieldsEnable
263{
264public:
265 std::string
266 getUri()
267 {
268 return "tcp4://127.0.0.1:26363";
269 }
270
271 boost::asio::ip::address_v4
272 getIpAddress()
273 {
274 return boost::asio::ip::address_v4::from_string("127.0.0.1");
275 }
276
277 ndn::nfd::FacePersistency
278 getPersistency()
279 {
280 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
281 }
282
283 bool
284 getInitLocalFieldsEnabled()
285 {
286 return false;
287 }
288
289 bool
290 getLocalFieldsEnabled()
291 {
292 return true;
293 }
294
295 bool
296 getLocalFieldsEnabledMask()
297 {
298 return true;
299 }
300
301 bool
302 shouldHaveWire()
303 {
304 return false;
305 }
306};
307
308class TcpLocalFieldsDisable
309{
310public:
311 std::string
312 getUri()
313 {
314 return "tcp4://127.0.0.1:26363";
315 }
316
317 ndn::nfd::FacePersistency
318 getPersistency()
319 {
320 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
321 }
322
323 bool
324 getInitLocalFieldsEnabled()
325 {
326 return true;
327 }
328
329 bool
330 getLocalFieldsEnabled()
331 {
332 return false;
333 }
334
335 bool
336 getLocalFieldsEnabledMask()
337 {
338 return true;
339 }
340
341 bool
342 shouldHaveWire()
343 {
344 return false;
345 }
346};
347
348// UDP faces are non-local by definition
349class UdpLocalFieldsEnable
350{
351public:
352 std::string
353 getUri()
354 {
355 return "udp4://127.0.0.1:26363";
356 }
357
358 ndn::nfd::FacePersistency
359 getPersistency()
360 {
361 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
362 }
363
364 bool
365 getInitLocalFieldsEnabled()
366 {
367 return false;
368 }
369
370 bool
371 getLocalFieldsEnabled()
372 {
373 return true;
374 }
375
376 bool
377 getLocalFieldsEnabledMask()
378 {
379 return true;
380 }
381
382 bool
383 shouldHaveWire()
384 {
385 return true;
386 }
387};
388
389// UDP faces are non-local by definition
390// In this test case, attempt to disable local fields on face with local fields already disabled
391class UdpLocalFieldsDisable
392{
393public:
394 std::string
395 getUri()
396 {
397 return "udp4://127.0.0.1:26363";
398 }
399
400 ndn::nfd::FacePersistency
401 getPersistency()
402 {
403 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
404 }
405
406 bool
407 getInitLocalFieldsEnabled()
408 {
409 return false;
410 }
411
412 bool
413 getLocalFieldsEnabled()
414 {
415 return false;
416 }
417
418 bool
419 getLocalFieldsEnabledMask()
420 {
421 return true;
422 }
423
424 bool
425 shouldHaveWire()
426 {
427 return false;
428 }
429};
430
431// In this test case, set Flags to enable local fields on non-local face, but exclude local fields
432// from Mask. This test case will pass as no action is taken due to the missing Mask bit.
433class UdpLocalFieldsEnableNoMaskBit
434{
435public:
436 std::string
437 getUri()
438 {
439 return "udp4://127.0.0.1:26363";
440 }
441
442 ndn::nfd::FacePersistency
443 getPersistency()
444 {
445 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
446 }
447
448 bool
449 getInitLocalFieldsEnabled()
450 {
451 return false;
452 }
453
454 bool
455 getLocalFieldsEnabled()
456 {
457 return true;
458 }
459
460 bool
461 getLocalFieldsEnabledMask()
462 {
463 return false;
464 }
465
466 bool
467 shouldHaveWire()
468 {
469 return false;
470 }
471};
472
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700473typedef mpl::vector<mpl::pair<TcpLocalFieldsEnable, CommandSuccess>,
474 mpl::pair<TcpLocalFieldsDisable, CommandSuccess>,
475 mpl::pair<UdpLocalFieldsEnable, CommandFailure<409>>,
476 mpl::pair<UdpLocalFieldsDisable, CommandSuccess>,
477 mpl::pair<UdpLocalFieldsEnableNoMaskBit, CommandSuccess>> LocalFieldFaces;
478
479BOOST_AUTO_TEST_CASE_TEMPLATE(UpdateLocalFields, T, LocalFieldFaces)
480{
481 typedef typename T::first TestType;
482 typedef typename T::second ResultType;
483
484 createFace(TestType().getUri(), TestType().getPersistency(), TestType().getInitLocalFieldsEnabled());
485
486 ControlParameters requestParams;
487 requestParams.setFaceId(faceId);
488 requestParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, TestType().getLocalFieldsEnabled());
489 if (!TestType().getLocalFieldsEnabledMask()) {
490 requestParams.unsetFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
491 }
492
493 updateFace(requestParams, false, [] (const ControlResponse& actual) {
494 ControlResponse expected(ResultType().getExpected().getCode(), "");
495 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
496 BOOST_TEST_MESSAGE(actual.getText());
497
498 if (TestType().shouldHaveWire() && actual.getBody().hasWire()) {
499 ControlParameters actualParams(actual.getBody());
500
501 BOOST_CHECK(!actualParams.hasFacePersistency());
502 BOOST_CHECK(actualParams.hasFlags());
503 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
504 BOOST_CHECK(actualParams.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
505 }
506 });
507}
508
509BOOST_AUTO_TEST_CASE(UpdateLocalFieldsEnableDisable)
510{
511 createFace();
512
513 ControlParameters enableParams;
514 enableParams.setFaceId(faceId);
515 enableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
516
517 ControlParameters disableParams;
518 disableParams.setFaceId(faceId);
519 disableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
520
521 updateFace(enableParams, false, [] (const ControlResponse& actual) {
522 ControlResponse expected(200, "OK");
523 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
524 BOOST_TEST_MESSAGE(actual.getText());
525
526 if (actual.getBody().hasWire()) {
527 ControlParameters actualParams(actual.getBody());
528
529 BOOST_CHECK(actualParams.hasFaceId());
530 BOOST_CHECK(actualParams.hasFacePersistency());
531 BOOST_REQUIRE(actualParams.hasFlags());
532 // Check if flags indicate local fields enabled
533 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
534 }
535 else {
536 BOOST_ERROR("Enable: Response does not contain ControlParameters");
537 }
538 });
539
540 updateFace(disableParams, false, [] (const ControlResponse& actual) {
541 ControlResponse expected(200, "OK");
542 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
543 BOOST_TEST_MESSAGE(actual.getText());
544
545 if (actual.getBody().hasWire()) {
546 ControlParameters actualParams(actual.getBody());
547
548 BOOST_CHECK(actualParams.hasFaceId());
549 BOOST_CHECK(actualParams.hasFacePersistency());
550 BOOST_REQUIRE(actualParams.hasFlags());
551 // Check if flags indicate local fields disabled
552 BOOST_CHECK(!actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
553 }
554 else {
555 BOOST_ERROR("Disable: Response does not contain ControlParameters");
556 }
557 });
558}
559
560BOOST_AUTO_TEST_CASE(SelfUpdating)
561{
562 createFace();
563
564 // Send a command that does nothing (will return 200) and does not contain a FaceId
565 ControlParameters sentParams;
566
567 updateFace(sentParams, true, [] (const ControlResponse& actual) {
568 ControlResponse expected(200, "OK");
569 BOOST_REQUIRE_EQUAL(actual.getCode(), expected.getCode());
570 BOOST_TEST_MESSAGE(actual.getText());
571 });
572}
573
574BOOST_AUTO_TEST_SUITE_END() // UpdateFace
575BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
576BOOST_AUTO_TEST_SUITE_END() // Mgmt
577
578} // namespace tests
579} // namespace nfd