blob: afa73b6aba765a8bd61c266e8c021aa5b619cb7a [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
Junxiao Shi890afe92016-12-15 14:34:34 +000035// The tester is unused in this file, but it's used in various templated test suites.
Davide Pesavento14e71f02019-03-28 17:35:25 -040036using AccessStrategyTester = StrategyTester<AccessStrategy>;
Junxiao Shi890afe92016-12-15 14:34:34 +000037NFD_REGISTER_STRATEGY(AccessStrategyTester);
38
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070039// This test suite tests AccessStrategy's behavior as a black box,
40// without accessing its internals.
41//
42// Many test assertions are qualitative rather than quantitative.
43// They capture the design highlights of the strategy without requiring a definite value,
44// so that the test suite is not fragile to minor changes in the strategy implementation.
45//
46// Topology graphes in this test suite are shown in ASCII art,
47// in a style similar to ns-3 and ndnSIM examples.
48// They are enclosed in multi-line comments, which is an intentional violation of
49// code style rule 3.25. This is necessary because some lines ends with '\' which
50// would cause "multi-line comment" compiler warning if '//' comments are used.
51
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040052class TwoLaptopsFixture : public GlobalIoTimeFixture
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070053{
54protected:
55 TwoLaptopsFixture()
56 {
57 /*
58 * +--------+
59 * +----->| router |<------+
60 * | +--------+ |
61 * 10ms | | 20ms
62 * v v
63 * +---------+ +---------+
64 * | laptopA | | laptopB |
65 * +---------+ +---------+
66 */
67
Junxiao Shi5e5e4452015-09-24 16:56:52 -070068 router = topo.addForwarder("R");
69 laptopA = topo.addForwarder("A");
70 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070071
72 topo.setStrategy<fw::AccessStrategy>(router);
73
Davide Pesavento14e71f02019-03-28 17:35:25 -040074 linkA = topo.addLink("RA", 10_ms, {router, laptopA});
75 linkB = topo.addLink("RB", 20_ms, {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070076 }
77
78protected:
79 TopologyTester topo;
80
81 TopologyNode router;
82 TopologyNode laptopA;
83 TopologyNode laptopB;
84 shared_ptr<TopologyLink> linkA;
85 shared_ptr<TopologyLink> linkB;
86};
87
Junxiao Shi91f6ee02016-12-29 21:44:44 +000088BOOST_AUTO_TEST_SUITE(Fw)
89BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, TwoLaptopsFixture)
90
91BOOST_AUTO_TEST_CASE(OneProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070092{
93 /*
94 * /------------------\
95 * | intervalConsumer |
96 * \------------------/
97 * ^ v
98 * | v /laptops/A
99 * |
100 * v
101 * /laptops << +--------+ >> /laptops
102 * +----->| router |<------+
103 * | +--------+ |
104 * 10ms | | 20ms
105 * v v
106 * +---------+ +---------+
107 * | laptopA | | laptopB |
108 * +---------+ +---------+
109 * ^ v
110 * | v /laptops/A
111 * v
112 * /--------------\
113 * | echoProducer |
114 * \--------------/
115 */
116
117 // two laptops have same prefix in router FIB
118 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
119 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
120
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700121 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
122 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700123
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700124 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400125 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700126
Davide Pesavento14e71f02019-03-28 17:35:25 -0400127 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700128
129 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700130 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
131 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
132 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700133}
134
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000135BOOST_AUTO_TEST_CASE(FastSlowProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700136{
137 /*
138 * /------------------\
139 * | intervalConsumer |
140 * \------------------/
141 * ^ v
142 * | v /laptops/BOTH
143 * |
144 * v
145 * /laptops << +--------+ >> /laptops
146 * +----->| router |<------+
147 * | +--------+ |
148 * 10ms | | 20ms
149 * v v
150 * +---------+ +---------+
151 * | laptopA | | laptopB |
152 * +---------+ +---------+
153 * ^ v ^ v
154 * | v /laptops/BOTH | v /laptops/BOTH
155 * v v
156 * /--------------\ /--------------\
157 * | echoProducer | | echoProducer |
158 * \--------------/ \--------------/
159 */
160
161 // two laptops have same prefix in router FIB
162 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
163 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
164
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700165 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
166 topo.addEchoProducer(producerA->getClientFace());
167 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
168 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700169
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700170 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400171 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700172
Davide Pesavento14e71f02019-03-28 17:35:25 -0400173 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700174
175 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700176 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
177 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
178 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700179}
180
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000181BOOST_AUTO_TEST_CASE(ProducerMobility)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700182{
183 /*
184 * /------------------\ /------------------\
185 * | intervalConsumer | | intervalConsumer |
186 * \------------------/ A \------------------/
187 * ^ v f ^ v
188 * | v /laptops/M t | v /laptops/M
189 * | e |
190 * v r v
191 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
192 * +----->| router |<------+ 6 +----->| router |<------+
193 * | +--------+ | | +--------+ |
194 * 10ms | | 20ms === s ==> 10ms | | 20ms
195 * v v e v v
196 * +---------+ +---------+ c +---------+ +---------+
197 * | laptopA | | laptopB | o | laptopA | | laptopB |
198 * +---------+ +---------+ n +---------+ +---------+
199 * ^ v d v ^
200 * | v /laptops/M s /laptops/M v |
201 * v v
202 * /--------------\ /--------------\
203 * | echoProducer | | echoProducer |
204 * \--------------/ \--------------/
205 */
206
207 // two laptops have same prefix in router FIB
208 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
209 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
210
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700211 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
212 topo.addEchoProducer(producerA->getClientFace());
213 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
214 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700215
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700216 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400217 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700218
219 // producer is initially on laptopA
220 producerB->fail();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400221 this->advanceClocks(5_ms, 6_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700222
223 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700224 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700225
226 // producer moves to laptopB
227 producerA->fail();
228 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700229 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Davide Pesavento14e71f02019-03-28 17:35:25 -0400230 this->advanceClocks(5_ms, 6_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700231
232 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700233 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700234
235 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700236 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700237}
238
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000239BOOST_AUTO_TEST_CASE(Bidirectional)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700240{
241 /*
242 * /laptops << +--------+ >> /laptops
243 * +----->| router |<------+
244 * | +--------+ |
245 * ^ 10ms | | 20ms ^
246 * / ^ v v ^ /
247 * +---------+ +---------+
248 * +----->| laptopA | | laptopB |<------------+
249 * | +---------+ +---------+ |
250 * | ^ v /laptops/A ^ v /laptops/B |
251 * ^ | | v | v | ^
252 * /laptops/B ^ v v v v ^ /laptops/A
253 * /------------------\ /--------------\ /--------------\ /------------------\
254 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
255 * \------------------/ \--------------/ \--------------/ \------------------/
256 */
257
258 // laptops have default routes toward the router
259 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
260 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
261
262 // two laptops have same prefix in router FIB
263 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
264 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
265
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700266 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
267 topo.addEchoProducer(producerA->getClientFace());
268 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
269 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700270
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700271 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400272 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B", 100_ms, 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700273 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400274 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700275
Davide Pesavento14e71f02019-03-28 17:35:25 -0400276 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700277
278 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700279 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
280 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700281}
282
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000283BOOST_AUTO_TEST_CASE(PacketLoss)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700284{
285 /*
286 * test case Interests
287 * |
288 * v
289 * +--------+
290 * | router |
291 * +--------+
292 * | v
293 * 10ms | v /laptops
294 * v
295 * +---------+
296 * | laptopA |
297 * +---------+
298 * ^ v
299 * | v /laptops/A
300 * v
301 * /--------------\
302 * | echoProducer |
303 * \--------------/
304 */
305
306 // laptopA has prefix in router FIB; laptopB is unused in this test case
307 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
308
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700309 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
310 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700311
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700312 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700313
314 // Interest 1 completes normally
315 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
316 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700317 consumer->getClientFace().expressInterest(*interest1,
Junxiao Shi352fc822016-08-09 03:53:05 +0000318 bind([&hasData1] { hasData1 = true; }),
319 nullptr, nullptr);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400320 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700321 BOOST_CHECK_EQUAL(hasData1, true);
322
323 // Interest 2 experiences a packet loss on initial transmission
324 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
325 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700326 consumer->getClientFace().expressInterest(*interest2a,
327 bind([&hasData2a] { hasData2a = true; }),
Junxiao Shi352fc822016-08-09 03:53:05 +0000328 nullptr,
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700329 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700330 producerA->fail();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400331 this->advanceClocks(5_ms, 60_ms);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700332 BOOST_CHECK_EQUAL(hasData2a, false);
333 BOOST_CHECK_EQUAL(hasTimeout2a, false);
334
335 // Interest 2 retransmission is suppressed
336 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
337 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700338 consumer->getClientFace().expressInterest(*interest2b,
Junxiao Shi352fc822016-08-09 03:53:05 +0000339 bind([&hasData2b] { hasData2b = true; }),
340 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700341 producerA->recover();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400342 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700343 BOOST_CHECK_EQUAL(hasData2b, false);
344
345 // Interest 2 retransmission gets through, and is answered
346 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
347 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700348 consumer->getClientFace().expressInterest(*interest2c,
Junxiao Shi352fc822016-08-09 03:53:05 +0000349 bind([&hasData2c] { hasData2c = true; }),
350 nullptr, nullptr);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400351 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700352 BOOST_CHECK_EQUAL(hasData2c, true);
353}
354
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000355BOOST_AUTO_TEST_CASE(Bug2831)
Junxiao Shi965d3a42015-06-01 06:55:23 -0700356{
357 // make a two-node loop
358 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
359 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
360
361 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700362 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400363 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net", 100_ms, 10);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700364
Davide Pesavento14e71f02019-03-28 17:35:25 -0400365 this->advanceClocks(5_ms, 2_s);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700366
367 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700368 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700369}
370
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700371BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
372BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700373
374} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800375} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700376} // namespace nfd