blob: b27fdcd376299856e57669f1c24f1598baa131f3 [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"
32#include "fw/best-route-strategy2.hpp"
33
34#include "tests/test-common.hpp"
35#include "tests/limited-io.hpp"
36#include "strategy-tester.hpp"
37#include "tests/daemon/face/dummy-face.hpp"
38#include <boost/mpl/copy_if.hpp>
39#include <boost/mpl/vector.hpp>
40
41namespace nfd {
42namespace fw {
43namespace tests {
44
45using namespace nfd::tests;
46
47template<typename S>
48class StrategyScopeControlFixture : public UnitTestTimeFixture
49{
50public:
51 StrategyScopeControlFixture()
52 : limitedIo(this)
53 , nStrategyActions(0)
54 , strategy(forwarder)
55 , fib(forwarder.getFib())
56 , pit(forwarder.getPit())
57 , nonLocalFace1(make_shared<DummyFace>("dummy://1", "dummy://1", ndn::nfd::FACE_SCOPE_NON_LOCAL))
58 , nonLocalFace2(make_shared<DummyFace>("dummy://2", "dummy://2", ndn::nfd::FACE_SCOPE_NON_LOCAL))
59 , localFace3(make_shared<DummyFace>("dummy://3", "dummy://3", ndn::nfd::FACE_SCOPE_LOCAL))
60 , localFace4(make_shared<DummyFace>("dummy://4", "dummy://4", ndn::nfd::FACE_SCOPE_LOCAL))
61 {
62 this->strategy.afterAction.connect([this] {
63 limitedIo.afterOp();
64 ++nStrategyActions;
65 });
66
67 forwarder.addFace(nonLocalFace1);
68 forwarder.addFace(nonLocalFace2);
69 forwarder.addFace(localFace3);
70 forwarder.addFace(localFace4);
71 }
72
73 /** \brief execute f and wait for a number of strategy actions
74 * \note The actions may occur either during f() invocation or afterwards.
75 */
76 void
77 waitForStrategyAction(const std::function<void()>& f, int nExpectedActions = 1)
78 {
79 nStrategyActions = 0;
80 f();
81 if (nStrategyActions < nExpectedActions) {
82 BOOST_REQUIRE_EQUAL(limitedIo.run(nExpectedActions - nStrategyActions, LimitedIo::UNLIMITED_TIME),
83 LimitedIo::EXCEED_OPS);
84 }
85 }
86
87public:
88 LimitedIo limitedIo;
89 int nStrategyActions;
90
91 Forwarder forwarder;
92 StrategyTester<S> strategy;
93 Fib& fib;
94 Pit& pit;
95
96 shared_ptr<Face> nonLocalFace1;
97 shared_ptr<Face> nonLocalFace2;
98 shared_ptr<Face> localFace3;
99 shared_ptr<Face> localFace4;
100};
101
102BOOST_AUTO_TEST_SUITE(Fw)
103BOOST_AUTO_TEST_SUITE(TestStrategyScopeControl)
104
105class AccessStrategyTest
106{
107public:
108 using S = AccessStrategy;
109
110 static bool
111 willSendNackNoRoute()
112 {
113 return false;
114 }
115
116 static bool
117 canProcessNack()
118 {
119 return false;
120 }
121};
122
123class BestRouteStrategy2Test
124{
125public:
126 using S = BestRouteStrategy2;
127
128 static bool
129 willSendNackNoRoute()
130 {
131 return true;
132 }
133
134 static bool
135 canProcessNack()
136 {
137 return true;
138 }
139};
140
141using Tests = boost::mpl::vector<
142 AccessStrategyTest,
143 BestRouteStrategy2Test
144>;
145
146BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToLocal,
147 T, Tests, StrategyScopeControlFixture<typename T::S>)
148{
149 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
150 fibEntry->addNextHop(*this->localFace4, 10);
151
152 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
153 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
154 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
155
156 this->waitForStrategyAction(
157 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); });
158
159 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 1);
160 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
161 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
162}
163
164BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToNonLocal,
165 T, Tests, StrategyScopeControlFixture<typename T::S>)
166{
167 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
168 fibEntry->addNextHop(*this->nonLocalFace2, 10);
169
170 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
171 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
172 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
173
174 this->waitForStrategyAction(
175 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); },
176 1 + T::willSendNackNoRoute());
177
178 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
179 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 1);
180 if (T::willSendNackNoRoute()) {
181 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
182 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
183 }
184}
185
186BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToLocalAndNonLocal,
187 T, Tests, StrategyScopeControlFixture<typename T::S>)
188{
189 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
190 fibEntry->addNextHop(*this->nonLocalFace2, 10);
191 fibEntry->addNextHop(*this->localFace4, 20);
192
193 shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
194 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
195 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
196
197 this->waitForStrategyAction(
198 [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); });
199
200 BOOST_REQUIRE_EQUAL(this->strategy.sendInterestHistory.size(), 1);
201 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.back().outFaceId, this->localFace4->getId());
202 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
203 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
204}
205
206BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocal,
207 T, Tests, StrategyScopeControlFixture<typename T::S>)
208{
209 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
210 fibEntry->addNextHop(*this->nonLocalFace2, 10);
211
212 shared_ptr<Interest> interest = makeInterest("/localhop/A/1");
213 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
214 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
215
216 this->waitForStrategyAction(
217 [&] { this->strategy.afterReceiveInterest(*this->nonLocalFace1, *interest, pitEntry); },
218 1 + T::willSendNackNoRoute());
219
220 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
221 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 1);
222 if (T::willSendNackNoRoute()) {
223 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
224 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
225 }
226}
227
228BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocalAndLocal,
229 T, Tests, StrategyScopeControlFixture<typename T::S>)
230{
231 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
232 fibEntry->addNextHop(*this->nonLocalFace2, 10);
233 fibEntry->addNextHop(*this->localFace4, 20);
234
235 shared_ptr<Interest> interest = makeInterest("/localhop/A/1");
236 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
237 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
238
239 this->waitForStrategyAction(
240 [&] { this->strategy.afterReceiveInterest(*this->nonLocalFace1, *interest, pitEntry); });
241
242 BOOST_REQUIRE_EQUAL(this->strategy.sendInterestHistory.size(), 1);
243 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.back().outFaceId, this->localFace4->getId());
244 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
245 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
246}
247
248BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostNackToNonLocal,
249 T, Tests, StrategyScopeControlFixture<typename T::S>)
250{
251 fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
252 fibEntry->addNextHop(*this->localFace4, 10);
253 fibEntry->addNextHop(*this->nonLocalFace2, 20);
254
255 shared_ptr<Interest> interest = makeInterest("/localhost/A/1", 1460);
256 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
257 pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);
258 lp::Nack nack = makeNack("/localhost/A/1", 1460, lp::NackReason::NO_ROUTE);
259 pitEntry->insertOrUpdateOutRecord(*this->localFace4, *interest)->setIncomingNack(nack);
260
261 this->waitForStrategyAction(
262 [&] { this->strategy.afterReceiveNack(*this->localFace4, nack, pitEntry); },
263 T::canProcessNack());
264
265 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
266 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
267 if (T::canProcessNack()) {
268 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
269 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
270 }
271}
272
273BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopNackToNonLocal,
274 T, Tests, StrategyScopeControlFixture<typename T::S>)
275{
276 fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
277 fibEntry->addNextHop(*this->localFace4, 10);
278 fibEntry->addNextHop(*this->nonLocalFace2, 20);
279
280 shared_ptr<Interest> interest = makeInterest("/localhop/A/1", 1377);
281 shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
282 pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
283 lp::Nack nack = makeNack("/localhop/A/1", 1377, lp::NackReason::NO_ROUTE);
284 pitEntry->insertOrUpdateOutRecord(*this->localFace4, *interest)->setIncomingNack(nack);
285
286 this->waitForStrategyAction(
287 [&] { this->strategy.afterReceiveNack(*this->localFace4, nack, pitEntry); },
288 T::canProcessNack());
289
290 BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
291 BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
292 if (T::canProcessNack()) {
293 BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
294 BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
295 }
296}
297
298BOOST_AUTO_TEST_SUITE_END() // TestStrategyScopeControl
299BOOST_AUTO_TEST_SUITE_END() // Fw
300
301} // namespace tests
302} // namespace fw
303} // namespace nfd