blob: a25c44cc307a48d514786dc5587b3e93eb6037e1 [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 Shi80ee7cb2014-12-14 10:53:05 -070063class TwoLaptopsFixture : public UnitTestTimeFixture
64{
65protected:
66 TwoLaptopsFixture()
67 {
68 /*
69 * +--------+
70 * +----->| router |<------+
71 * | +--------+ |
72 * 10ms | | 20ms
73 * v v
74 * +---------+ +---------+
75 * | laptopA | | laptopB |
76 * +---------+ +---------+
77 */
78
Junxiao Shi5e5e4452015-09-24 16:56:52 -070079 router = topo.addForwarder("R");
80 laptopA = topo.addForwarder("A");
81 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070082
83 topo.setStrategy<fw::AccessStrategy>(router);
84
Junxiao Shi5e5e4452015-09-24 16:56:52 -070085 linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
86 linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070087 }
88
89protected:
90 TopologyTester topo;
91
92 TopologyNode router;
93 TopologyNode laptopA;
94 TopologyNode laptopB;
95 shared_ptr<TopologyLink> linkA;
96 shared_ptr<TopologyLink> linkB;
97};
98
99BOOST_FIXTURE_TEST_CASE(OneProducer, TwoLaptopsFixture)
100{
101 /*
102 * /------------------\
103 * | intervalConsumer |
104 * \------------------/
105 * ^ v
106 * | v /laptops/A
107 * |
108 * v
109 * /laptops << +--------+ >> /laptops
110 * +----->| router |<------+
111 * | +--------+ |
112 * 10ms | | 20ms
113 * v v
114 * +---------+ +---------+
115 * | laptopA | | laptopB |
116 * +---------+ +---------+
117 * ^ v
118 * | v /laptops/A
119 * v
120 * /--------------\
121 * | echoProducer |
122 * \--------------/
123 */
124
125 // two laptops have same prefix in router FIB
126 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
127 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
128
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700129 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
130 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700131
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700132 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
133 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700134 time::milliseconds(100), 100);
135
136 this->advanceClocks(time::milliseconds(5), time::seconds(12));
137
138 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700139 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
140 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
141 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700142}
143
144BOOST_FIXTURE_TEST_CASE(FastSlowProducer, TwoLaptopsFixture)
145{
146 /*
147 * /------------------\
148 * | intervalConsumer |
149 * \------------------/
150 * ^ v
151 * | v /laptops/BOTH
152 * |
153 * v
154 * /laptops << +--------+ >> /laptops
155 * +----->| router |<------+
156 * | +--------+ |
157 * 10ms | | 20ms
158 * v v
159 * +---------+ +---------+
160 * | laptopA | | laptopB |
161 * +---------+ +---------+
162 * ^ v ^ v
163 * | v /laptops/BOTH | v /laptops/BOTH
164 * v v
165 * /--------------\ /--------------\
166 * | echoProducer | | echoProducer |
167 * \--------------/ \--------------/
168 */
169
170 // two laptops have same prefix in router FIB
171 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
172 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
173
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700174 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
175 topo.addEchoProducer(producerA->getClientFace());
176 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
177 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700178
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700179 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
180 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700181 time::milliseconds(100), 100);
182
183 this->advanceClocks(time::milliseconds(5), time::seconds(12));
184
185 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700186 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
187 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
188 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700189}
190
191BOOST_FIXTURE_TEST_CASE(ProducerMobility, TwoLaptopsFixture)
192{
193 /*
194 * /------------------\ /------------------\
195 * | intervalConsumer | | intervalConsumer |
196 * \------------------/ A \------------------/
197 * ^ v f ^ v
198 * | v /laptops/M t | v /laptops/M
199 * | e |
200 * v r v
201 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
202 * +----->| router |<------+ 6 +----->| router |<------+
203 * | +--------+ | | +--------+ |
204 * 10ms | | 20ms === s ==> 10ms | | 20ms
205 * v v e v v
206 * +---------+ +---------+ c +---------+ +---------+
207 * | laptopA | | laptopB | o | laptopA | | laptopB |
208 * +---------+ +---------+ n +---------+ +---------+
209 * ^ v d v ^
210 * | v /laptops/M s /laptops/M v |
211 * v v
212 * /--------------\ /--------------\
213 * | echoProducer | | echoProducer |
214 * \--------------/ \--------------/
215 */
216
217 // two laptops have same prefix in router FIB
218 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
219 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
220
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700221 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
222 topo.addEchoProducer(producerA->getClientFace());
223 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
224 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700225
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700226 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
227 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700228 time::milliseconds(100), 100);
229
230 // producer is initially on laptopA
231 producerB->fail();
232 this->advanceClocks(time::milliseconds(5), time::seconds(6));
233
234 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700235 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700236
237 // producer moves to laptopB
238 producerA->fail();
239 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700240 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700241 this->advanceClocks(time::milliseconds(5), time::seconds(6));
242
243 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700244 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700245
246 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700247 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700248}
249
250BOOST_FIXTURE_TEST_CASE(Bidirectional, TwoLaptopsFixture)
251{
252 /*
253 * /laptops << +--------+ >> /laptops
254 * +----->| router |<------+
255 * | +--------+ |
256 * ^ 10ms | | 20ms ^
257 * / ^ v v ^ /
258 * +---------+ +---------+
259 * +----->| laptopA | | laptopB |<------------+
260 * | +---------+ +---------+ |
261 * | ^ v /laptops/A ^ v /laptops/B |
262 * ^ | | v | v | ^
263 * /laptops/B ^ v v v v ^ /laptops/A
264 * /------------------\ /--------------\ /--------------\ /------------------\
265 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
266 * \------------------/ \--------------/ \--------------/ \------------------/
267 */
268
269 // laptops have default routes toward the router
270 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
271 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
272
273 // two laptops have same prefix in router FIB
274 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
275 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
276
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700277 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
278 topo.addEchoProducer(producerA->getClientFace());
279 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
280 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700281
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700282 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
283 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700284 time::milliseconds(100), 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700285 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
286 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700287 time::milliseconds(100), 100);
288
289 this->advanceClocks(time::milliseconds(5), time::seconds(12));
290
291 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700292 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
293 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700294}
295
296BOOST_FIXTURE_TEST_CASE(PacketLoss, TwoLaptopsFixture)
297{
298 /*
299 * test case Interests
300 * |
301 * v
302 * +--------+
303 * | router |
304 * +--------+
305 * | v
306 * 10ms | v /laptops
307 * v
308 * +---------+
309 * | laptopA |
310 * +---------+
311 * ^ v
312 * | v /laptops/A
313 * v
314 * /--------------\
315 * | echoProducer |
316 * \--------------/
317 */
318
319 // laptopA has prefix in router FIB; laptopB is unused in this test case
320 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
321
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700322 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
323 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700324
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700325 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700326
327 // Interest 1 completes normally
328 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
329 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700330 consumer->getClientFace().expressInterest(*interest1,
Junxiao Shi352fc822016-08-09 03:53:05 +0000331 bind([&hasData1] { hasData1 = true; }),
332 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700333 this->advanceClocks(time::milliseconds(5), time::seconds(1));
334 BOOST_CHECK_EQUAL(hasData1, true);
335
336 // Interest 2 experiences a packet loss on initial transmission
337 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
338 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700339 consumer->getClientFace().expressInterest(*interest2a,
340 bind([&hasData2a] { hasData2a = true; }),
Junxiao Shi352fc822016-08-09 03:53:05 +0000341 nullptr,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700342 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700343 producerA->fail();
344 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
345 BOOST_CHECK_EQUAL(hasData2a, false);
346 BOOST_CHECK_EQUAL(hasTimeout2a, false);
347
348 // Interest 2 retransmission is suppressed
349 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
350 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700351 consumer->getClientFace().expressInterest(*interest2b,
Junxiao Shi352fc822016-08-09 03:53:05 +0000352 bind([&hasData2b] { hasData2b = true; }),
353 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700354 producerA->recover();
355 this->advanceClocks(time::milliseconds(5), time::seconds(1));
356 BOOST_CHECK_EQUAL(hasData2b, false);
357
358 // Interest 2 retransmission gets through, and is answered
359 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
360 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700361 consumer->getClientFace().expressInterest(*interest2c,
Junxiao Shi352fc822016-08-09 03:53:05 +0000362 bind([&hasData2c] { hasData2c = true; }),
363 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700364 this->advanceClocks(time::milliseconds(5), time::seconds(1));
365 BOOST_CHECK_EQUAL(hasData2c, true);
366}
367
Junxiao Shi965d3a42015-06-01 06:55:23 -0700368BOOST_FIXTURE_TEST_CASE(Bug2831, TwoLaptopsFixture)
369{
370 // make a two-node loop
371 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
372 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
373
374 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700375 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
376 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
Junxiao Shi965d3a42015-06-01 06:55:23 -0700377 time::milliseconds(100), 10);
378
379 this->advanceClocks(time::milliseconds(5), time::seconds(2));
380
381 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700382 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700383}
384
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700385BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
386BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700387
388} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800389} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700390} // namespace nfd