blob: d950fc22817ba1b49dcf8dcbbe11c74ebce6f037 [file] [log] [blame]
Junxiao Shi80ee7cb2014-12-14 10:53:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventocf7db2f2019-03-24 23:17:28 -04002/*
3 * Copyright (c) 2014-2019, 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
Junxiao Shi890afe92016-12-15 14:34:34 +000028#include "strategy-tester.hpp"
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070029#include "topology-tester.hpp"
30
31namespace nfd {
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080032namespace fw {
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070033namespace tests {
34
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080035using namespace nfd::tests;
36
Junxiao Shi890afe92016-12-15 14:34:34 +000037// The tester is unused in this file, but it's used in various templated test suites.
38typedef StrategyTester<AccessStrategy> AccessStrategyTester;
39NFD_REGISTER_STRATEGY(AccessStrategyTester);
40
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070041// This test suite tests AccessStrategy's behavior as a black box,
42// without accessing its internals.
43//
44// Many test assertions are qualitative rather than quantitative.
45// They capture the design highlights of the strategy without requiring a definite value,
46// so that the test suite is not fragile to minor changes in the strategy implementation.
47//
48// Topology graphes in this test suite are shown in ASCII art,
49// in a style similar to ns-3 and ndnSIM examples.
50// They are enclosed in multi-line comments, which is an intentional violation of
51// code style rule 3.25. This is necessary because some lines ends with '\' which
52// would cause "multi-line comment" compiler warning if '//' comments are used.
53
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040054class TwoLaptopsFixture : public GlobalIoTimeFixture
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070055{
56protected:
57 TwoLaptopsFixture()
58 {
59 /*
60 * +--------+
61 * +----->| router |<------+
62 * | +--------+ |
63 * 10ms | | 20ms
64 * v v
65 * +---------+ +---------+
66 * | laptopA | | laptopB |
67 * +---------+ +---------+
68 */
69
Junxiao Shi5e5e4452015-09-24 16:56:52 -070070 router = topo.addForwarder("R");
71 laptopA = topo.addForwarder("A");
72 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070073
74 topo.setStrategy<fw::AccessStrategy>(router);
75
Junxiao Shi5e5e4452015-09-24 16:56:52 -070076 linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
77 linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070078 }
79
80protected:
81 TopologyTester topo;
82
83 TopologyNode router;
84 TopologyNode laptopA;
85 TopologyNode laptopB;
86 shared_ptr<TopologyLink> linkA;
87 shared_ptr<TopologyLink> linkB;
88};
89
Junxiao Shi91f6ee02016-12-29 21:44:44 +000090BOOST_AUTO_TEST_SUITE(Fw)
91BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, TwoLaptopsFixture)
92
93BOOST_AUTO_TEST_CASE(OneProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070094{
95 /*
96 * /------------------\
97 * | intervalConsumer |
98 * \------------------/
99 * ^ v
100 * | v /laptops/A
101 * |
102 * v
103 * /laptops << +--------+ >> /laptops
104 * +----->| router |<------+
105 * | +--------+ |
106 * 10ms | | 20ms
107 * v v
108 * +---------+ +---------+
109 * | laptopA | | laptopB |
110 * +---------+ +---------+
111 * ^ v
112 * | v /laptops/A
113 * v
114 * /--------------\
115 * | echoProducer |
116 * \--------------/
117 */
118
119 // two laptops have same prefix in router FIB
120 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
121 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
122
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700123 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
124 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700125
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700126 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
127 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700128 time::milliseconds(100), 100);
129
130 this->advanceClocks(time::milliseconds(5), time::seconds(12));
131
132 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700133 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
134 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
135 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700136}
137
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000138BOOST_AUTO_TEST_CASE(FastSlowProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700139{
140 /*
141 * /------------------\
142 * | intervalConsumer |
143 * \------------------/
144 * ^ v
145 * | v /laptops/BOTH
146 * |
147 * v
148 * /laptops << +--------+ >> /laptops
149 * +----->| router |<------+
150 * | +--------+ |
151 * 10ms | | 20ms
152 * v v
153 * +---------+ +---------+
154 * | laptopA | | laptopB |
155 * +---------+ +---------+
156 * ^ v ^ v
157 * | v /laptops/BOTH | v /laptops/BOTH
158 * v v
159 * /--------------\ /--------------\
160 * | echoProducer | | echoProducer |
161 * \--------------/ \--------------/
162 */
163
164 // two laptops have same prefix in router FIB
165 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
166 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
167
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700168 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
169 topo.addEchoProducer(producerA->getClientFace());
170 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
171 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700172
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700173 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
174 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700175 time::milliseconds(100), 100);
176
177 this->advanceClocks(time::milliseconds(5), time::seconds(12));
178
179 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700180 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
181 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
182 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700183}
184
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000185BOOST_AUTO_TEST_CASE(ProducerMobility)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700186{
187 /*
188 * /------------------\ /------------------\
189 * | intervalConsumer | | intervalConsumer |
190 * \------------------/ A \------------------/
191 * ^ v f ^ v
192 * | v /laptops/M t | v /laptops/M
193 * | e |
194 * v r v
195 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
196 * +----->| router |<------+ 6 +----->| router |<------+
197 * | +--------+ | | +--------+ |
198 * 10ms | | 20ms === s ==> 10ms | | 20ms
199 * v v e v v
200 * +---------+ +---------+ c +---------+ +---------+
201 * | laptopA | | laptopB | o | laptopA | | laptopB |
202 * +---------+ +---------+ n +---------+ +---------+
203 * ^ v d v ^
204 * | v /laptops/M s /laptops/M v |
205 * v v
206 * /--------------\ /--------------\
207 * | echoProducer | | echoProducer |
208 * \--------------/ \--------------/
209 */
210
211 // two laptops have same prefix in router FIB
212 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
213 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
214
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700215 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
216 topo.addEchoProducer(producerA->getClientFace());
217 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
218 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700219
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700220 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
221 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700222 time::milliseconds(100), 100);
223
224 // producer is initially on laptopA
225 producerB->fail();
226 this->advanceClocks(time::milliseconds(5), time::seconds(6));
227
228 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700229 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700230
231 // producer moves to laptopB
232 producerA->fail();
233 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700234 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700235 this->advanceClocks(time::milliseconds(5), time::seconds(6));
236
237 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700238 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700239
240 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700241 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700242}
243
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000244BOOST_AUTO_TEST_CASE(Bidirectional)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700245{
246 /*
247 * /laptops << +--------+ >> /laptops
248 * +----->| router |<------+
249 * | +--------+ |
250 * ^ 10ms | | 20ms ^
251 * / ^ v v ^ /
252 * +---------+ +---------+
253 * +----->| laptopA | | laptopB |<------------+
254 * | +---------+ +---------+ |
255 * | ^ v /laptops/A ^ v /laptops/B |
256 * ^ | | v | v | ^
257 * /laptops/B ^ v v v v ^ /laptops/A
258 * /------------------\ /--------------\ /--------------\ /------------------\
259 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
260 * \------------------/ \--------------/ \--------------/ \------------------/
261 */
262
263 // laptops have default routes toward the router
264 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
265 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
266
267 // two laptops have same prefix in router FIB
268 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
269 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
270
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700271 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
272 topo.addEchoProducer(producerA->getClientFace());
273 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
274 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700275
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700276 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
277 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700278 time::milliseconds(100), 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700279 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
280 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700281 time::milliseconds(100), 100);
282
283 this->advanceClocks(time::milliseconds(5), time::seconds(12));
284
285 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700286 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
287 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700288}
289
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000290BOOST_AUTO_TEST_CASE(PacketLoss)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700291{
292 /*
293 * test case Interests
294 * |
295 * v
296 * +--------+
297 * | router |
298 * +--------+
299 * | v
300 * 10ms | v /laptops
301 * v
302 * +---------+
303 * | laptopA |
304 * +---------+
305 * ^ v
306 * | v /laptops/A
307 * v
308 * /--------------\
309 * | echoProducer |
310 * \--------------/
311 */
312
313 // laptopA has prefix in router FIB; laptopB is unused in this test case
314 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
315
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700316 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
317 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700318
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700319 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700320
321 // Interest 1 completes normally
322 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
323 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700324 consumer->getClientFace().expressInterest(*interest1,
Junxiao Shi352fc822016-08-09 03:53:05 +0000325 bind([&hasData1] { hasData1 = true; }),
326 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700327 this->advanceClocks(time::milliseconds(5), time::seconds(1));
328 BOOST_CHECK_EQUAL(hasData1, true);
329
330 // Interest 2 experiences a packet loss on initial transmission
331 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
332 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700333 consumer->getClientFace().expressInterest(*interest2a,
334 bind([&hasData2a] { hasData2a = true; }),
Junxiao Shi352fc822016-08-09 03:53:05 +0000335 nullptr,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700336 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700337 producerA->fail();
338 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
339 BOOST_CHECK_EQUAL(hasData2a, false);
340 BOOST_CHECK_EQUAL(hasTimeout2a, false);
341
342 // Interest 2 retransmission is suppressed
343 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
344 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700345 consumer->getClientFace().expressInterest(*interest2b,
Junxiao Shi352fc822016-08-09 03:53:05 +0000346 bind([&hasData2b] { hasData2b = true; }),
347 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700348 producerA->recover();
349 this->advanceClocks(time::milliseconds(5), time::seconds(1));
350 BOOST_CHECK_EQUAL(hasData2b, false);
351
352 // Interest 2 retransmission gets through, and is answered
353 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
354 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700355 consumer->getClientFace().expressInterest(*interest2c,
Junxiao Shi352fc822016-08-09 03:53:05 +0000356 bind([&hasData2c] { hasData2c = true; }),
357 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700358 this->advanceClocks(time::milliseconds(5), time::seconds(1));
359 BOOST_CHECK_EQUAL(hasData2c, true);
360}
361
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000362BOOST_AUTO_TEST_CASE(Bug2831)
Junxiao Shi965d3a42015-06-01 06:55:23 -0700363{
364 // make a two-node loop
365 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
366 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
367
368 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700369 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
370 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
Junxiao Shi965d3a42015-06-01 06:55:23 -0700371 time::milliseconds(100), 10);
372
373 this->advanceClocks(time::milliseconds(5), time::seconds(2));
374
375 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700376 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700377}
378
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700379BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
380BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700381
382} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800383} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700384} // namespace nfd