blob: 148f5a895723963b8dab985d2597b2c564bdf711 [file] [log] [blame]
Junxiao Shi80ee7cb2014-12-14 10:53:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi352fc822016-08-09 03:53:05 +00003 * Copyright (c) 2014-2016, Regents of the University of California,
Junxiao Shi80ee7cb2014-12-14 10:53:05 -07004 * 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 "fw/access-strategy.hpp"
27
28#include "tests/test-common.hpp"
Junxiao Shi890afe92016-12-15 14:34:34 +000029#include "strategy-tester.hpp"
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070030#include "topology-tester.hpp"
31
32namespace nfd {
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080033namespace fw {
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070034namespace tests {
35
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080036using namespace nfd::tests;
37
Junxiao Shi890afe92016-12-15 14:34:34 +000038// The tester is unused in this file, but it's used in various templated test suites.
39typedef StrategyTester<AccessStrategy> AccessStrategyTester;
40NFD_REGISTER_STRATEGY(AccessStrategyTester);
41
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070042// This test suite tests AccessStrategy's behavior as a black box,
43// without accessing its internals.
44//
45// Many test assertions are qualitative rather than quantitative.
46// They capture the design highlights of the strategy without requiring a definite value,
47// so that the test suite is not fragile to minor changes in the strategy implementation.
48//
49// Topology graphes in this test suite are shown in ASCII art,
50// in a style similar to ns-3 and ndnSIM examples.
51// They are enclosed in multi-line comments, which is an intentional violation of
52// code style rule 3.25. This is necessary because some lines ends with '\' which
53// would cause "multi-line comment" compiler warning if '//' comments are used.
54
Junxiao Shi5e5e4452015-09-24 16:56:52 -070055BOOST_AUTO_TEST_SUITE(Fw)
56BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, UnitTestTimeFixture)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070057
Junxiao Shic34d1672016-12-09 15:57:59 +000058BOOST_AUTO_TEST_CASE(Registration)
59{
Junxiao Shi037f4ab2016-12-13 04:27:06 +000060 BOOST_CHECK_EQUAL(Strategy::listRegistered().count(AccessStrategy::getStrategyName()), 1);
Junxiao Shic34d1672016-12-09 15:57:59 +000061}
62
Junxiao Shi18739c42016-12-22 08:03:00 +000063BOOST_AUTO_TEST_CASE(InstanceName)
64{
65 Forwarder forwarder;
66 BOOST_REQUIRE(AccessStrategy::getStrategyName().at(-1).isVersion());
67 BOOST_CHECK_EQUAL(
68 AccessStrategy(forwarder, AccessStrategy::getStrategyName().getPrefix(-1)).getInstanceName(),
69 AccessStrategy::getStrategyName());
70 BOOST_CHECK_THROW(
71 AccessStrategy(forwarder, Name(AccessStrategy::getStrategyName()).append("param")),
72 std::invalid_argument);
73}
74
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070075class TwoLaptopsFixture : public UnitTestTimeFixture
76{
77protected:
78 TwoLaptopsFixture()
79 {
80 /*
81 * +--------+
82 * +----->| router |<------+
83 * | +--------+ |
84 * 10ms | | 20ms
85 * v v
86 * +---------+ +---------+
87 * | laptopA | | laptopB |
88 * +---------+ +---------+
89 */
90
Junxiao Shi5e5e4452015-09-24 16:56:52 -070091 router = topo.addForwarder("R");
92 laptopA = topo.addForwarder("A");
93 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070094
95 topo.setStrategy<fw::AccessStrategy>(router);
96
Junxiao Shi5e5e4452015-09-24 16:56:52 -070097 linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
98 linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070099 }
100
101protected:
102 TopologyTester topo;
103
104 TopologyNode router;
105 TopologyNode laptopA;
106 TopologyNode laptopB;
107 shared_ptr<TopologyLink> linkA;
108 shared_ptr<TopologyLink> linkB;
109};
110
111BOOST_FIXTURE_TEST_CASE(OneProducer, TwoLaptopsFixture)
112{
113 /*
114 * /------------------\
115 * | intervalConsumer |
116 * \------------------/
117 * ^ v
118 * | v /laptops/A
119 * |
120 * v
121 * /laptops << +--------+ >> /laptops
122 * +----->| router |<------+
123 * | +--------+ |
124 * 10ms | | 20ms
125 * v v
126 * +---------+ +---------+
127 * | laptopA | | laptopB |
128 * +---------+ +---------+
129 * ^ v
130 * | v /laptops/A
131 * v
132 * /--------------\
133 * | echoProducer |
134 * \--------------/
135 */
136
137 // two laptops have same prefix in router FIB
138 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
139 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
140
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700141 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
142 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700143
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700144 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
145 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700146 time::milliseconds(100), 100);
147
148 this->advanceClocks(time::milliseconds(5), time::seconds(12));
149
150 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700151 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
152 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
153 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700154}
155
156BOOST_FIXTURE_TEST_CASE(FastSlowProducer, TwoLaptopsFixture)
157{
158 /*
159 * /------------------\
160 * | intervalConsumer |
161 * \------------------/
162 * ^ v
163 * | v /laptops/BOTH
164 * |
165 * v
166 * /laptops << +--------+ >> /laptops
167 * +----->| router |<------+
168 * | +--------+ |
169 * 10ms | | 20ms
170 * v v
171 * +---------+ +---------+
172 * | laptopA | | laptopB |
173 * +---------+ +---------+
174 * ^ v ^ v
175 * | v /laptops/BOTH | v /laptops/BOTH
176 * v v
177 * /--------------\ /--------------\
178 * | echoProducer | | echoProducer |
179 * \--------------/ \--------------/
180 */
181
182 // two laptops have same prefix in router FIB
183 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
184 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
185
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700186 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
187 topo.addEchoProducer(producerA->getClientFace());
188 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
189 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700190
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700191 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
192 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700193 time::milliseconds(100), 100);
194
195 this->advanceClocks(time::milliseconds(5), time::seconds(12));
196
197 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700198 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
199 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
200 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700201}
202
203BOOST_FIXTURE_TEST_CASE(ProducerMobility, TwoLaptopsFixture)
204{
205 /*
206 * /------------------\ /------------------\
207 * | intervalConsumer | | intervalConsumer |
208 * \------------------/ A \------------------/
209 * ^ v f ^ v
210 * | v /laptops/M t | v /laptops/M
211 * | e |
212 * v r v
213 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
214 * +----->| router |<------+ 6 +----->| router |<------+
215 * | +--------+ | | +--------+ |
216 * 10ms | | 20ms === s ==> 10ms | | 20ms
217 * v v e v v
218 * +---------+ +---------+ c +---------+ +---------+
219 * | laptopA | | laptopB | o | laptopA | | laptopB |
220 * +---------+ +---------+ n +---------+ +---------+
221 * ^ v d v ^
222 * | v /laptops/M s /laptops/M v |
223 * v v
224 * /--------------\ /--------------\
225 * | echoProducer | | echoProducer |
226 * \--------------/ \--------------/
227 */
228
229 // two laptops have same prefix in router FIB
230 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
231 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
232
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700233 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
234 topo.addEchoProducer(producerA->getClientFace());
235 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
236 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700237
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700238 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
239 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700240 time::milliseconds(100), 100);
241
242 // producer is initially on laptopA
243 producerB->fail();
244 this->advanceClocks(time::milliseconds(5), time::seconds(6));
245
246 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700247 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700248
249 // producer moves to laptopB
250 producerA->fail();
251 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700252 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700253 this->advanceClocks(time::milliseconds(5), time::seconds(6));
254
255 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700256 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700257
258 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700259 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700260}
261
262BOOST_FIXTURE_TEST_CASE(Bidirectional, TwoLaptopsFixture)
263{
264 /*
265 * /laptops << +--------+ >> /laptops
266 * +----->| router |<------+
267 * | +--------+ |
268 * ^ 10ms | | 20ms ^
269 * / ^ v v ^ /
270 * +---------+ +---------+
271 * +----->| laptopA | | laptopB |<------------+
272 * | +---------+ +---------+ |
273 * | ^ v /laptops/A ^ v /laptops/B |
274 * ^ | | v | v | ^
275 * /laptops/B ^ v v v v ^ /laptops/A
276 * /------------------\ /--------------\ /--------------\ /------------------\
277 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
278 * \------------------/ \--------------/ \--------------/ \------------------/
279 */
280
281 // laptops have default routes toward the router
282 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
283 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
284
285 // two laptops have same prefix in router FIB
286 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
287 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
288
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700289 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
290 topo.addEchoProducer(producerA->getClientFace());
291 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
292 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700293
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700294 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
295 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700296 time::milliseconds(100), 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700297 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
298 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700299 time::milliseconds(100), 100);
300
301 this->advanceClocks(time::milliseconds(5), time::seconds(12));
302
303 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700304 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
305 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700306}
307
308BOOST_FIXTURE_TEST_CASE(PacketLoss, TwoLaptopsFixture)
309{
310 /*
311 * test case Interests
312 * |
313 * v
314 * +--------+
315 * | router |
316 * +--------+
317 * | v
318 * 10ms | v /laptops
319 * v
320 * +---------+
321 * | laptopA |
322 * +---------+
323 * ^ v
324 * | v /laptops/A
325 * v
326 * /--------------\
327 * | echoProducer |
328 * \--------------/
329 */
330
331 // laptopA has prefix in router FIB; laptopB is unused in this test case
332 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
333
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700334 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
335 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700336
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700337 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700338
339 // Interest 1 completes normally
340 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
341 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700342 consumer->getClientFace().expressInterest(*interest1,
Junxiao Shi352fc822016-08-09 03:53:05 +0000343 bind([&hasData1] { hasData1 = true; }),
344 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700345 this->advanceClocks(time::milliseconds(5), time::seconds(1));
346 BOOST_CHECK_EQUAL(hasData1, true);
347
348 // Interest 2 experiences a packet loss on initial transmission
349 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
350 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700351 consumer->getClientFace().expressInterest(*interest2a,
352 bind([&hasData2a] { hasData2a = true; }),
Junxiao Shi352fc822016-08-09 03:53:05 +0000353 nullptr,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700354 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700355 producerA->fail();
356 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
357 BOOST_CHECK_EQUAL(hasData2a, false);
358 BOOST_CHECK_EQUAL(hasTimeout2a, false);
359
360 // Interest 2 retransmission is suppressed
361 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
362 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700363 consumer->getClientFace().expressInterest(*interest2b,
Junxiao Shi352fc822016-08-09 03:53:05 +0000364 bind([&hasData2b] { hasData2b = true; }),
365 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700366 producerA->recover();
367 this->advanceClocks(time::milliseconds(5), time::seconds(1));
368 BOOST_CHECK_EQUAL(hasData2b, false);
369
370 // Interest 2 retransmission gets through, and is answered
371 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
372 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700373 consumer->getClientFace().expressInterest(*interest2c,
Junxiao Shi352fc822016-08-09 03:53:05 +0000374 bind([&hasData2c] { hasData2c = true; }),
375 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700376 this->advanceClocks(time::milliseconds(5), time::seconds(1));
377 BOOST_CHECK_EQUAL(hasData2c, true);
378}
379
Junxiao Shi965d3a42015-06-01 06:55:23 -0700380BOOST_FIXTURE_TEST_CASE(Bug2831, TwoLaptopsFixture)
381{
382 // make a two-node loop
383 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
384 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
385
386 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700387 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
388 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
Junxiao Shi965d3a42015-06-01 06:55:23 -0700389 time::milliseconds(100), 10);
390
391 this->advanceClocks(time::milliseconds(5), time::seconds(2));
392
393 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700394 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700395}
396
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700397BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
398BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700399
400} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800401} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700402} // namespace nfd