blob: 78ed88fe7da1f5d3283186b438261e2f21695a69 [file] [log] [blame]
Junxiao Shi80ee7cb2014-12-14 10:53:05 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2015, Regents of the University of California,
4 * 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"
29#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 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
Junxiao Shi5e5e4452015-09-24 16:56:52 -070050BOOST_AUTO_TEST_SUITE(Fw)
51BOOST_FIXTURE_TEST_SUITE(TestAccessStrategy, UnitTestTimeFixture)
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070052
53class TwoLaptopsFixture : public UnitTestTimeFixture
54{
55protected:
56 TwoLaptopsFixture()
57 {
58 /*
59 * +--------+
60 * +----->| router |<------+
61 * | +--------+ |
62 * 10ms | | 20ms
63 * v v
64 * +---------+ +---------+
65 * | laptopA | | laptopB |
66 * +---------+ +---------+
67 */
68
Junxiao Shi5e5e4452015-09-24 16:56:52 -070069 router = topo.addForwarder("R");
70 laptopA = topo.addForwarder("A");
71 laptopB = topo.addForwarder("B");
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070072
73 topo.setStrategy<fw::AccessStrategy>(router);
74
Junxiao Shi5e5e4452015-09-24 16:56:52 -070075 linkA = topo.addLink("RA", time::milliseconds(10), {router, laptopA});
76 linkB = topo.addLink("RB", time::milliseconds(20), {router, laptopB});
Junxiao Shi80ee7cb2014-12-14 10:53:05 -070077 }
78
79protected:
80 TopologyTester topo;
81
82 TopologyNode router;
83 TopologyNode laptopA;
84 TopologyNode laptopB;
85 shared_ptr<TopologyLink> linkA;
86 shared_ptr<TopologyLink> linkB;
87};
88
89BOOST_FIXTURE_TEST_CASE(OneProducer, TwoLaptopsFixture)
90{
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);
123 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700124 time::milliseconds(100), 100);
125
126 this->advanceClocks(time::milliseconds(5), time::seconds(12));
127
128 // most Interests should be satisfied, and few Interests can go to wrong laptop
Junxiao Shida93f1f2015-11-11 06:13:16 -0700129 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
130 BOOST_CHECK_GE(linkA->getFace(router).getCounters().nOutInterests, 97);
131 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700132}
133
134BOOST_FIXTURE_TEST_CASE(FastSlowProducer, TwoLaptopsFixture)
135{
136 /*
137 * /------------------\
138 * | intervalConsumer |
139 * \------------------/
140 * ^ v
141 * | v /laptops/BOTH
142 * |
143 * v
144 * /laptops << +--------+ >> /laptops
145 * +----->| router |<------+
146 * | +--------+ |
147 * 10ms | | 20ms
148 * v v
149 * +---------+ +---------+
150 * | laptopA | | laptopB |
151 * +---------+ +---------+
152 * ^ v ^ v
153 * | v /laptops/BOTH | v /laptops/BOTH
154 * v v
155 * /--------------\ /--------------\
156 * | echoProducer | | echoProducer |
157 * \--------------/ \--------------/
158 */
159
160 // two laptops have same prefix in router FIB
161 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
162 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
163
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700164 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/BOTH");
165 topo.addEchoProducer(producerA->getClientFace());
166 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/BOTH");
167 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700168
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700169 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
170 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/BOTH",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700171 time::milliseconds(100), 100);
172
173 this->advanceClocks(time::milliseconds(5), time::seconds(12));
174
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
181BOOST_FIXTURE_TEST_CASE(ProducerMobility, TwoLaptopsFixture)
182{
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);
217 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/laptops/M",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700218 time::milliseconds(100), 100);
219
220 // producer is initially on laptopA
221 producerB->fail();
222 this->advanceClocks(time::milliseconds(5), time::seconds(6));
223
224 // few Interests can go to laptopB
Junxiao Shida93f1f2015-11-11 06:13:16 -0700225 BOOST_CHECK_LE(linkB->getFace(router).getCounters().nOutInterests, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700226
227 // producer moves to laptopB
228 producerA->fail();
229 producerB->recover();
Junxiao Shida93f1f2015-11-11 06:13:16 -0700230 PacketCounter::rep nInterestsToA_beforeMove = linkA->getFace(router).getCounters().nOutInterests;
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700231 this->advanceClocks(time::milliseconds(5), time::seconds(6));
232
233 // few additional Interests can go to laptopA
Junxiao Shida93f1f2015-11-11 06:13:16 -0700234 BOOST_CHECK_LE(linkA->getFace(router).getCounters().nOutInterests - nInterestsToA_beforeMove, 5);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700235
236 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700237 BOOST_CHECK_GE(consumer->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700238}
239
240BOOST_FIXTURE_TEST_CASE(Bidirectional, TwoLaptopsFixture)
241{
242 /*
243 * /laptops << +--------+ >> /laptops
244 * +----->| router |<------+
245 * | +--------+ |
246 * ^ 10ms | | 20ms ^
247 * / ^ v v ^ /
248 * +---------+ +---------+
249 * +----->| laptopA | | laptopB |<------------+
250 * | +---------+ +---------+ |
251 * | ^ v /laptops/A ^ v /laptops/B |
252 * ^ | | v | v | ^
253 * /laptops/B ^ v v v v ^ /laptops/A
254 * /------------------\ /--------------\ /--------------\ /------------------\
255 * | intervalConsumer | | echoProducer | | echoProducer | | intervalConsumer |
256 * \------------------/ \--------------/ \--------------/ \------------------/
257 */
258
259 // laptops have default routes toward the router
260 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/");
261 topo.registerPrefix(laptopB, linkB->getFace(laptopB), "ndn:/");
262
263 // two laptops have same prefix in router FIB
264 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
265 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
266
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700267 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
268 topo.addEchoProducer(producerA->getClientFace());
269 shared_ptr<TopologyAppLink> producerB = topo.addAppFace("pB", laptopB, "ndn:/laptops/B");
270 topo.addEchoProducer(producerB->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700271
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700272 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace("cAB", laptopA);
273 topo.addIntervalConsumer(consumerAB->getClientFace(), "ndn:/laptops/B",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700274 time::milliseconds(100), 100);
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700275 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace("cBA", laptopB);
276 topo.addIntervalConsumer(consumerBA->getClientFace(), "ndn:/laptops/A",
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700277 time::milliseconds(100), 100);
278
279 this->advanceClocks(time::milliseconds(5), time::seconds(12));
280
281 // most Interests should be satisfied
Junxiao Shida93f1f2015-11-11 06:13:16 -0700282 BOOST_CHECK_GE(consumerAB->getForwarderFace().getCounters().nOutData, 97);
283 BOOST_CHECK_GE(consumerBA->getForwarderFace().getCounters().nOutData, 97);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700284}
285
286BOOST_FIXTURE_TEST_CASE(PacketLoss, TwoLaptopsFixture)
287{
288 /*
289 * test case Interests
290 * |
291 * v
292 * +--------+
293 * | router |
294 * +--------+
295 * | v
296 * 10ms | v /laptops
297 * v
298 * +---------+
299 * | laptopA |
300 * +---------+
301 * ^ v
302 * | v /laptops/A
303 * v
304 * /--------------\
305 * | echoProducer |
306 * \--------------/
307 */
308
309 // laptopA has prefix in router FIB; laptopB is unused in this test case
310 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
311
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700312 shared_ptr<TopologyAppLink> producerA = topo.addAppFace("pA", laptopA, "ndn:/laptops/A");
313 topo.addEchoProducer(producerA->getClientFace());
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700314
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700315 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", router);
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700316
317 // Interest 1 completes normally
318 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
319 bool hasData1 = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700320 consumer->getClientFace().expressInterest(*interest1,
321 bind([&hasData1] { hasData1 = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700322 this->advanceClocks(time::milliseconds(5), time::seconds(1));
323 BOOST_CHECK_EQUAL(hasData1, true);
324
325 // Interest 2 experiences a packet loss on initial transmission
326 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
327 bool hasData2a = false, hasTimeout2a = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700328 consumer->getClientFace().expressInterest(*interest2a,
329 bind([&hasData2a] { hasData2a = true; }),
330 bind([&hasTimeout2a] { hasTimeout2a = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700331 producerA->fail();
332 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
333 BOOST_CHECK_EQUAL(hasData2a, false);
334 BOOST_CHECK_EQUAL(hasTimeout2a, false);
335
336 // Interest 2 retransmission is suppressed
337 shared_ptr<Interest> interest2b = makeInterest("ndn:/laptops/A/2");
338 bool hasData2b = false;
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700339 consumer->getClientFace().expressInterest(*interest2b,
340 bind([&hasData2b] { hasData2b = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700341 producerA->recover();
342 this->advanceClocks(time::milliseconds(5), time::seconds(1));
343 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,
349 bind([&hasData2c] { hasData2c = true; }));
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700350 this->advanceClocks(time::milliseconds(5), time::seconds(1));
351 BOOST_CHECK_EQUAL(hasData2c, true);
352}
353
Junxiao Shi965d3a42015-06-01 06:55:23 -0700354BOOST_FIXTURE_TEST_CASE(Bug2831, TwoLaptopsFixture)
355{
356 // make a two-node loop
357 topo.registerPrefix(laptopA, linkA->getFace(laptopA), "ndn:/net");
358 topo.registerPrefix(router, linkA->getFace(router), "ndn:/net");
359
360 // send Interests from laptopA to router
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700361 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("c", laptopA);
362 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/net",
Junxiao Shi965d3a42015-06-01 06:55:23 -0700363 time::milliseconds(100), 10);
364
365 this->advanceClocks(time::milliseconds(5), time::seconds(2));
366
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