blob: ddc00929a3c223908b37f0f2c6ac26b5bae71cff [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
50BOOST_FIXTURE_TEST_SUITE(FwAccessStrategy, UnitTestTimeFixture)
51
52class TwoLaptopsFixture : public UnitTestTimeFixture
53{
54protected:
55 TwoLaptopsFixture()
56 {
57 /*
58 * +--------+
59 * +----->| router |<------+
60 * | +--------+ |
61 * 10ms | | 20ms
62 * v v
63 * +---------+ +---------+
64 * | laptopA | | laptopB |
65 * +---------+ +---------+
66 */
67
68 router = topo.addForwarder();
69 laptopA = topo.addForwarder();
70 laptopB = topo.addForwarder();
71
72 topo.setStrategy<fw::AccessStrategy>(router);
73
74 linkA = topo.addLink(time::milliseconds(10), {router, laptopA});
75 linkB = topo.addLink(time::milliseconds(20), {router, laptopB});
76 }
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
88BOOST_FIXTURE_TEST_CASE(OneProducer, TwoLaptopsFixture)
89{
90 /*
91 * /------------------\
92 * | intervalConsumer |
93 * \------------------/
94 * ^ v
95 * | v /laptops/A
96 * |
97 * v
98 * /laptops << +--------+ >> /laptops
99 * +----->| router |<------+
100 * | +--------+ |
101 * 10ms | | 20ms
102 * v v
103 * +---------+ +---------+
104 * | laptopA | | laptopB |
105 * +---------+ +---------+
106 * ^ v
107 * | v /laptops/A
108 * v
109 * /--------------\
110 * | echoProducer |
111 * \--------------/
112 */
113
114 // two laptops have same prefix in router FIB
115 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
116 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
117
118 shared_ptr<TopologyAppLink> producer = topo.addAppFace(laptopA, "ndn:/laptops/A");
119 topo.addEchoProducer(*producer->getClientFace());
120
121 shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
122 topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/A",
123 time::milliseconds(100), 100);
124
125 this->advanceClocks(time::milliseconds(5), time::seconds(12));
126
127 // most Interests should be satisfied, and few Interests can go to wrong laptop
128 BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
129 BOOST_CHECK_GE(linkA->getFace(router)->m_sentInterests.size(), 97);
130 BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 5);
131}
132
133BOOST_FIXTURE_TEST_CASE(FastSlowProducer, TwoLaptopsFixture)
134{
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
163 shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/BOTH");
164 topo.addEchoProducer(*producerA->getClientFace());
165 shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/BOTH");
166 topo.addEchoProducer(*producerB->getClientFace());
167
168 shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
169 topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/BOTH",
170 time::milliseconds(100), 100);
171
172 this->advanceClocks(time::milliseconds(5), time::seconds(12));
173
174 // most Interests should be satisfied, and few Interests can go to slower laptopB
175 BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
176 BOOST_CHECK_GE(linkA->getFace(router)->m_sentInterests.size(), 90);
177 BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 15);
178}
179
180BOOST_FIXTURE_TEST_CASE(ProducerMobility, TwoLaptopsFixture)
181{
182 /*
183 * /------------------\ /------------------\
184 * | intervalConsumer | | intervalConsumer |
185 * \------------------/ A \------------------/
186 * ^ v f ^ v
187 * | v /laptops/M t | v /laptops/M
188 * | e |
189 * v r v
190 * /laptops << +--------+ >> /laptops /laptops << +--------+ >> /laptops
191 * +----->| router |<------+ 6 +----->| router |<------+
192 * | +--------+ | | +--------+ |
193 * 10ms | | 20ms === s ==> 10ms | | 20ms
194 * v v e v v
195 * +---------+ +---------+ c +---------+ +---------+
196 * | laptopA | | laptopB | o | laptopA | | laptopB |
197 * +---------+ +---------+ n +---------+ +---------+
198 * ^ v d v ^
199 * | v /laptops/M s /laptops/M v |
200 * v v
201 * /--------------\ /--------------\
202 * | echoProducer | | echoProducer |
203 * \--------------/ \--------------/
204 */
205
206 // two laptops have same prefix in router FIB
207 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
208 topo.registerPrefix(router, linkB->getFace(router), "ndn:/laptops");
209
210 shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/M");
211 topo.addEchoProducer(*producerA->getClientFace());
212 shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/M");
213 topo.addEchoProducer(*producerB->getClientFace());
214
215 shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
216 topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/laptops/M",
217 time::milliseconds(100), 100);
218
219 // producer is initially on laptopA
220 producerB->fail();
221 this->advanceClocks(time::milliseconds(5), time::seconds(6));
222
223 // few Interests can go to laptopB
224 BOOST_CHECK_LE(linkB->getFace(router)->m_sentInterests.size(), 5);
225
226 // producer moves to laptopB
227 producerA->fail();
228 producerB->recover();
229 linkA->getFace(router)->m_sentInterests.clear();
230 this->advanceClocks(time::milliseconds(5), time::seconds(6));
231
232 // few additional Interests can go to laptopA
233 BOOST_CHECK_LE(linkA->getFace(router)->m_sentInterests.size(), 5);
234
235 // most Interests should be satisfied
236 BOOST_CHECK_GE(consumer->getForwarderFace()->m_sentDatas.size(), 97);
237}
238
239BOOST_FIXTURE_TEST_CASE(Bidirectional, TwoLaptopsFixture)
240{
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
266 shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/A");
267 topo.addEchoProducer(*producerA->getClientFace());
268 shared_ptr<TopologyAppLink> producerB = topo.addAppFace(laptopB, "ndn:/laptops/B");
269 topo.addEchoProducer(*producerB->getClientFace());
270
271 shared_ptr<TopologyAppLink> consumerAB = topo.addAppFace(laptopA);
272 topo.addIntervalConsumer(*consumerAB->getClientFace(), "ndn:/laptops/B",
273 time::milliseconds(100), 100);
274 shared_ptr<TopologyAppLink> consumerBA = topo.addAppFace(laptopB);
275 topo.addIntervalConsumer(*consumerBA->getClientFace(), "ndn:/laptops/A",
276 time::milliseconds(100), 100);
277
278 this->advanceClocks(time::milliseconds(5), time::seconds(12));
279
280 // most Interests should be satisfied
281 BOOST_CHECK_GE(consumerAB->getForwarderFace()->m_sentDatas.size(), 97);
282 BOOST_CHECK_GE(consumerBA->getForwarderFace()->m_sentDatas.size(), 97);
283}
284
285BOOST_FIXTURE_TEST_CASE(PacketLoss, TwoLaptopsFixture)
286{
287 /*
288 * test case Interests
289 * |
290 * v
291 * +--------+
292 * | router |
293 * +--------+
294 * | v
295 * 10ms | v /laptops
296 * v
297 * +---------+
298 * | laptopA |
299 * +---------+
300 * ^ v
301 * | v /laptops/A
302 * v
303 * /--------------\
304 * | echoProducer |
305 * \--------------/
306 */
307
308 // laptopA has prefix in router FIB; laptopB is unused in this test case
309 topo.registerPrefix(router, linkA->getFace(router), "ndn:/laptops");
310
311 shared_ptr<TopologyAppLink> producerA = topo.addAppFace(laptopA, "ndn:/laptops/A");
312 topo.addEchoProducer(*producerA->getClientFace());
313
314 shared_ptr<TopologyAppLink> consumer = topo.addAppFace(router);
315
316 // Interest 1 completes normally
317 shared_ptr<Interest> interest1 = makeInterest("ndn:/laptops/A/1");
318 bool hasData1 = false;
319 consumer->getClientFace()->expressInterest(*interest1,
320 bind([&hasData1] { hasData1 = true; }));
321 this->advanceClocks(time::milliseconds(5), time::seconds(1));
322 BOOST_CHECK_EQUAL(hasData1, true);
323
324 // Interest 2 experiences a packet loss on initial transmission
325 shared_ptr<Interest> interest2a = makeInterest("ndn:/laptops/A/2");
326 bool hasData2a = false, hasTimeout2a = false;
327 consumer->getClientFace()->expressInterest(*interest2a,
328 bind([&hasData2a] { hasData2a = true; }),
329 bind([&hasTimeout2a] { hasTimeout2a = true; }));
330 producerA->fail();
331 this->advanceClocks(time::milliseconds(5), time::milliseconds(60));
332 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;
338 consumer->getClientFace()->expressInterest(*interest2b,
339 bind([&hasData2b] { hasData2b = true; }));
340 producerA->recover();
341 this->advanceClocks(time::milliseconds(5), time::seconds(1));
342 BOOST_CHECK_EQUAL(hasData2b, false);
343
344 // Interest 2 retransmission gets through, and is answered
345 shared_ptr<Interest> interest2c = makeInterest("ndn:/laptops/A/2");
346 bool hasData2c = false;
347 consumer->getClientFace()->expressInterest(*interest2c,
348 bind([&hasData2c] { hasData2c = true; }));
349 this->advanceClocks(time::milliseconds(5), time::seconds(1));
350 BOOST_CHECK_EQUAL(hasData2c, true);
351}
352
Junxiao Shi965d3a42015-06-01 06:55:23 -0700353BOOST_FIXTURE_TEST_CASE(Bug2831, TwoLaptopsFixture)
354{
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
360 shared_ptr<TopologyAppLink> consumer = topo.addAppFace(laptopA);
361 topo.addIntervalConsumer(*consumer->getClientFace(), "ndn:/net",
362 time::milliseconds(100), 10);
363
364 this->advanceClocks(time::milliseconds(5), time::seconds(2));
365
366 // Interest shouldn't loop back from router
367 BOOST_CHECK_EQUAL(linkA->getFace(router)->m_sentInterests.size(), 0);
368}
369
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700370BOOST_AUTO_TEST_SUITE_END()
371
372} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800373} // namespace fw
Junxiao Shi80ee7cb2014-12-14 10:53:05 -0700374} // namespace nfd