blob: 6664a164b29d215bfafe10828ccca0482df0f7bf [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/*
Davide Pesaventoe422f9e2022-06-03 01:30:23 -04003 * Copyright (c) 2014-2022, 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
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040031namespace nfd::tests {
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070032
Junxiao Shi890afe92016-12-15 14:34:34 +000033// The tester is unused in this file, but it's used in various templated test suites.
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040034using AccessStrategyTester = StrategyTester<fw::AccessStrategy>;
Junxiao Shi890afe92016-12-15 14:34:34 +000035NFD_REGISTER_STRATEGY(AccessStrategyTester);
36
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070037// This test suite tests AccessStrategy's behavior as a black box,
38// without accessing its internals.
39//
40// Many test assertions are qualitative rather than quantitative.
41// They capture the design highlights of the strategy without requiring a definite value,
42// so that the test suite is not fragile to minor changes in the strategy implementation.
43//
44// Topology graphes in this test suite are shown in ASCII art,
45// in a style similar to ns-3 and ndnSIM examples.
46// They are enclosed in multi-line comments, which is an intentional violation of
47// code style rule 3.25. This is necessary because some lines ends with '\' which
48// would cause "multi-line comment" compiler warning if '//' comments are used.
49
Davide Pesaventocf7db2f2019-03-24 23:17:28 -040050class TwoLaptopsFixture : public GlobalIoTimeFixture
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070051{
52protected:
53 TwoLaptopsFixture()
54 {
55 /*
56 * +--------+
57 * +----->| router |<------+
58 * | +--------+ |
59 * 10ms | | 20ms
60 * v v
61 * +---------+ +---------+
62 * | laptopA | | laptopB |
63 * +---------+ +---------+
64 */
65
Junxiao Shi5e5e4452015-09-24 16:56:52 -070066 router = topo.addForwarder("R");
67 laptopA = topo.addForwarder("A");
68 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070069
70 topo.setStrategy<fw::AccessStrategy>(router);
71
Davide Pesavento14e71f02019-03-28 17:35:25 -040072 linkA = topo.addLink("RA", 10_ms, {router, laptopA});
73 linkB = topo.addLink("RB", 20_ms, {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070074 }
75
76protected:
77 TopologyTester topo;
78
79 TopologyNode router;
80 TopologyNode laptopA;
81 TopologyNode laptopB;
82 shared_ptr<TopologyLink> linkA;
83 shared_ptr<TopologyLink> linkB;
84};
85
Junxiao Shi91f6ee02016-12-29 21:44:44 +000086BOOST_AUTO_TEST_SUITE(Fw)
87BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, TwoLaptopsFixture)
88
89BOOST_AUTO_TEST_CASE(OneProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070090{
91 /*
92 * /------------------\
93 * | intervalConsumer |
94 * \------------------/
95 * ^ v
96 * | v /laptops/A
97 * |
98 * v
99 * /laptops << +--------+ >> /laptops
100 * +----->| router |<------+
101 * | +--------+ |
102 * 10ms | | 20ms
103 * v v
104 * +---------+ +---------+
105 * | laptopA | | laptopB |
106 * +---------+ +---------+
107 * ^ v
108 * | v /laptops/A
109 * v
110 * /--------------\
111 * | echoProducer |
112 * \--------------/
113 */
114
115 // two laptops have same prefix in router FIB
116 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
117 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
118
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700119 shared_ptr<TopologyAppLink> producer = topo.addAppFace("p", laptopA, "ndn:/laptops/A");
120 topo.addEchoProducer(producer->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700121
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700122 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400123 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700124
Davide Pesavento14e71f02019-03-28 17:35:25 -0400125 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700126
127 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700128 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
129 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
130 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700131}
132
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000133BOOST_AUTO_TEST_CASE(FastSlowProducer)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700134{
135 /*
136 * /------------------\
137 * | intervalConsumer |
138 * \------------------/
139 * ^ v
140 * | v /laptops/BOTH
141 * |
142 * v
143 * /laptops << +--------+ >> /laptops
144 * +----->| router |<------+
145 * | +--------+ |
146 * 10ms | | 20ms
147 * v v
148 * +---------+ +---------+
149 * | laptopA | | laptopB |
150 * +---------+ +---------+
151 * ^ v ^ v
152 * | v /laptops/BOTH | v /laptops/BOTH
153 * v v
154 * /--------------\ /--------------\
155 * | echoProducer | | echoProducer |
156 * \--------------/ \--------------/
157 */
158
159 // two laptops have same prefix in router FIB
160 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
161 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
162
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700163 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
164 topo.addEchoProducer(producerA->getClientFace());
165 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
166 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700167
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700168 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400169 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700170
Davide Pesavento14e71f02019-03-28 17:35:25 -0400171 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700172
173 // most Interests should be satisfied, and few Interests can go to slower laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700174 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
175 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 90);
176 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 15);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700177}
178
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000179BOOST_AUTO_TEST_CASE(ProducerMobility)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700180{
181 /*
182 * /------------------\ /------------------\
183 * | intervalConsumer | | intervalConsumer |
184 * \------------------/ A \------------------/
185 * ^ v f ^ v
186 * | v /laptops/M t | v /laptops/M
187 * | e |
188 * v r v
189 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
190 * +----->| router |<------+ 6 +----->| router |<------+
191 * | +--------+ | | +--------+ |
192 * 10ms | | 20ms === s ==> 10ms | | 20ms
193 * v v e v v
194 * +---------+ +---------+ c +---------+ +---------+
195 * | laptopA | | laptopB | o | laptopA | | laptopB |
196 * +---------+ +---------+ n +---------+ +---------+
197 * ^ v d v ^
198 * | v /laptops/M s /laptops/M v |
199 * v v
200 * /--------------\ /--------------\
201 * | echoProducer | | echoProducer |
202 * \--------------/ \--------------/
203 */
204
205 // two laptops have same prefix in router FIB
206 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
207 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
208
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700209 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/M");
210 topo.addEchoProducer(producerA->getClientFace());
211 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/M");
212 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700213
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700214 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400215 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700216
217 // producer is initially on laptopA
218 producerB->fail();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400219 this->advanceClocks(5_ms, 6_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700220
221 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700222 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700223
224 // producer moves to laptopB
225 producerA->fail();
226 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700227 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Davide Pesavento14e71f02019-03-28 17:35:25 -0400228 this->advanceClocks(5_ms, 6_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700229
230 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700231 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700232
233 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700234 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700235}
236
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000237BOOST_AUTO_TEST_CASE(Bidirectional)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700238{
239 /*
240 * /laptops << +--------+ >> /laptops
241 * +----->| router |<------+
242 * | +--------+ |
243 * ^ 10ms | | 20ms ^
244 * / ^ v v ^ /
245 * +---------+ +---------+
246 * +----->| laptopA | | laptopB |<------------+
247 * | +---------+ +---------+ |
248 * | ^ v /laptops/A ^ v /laptops/B |
249 * ^ | | v | v | ^
250 * /laptops/B ^ v v v v ^ /laptops/A
251 * /------------------\ /--------------\ /--------------\ /------------------\
252 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
253 * \------------------/ \--------------/ \--------------/ \------------------/
254 */
255
256 // laptops have default routes toward the router
257 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
258 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
259
260 // two laptops have same prefix in router FIB
261 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
262 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
263
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700264 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
265 topo.addEchoProducer(producerA->getClientFace());
266 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
267 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700268
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700269 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400270 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B", 100_ms, 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700271 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400272 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A", 100_ms, 100);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700273
Davide Pesavento14e71f02019-03-28 17:35:25 -0400274 this->advanceClocks(5_ms, 12_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700275
276 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700277 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
278 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700279}
280
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000281BOOST_AUTO_TEST_CASE(PacketLoss)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700282{
283 /*
284 * test case Interests
285 * |
286 * v
287 * +--------+
288 * | router |
289 * +--------+
290 * | v
291 * 10ms | v /laptops
292 * v
293 * +---------+
294 * | laptopA |
295 * +---------+
296 * ^ v
297 * | v /laptops/A
298 * v
299 * /--------------\
300 * | echoProducer |
301 * \--------------/
302 */
303
304 // laptopA has prefix in router FIB; laptopB is unused in this test case
305 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
306
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700307 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
308 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700309
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700310 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700311
312 // Interest 1 completes normally
313 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
314 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700315 consumer->getClientFace().expressInterest(*interest1,
Davide Pesavento412c9822021-07-02 00:21:05 -0400316 [&] (auto&&...) { hasData1 = true; },
Junxiao Shi352fc822016-08-09 03:53:05 +0000317 nullptr, nullptr);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400318 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700319 BOOST_CHECK_EQUAL(hasData1, true);
320
321 // Interest 2 experiences a packet loss on initial transmission
322 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
323 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700324 consumer->getClientFace().expressInterest(*interest2a,
Davide Pesavento412c9822021-07-02 00:21:05 -0400325 [&] (auto&&...) { hasData2a = true; },
Junxiao Shi352fc822016-08-09 03:53:05 +0000326 nullptr,
Davide Pesavento412c9822021-07-02 00:21:05 -0400327 [&] (auto&&...) { hasTimeout2a = true; });
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700328 producerA->fail();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400329 this->advanceClocks(5_ms, 60_ms);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700330 BOOST_CHECK_EQUAL(hasData2a, false);
331 BOOST_CHECK_EQUAL(hasTimeout2a, false);
332
333 // Interest 2 retransmission is suppressed
334 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
335 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700336 consumer->getClientFace().expressInterest(*interest2b,
Davide Pesavento412c9822021-07-02 00:21:05 -0400337 [&] (auto&&...) { hasData2b = true; },
Junxiao Shi352fc822016-08-09 03:53:05 +0000338 nullptr, nullptr);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700339 producerA->recover();
Davide Pesavento14e71f02019-03-28 17:35:25 -0400340 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700341 BOOST_CHECK_EQUAL(hasData2b, false);
342
343 // Interest 2 retransmission gets through, and is answered
344 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
345 bool hasData2c = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700346 consumer->getClientFace().expressInterest(*interest2c,
Davide Pesavento412c9822021-07-02 00:21:05 -0400347 [&] (auto&&...) { hasData2c = true; },
Junxiao Shi352fc822016-08-09 03:53:05 +0000348 nullptr, nullptr);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400349 this->advanceClocks(5_ms, 1_s);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700350 BOOST_CHECK_EQUAL(hasData2c, true);
351}
352
Junxiao Shi91f6ee02016-12-29 21:44:44 +0000353BOOST_AUTO_TEST_CASE(Bug2831)
Junxiao Shi965d3a42015-06-01 06:55:23 -0700354{
355 // make a two-node loop
356 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
357 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
358
359 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700360 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
Davide Pesavento14e71f02019-03-28 17:35:25 -0400361 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net", 100_ms, 10);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700362
Davide Pesavento14e71f02019-03-28 17:35:25 -0400363 this->advanceClocks(5_ms, 2_s);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700364
365 // Interest shouldn't loop back from router
Junxiao Shida93f1f2015-11-11 06:13:16 -0700366 BOOST_CHECK_EQUAL(linkA->getFace(router).getCounters().nOutInterests, 0);
Junxiao Shi965d3a42015-06-01 06:55:23 -0700367}
368
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700369BOOST_AUTO_TEST_SUITE_END() // TestAccessStrategy
370BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700371
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400372} // namespace nfd::tests