blob: 12834f61aa273441f40db25a40a0010a00fdea7b [file] [log] [blame]
Junxiao Shi15b12e72014-08-09 19:56:24 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California,
4 * 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
26#include "core/notification-subscriber.hpp"
27#include "core/notification-stream.hpp"
28#include "simple-notification.hpp"
29
30#include "tests/test-common.hpp"
31#include "tests/dummy-client-face.hpp"
32
33
34namespace nfd {
35namespace tests {
36
37BOOST_FIXTURE_TEST_SUITE(CoreNotificationSubscriber, BaseFixture)
38
39class EndToEndFixture : public BaseFixture
40{
41public:
42 EndToEndFixture()
43 : streamPrefix("ndn:/NotificationSubscriberTest")
44 , publisherFace(makeDummyClientFace())
45 , notificationStream(*publisherFace, streamPrefix, publisherKeyChain)
46 , subscriberFace(makeDummyClientFace())
47 , subscriber(*subscriberFace, streamPrefix)
48 {
49 }
50
51 /** \brief post one notification and deliver to subscriber
52 */
53 void
54 deliverNotification(const std::string& msg)
55 {
56 publisherFace->m_sentDatas.clear();
57 SimpleNotification notification(msg);
58 notificationStream.postNotification(notification);
59 publisherFace->processEvents();
60 BOOST_REQUIRE_EQUAL(publisherFace->m_sentDatas.size(), 1);
61
62 lastDeliveredSeqNo = publisherFace->m_sentDatas[0].getName().at(-1).toSequenceNumber();
63
64 lastNotification.setMessage("");
65 subscriberFace->receive(publisherFace->m_sentDatas[0]);
66 }
67
68 void
69 afterNotification(const SimpleNotification& notification)
70 {
71 lastNotification = notification;
72 }
73
74 void
75 clearNotificationHandlers()
76 {
77 subscriber.onNotification.clear();
78 }
79
80 void
81 afterTimeout()
82 {
83 hasTimeout = true;
84 }
85
86 void
87 afterDecodeError(const Data& data)
88 {
89 lastDecodeErrorData = data;
90 }
91
92 /** \return true if subscriberFace has an initial request as sole sent Interest
93 */
94 bool
95 hasInitialRequest() const
96 {
97 if (subscriberFace->m_sentInterests.size() != 1)
98 return 0;
99
100 const Interest& interest = subscriberFace->m_sentInterests[0];
101 return interest.getName() == streamPrefix &&
102 interest.getChildSelector() == 1 &&
103 interest.getMustBeFresh() &&
104 interest.getInterestLifetime() ==
105 NotificationSubscriber<SimpleNotification>::getInterestLifetime();
106 }
107
108 /** \return sequence number of the continuation request sent from subscriberFace
109 * or 0 if there's no such request as sole sent Interest
110 */
111 uint64_t
112 getRequestSeqNo() const
113 {
114 if (subscriberFace->m_sentInterests.size() != 1)
115 return 0;
116
117 const Interest& interest = subscriberFace->m_sentInterests[0];
118 const Name& name = interest.getName();
119 if (streamPrefix.isPrefixOf(name) &&
120 name.size() == streamPrefix.size() + 1 &&
121 interest.getInterestLifetime() ==
122 NotificationSubscriber<SimpleNotification>::getInterestLifetime())
123 return name[-1].toSequenceNumber();
124 else
125 return 0;
126 }
127
128protected:
129 Name streamPrefix;
130 shared_ptr<DummyClientFace> publisherFace;
131 ndn::KeyChain publisherKeyChain;
132 NotificationStream<DummyClientFace> notificationStream;
133 shared_ptr<DummyClientFace> subscriberFace;
134 NotificationSubscriber<SimpleNotification> subscriber;
135
136 uint64_t lastDeliveredSeqNo;
137
138 SimpleNotification lastNotification;
139 bool hasTimeout;
140 Data lastDecodeErrorData;
141};
142
143BOOST_FIXTURE_TEST_CASE(EndToEnd, EndToEndFixture)
144{
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
151 subscriber.onNotification += bind(&EndToEndFixture::afterNotification, this, _1);
152 subscriber.onTimeout += bind(&EndToEndFixture::afterTimeout, this);
153 subscriber.onDecodeError += bind(&EndToEndFixture::afterDecodeError, this, _1);
154
155 // not received when subscriber is not running
156 this->deliverNotification("n1");
157 subscriberFace->processEvents(time::milliseconds(10));
158 BOOST_CHECK(lastNotification.getMessage().empty());
159 BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0);
160
161 subscriberFace->m_sentInterests.clear();
162 subscriber.start();
163 subscriberFace->processEvents(time::milliseconds(10));
164 BOOST_REQUIRE_EQUAL(subscriber.isRunning(), true);
165 BOOST_CHECK(this->hasInitialRequest());
166
167 // respond to initial request
168 subscriberFace->m_sentInterests.clear();
169 this->deliverNotification("n2");
170 subscriberFace->processEvents(time::milliseconds(10));
171 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n2");
172 BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1);
173
174 // respond to continuation request
175 subscriberFace->m_sentInterests.clear();
176 this->deliverNotification("n3");
177 subscriberFace->processEvents(time::milliseconds(10));
178 BOOST_CHECK_EQUAL(lastNotification.getMessage(), "n3");
179 BOOST_CHECK_EQUAL(this->getRequestSeqNo(), lastDeliveredSeqNo + 1);
180
181 // timeout
182 subscriberFace->m_sentInterests.clear();
183 lastNotification.setMessage("");
184 subscriberFace->processEvents(
185 NotificationSubscriber<SimpleNotification>::getInterestLifetime() +
186 time::milliseconds(1000));
187 BOOST_CHECK(lastNotification.getMessage().empty());
188 BOOST_CHECK_EQUAL(hasTimeout, true);
189 BOOST_CHECK(this->hasInitialRequest());
190
191 // decode error on sequence number
192 Name wrongName = streamPrefix;
193 wrongName.append("%07%07");
194 Data wrongData(wrongName);
195 publisherKeyChain.sign(wrongData);
196 subscriberFace->receive(wrongData);
197 subscriberFace->m_sentInterests.clear();
198 lastNotification.setMessage("");
199 subscriberFace->processEvents(time::milliseconds(10));
200 BOOST_CHECK(lastNotification.getMessage().empty());
201 BOOST_CHECK_EQUAL(lastDecodeErrorData.getName(), wrongName);
202 BOOST_CHECK(this->hasInitialRequest());
203
204 // decode error in payload
205 subscriberFace->m_sentInterests.clear();
206 lastNotification.setMessage("");
207 this->deliverNotification("\x07n4");
208 subscriberFace->processEvents(time::milliseconds(10));
209 BOOST_CHECK(lastNotification.getMessage().empty());
210 BOOST_CHECK(this->hasInitialRequest());
211
212 // stop if handlers are cleared
213 subscriber.onNotification += bind(&EndToEndFixture::clearNotificationHandlers, this);
214 subscriberFace->m_sentInterests.clear();
215 this->deliverNotification("n5");
216 subscriberFace->processEvents(time::milliseconds(10));
217 BOOST_CHECK_EQUAL(subscriberFace->m_sentInterests.size(), 0);
218}
219
220BOOST_AUTO_TEST_SUITE_END()
221
222} // namespace tests
223} // namespace nfd