blob: e81e3bede4507dc543a198ede3eed88304bdf7ba [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 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +000071 Interest req = makeControlCommandRequest("/localhost/nfd/faces/create", createParams);
Eric Newberryb5aa7f52016-09-03 20:36:12 -070072
Yanbiao Li58ba3f92017-02-15 14:27:18 +000073 // if this creation if for on-demand face then create it on node2
74 FaceManagerCommandNode& target = isForOnDemandFace ? this->node2 : this->node1;
75
Eric Newberryb5aa7f52016-09-03 20:36:12 -070076 bool hasCallbackFired = false;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000077 signal::ScopedConnection connection = target.face.onSendData.connect(
Junxiao Shi8a1f1702017-07-03 00:05:08 +000078 [&, req, isForOnDemandFace, this] (const Data& response) {
79 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -070080 return;
81 }
82
83 ControlResponse create(response.getContent().blockFromValue());
84 BOOST_REQUIRE_EQUAL(create.getCode(), 200);
Yanbiao Li58ba3f92017-02-15 14:27:18 +000085 BOOST_REQUIRE(create.getBody().hasWire());
Eric Newberryb5aa7f52016-09-03 20:36:12 -070086
Yanbiao Li58ba3f92017-02-15 14:27:18 +000087 ControlParameters faceParams(create.getBody());
88 BOOST_REQUIRE(faceParams.hasFaceId());
89 this->faceId = faceParams.getFaceId();
Eric Newberryb5aa7f52016-09-03 20:36:12 -070090
91 hasCallbackFired = true;
Yanbiao Li58ba3f92017-02-15 14:27:18 +000092
93 if (isForOnDemandFace) {
94 auto face = target.faceTable.get(static_cast<FaceId>(this->faceId));
95
96 // to force creation of on-demand face
97 face->sendInterest(*make_shared<Interest>("/hello/world"));
98 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -070099 });
100
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000101 target.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700102 this->advanceClocks(time::milliseconds(1), 5);
103
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000104 if (isForOnDemandFace) {
105 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // allow wallclock time for socket IO
106 this->advanceClocks(time::milliseconds(1), 5); // let node1 accept Interest and create on-demand face
107 }
108
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700109 BOOST_REQUIRE(hasCallbackFired);
110 }
111
112 void
113 updateFace(const ControlParameters& requestParams,
114 bool isSelfUpdating,
115 const function<void(const ControlResponse& resp)>& checkResp)
116 {
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000117 Interest req = makeControlCommandRequest("/localhost/nfd/faces/update", requestParams);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700118 if (isSelfUpdating) {
119 // Attach IncomingFaceIdTag to interest
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000120 req.setTag(make_shared<lp::IncomingFaceIdTag>(faceId));
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700121 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700122
123 bool hasCallbackFired = false;
124 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000125 [this, req, &hasCallbackFired, &checkResp] (const Data& response) {
126 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700127 return;
128 }
129
130 ControlResponse actual(response.getContent().blockFromValue());
131 checkResp(actual);
132
133 hasCallbackFired = true;
134 });
135
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000136 this->node1.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700137 this->advanceClocks(time::milliseconds(1), 5);
138
139 BOOST_CHECK(hasCallbackFired);
140 }
141
142private:
143 void
144 destroyFace()
145 {
146 if (faceId == 0) {
147 return;
148 }
149
150 ControlParameters params;
151 params.setFaceId(faceId);
152
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000153 Interest req = makeControlCommandRequest("/localhost/nfd/faces/destroy", params);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700154
155 bool hasCallbackFired = false;
156 signal::ScopedConnection connection = this->node1.face.onSendData.connect(
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000157 [this, req, &hasCallbackFired] (const Data& response) {
158 if (!req.getName().isPrefixOf(response.getName())) {
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700159 return;
160 }
161
162 ControlResponse destroy(response.getContent().blockFromValue());
163 BOOST_CHECK_EQUAL(destroy.getCode(), 200);
164
165 faceId = 0;
166 hasCallbackFired = true;
167 });
168
Junxiao Shi8a1f1702017-07-03 00:05:08 +0000169 this->node1.face.receive(req);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700170 this->advanceClocks(time::milliseconds(1), 5);
171
172 BOOST_CHECK(hasCallbackFired);
173 }
174
175public:
176 FaceId faceId;
177};
178
179BOOST_FIXTURE_TEST_SUITE(UpdateFace, FaceManagerUpdateFixture)
180
181BOOST_AUTO_TEST_CASE(FaceDoesNotExist)
182{
183 ControlParameters requestParams;
184 requestParams.setFaceId(65535);
185
186 updateFace(requestParams, false, [] (const ControlResponse& actual) {
187 ControlResponse expected(404, "Specified face does not exist");
188 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
189 BOOST_TEST_MESSAGE(actual.getText());
190 });
191}
192
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000193template<bool CAN_CHANGE_PERSISTENCY>
194class UpdatePersistencyDummyTransport : public face::Transport
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700195{
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000196public:
197 UpdatePersistencyDummyTransport()
198 {
199 this->setPersistency(ndn::nfd::FACE_PERSISTENCY_PERSISTENT);
200 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700201
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000202protected:
203 bool
204 canChangePersistencyToImpl(ndn::nfd::FacePersistency newPersistency) const override
205 {
206 return CAN_CHANGE_PERSISTENCY;
207 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700208
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000209 void
210 doClose() override
211 {
212 }
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700213
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000214private:
215 void
216 doSend(face::Transport::Packet&& packet) override
217 {
218 }
219};
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700220
Yanbiao Li58ba3f92017-02-15 14:27:18 +0000221namespace mpl = boost::mpl;
222
223using UpdatePersistencyTests =
224 mpl::vector<mpl::pair<UpdatePersistencyDummyTransport<true>, CommandSuccess>,
225 mpl::pair<UpdatePersistencyDummyTransport<false>, CommandFailure<409>>>;
226
227BOOST_FIXTURE_TEST_CASE_TEMPLATE(UpdatePersistency, T, UpdatePersistencyTests, FaceManagerUpdateFixture)
228{
229 using TransportType = typename T::first;
230 using ResultType = typename T::second;
231
232 auto face = make_shared<face::Face>(make_unique<face::GenericLinkService>(),
233 make_unique<TransportType>());
234 this->node1.faceTable.add(face);
235
236 auto parameters = ControlParameters()
237 .setFaceId(face->getId())
238 .setFacePersistency(ndn::nfd::FACE_PERSISTENCY_PERMANENT);
239
240 updateFace(parameters, false, [] (const ControlResponse& actual) {
241 BOOST_TEST_MESSAGE(actual.getText());
242 BOOST_CHECK_EQUAL(actual.getCode(), ResultType::getExpected().getCode());
243
244 // the response for either 200 or 409 will have a content body
245 BOOST_REQUIRE(actual.getBody().hasWire());
246
247 ControlParameters resp;
248 resp.wireDecode(actual.getBody());
249 BOOST_CHECK_EQUAL(resp.getFacePersistency(), ndn::nfd::FACE_PERSISTENCY_PERMANENT);
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700250 });
251}
252
253class TcpLocalFieldsEnable
254{
255public:
256 std::string
257 getUri()
258 {
259 return "tcp4://127.0.0.1:26363";
260 }
261
262 boost::asio::ip::address_v4
263 getIpAddress()
264 {
265 return boost::asio::ip::address_v4::from_string("127.0.0.1");
266 }
267
268 ndn::nfd::FacePersistency
269 getPersistency()
270 {
271 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
272 }
273
274 bool
275 getInitLocalFieldsEnabled()
276 {
277 return false;
278 }
279
280 bool
281 getLocalFieldsEnabled()
282 {
283 return true;
284 }
285
286 bool
287 getLocalFieldsEnabledMask()
288 {
289 return true;
290 }
291
292 bool
293 shouldHaveWire()
294 {
295 return false;
296 }
297};
298
299class TcpLocalFieldsDisable
300{
301public:
302 std::string
303 getUri()
304 {
305 return "tcp4://127.0.0.1:26363";
306 }
307
308 ndn::nfd::FacePersistency
309 getPersistency()
310 {
311 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
312 }
313
314 bool
315 getInitLocalFieldsEnabled()
316 {
317 return true;
318 }
319
320 bool
321 getLocalFieldsEnabled()
322 {
323 return false;
324 }
325
326 bool
327 getLocalFieldsEnabledMask()
328 {
329 return true;
330 }
331
332 bool
333 shouldHaveWire()
334 {
335 return false;
336 }
337};
338
339// UDP faces are non-local by definition
340class UdpLocalFieldsEnable
341{
342public:
343 std::string
344 getUri()
345 {
346 return "udp4://127.0.0.1:26363";
347 }
348
349 ndn::nfd::FacePersistency
350 getPersistency()
351 {
352 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
353 }
354
355 bool
356 getInitLocalFieldsEnabled()
357 {
358 return false;
359 }
360
361 bool
362 getLocalFieldsEnabled()
363 {
364 return true;
365 }
366
367 bool
368 getLocalFieldsEnabledMask()
369 {
370 return true;
371 }
372
373 bool
374 shouldHaveWire()
375 {
376 return true;
377 }
378};
379
380// UDP faces are non-local by definition
381// In this test case, attempt to disable local fields on face with local fields already disabled
382class UdpLocalFieldsDisable
383{
384public:
385 std::string
386 getUri()
387 {
388 return "udp4://127.0.0.1:26363";
389 }
390
391 ndn::nfd::FacePersistency
392 getPersistency()
393 {
394 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
395 }
396
397 bool
398 getInitLocalFieldsEnabled()
399 {
400 return false;
401 }
402
403 bool
404 getLocalFieldsEnabled()
405 {
406 return false;
407 }
408
409 bool
410 getLocalFieldsEnabledMask()
411 {
412 return true;
413 }
414
415 bool
416 shouldHaveWire()
417 {
418 return false;
419 }
420};
421
422// In this test case, set Flags to enable local fields on non-local face, but exclude local fields
423// from Mask. This test case will pass as no action is taken due to the missing Mask bit.
424class UdpLocalFieldsEnableNoMaskBit
425{
426public:
427 std::string
428 getUri()
429 {
430 return "udp4://127.0.0.1:26363";
431 }
432
433 ndn::nfd::FacePersistency
434 getPersistency()
435 {
436 return ndn::nfd::FACE_PERSISTENCY_PERSISTENT;
437 }
438
439 bool
440 getInitLocalFieldsEnabled()
441 {
442 return false;
443 }
444
445 bool
446 getLocalFieldsEnabled()
447 {
448 return true;
449 }
450
451 bool
452 getLocalFieldsEnabledMask()
453 {
454 return false;
455 }
456
457 bool
458 shouldHaveWire()
459 {
460 return false;
461 }
462};
463
Eric Newberryb5aa7f52016-09-03 20:36:12 -0700464typedef mpl::vector<mpl::pair<TcpLocalFieldsEnable, CommandSuccess>,
465 mpl::pair<TcpLocalFieldsDisable, CommandSuccess>,
466 mpl::pair<UdpLocalFieldsEnable, CommandFailure<409>>,
467 mpl::pair<UdpLocalFieldsDisable, CommandSuccess>,
468 mpl::pair<UdpLocalFieldsEnableNoMaskBit, CommandSuccess>> LocalFieldFaces;
469
470BOOST_AUTO_TEST_CASE_TEMPLATE(UpdateLocalFields, T, LocalFieldFaces)
471{
472 typedef typename T::first TestType;
473 typedef typename T::second ResultType;
474
475 createFace(TestType().getUri(), TestType().getPersistency(), TestType().getInitLocalFieldsEnabled());
476
477 ControlParameters requestParams;
478 requestParams.setFaceId(faceId);
479 requestParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, TestType().getLocalFieldsEnabled());
480 if (!TestType().getLocalFieldsEnabledMask()) {
481 requestParams.unsetFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED);
482 }
483
484 updateFace(requestParams, false, [] (const ControlResponse& actual) {
485 ControlResponse expected(ResultType().getExpected().getCode(), "");
486 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
487 BOOST_TEST_MESSAGE(actual.getText());
488
489 if (TestType().shouldHaveWire() && actual.getBody().hasWire()) {
490 ControlParameters actualParams(actual.getBody());
491
492 BOOST_CHECK(!actualParams.hasFacePersistency());
493 BOOST_CHECK(actualParams.hasFlags());
494 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
495 BOOST_CHECK(actualParams.hasFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
496 }
497 });
498}
499
500BOOST_AUTO_TEST_CASE(UpdateLocalFieldsEnableDisable)
501{
502 createFace();
503
504 ControlParameters enableParams;
505 enableParams.setFaceId(faceId);
506 enableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, true);
507
508 ControlParameters disableParams;
509 disableParams.setFaceId(faceId);
510 disableParams.setFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED, false);
511
512 updateFace(enableParams, false, [] (const ControlResponse& actual) {
513 ControlResponse expected(200, "OK");
514 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
515 BOOST_TEST_MESSAGE(actual.getText());
516
517 if (actual.getBody().hasWire()) {
518 ControlParameters actualParams(actual.getBody());
519
520 BOOST_CHECK(actualParams.hasFaceId());
521 BOOST_CHECK(actualParams.hasFacePersistency());
522 BOOST_REQUIRE(actualParams.hasFlags());
523 // Check if flags indicate local fields enabled
524 BOOST_CHECK(actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
525 }
526 else {
527 BOOST_ERROR("Enable: Response does not contain ControlParameters");
528 }
529 });
530
531 updateFace(disableParams, false, [] (const ControlResponse& actual) {
532 ControlResponse expected(200, "OK");
533 BOOST_CHECK_EQUAL(actual.getCode(), expected.getCode());
534 BOOST_TEST_MESSAGE(actual.getText());
535
536 if (actual.getBody().hasWire()) {
537 ControlParameters actualParams(actual.getBody());
538
539 BOOST_CHECK(actualParams.hasFaceId());
540 BOOST_CHECK(actualParams.hasFacePersistency());
541 BOOST_REQUIRE(actualParams.hasFlags());
542 // Check if flags indicate local fields disabled
543 BOOST_CHECK(!actualParams.getFlagBit(ndn::nfd::BIT_LOCAL_FIELDS_ENABLED));
544 }
545 else {
546 BOOST_ERROR("Disable: Response does not contain ControlParameters");
547 }
548 });
549}
550
551BOOST_AUTO_TEST_CASE(SelfUpdating)
552{
553 createFace();
554
555 // Send a command that does nothing (will return 200) and does not contain a FaceId
556 ControlParameters sentParams;
557
558 updateFace(sentParams, true, [] (const ControlResponse& actual) {
559 ControlResponse expected(200, "OK");
560 BOOST_REQUIRE_EQUAL(actual.getCode(), expected.getCode());
561 BOOST_TEST_MESSAGE(actual.getText());
562 });
563}
564
565BOOST_AUTO_TEST_SUITE_END() // UpdateFace
566BOOST_AUTO_TEST_SUITE_END() // TestFaceManager
567BOOST_AUTO_TEST_SUITE_END() // Mgmt
568
569} // namespace tests
570} // namespace nfd