blob: 9adc6abc15584fa17117c86bb95d11b753f6ff7a [file] [log] [blame]
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Hila Ben Abraham39a79be2016-03-30 22:00:55 -07003 * Copyright (c) 2014-2016, Regents of the University of California,
Junxiao Shi63162202015-01-14 22:27:33 -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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Junxiao Shi82e7f582014-09-07 15:15:40 -070024 */
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070025
26#include "fw/ncc-strategy.hpp"
27#include "strategy-tester.hpp"
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070028#include "topology-tester.hpp"
Alexander Afanasyev613e2a92014-04-15 13:36:58 -070029#include "tests/daemon/face/dummy-face.hpp"
30#include "tests/limited-io.hpp"
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070031
Junxiao Shid9ee45c2014-02-27 15:38:11 -070032#include "tests/test-common.hpp"
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070033
34namespace nfd {
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080035namespace fw {
Junxiao Shid9ee45c2014-02-27 15:38:11 -070036namespace tests {
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070037
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -080038using namespace nfd::tests;
39
Junxiao Shi5e5e4452015-09-24 16:56:52 -070040BOOST_AUTO_TEST_SUITE(Fw)
41BOOST_FIXTURE_TEST_SUITE(TestNccStrategy, UnitTestTimeFixture)
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070042
Hila Ben Abraham39a79be2016-03-30 22:00:55 -070043using fw::NccStrategy;
44
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070045// NccStrategy is fairly complex.
46// The most important property is:
47// it remembers which upstream is the fastest to return Data,
48// and favors this upstream in subsequent Interests.
49BOOST_AUTO_TEST_CASE(FavorRespondingUpstream)
50{
Junxiao Shi3cb4fc62014-12-25 22:17:39 -070051 LimitedIo limitedIo(this);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070052 Forwarder forwarder;
Junxiao Shia49a1ab2016-07-15 18:24:36 +000053 StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
54 strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070055
56 shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
57 shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
58 shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
59 forwarder.addFace(face1);
60 forwarder.addFace(face2);
61 forwarder.addFace(face3);
62
63 Fib& fib = forwarder.getFib();
Junxiao Shia6de4292016-07-12 02:08:10 +000064 fib::Entry& fibEntry = *fib.insert(Name()).first;
65 fibEntry.addNextHop(*face1, 10);
66 fibEntry.addNextHop(*face2, 20);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070067
68 Pit& pit = forwarder.getPit();
69
70 // first Interest: strategy knows nothing and follows routing
Junxiao Shif3c07812014-03-11 21:48:49 -070071 shared_ptr<Interest> interest1p = makeInterest("ndn:/0Jm1ajrW/%00");
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070072 Interest& interest1 = *interest1p;
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070073 interest1.setInterestLifetime(time::milliseconds(8000));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070074 shared_ptr<pit::Entry> pitEntry1 = pit.insert(interest1).first;
75
76 pitEntry1->insertOrUpdateInRecord(face3, interest1);
Junxiao Shia49a1ab2016-07-15 18:24:36 +000077 strategy.afterReceiveInterest(*face3, interest1, pitEntry1);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070078
79 // forwards to face1 because routing says it's best
Junxiao Shi15539102014-10-08 22:39:51 -070080 // (no io run here: afterReceiveInterest has already sent the Interest)
Junxiao Shia49a1ab2016-07-15 18:24:36 +000081 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
82 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070083
84 // forwards to face2 because face1 doesn't respond
Junxiao Shi3cb4fc62014-12-25 22:17:39 -070085 limitedIo.run(1, time::milliseconds(500), time::milliseconds(10));
Junxiao Shia49a1ab2016-07-15 18:24:36 +000086 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
87 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070088
89 // face2 responds
Junxiao Shif3c07812014-03-11 21:48:49 -070090 shared_ptr<Data> data1p = makeData("ndn:/0Jm1ajrW/%00");
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070091 Data& data1 = *data1p;
Junxiao Shia49a1ab2016-07-15 18:24:36 +000092 strategy.beforeSatisfyInterest(pitEntry1, *face2, data1);
Junxiao Shi3cb4fc62014-12-25 22:17:39 -070093 this->advanceClocks(time::milliseconds(10), time::milliseconds(500));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070094
95 // second Interest: strategy knows face2 is best
Junxiao Shif3c07812014-03-11 21:48:49 -070096 shared_ptr<Interest> interest2p = makeInterest("ndn:/0Jm1ajrW/%00%01");
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070097 Interest& interest2 = *interest2p;
Alexander Afanasyeveb3197f2014-03-17 19:28:18 -070098 interest2.setInterestLifetime(time::milliseconds(8000));
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -070099 shared_ptr<pit::Entry> pitEntry2 = pit.insert(interest2).first;
100
101 pitEntry2->insertOrUpdateInRecord(face3, interest2);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000102 strategy.afterReceiveInterest(*face3, interest2, pitEntry2);
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700103
104 // forwards to face2 because it responds previously
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700105 this->advanceClocks(time::milliseconds(1));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000106 BOOST_REQUIRE_GE(strategy.sendInterestHistory.size(), 3);
107 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[2].outFaceId, face2->getId());
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700108}
109
Junxiao Shicbb490a2014-08-13 12:24:24 -0700110BOOST_AUTO_TEST_CASE(Bug1853)
111{
Junxiao Shicbb490a2014-08-13 12:24:24 -0700112 Forwarder forwarder;
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000113 StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
Junxiao Shicbb490a2014-08-13 12:24:24 -0700114
115 shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
116 shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
117 shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
118 forwarder.addFace(face1);
119 forwarder.addFace(face2);
120 forwarder.addFace(face3);
121
122 Fib& fib = forwarder.getFib();
Junxiao Shia6de4292016-07-12 02:08:10 +0000123 fib::Entry& fibEntry = *fib.insert(Name()).first;
124 fibEntry.addNextHop(*face1, 10);
Junxiao Shicbb490a2014-08-13 12:24:24 -0700125
Junxiao Shicbb490a2014-08-13 12:24:24 -0700126 Pit& pit = forwarder.getPit();
127
128 // first Interest: strategy follows routing and forwards to face1
129 shared_ptr<Interest> interest1 = makeInterest("ndn:/nztwIvHX/%00");
130 interest1->setInterestLifetime(time::milliseconds(8000));
131 shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
132
133 pitEntry1->insertOrUpdateInRecord(face3, *interest1);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000134 strategy.afterReceiveInterest(*face3, *interest1, pitEntry1);
Junxiao Shicbb490a2014-08-13 12:24:24 -0700135
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700136 this->advanceClocks(time::milliseconds(1));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000137 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
138 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
Junxiao Shicbb490a2014-08-13 12:24:24 -0700139
140 // face1 responds
141 shared_ptr<Data> data1 = makeData("ndn:/nztwIvHX/%00");
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000142 strategy.beforeSatisfyInterest(pitEntry1, *face1, *data1);
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700143 this->advanceClocks(time::milliseconds(10), time::milliseconds(500));
Junxiao Shicbb490a2014-08-13 12:24:24 -0700144
145 // second Interest: bestFace is face1, nUpstreams becomes 0,
146 // therefore pitEntryInfo->maxInterval cannot be calculated from deferRange and nUpstreams
147 shared_ptr<Interest> interest2 = makeInterest("ndn:/nztwIvHX/%01");
148 interest2->setInterestLifetime(time::milliseconds(8000));
149 shared_ptr<pit::Entry> pitEntry2 = pit.insert(*interest2).first;
150
151 pitEntry2->insertOrUpdateInRecord(face3, *interest2);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000152 strategy.afterReceiveInterest(*face3, *interest2, pitEntry2);
Junxiao Shicbb490a2014-08-13 12:24:24 -0700153
154 // FIB entry is changed before doPropagate executes
Junxiao Shia6de4292016-07-12 02:08:10 +0000155 fibEntry.addNextHop(*face2, 20);
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700156 this->advanceClocks(time::milliseconds(10), time::milliseconds(1000));// should not crash
Junxiao Shicbb490a2014-08-13 12:24:24 -0700157}
158
Junxiao Shi82e7f582014-09-07 15:15:40 -0700159BOOST_AUTO_TEST_CASE(Bug1961)
160{
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700161 LimitedIo limitedIo(this);
Junxiao Shi82e7f582014-09-07 15:15:40 -0700162 Forwarder forwarder;
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000163 StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
164 strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
Junxiao Shi82e7f582014-09-07 15:15:40 -0700165
166 shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
167 shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
168 shared_ptr<DummyFace> face3 = make_shared<DummyFace>();
169 forwarder.addFace(face1);
170 forwarder.addFace(face2);
171 forwarder.addFace(face3);
172
173 Fib& fib = forwarder.getFib();
Junxiao Shia6de4292016-07-12 02:08:10 +0000174 fib::Entry& fibEntry = *fib.insert(Name()).first;
175 fibEntry.addNextHop(*face1, 10);
176 fibEntry.addNextHop(*face2, 20);
Junxiao Shi82e7f582014-09-07 15:15:40 -0700177
Junxiao Shi82e7f582014-09-07 15:15:40 -0700178 Pit& pit = forwarder.getPit();
179
180 // first Interest: strategy forwards to face1 and face2
181 shared_ptr<Interest> interest1 = makeInterest("ndn:/seRMz5a6/%00");
182 interest1->setInterestLifetime(time::milliseconds(2000));
183 shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
184
185 pitEntry1->insertOrUpdateInRecord(face3, *interest1);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000186 strategy.afterReceiveInterest(*face3, *interest1, pitEntry1);
187 limitedIo.run(2 - strategy.sendInterestHistory.size(),
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700188 time::milliseconds(2000), time::milliseconds(10));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000189 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
190 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face1->getId());
191 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
Junxiao Shi82e7f582014-09-07 15:15:40 -0700192
193 // face1 responds
194 shared_ptr<Data> data1 = makeData("ndn:/seRMz5a6/%00");
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000195 strategy.beforeSatisfyInterest(pitEntry1, *face1, *data1);
Junxiao Shi4846f372016-04-05 13:39:30 -0700196 pitEntry1->clearInRecords();
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700197 this->advanceClocks(time::milliseconds(10));
Junxiao Shi82e7f582014-09-07 15:15:40 -0700198 // face2 also responds
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000199 strategy.beforeSatisfyInterest(pitEntry1, *face2, *data1);
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700200 this->advanceClocks(time::milliseconds(10));
Junxiao Shi82e7f582014-09-07 15:15:40 -0700201
202 // second Interest: bestFace should be face 1
203 shared_ptr<Interest> interest2 = makeInterest("ndn:/seRMz5a6/%01");
204 interest2->setInterestLifetime(time::milliseconds(2000));
205 shared_ptr<pit::Entry> pitEntry2 = pit.insert(*interest2).first;
206
207 pitEntry2->insertOrUpdateInRecord(face3, *interest2);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000208 strategy.afterReceiveInterest(*face3, *interest2, pitEntry2);
209 limitedIo.run(3 - strategy.sendInterestHistory.size(),
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700210 time::milliseconds(2000), time::milliseconds(10));
Junxiao Shi82e7f582014-09-07 15:15:40 -0700211
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000212 BOOST_REQUIRE_GE(strategy.sendInterestHistory.size(), 3);
213 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[2].outFaceId, face1->getId());
Junxiao Shi82e7f582014-09-07 15:15:40 -0700214}
Junxiao Shicbb490a2014-08-13 12:24:24 -0700215
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700216BOOST_AUTO_TEST_CASE(Bug1971)
217{
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700218 LimitedIo limitedIo(this);
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700219 Forwarder forwarder;
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000220 StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
221 strategy.afterAction.connect(bind(&LimitedIo::afterOp, &limitedIo));
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700222
223 shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
224 shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
225 forwarder.addFace(face1);
226 forwarder.addFace(face2);
227
228 Fib& fib = forwarder.getFib();
Junxiao Shia6de4292016-07-12 02:08:10 +0000229 fib::Entry& fibEntry = *fib.insert(Name()).first;
230 fibEntry.addNextHop(*face2, 10);
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700231
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700232 Pit& pit = forwarder.getPit();
233
234 // first Interest: strategy forwards to face2
235 shared_ptr<Interest> interest1 = makeInterest("ndn:/M4mBXCsd");
236 interest1->setInterestLifetime(time::milliseconds(2000));
237 shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
238
239 pitEntry1->insertOrUpdateInRecord(face1, *interest1);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000240 strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
241 limitedIo.run(1 - strategy.sendInterestHistory.size(),
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700242 time::milliseconds(2000), time::milliseconds(10));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000243 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
244 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face2->getId());
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700245
246 // face2 responds
247 shared_ptr<Data> data1 = makeData("ndn:/M4mBXCsd");
248 data1->setFreshnessPeriod(time::milliseconds(5));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000249 strategy.beforeSatisfyInterest(pitEntry1, *face2, *data1);
Junxiao Shib2bcbcd2014-11-08 09:30:28 -0700250 pitEntry1->deleteOutRecord(*face2);
Junxiao Shi4846f372016-04-05 13:39:30 -0700251 pitEntry1->clearInRecords();
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700252 this->advanceClocks(time::milliseconds(10));
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700253
254 // similar Interest: strategy should still forward it
255 pitEntry1->insertOrUpdateInRecord(face1, *interest1);
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000256 strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
257 limitedIo.run(2 - strategy.sendInterestHistory.size(),
Junxiao Shi3cb4fc62014-12-25 22:17:39 -0700258 time::milliseconds(2000), time::milliseconds(10));
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000259 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 2);
260 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[1].outFaceId, face2->getId());
Junxiao Shi8bfd56d2014-10-08 10:06:00 -0700261}
262
Junxiao Shi63162202015-01-14 22:27:33 -0700263BOOST_AUTO_TEST_CASE(Bug1998)
264{
265 Forwarder forwarder;
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000266 StrategyTester<NccStrategy>& strategy = choose<StrategyTester<NccStrategy>>(forwarder);
Junxiao Shi63162202015-01-14 22:27:33 -0700267
268 shared_ptr<DummyFace> face1 = make_shared<DummyFace>();
269 shared_ptr<DummyFace> face2 = make_shared<DummyFace>();
270 forwarder.addFace(face1);
271 forwarder.addFace(face2);
272
273 Fib& fib = forwarder.getFib();
Junxiao Shia6de4292016-07-12 02:08:10 +0000274 fib::Entry& fibEntry = *fib.insert(Name()).first;
275 fibEntry.addNextHop(*face1, 10); // face1 is top-ranked nexthop
276 fibEntry.addNextHop(*face2, 20);
Junxiao Shi63162202015-01-14 22:27:33 -0700277
Junxiao Shi63162202015-01-14 22:27:33 -0700278 Pit& pit = forwarder.getPit();
279
280 // Interest comes from face1, which is sole downstream
281 shared_ptr<Interest> interest1 = makeInterest("ndn:/tFy5HzUzD4");
282 shared_ptr<pit::Entry> pitEntry1 = pit.insert(*interest1).first;
283 pitEntry1->insertOrUpdateInRecord(face1, *interest1);
284
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000285 strategy.afterReceiveInterest(*face1, *interest1, pitEntry1);
Junxiao Shi63162202015-01-14 22:27:33 -0700286
287 // Interest shall go to face2, not loop back to face1
Junxiao Shia49a1ab2016-07-15 18:24:36 +0000288 BOOST_REQUIRE_EQUAL(strategy.sendInterestHistory.size(), 1);
289 BOOST_CHECK_EQUAL(strategy.sendInterestHistory[0].outFaceId, face2->getId());
Junxiao Shi63162202015-01-14 22:27:33 -0700290}
291
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700292BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(PredictionAdjustment, 1)
293BOOST_AUTO_TEST_CASE(PredictionAdjustment) // Bug 3411
294{
295 /*
296 * /----------\
297 * | consumer |
298 * \----------/
299 * |
300 * |
301 * +---+ 5ms +---+
302 * | A |-------| B |
303 * +---+ +---+
304 * | |
305 * | 5ms | 15ms/5ms
306 * | |
307 * +---+ +---+
308 * | C |-------| D |
309 * +---+ 15ms +---+
310 * /5ms |
311 * |
312 * /----------\
313 * | producer |
314 * \----------/
315 */
316
317 TopologyTester topo;
318 TopologyNode nodeA = topo.addForwarder("A"),
319 nodeB = topo.addForwarder("B"),
320 nodeC = topo.addForwarder("C"),
321 nodeD = topo.addForwarder("D");
322
323 for (TopologyNode node : {nodeA, nodeB, nodeC, nodeD}) {
324 topo.setStrategy<NccStrategy>(node);
325 }
326
327 shared_ptr<TopologyLink> linkAB = topo.addLink("AB", time::milliseconds( 5), {nodeA, nodeB}),
328 linkAC = topo.addLink("AC", time::milliseconds( 5), {nodeA, nodeC}),
329 linkBD = topo.addLink("BD", time::milliseconds(15), {nodeB, nodeD}),
330 linkCD = topo.addLink("CD", time::milliseconds(15), {nodeC, nodeD});
331
332 topo.registerPrefix(nodeA, linkAB->getFace(nodeA), "ndn:/P");
333 topo.registerPrefix(nodeA, linkAC->getFace(nodeA), "ndn:/P");
334 topo.registerPrefix(nodeB, linkBD->getFace(nodeB), "ndn:/P");
335 topo.registerPrefix(nodeC, linkCD->getFace(nodeC), "ndn:/P");
336
337 shared_ptr<TopologyAppLink> producer = topo.addAppFace("producer", nodeD, "ndn:/P");
338 topo.addEchoProducer(producer->getClientFace());
339
340 shared_ptr<TopologyAppLink> consumer = topo.addAppFace("consumer", nodeA);
341 topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/P",
342 time::milliseconds(100), 300);
343
344 auto getMeInfo = [&] () -> shared_ptr<NccStrategy::MeasurementsEntryInfo> {
345 Measurements& measurements = topo.getForwarder(nodeA).getMeasurements();
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000346 measurements::Entry* me = measurements.findExactMatch("ndn:/P");
Hila Ben Abraham39a79be2016-03-30 22:00:55 -0700347 return me == nullptr ? nullptr : me->getStrategyInfo<NccStrategy::MeasurementsEntryInfo>();
348 };
349
350 // NccStrategy starts with an exploration period when the algorithm adjusts
351 // its prediction to converge near the path RTT.
352 bool isExplorationFinished = false;
353 const time::milliseconds TRUE_RTT1(40);
354 bool isLastPredictionUnder = true;
355 int nPredictionCrossings = 0;
356 for (int i = 0; i < 10000; ++i) {
357 this->advanceClocks(time::milliseconds(5));
358 auto meInfo = getMeInfo();
359 if (meInfo == nullptr) {
360 continue;
361 }
362
363 if ((isLastPredictionUnder && meInfo->prediction > TRUE_RTT1) ||
364 (!isLastPredictionUnder && meInfo->prediction < TRUE_RTT1)) {
365 isLastPredictionUnder = !isLastPredictionUnder;
366 if (++nPredictionCrossings > 6) {
367 isExplorationFinished = true;
368 BOOST_TEST_MESSAGE("exploration finishes after " << (i * 5) << "ms");
369 break;
370 }
371 }
372 }
373 BOOST_REQUIRE_MESSAGE(isExplorationFinished, "exploration does not finish in 50000ms");
374
375 // NccStrategy has selected one path as the best.
376 // When we reduce the RTT of the other path, ideally it should be selected as the best face.
377 // However, this won't happen due to a weakness in NccStrategy.
378 // See http://redmine.named-data.net/issues/3411#note-4
379 shared_ptr<Face> bestFace1 = getMeInfo()->bestFace.lock();
380 if (bestFace1.get() == &linkAB->getFace(nodeA)) {
381 linkCD->setDelay(time::milliseconds(5));
382 }
383 else if (bestFace1.get() == &linkAC->getFace(nodeA)) {
384 linkBD->setDelay(time::milliseconds(5));
385 }
386 else {
387 BOOST_FAIL("unexpected best face");
388 }
389
390 bool isNewBestChosen = false;
391 for (int i = 0; i < 10000; ++i) {
392 this->advanceClocks(time::milliseconds(5));
393 auto meInfo = getMeInfo();
394 if (meInfo == nullptr) {
395 continue;
396 }
397
398 if (meInfo->bestFace.lock() != bestFace1) {
399 isNewBestChosen = true;
400 BOOST_TEST_MESSAGE("new best face is found after " << (i * 5) << "ms");
401 break;
402 }
403 }
404 BOOST_CHECK_MESSAGE(isNewBestChosen, "new best face is not found in 50000ms"); // expected failure
405}
406
Junxiao Shi5e5e4452015-09-24 16:56:52 -0700407BOOST_AUTO_TEST_SUITE_END() // TestNccStrategy
408BOOST_AUTO_TEST_SUITE_END() // Fw
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700409
Junxiao Shid9ee45c2014-02-27 15:38:11 -0700410} // namespace tests
Spyridon Mastorakisd0381c02015-02-19 10:29:41 -0800411} // namespace fw
Junxiao Shi0b5fbbb2014-02-20 15:54:03 -0700412} // namespace nfd