/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /** * Copyright (c) 2014, Regents of the University of California, * Arizona Board of Regents, * Colorado State University, * University Pierre & Marie Curie, Sorbonne University, * Washington University in St. Louis, * Beijing Institute of Technology, * The University of Memphis * * This file is part of NFD (Named Data Networking Forwarding Daemon). * See AUTHORS.md for complete list of NFD authors and contributors. * * NFD is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * NFD, e.g., in COPYING.md file. If not, see . */ #include "core/notification-subscriber.hpp" #include "core/notification-stream.hpp" #include "simple-notification.hpp" #include "tests/test-common.hpp" #include "tests/dummy-client-face.hpp" namespace nfd { namespace tests { BOOST_FIXTURE_TEST_SUITE(CoreNotificationSubscriber, BaseFixture) class EndToEndFixture : public BaseFixture { public: EndToEndFixture() : streamPrefix("ndn:/NotificationSubscriberTest") , publisherFace(makeDummyClientFace()) , notificationStream(*publisherFace, streamPrefix, publisherKeyChain) , subscriberFace(makeDummyClientFace()) , subscriber(*subscriberFace, streamPrefix) { } /** \brief post one notification and deliver to subscriber */ void deliverNotification(const std::string& msg) { publisherFace->m_sentDatas.clear(); SimpleNotification notification(msg); notificationStream.postNotification(notification); publisherFace->processEvents(); BOOST_REQUIRE_EQUAL(publisherFace->m_sentDatas.size(), 1); lastDeliveredSeqNo = publisherFace->m_sentDatas[0].getName().at(-1).toSequenceNumber(); lastNotification.setMessage(""); subscriberFace->receive(publisherFace->m_sentDatas[0]); } void afterNotification(const SimpleNotification& notification) { lastNotification = notification; } void clearNotificationHandlers() { subscriber.onNotification.clear(); } void afterTimeout() { hasTimeout = true; } void afterDecodeError(const Data& data) { lastDecodeErrorData = data; } /** \return true if subscriberFace has an initial request as sole sent Interest */ bool hasInitialRequest() const { if (subscriberFace->m_sentInterests.size() != 1) return 0; const Interest& interest = subscriberFace->m_sentInterests[0]; return interest.getName() == streamPrefix && interest.getChildSelector() == 1 && interest.getMustBeFresh() && interest.getInterestLifetime() == NotificationSubscriber::getInterestLifetime(); } /** \return sequence number of the continuation request sent from subscriberFace * or 0 if there's no such request as sole sent Interest */ uint64_t getRequestSeqNo() const { if (subscriberFace->m_sentInterests.size() != 1) return 0; const Interest& interest = subscriberFace->m_sentInterests[0]; const Name& name = interest.getName(); if (streamPrefix.isPrefixOf(name) && name.size() == streamPrefix.size() + 1 && interest.getInterestLifetime() == NotificationSubscriber::getInterestLifetime()) return name[-1].toSequenceNumber(); else return 0; } protected: Name streamPrefix; shared_ptr publisherFace; ndn::KeyChain publisherKeyChain; NotificationStream notificationStream; shared_ptr subscriberFace; NotificationSubscriber subscriber; uint64_t lastDeliveredSeqNo; SimpleNotification lastNotification; bool hasTimeout; Data lastDecodeErrorData; }; BOOST_FIXTURE_TEST_CASE(EndToEnd, EndToEndFixture) { BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false); // has no effect because onNotification has no handler subscriber.start(); BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false); subscriber.onNotification += bind(&EndToEndFixture::afterNotification, this, _1); subscriber.onTimeout += bind(&EndToEndFixture::afterTimeout, this); subscriber.onDecodeError += bind(&EndToEndFixture::afterDecodeError, this, _1); // not received when subscriber is not running this->deliverNotification("n1"); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0); subscriberFace->m_sentInterests.clear(); subscriber.start(); subscriberFace->processEvents(time::milliseconds(10)); BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true); BOOST_CHECK(this->hasInitialRequest()); // respond to initial request subscriberFace->m_sentInterests.clear(); this->deliverNotification("n2"); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2"); BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); // respond to continuation request subscriberFace->m_sentInterests.clear(); this->deliverNotification("n3"); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n3"); BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1); // timeout subscriberFace->m_sentInterests.clear(); lastNotification.setMessage(""); subscriberFace->processEvents( NotificationSubscriber::getInterestLifetime() + time::milliseconds(1000)); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK_EQUAL(hasTimeout, true); BOOST_CHECK(this->hasInitialRequest()); // decode error on sequence number Name wrongName = streamPrefix; wrongName.append("%07%07"); Data wrongData(wrongName); publisherKeyChain.sign(wrongData); subscriberFace->receive(wrongData); subscriberFace->m_sentInterests.clear(); lastNotification.setMessage(""); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName); BOOST_CHECK(this->hasInitialRequest()); // decode error in payload subscriberFace->m_sentInterests.clear(); lastNotification.setMessage(""); this->deliverNotification("\x07n4"); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK(lastNotification.getMessage().empty()); BOOST_CHECK(this->hasInitialRequest()); // stop if handlers are cleared subscriber.onNotification += bind(&EndToEndFixture::clearNotificationHandlers, this); subscriberFace->m_sentInterests.clear(); this->deliverNotification("n5"); subscriberFace->processEvents(time::milliseconds(10)); BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0); } BOOST_AUTO_TEST_SUITE_END() } // namespace tests } // namespace nfd