blob: 2311ff7bde73c58486bc8a1954b3b7240ccc22fb [file] [log] [blame]
Junxiao Shia7f9a292016-11-22 16:31:38 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2016, 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/** \file
27 * This test suite tests localhost and localhop scope control in strategies.
28 */
29
30// Strategies implementing namespace-based scope control, sorted alphabetically.
31#include "fw/access-strategy.hpp"
Ashlesh Gawande2a73f352016-12-01 15:37:03 +000032#include "fw/asf-strategy.hpp"
Junxiao Shie21b3f32016-11-24 14:13:46 +000033#include "fw/best-route-strategy.hpp"
Junxiao Shia7f9a292016-11-22 16:31:38 +000034#include "fw/best-route-strategy2.hpp"
Junxiao Shie21b3f32016-11-24 14:13:46 +000035#include "fw/multicast-strategy.hpp"
36#include "fw/ncc-strategy.hpp"
Junxiao Shia7f9a292016-11-22 16:31:38 +000037
38#include "tests/test-common.hpp"
39#include "tests/limited-io.hpp"
Junxiao Shie21b3f32016-11-24 14:13:46 +000040#include "install-strategy.hpp"
Junxiao Shia7f9a292016-11-22 16:31:38 +000041#include "strategy-tester.hpp"
42#include "tests/daemon/face/dummy-face.hpp"
43#include <boost/mpl/copy_if.hpp>
44#include <boost/mpl/vector.hpp>
45
46namespace nfd {
47namespace fw {
48namespace tests {
49
50using namespace nfd::tests;
51
52template<typename S>
53class StrategyScopeControlFixture : public UnitTestTimeFixture
54{
55public:
56 StrategyScopeControlFixture()
57 : limitedIo(this)
58 , nStrategyActions(0)
Junxiao Shie21b3f32016-11-24 14:13:46 +000059 , strategy(choose<StrategyTester<S>>(forwarder))
Junxiao Shia7f9a292016-11-22 16:31:38 +000060 , fib(forwarder.getFib())
61 , pit(forwarder.getPit())
62 , nonLocalFace1(make_shared<DummyFace>("dummy://1", "dummy://1", ndn::nfd::FACE_SCOPE_NON_LOCAL))
63 , nonLocalFace2(make_shared<DummyFace>("dummy://2", "dummy://2", ndn::nfd::FACE_SCOPE_NON_LOCAL))
64 , localFace3(make_shared<DummyFace>("dummy://3", "dummy://3", ndn::nfd::FACE_SCOPE_LOCAL))
65 , localFace4(make_shared<DummyFace>("dummy://4", "dummy://4", ndn::nfd::FACE_SCOPE_LOCAL))
66 {
67 this->strategy.afterAction.connect([this] {
68 limitedIo.afterOp();
69 ++nStrategyActions;
70 });
71
72 forwarder.addFace(nonLocalFace1);
73 forwarder.addFace(nonLocalFace2);
74 forwarder.addFace(localFace3);
75 forwarder.addFace(localFace4);
76 }
77
78 /** \brief execute f and wait for a number of strategy actions
79 * \note The actions may occur either during f() invocation or afterwards.
80 */
81 void
82 waitForStrategyAction(const std::function<void()>& f, int nExpectedActions = 1)
83 {
84 nStrategyActions = 0;
85 f();
86 if (nStrategyActions < nExpectedActions) {
87 BOOST_REQUIRE_EQUAL(limitedIo.run(nExpectedActions - nStrategyActions, LimitedIo::UNLIMITED_TIME),
88 LimitedIo::EXCEED_OPS);
89 }
Junxiao Shie21b3f32016-11-24 14:13:46 +000090 // A correctly implemented strategy is required to invoke reject pending Interest action
91 // if it decides to not forward an Interest. If a test case is stuck in an endless loop within
92 // this function, check that rejectPendingInterest is invoked under proper condition.
Junxiao Shia7f9a292016-11-22 16:31:38 +000093 }
94
95public:
96 LimitedIo limitedIo;
97 int nStrategyActions;
98
99 Forwarder forwarder;
Junxiao Shie21b3f32016-11-24 14:13:46 +0000100 StrategyTester<S>& strategy;
Junxiao Shia7f9a292016-11-22 16:31:38 +0000101 Fib& fib;
102 Pit& pit;
103
104 shared_ptr<Face> nonLocalFace1;
105 shared_ptr<Face> nonLocalFace2;
106 shared_ptr<Face> localFace3;
107 shared_ptr<Face> localFace4;
108};
109
110BOOST_AUTO_TEST_SUITE(Fw)
111BOOST_AUTO_TEST_SUITE(TestStrategyScopeControl)
112
Junxiao Shie21b3f32016-11-24 14:13:46 +0000113template<typename S, bool WillSendNackNoRoute, bool CanProcessNack>
114class Test
Junxiao Shia7f9a292016-11-22 16:31:38 +0000115{
116public:
Junxiao Shie21b3f32016-11-24 14:13:46 +0000117 using Strategy = S;
Junxiao Shia7f9a292016-11-22 16:31:38 +0000118
119 static bool
120 willSendNackNoRoute()
121 {
Junxiao Shie21b3f32016-11-24 14:13:46 +0000122 return WillSendNackNoRoute;
Junxiao Shia7f9a292016-11-22 16:31:38 +0000123 }
124
125 static bool
126 canProcessNack()
127 {
Junxiao Shie21b3f32016-11-24 14:13:46 +0000128 return CanProcessNack;
Junxiao Shia7f9a292016-11-22 16:31:38 +0000129 }
130};
131
132using Tests = boost::mpl::vector<
Junxiao Shie21b3f32016-11-24 14:13:46 +0000133 Test<AccessStrategy, false, false>,
Ashlesh Gawande2a73f352016-12-01 15:37:03 +0000134 Test<AsfStrategy, true, false>,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000135 Test<BestRouteStrategy, false, false>,
136 Test<BestRouteStrategy2, true, true>,
137 Test<MulticastStrategy, false, false>,
138 Test<NccStrategy, false, false>
Junxiao Shia7f9a292016-11-22 16:31:38 +0000139>;
140
141BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000142 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000143{
144 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
145 fibEntry->addNextHop(*this->localFace4, 10);
146
147 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
148 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
149 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
150
151 this->waitForStrategyAction(
152 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); });
153
154 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 1);
155 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
156 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
157}
158
159BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToNonLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000160 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000161{
162 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
163 fibEntry->addNextHop(*this->nonLocalFace2, 10);
164
165 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
166 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
167 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
168
169 this->waitForStrategyAction(
170 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); },
171 1 + T::willSendNackNoRoute());
172
173 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
174 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 1);
175 if (T::willSendNackNoRoute()) {
176 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
177 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
178 }
179}
180
181BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToLocalAndNonLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000182 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000183{
184 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
185 fibEntry->addNextHop(*this->nonLocalFace2, 10);
186 fibEntry->addNextHop(*this->localFace4, 20);
187
188 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
189 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
190 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
191
192 this->waitForStrategyAction(
193 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); });
194
195 BOOST_REQUIRE_EQUAL(this->strategy.sendInterestHistory.size(), 1);
196 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.back().outFaceId, this->localFace4->getId());
197 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
198 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
199}
200
201BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000202 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000203{
204 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
205 fibEntry->addNextHop(*this->nonLocalFace2, 10);
206
207 shared_ptr<Interest> interest = makeInterest("/localhop/A/1");
208 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
209 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
210
211 this->waitForStrategyAction(
212 [&] { this->strategy.afterReceiveInterest(*this->nonLocalFace1, *interest, pitEntry); },
213 1 + T::willSendNackNoRoute());
214
215 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
216 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 1);
217 if (T::willSendNackNoRoute()) {
218 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
219 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
220 }
221}
222
223BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocalAndLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000224 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000225{
226 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
227 fibEntry->addNextHop(*this->nonLocalFace2, 10);
228 fibEntry->addNextHop(*this->localFace4, 20);
229
230 shared_ptr<Interest> interest = makeInterest("/localhop/A/1");
231 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
232 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
233
234 this->waitForStrategyAction(
235 [&] { this->strategy.afterReceiveInterest(*this->nonLocalFace1, *interest, pitEntry); });
236
237 BOOST_REQUIRE_EQUAL(this->strategy.sendInterestHistory.size(), 1);
238 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.back().outFaceId, this->localFace4->getId());
239 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
240 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
241}
242
243BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostNackToNonLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000244 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000245{
246 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
247 fibEntry->addNextHop(*this->localFace4, 10);
248 fibEntry->addNextHop(*this->nonLocalFace2, 20);
249
250 shared_ptr<Interest> interest = makeInterest("/localhost/A/1", 1460);
251 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
252 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
253 lp::Nack nack = makeNack("/localhost/A/1", 1460, lp::NackReason::NO_ROUTE);
254 pitEntry->insertOrUpdateOutRecord(*this->localFace4, *interest)->setIncomingNack(nack);
255
256 this->waitForStrategyAction(
257 [&] { this->strategy.afterReceiveNack(*this->localFace4, nack, pitEntry); },
258 T::canProcessNack());
259
260 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
261 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
262 if (T::canProcessNack()) {
263 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
264 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
265 }
266}
267
268BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopNackToNonLocal,
Junxiao Shie21b3f32016-11-24 14:13:46 +0000269 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
Junxiao Shia7f9a292016-11-22 16:31:38 +0000270{
271 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
272 fibEntry->addNextHop(*this->localFace4, 10);
273 fibEntry->addNextHop(*this->nonLocalFace2, 20);
274
275 shared_ptr<Interest> interest = makeInterest("/localhop/A/1", 1377);
276 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
277 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
278 lp::Nack nack = makeNack("/localhop/A/1", 1377, lp::NackReason::NO_ROUTE);
279 pitEntry->insertOrUpdateOutRecord(*this->localFace4, *interest)->setIncomingNack(nack);
280
281 this->waitForStrategyAction(
282 [&] { this->strategy.afterReceiveNack(*this->localFace4, nack, pitEntry); },
283 T::canProcessNack());
284
285 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
286 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
287 if (T::canProcessNack()) {
288 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
289 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
290 }
291}
292
293BOOST_AUTO_TEST_SUITE_END() // TestStrategyScopeControl
294BOOST_AUTO_TEST_SUITE_END() // Fw
295
296} // namespace tests
297} // namespace fw
298} // namespace nfd