blob: 2f825bec7a55ea6cad748e793b3843b2357e0e61 [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 Shi80ee7cb2014-12-14 10:53:05 -070055class TwoLaptopsFixture : public UnitTestTimeFixture
56{
57protected:
58 TwoLaptopsFixture()
59 {
60 /*
61 * +--------+
62 * +----->| router |<------+
63 * | +--------+ |
64 * 10ms | | 20ms
65 * v v
66 * +---------+ +---------+
67 * | laptopA | | laptopB |
68 * +---------+ +---------+
69 */
70
Junxiao Shi5e5e4452015-09-24 16:56:52 -070071 router = topo.addForwarder("R");
72 laptopA = topo.addForwarder("A");
73 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070074
75 topo.setStrategy<fw::AccessStrategy>(router);
76
Junxiao Shi5e5e4452015-09-24 16:56:52 -070077 linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
78 linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070079 }
80
81protected:
82 TopologyTester topo;
83
84 TopologyNode router;
85 TopologyNode laptopA;
86 TopologyNode laptopB;
87 shared_ptr<TopologyLink> linkA;
88 shared_ptr<TopologyLink> linkB;
89};
90
Junxiao Shi91f6ee02016-12-29 21:44:44 +000091BOOST_AUTO_TEST_SUITE(Fw)
92BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, TwoLaptopsFixture)
93
94BOOST_AUTO_TEST_CASE(OneProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070095{
96 /*
97 * /------------------\
98 * | intervalConsumer |
99 * \------------------/
100 * ^ v
101 * | v /laptops/A
102 * |
103 * v
104 * /laptops << +--------+ >> /laptops
105 * +----->| router |<------+
106 * | +--------+ |
107 * 10ms | | 20ms
108 * v v
109 * +---------+ +---------+
110 * | laptopA | | laptopB |
111 * +---------+ +---------+
112 * ^ v
113 * | v /laptops/A
114 * v
115 * /--------------\
116 * | echoProducer |
117 * \--------------/
118 */
119
120 // two laptops have same prefix in router FIB
121 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
122 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
123
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700124 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
125 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700126
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700127 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
128 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700129 time::milliseconds(100), 100);
130
131 this->advanceClocks(time::milliseconds(5), time::seconds(12));
132
133 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700134 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
135 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
136 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700137}
138
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000139BOOST_AUTO_TEST_CASE(FastSlowProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700140{
141 /*
142 * /------------------\
143 * | intervalConsumer |
144 * \------------------/
145 * ^ v
146 * | v /laptops/BOTH
147 * |
148 * v
149 * /laptops << +--------+ >> /laptops
150 * +----->| router |<------+
151 * | +--------+ |
152 * 10ms | | 20ms
153 * v v
154 * +---------+ +---------+
155 * | laptopA | | laptopB |
156 * +---------+ +---------+
157 * ^ v ^ v
158 * | v /laptops/BOTH | v /laptops/BOTH
159 * v v
160 * /--------------\ /--------------\
161 * | echoProducer | | echoProducer |
162 * \--------------/ \--------------/
163 */
164
165 // two laptops have same prefix in router FIB
166 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
167 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
168
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700169 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
170 topo.addEchoProducer(producerA->getClientFace());
171 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
172 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700173
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700174 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
175 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700176 time::milliseconds(100), 100);
177
178 this->advanceClocks(time::milliseconds(5), time::seconds(12));
179
180 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700181 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
182 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
183 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700184}
185
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000186BOOST_AUTO_TEST_CASE(ProducerMobility)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700187{
188 /*
189 * /------------------\ /------------------\
190 * | intervalConsumer | | intervalConsumer |
191 * \------------------/ A \------------------/
192 * ^ v f ^ v
193 * | v /laptops/M t | v /laptops/M
194 * | e |
195 * v r v
196 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
197 * +----->| router |<------+ 6 +----->| router |<------+
198 * | +--------+ | | +--------+ |
199 * 10ms | | 20ms === s ==> 10ms | | 20ms
200 * v v e v v
201 * +---------+ +---------+ c +---------+ +---------+
202 * | laptopA | | laptopB | o | laptopA | | laptopB |
203 * +---------+ +---------+ n +---------+ +---------+
204 * ^ v d v ^
205 * | v /laptops/M s /laptops/M v |
206 * v v
207 * /--------------\ /--------------\
208 * | echoProducer | | echoProducer |
209 * \--------------/ \--------------/
210 */
211
212 // two laptops have same prefix in router FIB
213 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
214 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
215
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700216 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
217 topo.addEchoProducer(producerA->getClientFace());
218 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
219 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700220
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700221 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
222 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700223 time::milliseconds(100), 100);
224
225 // producer is initially on laptopA
226 producerB->fail();
227 this->advanceClocks(time::milliseconds(5), time::seconds(6));
228
229 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700230 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700231
232 // producer moves to laptopB
233 producerA->fail();
234 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700235 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700236 this->advanceClocks(time::milliseconds(5), time::seconds(6));
237
238 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700239 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700240
241 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700242 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700243}
244
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000245BOOST_AUTO_TEST_CASE(Bidirectional)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700246{
247 /*
248 * /laptops << +--------+ >> /laptops
249 * +----->| router |<------+
250 * | +--------+ |
251 * ^ 10ms | | 20ms ^
252 * / ^ v v ^ /
253 * +---------+ +---------+
254 * +----->| laptopA | | laptopB |<------------+
255 * | +---------+ +---------+ |
256 * | ^ v /laptops/A ^ v /laptops/B |
257 * ^ | | v | v | ^
258 * /laptops/B ^ v v v v ^ /laptops/A
259 * /------------------\ /--------------\ /--------------\ /------------------\
260 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
261 * \------------------/ \--------------/ \--------------/ \------------------/
262 */
263
264 // laptops have default routes toward the router
265 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
266 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
267
268 // two laptops have same prefix in router FIB
269 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
270 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
271
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700272 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
273 topo.addEchoProducer(producerA->getClientFace());
274 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
275 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700276
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700277 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
278 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700279 time::milliseconds(100), 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700280 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
281 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700282 time::milliseconds(100), 100);
283
284 this->advanceClocks(time::milliseconds(5), time::seconds(12));
285
286 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700287 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
288 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700289}
290
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000291BOOST_AUTO_TEST_CASE(PacketLoss)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700292{
293 /*
294 * test case Interests
295 * |
296 * v
297 * +--------+
298 * | router |
299 * +--------+
300 * | v
301 * 10ms | v /laptops
302 * v
303 * +---------+
304 * | laptopA |
305 * +---------+
306 * ^ v
307 * | v /laptops/A
308 * v
309 * /--------------\
310 * | echoProducer |
311 * \--------------/
312 */
313
314 // laptopA has prefix in router FIB; laptopB is unused in this test case
315 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
316
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700317 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
318 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700319
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700320 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700321
322 // Interest 1 completes normally
323 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
324 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700325 consumer->getClientFace().expressInterest(*interest1,
Junxiao Shi352fc822016-08-09 03:53:05 +0000326 bind([&hasData1] { hasData1 = true; }),
327 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700328 this->advanceClocks(time::milliseconds(5), time::seconds(1));
329 BOOST_CHECK_EQUAL(hasData1, true);
330
331 // Interest 2 experiences a packet loss on initial transmission
332 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
333 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700334 consumer->getClientFace().expressInterest(*interest2a,
335 bind([&hasData2a] { hasData2a = true; }),
Junxiao Shi352fc822016-08-09 03:53:05 +0000336 nullptr,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700337 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700338 producerA->fail();
339 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
340 BOOST_CHECK_EQUAL(hasData2a, false);
341 BOOST_CHECK_EQUAL(hasTimeout2a, false);
342
343 // Interest 2 retransmission is suppressed
344 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
345 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700346 consumer->getClientFace().expressInterest(*interest2b,
Junxiao Shi352fc822016-08-09 03:53:05 +0000347 bind([&hasData2b] { hasData2b = true; }),
348 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700349 producerA->recover();
350 this->advanceClocks(time::milliseconds(5), time::seconds(1));
351 BOOST_CHECK_EQUAL(hasData2b, false);
352
353 // Interest 2 retransmission gets through, and is answered
354 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
355 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700356 consumer->getClientFace().expressInterest(*interest2c,
Junxiao Shi352fc822016-08-09 03:53:05 +0000357 bind([&hasData2c] { hasData2c = true; }),
358 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700359 this->advanceClocks(time::milliseconds(5), time::seconds(1));
360 BOOST_CHECK_EQUAL(hasData2c, true);
361}
362
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000363BOOST_AUTO_TEST_CASE(Bug2831)
Junxiao Shi965d3a42015-06-01 06:55:23 -0700364{
365 // make a two-node loop
366 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
367 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
368
369 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700370 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
371 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
Junxiao Shi965d3a42015-06-01 06:55:23 -0700372 time::milliseconds(100), 10);
373
374 this->advanceClocks(time::milliseconds(5), time::seconds(2));
375
376 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700377 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700378}
379
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700380BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
381BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700382
383} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800384} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700385} // namespace nfd