blob: d8f9dfd6cb9204ca89f2a16aa7107d8849e3f2de [file] [log] [blame]
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Junxiao Shi2bea5c42017-08-14 20:10:32 +00002/*
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -05003 * Copyright (c) 2014-2020 Regents of the University of California,
Spyridon Mastorakis429634f2015-02-19 17:35:33 -08004 * 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.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070010 *
11 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
12 *
13 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
14 * terms of the GNU Lesser General Public License as published by the Free Software
15 * Foundation, either version 3 of the License, or (at your option) any later version.
16 *
17 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
18 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
20 *
21 * You should have received copies of the GNU General Public License and GNU Lesser
22 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
26 */
27
Davide Pesavento7e780642018-11-24 15:51:34 -050028#include "ndn-cxx/util/notification-subscriber.hpp"
29#include "ndn-cxx/util/dummy-client-face.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070030
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050031#include "tests/test-common.hpp"
32#include "tests/unit/io-key-chain-fixture.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050033#include "tests/unit/util/simple-notification.hpp"
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070034
35namespace ndn {
Junxiao Shia60d9362014-11-12 09:38:21 -070036namespace util {
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070037namespace tests {
38
Teng Liang93adaff2016-07-30 15:57:12 -070039using namespace ndn::tests;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070040
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050041class NotificationSubscriberFixture : public IoKeyChainFixture
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070042{
43public:
Teng Liang93adaff2016-07-30 15:57:12 -070044 NotificationSubscriberFixture()
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050045 : streamPrefix("/NotificationSubscriberTest")
46 , subscriberFace(m_io, m_keyChain)
Davide Pesavento0f830802018-01-16 23:58:58 -050047 , subscriber(subscriberFace, streamPrefix, 1_s)
Teng Liang93adaff2016-07-30 15:57:12 -070048 , nextSendNotificationNo(0)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070049 {
50 }
51
Teng Liang93adaff2016-07-30 15:57:12 -070052 /** \brief deliver one notification to subscriber
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070053 */
54 void
55 deliverNotification(const std::string& msg)
56 {
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070057 SimpleNotification notification(msg);
Alexander Afanasyev370d2602014-08-20 10:21:34 -050058
Teng Liang93adaff2016-07-30 15:57:12 -070059 Name dataName = streamPrefix;
60 dataName.appendSequenceNumber(nextSendNotificationNo);
61 Data data(dataName);
62 data.setContent(notification.wireEncode());
Davide Pesavento0f830802018-01-16 23:58:58 -050063 data.setFreshnessPeriod(1_s);
Teng Liang93adaff2016-07-30 15:57:12 -070064 m_keyChain.sign(data);
Alexander Afanasyev370d2602014-08-20 10:21:34 -050065
Junxiao Shi946a51c2018-11-24 00:25:57 +000066 lastDeliveredSeqNum = nextSendNotificationNo;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070067 lastNotification.setMessage("");
Teng Liang93adaff2016-07-30 15:57:12 -070068 ++nextSendNotificationNo;
69 subscriberFace.receive(data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070070 }
71
Teng Liangf8bf1b02016-07-17 11:54:19 -070072 /** \brief deliver a Nack to subscriber
73 */
74 void
75 deliverNack(const Interest& interest, const lp::NackReason& reason)
76 {
77 lp::Nack nack = makeNack(interest, reason);
78 subscriberFace.receive(nack);
79 }
80
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070081 void
82 afterNotification(const SimpleNotification& notification)
83 {
84 lastNotification = notification;
85 }
86
87 void
Teng Liangf8bf1b02016-07-17 11:54:19 -070088 afterNack(const lp::Nack& nack)
89 {
90 lastNack = nack;
91 }
92
93 void
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070094 afterTimeout()
95 {
96 hasTimeout = true;
97 }
98
99 void
100 afterDecodeError(const Data& data)
101 {
102 lastDecodeErrorData = data;
103 }
104
Teng Liang93adaff2016-07-30 15:57:12 -0700105 void
106 connectHandlers()
107 {
108 notificationConn = subscriber.onNotification.connect(
109 bind(&NotificationSubscriberFixture::afterNotification, this, _1));
Teng Liangf8bf1b02016-07-17 11:54:19 -0700110 nackConn = subscriber.onNack.connect(
111 bind(&NotificationSubscriberFixture::afterNack, this, _1));
Teng Liang93adaff2016-07-30 15:57:12 -0700112 subscriber.onTimeout.connect(
113 bind(&NotificationSubscriberFixture::afterTimeout, this));
114 subscriber.onDecodeError.connect(
115 bind(&NotificationSubscriberFixture::afterDecodeError, this, _1));
116 }
117
118 void
119 disconnectHandlers()
120 {
121 notificationConn.disconnect();
Teng Liangf8bf1b02016-07-17 11:54:19 -0700122 nackConn.disconnect();
Teng Liang93adaff2016-07-30 15:57:12 -0700123 }
124
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700125 /** \return true if subscriberFace has an initial request (first sent Interest)
126 */
127 bool
128 hasInitialRequest() const
129 {
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800130 if (subscriberFace.sentInterests.empty())
Teng Liang93adaff2016-07-30 15:57:12 -0700131 return false;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700132
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800133 const Interest& interest = subscriberFace.sentInterests[0];
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700134 return interest.getName() == streamPrefix &&
Junxiao Shi946a51c2018-11-24 00:25:57 +0000135 interest.getCanBePrefix() &&
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700136 interest.getMustBeFresh() &&
137 interest.getInterestLifetime() == subscriber.getInterestLifetime();
138 }
139
140 /** \return sequence number of the continuation request sent from subscriberFace
141 * or 0 if there's no such request as sole sent Interest
142 */
143 uint64_t
Junxiao Shi946a51c2018-11-24 00:25:57 +0000144 getRequestSeqNum() const
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700145 {
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800146 if (subscriberFace.sentInterests.size() != 1)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700147 return 0;
148
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800149 const Interest& interest = subscriberFace.sentInterests[0];
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700150 const Name& name = interest.getName();
151 if (streamPrefix.isPrefixOf(name) &&
152 name.size() == streamPrefix.size() + 1 &&
153 interest.getInterestLifetime() == subscriber.getInterestLifetime())
154 return name[-1].toSequenceNumber();
155 else
156 return 0;
157 }
158
159protected:
160 Name streamPrefix;
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800161 DummyClientFace subscriberFace;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700162 util::NotificationSubscriber<SimpleNotification> subscriber;
Junxiao Shi728873f2015-01-20 16:01:26 -0700163 util::signal::Connection notificationConn;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700164 util::signal::Connection nackConn;
Teng Liang93adaff2016-07-30 15:57:12 -0700165 uint64_t nextSendNotificationNo;
Junxiao Shi946a51c2018-11-24 00:25:57 +0000166 uint64_t lastDeliveredSeqNum;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700167 SimpleNotification lastNotification;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700168 lp::Nack lastNack;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700169 bool hasTimeout;
170 Data lastDecodeErrorData;
171};
172
Teng Liang93adaff2016-07-30 15:57:12 -0700173BOOST_AUTO_TEST_SUITE(Util)
174BOOST_FIXTURE_TEST_SUITE(TestNotificationSubscriber, NotificationSubscriberFixture)
175
176BOOST_AUTO_TEST_CASE(StartStop)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700177{
178 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false);
179
180 // has no effect because onNotification has no handler
181 subscriber.start();
182 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false);
183
Teng Liang93adaff2016-07-30 15:57:12 -0700184 this->connectHandlers();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700185 subscriber.start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700186 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true);
Davide Pesavento0f830802018-01-16 23:58:58 -0500187 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700188 BOOST_CHECK(this->hasInitialRequest());
189
Teng Liang93adaff2016-07-30 15:57:12 -0700190 subscriberFace.sentInterests.clear();
191 this->disconnectHandlers();
192 this->deliverNotification("n1");
193 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 0);
194}
195
196BOOST_AUTO_TEST_CASE(Notifications)
197{
198 this->connectHandlers();
199 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500200 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700201
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700202 // respond to initial request
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800203 subscriberFace.sentInterests.clear();
Teng Liang93adaff2016-07-30 15:57:12 -0700204 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500205 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700206 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1");
Junxiao Shi946a51c2018-11-24 00:25:57 +0000207 BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1);
Teng Liang93adaff2016-07-30 15:57:12 -0700208
209 // respond to continuation request
210 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700211 this->deliverNotification("n2");
Davide Pesavento0f830802018-01-16 23:58:58 -0500212 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700213 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2");
Junxiao Shi946a51c2018-11-24 00:25:57 +0000214 BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1);
Teng Liang93adaff2016-07-30 15:57:12 -0700215}
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700216
Teng Liangf8bf1b02016-07-17 11:54:19 -0700217BOOST_AUTO_TEST_CASE(Nack)
218{
219 this->connectHandlers();
220 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500221 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700222
223 // send the first Nack to initial request
224 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
225 Interest interest = subscriberFace.sentInterests[0];
226 subscriberFace.sentInterests.clear();
227 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500228 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700229 BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION);
230 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500231 advanceClocks(300_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700232 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
233
234 // send the second Nack to initial request
235 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
236 interest = subscriberFace.sentInterests[0];
237 subscriberFace.sentInterests.clear();
238 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500239 advanceClocks(301_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700240 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500241 advanceClocks(200_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700242 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
243
244 // send a notification to initial request
245 subscriberFace.sentInterests.clear();
246 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500247 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700248
249 // send a Nack to subsequent request
250 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
251 interest = subscriberFace.sentInterests[0];
252 subscriberFace.sentInterests.clear();
253 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500254 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700255 BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION);
256 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500257 advanceClocks(300_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700258 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
259}
260
Teng Liang93adaff2016-07-30 15:57:12 -0700261BOOST_AUTO_TEST_CASE(Timeout)
262{
263 this->connectHandlers();
264 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500265 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700266
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800267 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700268 lastNotification.setMessage("");
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800269 advanceClocks(subscriber.getInterestLifetime(), 2);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700270 BOOST_CHECK(lastNotification.getMessage().empty());
271 BOOST_CHECK_EQUAL(hasTimeout, true);
272 BOOST_CHECK(this->hasInitialRequest());
273
Teng Liang93adaff2016-07-30 15:57:12 -0700274 subscriberFace.sentInterests.clear();
275 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500276 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700277 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1");
278}
279
280BOOST_AUTO_TEST_CASE(SequenceError)
281{
282 this->connectHandlers();
283 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500284 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700285
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700286 Name wrongName = streamPrefix;
287 wrongName.append("%07%07");
288 Data wrongData(wrongName);
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000289 wrongData.setFreshnessPeriod(1_s);
Alexander Afanasyeve4f8c3b2016-06-23 16:03:48 -0700290 m_keyChain.sign(wrongData);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800291 subscriberFace.receive(wrongData);
292 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700293 lastNotification.setMessage("");
Davide Pesavento0f830802018-01-16 23:58:58 -0500294 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700295 BOOST_CHECK(lastNotification.getMessage().empty());
296 BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName);
297 BOOST_CHECK(this->hasInitialRequest());
Teng Liang93adaff2016-07-30 15:57:12 -0700298}
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700299
Teng Liang93adaff2016-07-30 15:57:12 -0700300BOOST_AUTO_TEST_CASE(PayloadError)
301{
302 this->connectHandlers();
303 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500304 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700305
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800306 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700307 lastNotification.setMessage("");
308 this->deliverNotification("\x07n4");
Davide Pesavento0f830802018-01-16 23:58:58 -0500309 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700310 BOOST_CHECK(lastNotification.getMessage().empty());
311 BOOST_CHECK(this->hasInitialRequest());
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700312}
313
Teng Liang93adaff2016-07-30 15:57:12 -0700314BOOST_AUTO_TEST_SUITE_END() // TestNotificationSubscriber
315BOOST_AUTO_TEST_SUITE_END() // Util
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700316
317} // namespace tests
Junxiao Shia60d9362014-11-12 09:38:21 -0700318} // namespace util
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700319} // namespace ndn