| /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| /** |
| * Copyright (C) 2014 Named Data Networking Project |
| * See COPYING for copyright and distribution information. |
| */ |
| |
| #include "mgmt/face-manager.hpp" |
| #include "mgmt/internal-face.hpp" |
| #include "mgmt/face-status-publisher.hpp" |
| |
| #include "face/face.hpp" |
| #include "../face/dummy-face.hpp" |
| #include "fw/face-table.hpp" |
| #include "fw/forwarder.hpp" |
| |
| #include "common.hpp" |
| #include "tests/test-common.hpp" |
| #include "validation-common.hpp" |
| #include "face-status-publisher-common.hpp" |
| |
| #include <ndn-cpp-dev/encoding/tlv.hpp> |
| #include <ndn-cpp-dev/management/nfd-face-event-notification.hpp> |
| |
| namespace nfd { |
| namespace tests { |
| |
| NFD_LOG_INIT("FaceManagerTest"); |
| |
| class FaceManagerTestFace : public DummyFace |
| { |
| public: |
| |
| FaceManagerTestFace() |
| : m_closeFired(false) |
| { |
| |
| } |
| |
| virtual |
| ~FaceManagerTestFace() |
| { |
| |
| } |
| |
| virtual void |
| close() |
| { |
| m_closeFired = true; |
| } |
| |
| bool |
| didCloseFire() const |
| { |
| return m_closeFired; |
| } |
| |
| private: |
| bool m_closeFired; |
| }; |
| |
| class TestFaceTable : public FaceTable |
| { |
| public: |
| TestFaceTable(Forwarder& forwarder) |
| : FaceTable(forwarder), |
| m_addFired(false), |
| m_getFired(false), |
| m_dummy(make_shared<FaceManagerTestFace>()) |
| { |
| |
| } |
| |
| virtual |
| ~TestFaceTable() |
| { |
| |
| } |
| |
| virtual void |
| add(shared_ptr<Face> face) |
| { |
| m_addFired = true; |
| } |
| |
| virtual shared_ptr<Face> |
| get(FaceId id) const |
| { |
| m_getFired = true; |
| return m_dummy; |
| } |
| |
| bool |
| didAddFire() const |
| { |
| return m_addFired; |
| } |
| |
| bool |
| didGetFire() const |
| { |
| return m_getFired; |
| } |
| |
| void |
| reset() |
| { |
| m_addFired = false; |
| m_getFired = false; |
| } |
| |
| shared_ptr<FaceManagerTestFace>& |
| getDummyFace() |
| { |
| return m_dummy; |
| } |
| |
| private: |
| bool m_addFired; |
| mutable bool m_getFired; |
| shared_ptr<FaceManagerTestFace> m_dummy; |
| }; |
| |
| |
| class TestFaceTableFixture : public BaseFixture |
| { |
| public: |
| TestFaceTableFixture() |
| : m_faceTable(m_forwarder) |
| { |
| |
| } |
| |
| virtual |
| ~TestFaceTableFixture() |
| { |
| |
| } |
| |
| protected: |
| Forwarder m_forwarder; |
| TestFaceTable m_faceTable; |
| }; |
| |
| class TestFaceManagerCommon |
| { |
| public: |
| TestFaceManagerCommon() |
| : m_face(make_shared<InternalFace>()), |
| m_callbackFired(false) |
| { |
| |
| } |
| |
| virtual |
| ~TestFaceManagerCommon() |
| { |
| |
| } |
| |
| shared_ptr<InternalFace>& |
| getFace() |
| { |
| return m_face; |
| } |
| |
| void |
| validateControlResponseCommon(const Data& response, |
| const Name& expectedName, |
| uint32_t expectedCode, |
| const std::string& expectedText, |
| ControlResponse& control) |
| { |
| m_callbackFired = true; |
| Block controlRaw = response.getContent().blockFromValue(); |
| |
| control.wireDecode(controlRaw); |
| |
| // NFD_LOG_DEBUG("received control response" |
| // << " Name: " << response.getName() |
| // << " code: " << control.getCode() |
| // << " text: " << control.getText()); |
| |
| BOOST_CHECK_EQUAL(response.getName(), expectedName); |
| BOOST_CHECK_EQUAL(control.getCode(), expectedCode); |
| BOOST_CHECK_EQUAL(control.getText(), expectedText); |
| } |
| |
| void |
| validateControlResponse(const Data& response, |
| const Name& expectedName, |
| uint32_t expectedCode, |
| const std::string& expectedText) |
| { |
| ControlResponse control; |
| validateControlResponseCommon(response, expectedName, |
| expectedCode, expectedText, control); |
| |
| if (!control.getBody().empty()) |
| { |
| BOOST_FAIL("found unexpected control response body"); |
| } |
| } |
| |
| void |
| validateControlResponse(const Data& response, |
| const Name& expectedName, |
| uint32_t expectedCode, |
| const std::string& expectedText, |
| const Block& expectedBody) |
| { |
| ControlResponse control; |
| validateControlResponseCommon(response, expectedName, |
| expectedCode, expectedText, control); |
| |
| BOOST_REQUIRE(!control.getBody().empty()); |
| BOOST_REQUIRE(control.getBody().value_size() == expectedBody.value_size()); |
| |
| BOOST_CHECK(memcmp(control.getBody().value(), expectedBody.value(), |
| expectedBody.value_size()) == 0); |
| |
| } |
| |
| bool |
| didCallbackFire() const |
| { |
| return m_callbackFired; |
| } |
| |
| void |
| resetCallbackFired() |
| { |
| m_callbackFired = false; |
| } |
| |
| protected: |
| shared_ptr<InternalFace> m_face; |
| |
| private: |
| bool m_callbackFired; |
| }; |
| |
| class FaceManagerFixture : public TestFaceTableFixture, public TestFaceManagerCommon |
| { |
| public: |
| FaceManagerFixture() |
| : m_manager(m_faceTable, m_face) |
| { |
| m_manager.setConfigFile(m_config); |
| } |
| |
| virtual |
| ~FaceManagerFixture() |
| { |
| |
| } |
| |
| void |
| parseConfig(const std::string configuration, bool isDryRun) |
| { |
| m_config.parse(configuration, isDryRun, "dummy-config"); |
| } |
| |
| FaceManager& |
| getManager() |
| { |
| return m_manager; |
| } |
| |
| void |
| addInterestRule(const std::string& regex, |
| ndn::IdentityCertificate& certificate) |
| { |
| m_manager.addInterestRule(regex, certificate); |
| } |
| |
| bool |
| didFaceTableAddFire() const |
| { |
| return m_faceTable.didAddFire(); |
| } |
| |
| bool |
| didFaceTableGetFire() const |
| { |
| return m_faceTable.didGetFire(); |
| } |
| |
| void |
| resetFaceTable() |
| { |
| m_faceTable.reset(); |
| } |
| |
| private: |
| FaceManager m_manager; |
| ConfigFile m_config; |
| }; |
| |
| BOOST_FIXTURE_TEST_SUITE(MgmtFaceManager, FaceManagerFixture) |
| |
| bool |
| isExpectedException(const ConfigFile::Error& error, const std::string& expectedMessage) |
| { |
| if (error.what() != expectedMessage) |
| { |
| NFD_LOG_ERROR("expected: " << expectedMessage << "\tgot: " << error.what()); |
| } |
| return error.what() == expectedMessage; |
| } |
| |
| #ifdef HAVE_UNIX_SOCKETS |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUnix) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " unix\n" |
| " {\n" |
| " listen yes\n" |
| " path /tmp/nfd.sock\n" |
| " }\n" |
| "}\n"; |
| BOOST_TEST_CHECKPOINT("Calling parse"); |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUnixDryRun) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " unix\n" |
| " {\n" |
| " listen yes\n" |
| " path /var/run/nfd.sock\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUnixBadListen) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " unix\n" |
| " {\n" |
| " listen hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"listen\" in \"unix\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUnixUnknownOption) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " unix\n" |
| " {\n" |
| " hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Unrecognized option \"hello\" in \"unix\" section")); |
| } |
| |
| #endif // HAVE_UNIX_SOCKETS |
| |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionTcp) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " tcp\n" |
| " {\n" |
| " listen yes\n" |
| " port 6363\n" |
| " }\n" |
| "}\n"; |
| try |
| { |
| parseConfig(CONFIG, false); |
| } |
| catch (const std::runtime_error& e) |
| { |
| const std::string reason = e.what(); |
| if (reason.find("Address in use") != std::string::npos) |
| { |
| BOOST_FAIL(reason); |
| } |
| } |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionTcpDryRun) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " tcp\n" |
| " {\n" |
| " listen yes\n" |
| " port 6363\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionTcpBadListen) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " tcp\n" |
| " {\n" |
| " listen hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"listen\" in \"tcp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionTcpUnknownOption) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " tcp\n" |
| " {\n" |
| " hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Unrecognized option \"hello\" in \"tcp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdp) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " port 6363\n" |
| " idle_timeout 30\n" |
| " keep_alive_interval 25\n" |
| " mcast yes\n" |
| " mcast_port 56363\n" |
| " mcast_group 224.0.23.170\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpDryRun) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " port 6363\n" |
| " idle_timeout 30\n" |
| " keep_alive_interval 25\n" |
| " mcast yes\n" |
| " mcast_port 56363\n" |
| " mcast_group 224.0.23.170\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpBadIdleTimeout) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " idle_timeout hello\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"idle_timeout\" in \"udp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpBadMcast) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " mcast hello\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"mcast\" in \"udp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpBadMcastGroup) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " mcast no\n" |
| " mcast_port 50\n" |
| " mcast_group hello\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"mcast_group\" in \"udp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpBadMcastGroupV6) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " mcast no\n" |
| " mcast_port 50\n" |
| " mcast_group ::1\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"mcast_group\" in \"udp\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionUdpUnknownOption) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " udp\n" |
| " {\n" |
| " hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Unrecognized option \"hello\" in \"udp\" section")); |
| } |
| |
| #ifdef HAVE_PCAP |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionEther) |
| { |
| |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " ether\n" |
| " {\n" |
| " mcast yes\n" |
| " mcast_group 01:00:5E:00:17:AA\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, false)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionEtherDryRun) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " ether\n" |
| " {\n" |
| " mcast yes\n" |
| " mcast_group 01:00:5E:00:17:AA\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_NO_THROW(parseConfig(CONFIG, true)); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionEtherBadMcast) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " ether\n" |
| " {\n" |
| " mcast hello\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"mcast\" in \"ether\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionEtherBadMcastGroup) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " ether\n" |
| " {\n" |
| " mcast yes\n" |
| " mcast_group\n" |
| " }\n" |
| "}\n"; |
| |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Invalid value for option \"mcast_group\" in \"ether\" section")); |
| } |
| |
| BOOST_AUTO_TEST_CASE(TestProcessSectionEtherUnknownOption) |
| { |
| const std::string CONFIG = |
| "face_system\n" |
| "{\n" |
| " ether\n" |
| " {\n" |
| " hello\n" |
| " }\n" |
| "}\n"; |
| BOOST_CHECK_EXCEPTION(parseConfig(CONFIG, false), ConfigFile::Error, |
| bind(&isExpectedException, _1, |
| "Unrecognized option \"hello\" in \"ether\" section")); |
| } |
| |
| #endif |
| |
| BOOST_AUTO_TEST_CASE(TestFireInterestFilter) |
| { |
| shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/faces")); |
| |
| getFace()->onReceiveData += |
| bind(&FaceManagerFixture::validateControlResponse, this, _1, |
| command->getName(), 400, "Malformed command"); |
| |
| getFace()->sendInterest(*command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(MalformedCommmand) |
| { |
| shared_ptr<Interest> command(make_shared<Interest>("/localhost/nfd/faces")); |
| |
| getFace()->onReceiveData += |
| bind(&FaceManagerFixture::validateControlResponse, this, _1, |
| command->getName(), 400, "Malformed command"); |
| |
| getManager().onFaceRequest(*command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_AUTO_TEST_CASE(UnsignedCommand) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| |
| getFace()->onReceiveData += |
| bind(&FaceManagerFixture::validateControlResponse, this, _1, |
| command->getName(), 401, "Signature required"); |
| |
| getManager().onFaceRequest(*command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(UnauthorizedCommand, UnauthorizedCommandFixture<FaceManagerFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&FaceManagerFixture::validateControlResponse, this, _1, |
| command->getName(), 403, "Unauthorized command"); |
| |
| getManager().onFaceRequest(*command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| template <typename T> class AuthorizedCommandFixture : public CommandFixture<T> |
| { |
| public: |
| AuthorizedCommandFixture() |
| { |
| const std::string regex = "^<localhost><nfd><faces>"; |
| T::addInterestRule(regex, *CommandFixture<T>::m_certificate); |
| } |
| |
| virtual |
| ~AuthorizedCommandFixture() |
| { |
| |
| } |
| }; |
| |
| BOOST_FIXTURE_TEST_CASE(UnsupportedCommand, AuthorizedCommandFixture<FaceManagerFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("unsupported"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&FaceManagerFixture::validateControlResponse, this, _1, |
| command->getName(), 501, "Unsupported command"); |
| |
| getManager().onFaceRequest(*command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| class ValidatedFaceRequestFixture : public TestFaceTableFixture, |
| public TestFaceManagerCommon, |
| public FaceManager |
| { |
| public: |
| |
| ValidatedFaceRequestFixture() |
| : FaceManager(TestFaceTableFixture::m_faceTable, TestFaceManagerCommon::m_face), |
| m_createFaceFired(false), |
| m_destroyFaceFired(false) |
| { |
| |
| } |
| |
| virtual void |
| createFace(const Name& requestName, |
| ndn::nfd::FaceManagementOptions& options) |
| { |
| m_createFaceFired = true; |
| } |
| |
| virtual void |
| destroyFace(const Name& requestName, |
| ndn::nfd::FaceManagementOptions& options) |
| { |
| m_destroyFaceFired = true; |
| } |
| |
| virtual |
| ~ValidatedFaceRequestFixture() |
| { |
| |
| } |
| |
| bool |
| didCreateFaceFire() const |
| { |
| return m_createFaceFired; |
| } |
| |
| bool |
| didDestroyFaceFire() const |
| { |
| return m_destroyFaceFired; |
| } |
| |
| private: |
| bool m_createFaceFired; |
| bool m_destroyFaceFired; |
| }; |
| |
| BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestBadOptionParse, |
| AuthorizedCommandFixture<ValidatedFaceRequestFixture>) |
| { |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append("NotReallyOptions"); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&ValidatedFaceRequestFixture::validateControlResponse, this, _1, |
| command->getName(), 400, "Malformed command"); |
| |
| onValidatedFaceRequest(command); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestCreateFace, |
| AuthorizedCommandFixture<ValidatedFaceRequestFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| onValidatedFaceRequest(command); |
| BOOST_CHECK(didCreateFaceFire()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(ValidatedFaceRequestDestroyFace, |
| AuthorizedCommandFixture<ValidatedFaceRequestFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("destroy"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| onValidatedFaceRequest(command); |
| BOOST_CHECK(didDestroyFaceFire()); |
| } |
| |
| class FaceTableFixture |
| { |
| public: |
| FaceTableFixture() |
| : m_faceTable(m_forwarder) |
| { |
| } |
| |
| virtual |
| ~FaceTableFixture() |
| { |
| } |
| |
| protected: |
| Forwarder m_forwarder; |
| FaceTable m_faceTable; |
| }; |
| |
| class FaceFixture : public FaceTableFixture, |
| public TestFaceManagerCommon, |
| public FaceManager |
| { |
| public: |
| FaceFixture() |
| : FaceManager(FaceTableFixture::m_faceTable, |
| TestFaceManagerCommon::m_face) |
| , m_receivedNotification(false) |
| { |
| |
| } |
| |
| virtual |
| ~FaceFixture() |
| { |
| |
| } |
| |
| void |
| callbackDispatch(const Data& response, |
| const Name& expectedName, |
| uint32_t expectedCode, |
| const std::string& expectedText, |
| const Block& expectedBody, |
| const ndn::nfd::FaceEventNotification& expectedFaceEvent) |
| { |
| Block payload = response.getContent().blockFromValue(); |
| if (payload.type() == ndn::tlv::nfd::ControlResponse) |
| { |
| validateControlResponse(response, expectedName, expectedCode, |
| expectedText, expectedBody); |
| } |
| else if (payload.type() == ndn::tlv::nfd::FaceEventNotification) |
| { |
| validateFaceEvent(payload, expectedFaceEvent); |
| } |
| else |
| { |
| BOOST_FAIL("Received unknown message type: #" << payload.type()); |
| } |
| } |
| |
| void |
| callbackDispatch(const Data& response, |
| const Name& expectedName, |
| uint32_t expectedCode, |
| const std::string& expectedText, |
| const ndn::nfd::FaceEventNotification& expectedFaceEvent) |
| { |
| Block payload = response.getContent().blockFromValue(); |
| if (payload.type() == ndn::tlv::nfd::ControlResponse) |
| { |
| validateControlResponse(response, expectedName, |
| expectedCode, expectedText); |
| } |
| else if (payload.type() == ndn::tlv::nfd::FaceEventNotification) |
| { |
| validateFaceEvent(payload, expectedFaceEvent); |
| } |
| else |
| { |
| BOOST_FAIL("Received unknown message type: #" << payload.type()); |
| } |
| } |
| |
| void |
| validateFaceEvent(const Block& wire, |
| const ndn::nfd::FaceEventNotification& expectedFaceEvent) |
| { |
| |
| m_receivedNotification = true; |
| |
| ndn::nfd::FaceEventNotification notification(wire); |
| |
| BOOST_CHECK_EQUAL(notification.getFaceId(), expectedFaceEvent.getFaceId()); |
| BOOST_CHECK_EQUAL(notification.getUri(), expectedFaceEvent.getUri()); |
| BOOST_CHECK_EQUAL(notification.getEventKind(), expectedFaceEvent.getEventKind()); |
| } |
| |
| bool |
| didReceiveNotication() const |
| { |
| return m_receivedNotification; |
| } |
| |
| protected: |
| bool m_receivedNotification; |
| }; |
| |
| BOOST_FIXTURE_TEST_CASE(CreateFaceBadUri, AuthorizedCommandFixture<FaceFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp:/127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&FaceFixture::validateControlResponse, this, _1, |
| command->getName(), 400, "Malformed command"); |
| |
| createFace(command->getName(), options); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(CreateFaceUnknownScheme, AuthorizedCommandFixture<FaceFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| // this will be an unsupported protocol because no factories have been |
| // added to the face manager |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&FaceFixture::validateControlResponse, this, _1, |
| command->getName(), 501, "Unsupported protocol"); |
| |
| createFace(command->getName(), options); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(OnCreated, AuthorizedCommandFixture<FaceFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| ndn::nfd::FaceManagementOptions resultOptions; |
| resultOptions.setUri("tcp://127.0.0.1"); |
| resultOptions.setFaceId(1); |
| |
| shared_ptr<DummyFace> dummy(make_shared<DummyFace>()); |
| |
| ndn::nfd::FaceEventNotification expectedFaceEvent(ndn::nfd::FACE_EVENT_CREATED, |
| 1, |
| dummy->getUri().toString(), |
| 0); |
| |
| Block encodedResultOptions(resultOptions.wireEncode()); |
| |
| getFace()->onReceiveData += |
| bind(&FaceFixture::callbackDispatch, this, _1, |
| command->getName(), 200, "Success", |
| encodedResultOptions, expectedFaceEvent); |
| |
| onCreated(command->getName(), options, dummy); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| BOOST_REQUIRE(didReceiveNotication()); |
| } |
| |
| BOOST_FIXTURE_TEST_CASE(OnConnectFailed, AuthorizedCommandFixture<FaceFixture>) |
| { |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("create"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| getFace()->onReceiveData += |
| bind(&FaceFixture::validateControlResponse, this, _1, |
| command->getName(), 400, "Failed to create face"); |
| |
| onConnectFailed(command->getName(), "unit-test-reason"); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| BOOST_CHECK_EQUAL(didReceiveNotication(), false); |
| } |
| |
| |
| BOOST_FIXTURE_TEST_CASE(DestroyFace, AuthorizedCommandFixture<FaceFixture>) |
| { |
| shared_ptr<DummyFace> dummy(make_shared<DummyFace>()); |
| FaceTableFixture::m_faceTable.add(dummy); |
| |
| ndn::nfd::FaceManagementOptions options; |
| options.setUri("tcp://127.0.0.1"); |
| options.setFaceId(dummy->getId()); |
| |
| Block encodedOptions(options.wireEncode()); |
| |
| Name commandName("/localhost/nfd/faces"); |
| commandName.append("destroy"); |
| commandName.append(encodedOptions); |
| |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| generateCommand(*command); |
| |
| ndn::nfd::FaceEventNotification expectedFaceEvent(ndn::nfd::FACE_EVENT_DESTROYED, |
| dummy->getId(), |
| dummy->getUri().toString(), 0); |
| |
| getFace()->onReceiveData += |
| bind(&FaceFixture::callbackDispatch, this, _1, |
| command->getName(), 200, "Success", expectedFaceEvent); |
| |
| destroyFace(command->getName(), options); |
| |
| BOOST_REQUIRE(didCallbackFire()); |
| BOOST_REQUIRE(didReceiveNotication()); |
| } |
| |
| class FaceListFixture : public FaceStatusPublisherFixture |
| { |
| public: |
| FaceListFixture() |
| : m_manager(m_table, m_face) |
| { |
| |
| } |
| |
| virtual |
| ~FaceListFixture() |
| { |
| |
| } |
| |
| protected: |
| FaceManager m_manager; |
| }; |
| |
| BOOST_FIXTURE_TEST_CASE(TestFaceList, FaceListFixture) |
| |
| { |
| Name commandName("/localhost/nfd/faces/list"); |
| shared_ptr<Interest> command(make_shared<Interest>(commandName)); |
| |
| // MAX_SEGMENT_SIZE == 4400, FaceStatus size with filler counters is 55 |
| // 55 divides 4400 (== 80), so only use 79 FaceStatuses and then two smaller ones |
| // to force a FaceStatus to span Data packets |
| for (int i = 0; i < 79; i++) |
| { |
| shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>()); |
| |
| uint64_t filler = std::numeric_limits<uint64_t>::max() - 1; |
| dummy->setCounters(filler, filler, filler, filler); |
| |
| m_referenceFaces.push_back(dummy); |
| |
| add(dummy); |
| } |
| |
| for (int i = 0; i < 2; i++) |
| { |
| shared_ptr<TestCountersFace> dummy(make_shared<TestCountersFace>()); |
| uint64_t filler = std::numeric_limits<uint32_t>::max() - 1; |
| dummy->setCounters(filler, filler, filler, filler); |
| |
| m_referenceFaces.push_back(dummy); |
| |
| add(dummy); |
| } |
| |
| ndn::EncodingBuffer buffer; |
| |
| m_face->onReceiveData += |
| bind(&FaceStatusPublisherFixture::decodeFaceStatusBlock, this, _1); |
| |
| m_manager.listFaces(*command); |
| BOOST_REQUIRE(m_finished); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() |
| |
| } // namespace tests |
| } // namespace nfd |
| |
| |