blob: 6eb39c2efee97e4a52a262a5d3fad0263b834cfc [file] [log] [blame]
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2011-2015 Regents of the University of California.
4 *
5 * This file is part of ndnSIM. See AUTHORS for complete list of ndnSIM authors and
6 * contributors.
7 *
8 * ndnSIM is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndnSIM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndnSIM, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20#include <ndn-cxx/face.hpp>
21#include <ndn-cxx/util/scheduler.hpp>
Alexander Afanasyev09703402017-02-08 20:18:17 -080022#include <ndn-cxx/lp/tags.hpp>
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -070023
24#include "ns3/ndnSIM/helper/ndn-app-helper.hpp"
Spyridon Mastorakis5ea33222016-12-07 14:33:53 -080025#include "ns3/error-model.h"
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -070026
27#include "../tests-common.hpp"
28
29namespace ns3 {
30namespace ndn {
31
32class NndCxxFaceFixture : public ScenarioHelperWithCleanupFixture
33{
34public:
35 NndCxxFaceFixture()
36 : hasFired(false)
37 {
38 Config::SetDefault("ns3::PointToPointNetDevice::DataRate", StringValue("10Mbps"));
39 Config::SetDefault("ns3::PointToPointChannel::Delay", StringValue("10ms"));
Alexander Afanasyev77f84c62018-10-08 13:37:42 -040040 Config::SetDefault("ns3::QueueBase::MaxSize", StringValue("20p"));
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -070041
42 createTopology({{"A", "B"}});
43 addRoutes({{"A", "B", "/test", 1}});
44 }
45
46protected:
47 bool hasFired;
48};
49
50BOOST_FIXTURE_TEST_SUITE(NdnCxxFace, NndCxxFaceFixture)
51
52class BaseTesterApp
53{
54public:
55 typedef std::function<void(const Name&)> NameCallback;
56 typedef std::function<void()> VoidCallback;
57
58protected:
59 ::ndn::Face m_face;
60};
61
62/////////////////////////////////////////////////////////////////////
63/////////////////////////////////////////////////////////////////////
64/////////////////////////////////////////////////////////////////////
65
66class BasicProducer : public BaseTesterApp
67{
68public:
69 BasicProducer(const Name& name, const NameCallback& onInterest, const VoidCallback& onFail)
70 {
71 m_face.setInterestFilter(name,
72 [this, onInterest] (const ::ndn::InterestFilter& filter, const Interest& interest) {
73 auto data = make_shared<Data>(Name(interest.getName()));
74 StackHelper::getKeyChain().sign(*data);
75 m_face.put(*data);
76 onInterest(interest.getName());
77 },
78 std::bind(onFail));
79 }
80};
81
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -070082BOOST_AUTO_TEST_CASE(SetInterestFilter)
83{
84 FactoryCallbackApp::Install(getNode("B"), [this] () -> shared_ptr<void> {
85 return make_shared<BasicProducer>("/test", [this] (const Name& interest) {
86 BOOST_CHECK_EQUAL(interest, "/test/prefix/%FE%00");
87 this->hasFired = true;
88 },
89 [] {
90 BOOST_ERROR("Unexpected failure to set interest filter");
91 });
92 })
93 .Start(Seconds(0.01));
94
95 addApps({{"A", "ns3::ndn::ConsumerBatches",
96 {{"Prefix", "/test/prefix"}, {"Batches", "0s 1"}}, "1s", "5.1s"}});
97
98 Simulator::Stop(Seconds(20));
99 Simulator::Run();
100
101 BOOST_CHECK(hasFired);
102}
103
104/////////////////////////////////////////////////////////////////////
105/////////////////////////////////////////////////////////////////////
106/////////////////////////////////////////////////////////////////////
107
108class SingleInterest : public BaseTesterApp
109{
110public:
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700111 SingleInterest(const Name& name, const std::function<void(const Data&)>& onData,
112 const VoidCallback& onNack, const VoidCallback& onTimeout)
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700113 {
Alexander Afanasyevdc3c3a32019-02-17 20:17:32 -0500114 m_face.expressInterest(Interest(name).setCanBePrefix(true), std::bind([onData] (const Data& data) {
Alexander Afanasyev09703402017-02-08 20:18:17 -0800115 onData(data);
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700116 }, _2),
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700117 std::bind(onNack),
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700118 std::bind(onTimeout));
119 }
120};
121
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700122BOOST_AUTO_TEST_CASE(ExpressInterestLocalhost)
123{
124 // Retrieve data from remote
125 FactoryCallbackApp::Install(getNode("A"), [this] () -> shared_ptr<void> {
Alexander Afanasyev09703402017-02-08 20:18:17 -0800126 return make_shared<SingleInterest>("/localhost", [this] (const Data& data) {
127 BOOST_CHECK(Name("/localhost").isPrefixOf(data.getName()));
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700128 this->hasFired = true;
129 BOOST_CHECK_LE(Simulator::Now().ToDouble(Time::S), 1.01);
130 },
131 [] {
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700132 BOOST_ERROR("Unexpected NACK");
133 },
134 [] {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700135 BOOST_ERROR("Unexpected timeout");
136 });
137 })
138 .Start(Seconds(1.01));
139
140 Simulator::Stop(Seconds(20));
141 Simulator::Run();
142
143 BOOST_CHECK(hasFired);
144}
145
146BOOST_AUTO_TEST_CASE(ExpressInterestRemote)
147{
148 addApps({{"B", "ns3::ndn::Producer", {{"Prefix", "/test"}}, "0s", "100s"}});
149
150 // Retrieve data from remote
151 FactoryCallbackApp::Install(getNode("A"), [this] () -> shared_ptr<void> {
Alexander Afanasyev09703402017-02-08 20:18:17 -0800152 return make_shared<SingleInterest>("/test/prefix", [this] (const Data& data) {
153 BOOST_CHECK_EQUAL(data.getName(), "/test/prefix");
154 BOOST_REQUIRE(data.getTag<lp::HopCountTag>() != nullptr);
155 BOOST_CHECK_EQUAL(*data.getTag<lp::HopCountTag>(), 2);
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700156 this->hasFired = true;
157 BOOST_CHECK_LE(Simulator::Now().ToDouble(Time::S), 2.0);
158 },
159 [] {
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700160 BOOST_ERROR("Unexpected NACK");
161 },
162 [] {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700163 BOOST_ERROR("Unexpected timeout");
164 });
165 })
166 .Start(Seconds(1.01));
167
168 Simulator::Stop(Seconds(20));
169 Simulator::Run();
170
171 BOOST_CHECK(hasFired);
172}
173
174BOOST_AUTO_TEST_CASE(ExpressInterestTimeout)
175{
176 FactoryCallbackApp::Install(getNode("A"), [this] () -> shared_ptr<void> {
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700177 return make_shared<SingleInterest>(Name("/test/prefix"), [] (const Data&) {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700178 BOOST_ERROR("Unexpected data");
179 },
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700180 [] {
181 BOOST_ERROR("Unexpected NACK");
182 },
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700183 [this] {
184 BOOST_CHECK_GT(Simulator::Now().ToDouble(Time::S), 6.0);
185 this->hasFired = true;
186 });
187 })
188 .Start(Seconds(2.01));
189
Spyridon Mastorakis5ea33222016-12-07 14:33:53 -0800190 // Make sure NACKs are never received
191 Ptr<ns3::RateErrorModel> model = CreateObject<ns3::RateErrorModel>();
192 model->SetRate(std::numeric_limits<double>::max());
193 Config::Set("/NodeList/*/DeviceList/*/$ns3::PointToPointNetDevice/ReceiveErrorModel", PointerValue(model));
194
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700195 Simulator::Stop(Seconds(20));
196 Simulator::Run();
197
198 BOOST_CHECK(hasFired);
199}
200
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700201/////////////////////////////////////////////////////////////////////
202/////////////////////////////////////////////////////////////////////
203/////////////////////////////////////////////////////////////////////
204
205class MultipleInterest : public BaseTesterApp
206{
207public:
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700208 MultipleInterest(const Name& name, const NameCallback& onData, const VoidCallback& onTimeout,
209 const VoidCallback& onNack)
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700210 : m_scheduler(m_face.getIoService())
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700211 {
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700212 expressNextInterest(name, 0, onData, onTimeout, onNack);
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700213 }
214
215private:
216 void
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700217 expressNextInterest(const Name& name, uint32_t seqNo, const NameCallback& onData,
218 const VoidCallback& onTimeout, const VoidCallback& onNack)
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700219 {
Alexander Afanasyevdc3c3a32019-02-17 20:17:32 -0500220 m_face.expressInterest(Interest(Name(name).appendSegment(seqNo)).setCanBePrefix(true), std::bind([=] (const Data& data) {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700221 onData(data.getName());
222
223 m_event = m_scheduler.scheduleEvent(time::seconds(1),
224 std::bind(&MultipleInterest::expressNextInterest, this,
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700225 name, seqNo + 1, onData, onTimeout, onNack));
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700226 }, _2),
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700227 std::bind(onNack),
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700228 std::bind(onTimeout));
229 }
230
231private:
232 ::ndn::Scheduler m_scheduler;
233 ::ndn::util::scheduler::ScopedEventId m_event;
234};
235
236BOOST_AUTO_TEST_CASE(ExpressMultipleInterests)
237{
238 addApps({{"B", "ns3::ndn::Producer", {{"Prefix", "/test"}}, "0s", "100s"}});
239
240 size_t recvCount = 0;
241
242 // Retrieve data from remote
Alexander Afanasyeve93e8b02018-05-08 20:10:01 -0400243 FactoryCallbackApp::Install(getNode("A"), [&recvCount] () -> shared_ptr<void> {
244 return make_shared<MultipleInterest>("/test/prefix", [&recvCount] (const Name& data) {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700245 BOOST_CHECK_EQUAL(data, Name("/test/prefix").appendSegment(recvCount));
246 ++recvCount;
247 },
248 [] {
249 BOOST_ERROR("Unexpected timeout");
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700250 },
251 [] {
252 BOOST_ERROR("Unexpected NACK");
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700253 });
254 })
255 .Start(Seconds(1.01));
256
257 Simulator::Stop(Seconds(10.9)); // this test case also checks that apps stops properly
258 Simulator::Run();
259
260 BOOST_CHECK_EQUAL(recvCount, 10);
261}
262
263class SingleInterestWithFaceShutdown : public BaseTesterApp
264{
265public:
266 SingleInterestWithFaceShutdown()
267 {
Alexander Afanasyevdc3c3a32019-02-17 20:17:32 -0500268 m_face.expressInterest(Interest(Name("/interest/to/timeout")).setCanBePrefix(true),
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700269 std::bind([] {
270 BOOST_ERROR("Unexpected response");
271 }),
272 std::bind([this] {
273 m_face.shutdown();
Spyridon Mastorakisf6d32852017-09-27 20:28:52 -0700274 }),
275 std::bind([this] {
276 m_face.shutdown();
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700277 }));
278 }
279};
280
281BOOST_AUTO_TEST_CASE(FaceShutdownFromTimeoutCallback)
282{
283 // This test case to check if Face.shutdown from an onTimeout callback doesn't cause segfaults
Alexander Afanasyeve93e8b02018-05-08 20:10:01 -0400284 FactoryCallbackApp::Install(getNode("A"), [] () -> shared_ptr<void> {
Alexander Afanasyev5b4c4672015-08-21 12:23:55 -0700285 return make_shared<SingleInterestWithFaceShutdown>();
286 })
287 .Start(Seconds(1.01));
288
289 Simulator::Stop(Seconds(20));
290 Simulator::Run();
291}
292
293BOOST_AUTO_TEST_SUITE_END()
294
295} // namespace ndn
296} // namespace ns3