blob: 107784ae7569cfe1fb90ed24220f474eef55fa41 [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 Pesavento47ce2ee2023-05-09 01:33:33 -04003 * Copyright (c) 2014-2023 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
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040035namespace ndn::tests {
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070036
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050037class NotificationSubscriberFixture : public IoKeyChainFixture
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070038{
39public:
Teng Liang93adaff2016-07-30 15:57:12 -070040 NotificationSubscriberFixture()
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050041 : streamPrefix("/NotificationSubscriberTest")
42 , subscriberFace(m_io, m_keyChain)
Davide Pesavento0f830802018-01-16 23:58:58 -050043 , subscriber(subscriberFace, streamPrefix, 1_s)
Teng Liang93adaff2016-07-30 15:57:12 -070044 , nextSendNotificationNo(0)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070045 {
46 }
47
Davide Pesaventoc860bd12022-10-04 03:23:43 -040048 /** \brief Deliver one notification to subscriber.
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070049 */
50 void
51 deliverNotification(const std::string& msg)
52 {
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070053 SimpleNotification notification(msg);
Alexander Afanasyev370d2602014-08-20 10:21:34 -050054
Teng Liang93adaff2016-07-30 15:57:12 -070055 Name dataName = streamPrefix;
56 dataName.appendSequenceNumber(nextSendNotificationNo);
57 Data data(dataName);
58 data.setContent(notification.wireEncode());
Davide Pesavento0f830802018-01-16 23:58:58 -050059 data.setFreshnessPeriod(1_s);
Teng Liang93adaff2016-07-30 15:57:12 -070060 m_keyChain.sign(data);
Alexander Afanasyev370d2602014-08-20 10:21:34 -050061
Junxiao Shi946a51c2018-11-24 00:25:57 +000062 lastDeliveredSeqNum = nextSendNotificationNo;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070063 lastNotification.setMessage("");
Teng Liang93adaff2016-07-30 15:57:12 -070064 ++nextSendNotificationNo;
65 subscriberFace.receive(data);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070066 }
67
Davide Pesaventoc860bd12022-10-04 03:23:43 -040068 /** \brief Deliver a Nack to subscriber.
Teng Liangf8bf1b02016-07-17 11:54:19 -070069 */
70 void
71 deliverNack(const Interest& interest, const lp::NackReason& reason)
72 {
Davide Pesavento2e481fc2021-07-02 18:20:03 -040073 subscriberFace.receive(makeNack(interest, reason));
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070074 }
75
Teng Liang93adaff2016-07-30 15:57:12 -070076 void
77 connectHandlers()
78 {
Davide Pesavento2e481fc2021-07-02 18:20:03 -040079 notificationConn = subscriber.onNotification.connect([this] (const auto& n) { lastNotification = n; });
80 nackConn = subscriber.onNack.connect([this] (const auto& nack) { lastNack = nack; });
81 subscriber.onTimeout.connect([this] { hasTimeout = true; });
82 subscriber.onDecodeError.connect([this] (const auto& data) { lastDecodeErrorData = data; });
Teng Liang93adaff2016-07-30 15:57:12 -070083 }
84
85 void
86 disconnectHandlers()
87 {
88 notificationConn.disconnect();
Teng Liangf8bf1b02016-07-17 11:54:19 -070089 nackConn.disconnect();
Teng Liang93adaff2016-07-30 15:57:12 -070090 }
91
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070092 /** \return true if subscriberFace has an initial request (first sent Interest)
93 */
94 bool
95 hasInitialRequest() const
96 {
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -080097 if (subscriberFace.sentInterests.empty())
Teng Liang93adaff2016-07-30 15:57:12 -070098 return false;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -070099
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800100 const Interest& interest = subscriberFace.sentInterests[0];
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700101 return interest.getName() == streamPrefix &&
Junxiao Shi946a51c2018-11-24 00:25:57 +0000102 interest.getCanBePrefix() &&
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700103 interest.getMustBeFresh() &&
104 interest.getInterestLifetime() == subscriber.getInterestLifetime();
105 }
106
107 /** \return sequence number of the continuation request sent from subscriberFace
108 * or 0 if there's no such request as sole sent Interest
109 */
110 uint64_t
Junxiao Shi946a51c2018-11-24 00:25:57 +0000111 getRequestSeqNum() const
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700112 {
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800113 if (subscriberFace.sentInterests.size() != 1)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700114 return 0;
115
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800116 const Interest& interest = subscriberFace.sentInterests[0];
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700117 const Name& name = interest.getName();
118 if (streamPrefix.isPrefixOf(name) &&
119 name.size() == streamPrefix.size() + 1 &&
120 interest.getInterestLifetime() == subscriber.getInterestLifetime())
121 return name[-1].toSequenceNumber();
122 else
123 return 0;
124 }
125
126protected:
127 Name streamPrefix;
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800128 DummyClientFace subscriberFace;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700129 util::NotificationSubscriber<SimpleNotification> subscriber;
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400130 signal::Connection notificationConn;
131 signal::Connection nackConn;
Teng Liang93adaff2016-07-30 15:57:12 -0700132 uint64_t nextSendNotificationNo;
Junxiao Shi946a51c2018-11-24 00:25:57 +0000133 uint64_t lastDeliveredSeqNum;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700134 SimpleNotification lastNotification;
Teng Liangf8bf1b02016-07-17 11:54:19 -0700135 lp::Nack lastNack;
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700136 bool hasTimeout;
137 Data lastDecodeErrorData;
138};
139
Teng Liang93adaff2016-07-30 15:57:12 -0700140BOOST_AUTO_TEST_SUITE(Util)
141BOOST_FIXTURE_TEST_SUITE(TestNotificationSubscriber, NotificationSubscriberFixture)
142
143BOOST_AUTO_TEST_CASE(StartStop)
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700144{
145 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false);
146
147 // has no effect because onNotification has no handler
148 subscriber.start();
149 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), false);
150
Teng Liang93adaff2016-07-30 15:57:12 -0700151 this->connectHandlers();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700152 subscriber.start();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700153 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true);
Davide Pesavento0f830802018-01-16 23:58:58 -0500154 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700155 BOOST_CHECK(this->hasInitialRequest());
156
Teng Liang93adaff2016-07-30 15:57:12 -0700157 subscriberFace.sentInterests.clear();
158 this->disconnectHandlers();
159 this->deliverNotification("n1");
160 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 0);
161}
162
163BOOST_AUTO_TEST_CASE(Notifications)
164{
165 this->connectHandlers();
166 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500167 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700168
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700169 // respond to initial request
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800170 subscriberFace.sentInterests.clear();
Teng Liang93adaff2016-07-30 15:57:12 -0700171 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500172 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700173 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1");
Junxiao Shi946a51c2018-11-24 00:25:57 +0000174 BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1);
Teng Liang93adaff2016-07-30 15:57:12 -0700175
176 // respond to continuation request
177 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700178 this->deliverNotification("n2");
Davide Pesavento0f830802018-01-16 23:58:58 -0500179 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700180 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2");
Junxiao Shi946a51c2018-11-24 00:25:57 +0000181 BOOST_CHECK_EQUAL(this->getRequestSeqNum(), lastDeliveredSeqNum + 1);
Teng Liang93adaff2016-07-30 15:57:12 -0700182}
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700183
Teng Liangf8bf1b02016-07-17 11:54:19 -0700184BOOST_AUTO_TEST_CASE(Nack)
185{
186 this->connectHandlers();
187 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500188 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700189
190 // send the first Nack to initial request
191 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
192 Interest interest = subscriberFace.sentInterests[0];
193 subscriberFace.sentInterests.clear();
194 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500195 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700196 BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION);
197 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500198 advanceClocks(300_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700199 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
200
201 // send the second Nack to initial request
202 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
203 interest = subscriberFace.sentInterests[0];
204 subscriberFace.sentInterests.clear();
205 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500206 advanceClocks(301_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700207 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500208 advanceClocks(200_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700209 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
210
211 // send a notification to initial request
212 subscriberFace.sentInterests.clear();
213 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500214 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700215
216 // send a Nack to subsequent request
217 BOOST_REQUIRE_EQUAL(subscriberFace.sentInterests.size(), 1);
218 interest = subscriberFace.sentInterests[0];
219 subscriberFace.sentInterests.clear();
220 this->deliverNack(interest, lp::NackReason::CONGESTION);
Davide Pesavento0f830802018-01-16 23:58:58 -0500221 advanceClocks(1_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700222 BOOST_CHECK_EQUAL(lastNack.getReason(), lp::NackReason::CONGESTION);
223 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), false);
Davide Pesavento0f830802018-01-16 23:58:58 -0500224 advanceClocks(300_ms);
Teng Liangf8bf1b02016-07-17 11:54:19 -0700225 BOOST_REQUIRE_EQUAL(this->hasInitialRequest(), true);
226}
227
Teng Liang93adaff2016-07-30 15:57:12 -0700228BOOST_AUTO_TEST_CASE(Timeout)
229{
230 this->connectHandlers();
231 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500232 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700233
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800234 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700235 lastNotification.setMessage("");
Alexander Afanasyevd3a55b22014-11-18 19:23:28 -0800236 advanceClocks(subscriber.getInterestLifetime(), 2);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700237 BOOST_CHECK(lastNotification.getMessage().empty());
238 BOOST_CHECK_EQUAL(hasTimeout, true);
239 BOOST_CHECK(this->hasInitialRequest());
240
Teng Liang93adaff2016-07-30 15:57:12 -0700241 subscriberFace.sentInterests.clear();
242 this->deliverNotification("n1");
Davide Pesavento0f830802018-01-16 23:58:58 -0500243 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700244 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n1");
245}
246
247BOOST_AUTO_TEST_CASE(SequenceError)
248{
249 this->connectHandlers();
250 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500251 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700252
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700253 Name wrongName = streamPrefix;
254 wrongName.append("%07%07");
255 Data wrongData(wrongName);
Junxiao Shi2ad2fbe2019-05-24 03:11:05 +0000256 wrongData.setFreshnessPeriod(1_s);
Alexander Afanasyeve4f8c3b2016-06-23 16:03:48 -0700257 m_keyChain.sign(wrongData);
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800258 subscriberFace.receive(wrongData);
259 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700260 lastNotification.setMessage("");
Davide Pesavento0f830802018-01-16 23:58:58 -0500261 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700262 BOOST_CHECK(lastNotification.getMessage().empty());
263 BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName);
264 BOOST_CHECK(this->hasInitialRequest());
Teng Liang93adaff2016-07-30 15:57:12 -0700265}
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700266
Teng Liang93adaff2016-07-30 15:57:12 -0700267BOOST_AUTO_TEST_CASE(PayloadError)
268{
269 this->connectHandlers();
270 subscriber.start();
Davide Pesavento0f830802018-01-16 23:58:58 -0500271 advanceClocks(1_ms);
Teng Liang93adaff2016-07-30 15:57:12 -0700272
Alexander Afanasyev9bdbb832015-12-30 12:54:22 -0800273 subscriberFace.sentInterests.clear();
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700274 lastNotification.setMessage("");
275 this->deliverNotification("\x07n4");
Davide Pesavento0f830802018-01-16 23:58:58 -0500276 advanceClocks(1_ms);
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700277 BOOST_CHECK(lastNotification.getMessage().empty());
278 BOOST_CHECK(this->hasInitialRequest());
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700279}
280
Teng Liang93adaff2016-07-30 15:57:12 -0700281BOOST_AUTO_TEST_SUITE_END() // TestNotificationSubscriber
282BOOST_AUTO_TEST_SUITE_END() // Util
Alexander Afanasyev4abdbf12014-08-11 12:48:54 -0700283
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400284} // namespace ndn::tests