blob: ef3cfc591a944b39a3d7c005285c4986c13bc40c [file] [log] [blame]
Andrea Tosatto672b9a72016-01-05 16:18:20 +01001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoe9c69852017-11-04 18:08:37 -04002/*
Davide Pesaventobf1c0692017-01-15 19:15:09 -05003 * Copyright (c) 2016-2017, Regents of the University of California,
4 * Colorado State University,
5 * University Pierre & Marie Curie, Sorbonne University.
Andrea Tosatto672b9a72016-01-05 16:18:20 +01006 *
7 * This file is part of ndn-tools (Named Data Networking Essential Tools).
8 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
9 *
10 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
22 *
23 * @author Andrea Tosatto
24 */
25
Weiwei Liue4765012016-06-01 00:10:29 -070026#include "tools/chunks/catchunks/pipeline-interests-fixed-window.hpp"
Andrea Tosatto672b9a72016-01-05 16:18:20 +010027#include "tools/chunks/catchunks/data-fetcher.hpp"
28
Weiwei Liue4765012016-06-01 00:10:29 -070029#include "pipeline-interests-fixture.hpp"
Andrea Tosatto672b9a72016-01-05 16:18:20 +010030
31namespace ndn {
32namespace chunks {
33namespace tests {
34
Weiwei Liue4765012016-06-01 00:10:29 -070035class PipelineInterestFixedWindowFixture : public PipelineInterestsFixture
Andrea Tosatto672b9a72016-01-05 16:18:20 +010036{
37public:
Weiwei Liue4765012016-06-01 00:10:29 -070038 typedef PipelineInterestsFixedWindowOptions Options;
Andrea Tosatto672b9a72016-01-05 16:18:20 +010039
40public:
Weiwei Liue4765012016-06-01 00:10:29 -070041 PipelineInterestFixedWindowFixture()
42 : PipelineInterestsFixture()
Andrea Tosatto672b9a72016-01-05 16:18:20 +010043 , opt(makeOptions())
Andrea Tosatto672b9a72016-01-05 16:18:20 +010044 {
Weiwei Liue4765012016-06-01 00:10:29 -070045 setPipeline(make_unique<PipelineInterestsFixedWindow>(face, PipelineInterestsFixedWindow::Options(opt)));
Andrea Tosatto672b9a72016-01-05 16:18:20 +010046 }
Davide Pesaventoe9c69852017-11-04 18:08:37 -040047
Andrea Tosatto672b9a72016-01-05 16:18:20 +010048protected:
Weiwei Liue4765012016-06-01 00:10:29 -070049 Options opt;
Andrea Tosatto672b9a72016-01-05 16:18:20 +010050
51private:
Andrea Tosatto672b9a72016-01-05 16:18:20 +010052 static Options
53 makeOptions()
54 {
55 Options options;
56 options.isVerbose = false;
57 options.interestLifetime = time::seconds(1);
58 options.maxRetriesOnTimeoutOrNack = 3;
59 options.maxPipelineSize = 5;
60 return options;
61 }
Andrea Tosatto672b9a72016-01-05 16:18:20 +010062};
63
64BOOST_AUTO_TEST_SUITE(Chunks)
Davide Pesaventoe9c69852017-11-04 18:08:37 -040065BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsFixedWindow, PipelineInterestFixedWindowFixture)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010066
Davide Pesaventoe9c69852017-11-04 18:08:37 -040067BOOST_AUTO_TEST_CASE(FewerSegmentsThanPipelineCapacity)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010068{
69 nDataSegments = 3;
70 BOOST_ASSERT(nDataSegments <= opt.maxPipelineSize);
71
72 runWithData(*makeDataWithSegment(0));
73 advanceClocks(io, time::nanoseconds(1), 1);
74 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
75
Davide Pesaventoe9c69852017-11-04 18:08:37 -040076 for (uint64_t i = 1; i < nDataSegments - 1; ++i) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +010077 face.receive(*makeDataWithSegment(i));
78 advanceClocks(io, time::nanoseconds(1), 1);
79
Davide Pesaventoe9c69852017-11-04 18:08:37 -040080 BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010081 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
82 // check if the interest for the segment i+1 is well formed
Davide Pesaventobf1c0692017-01-15 19:15:09 -050083 const auto& sentInterest = face.sentInterests[i];
Andrea Tosatto672b9a72016-01-05 16:18:20 +010084 BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
85 BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
86 BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
87 BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
Davide Pesaventobf1c0692017-01-15 19:15:09 -050088 BOOST_CHECK_EQUAL(getSegmentFromPacket(sentInterest), i + 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010089 }
90
91 BOOST_CHECK_EQUAL(hasFailed, false);
92
93 advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
94 BOOST_CHECK_EQUAL(hasFailed, true);
95}
96
Davide Pesaventoe9c69852017-11-04 18:08:37 -040097BOOST_AUTO_TEST_CASE(FullPipeline)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010098{
99 nDataSegments = 13;
100 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
101
102 runWithData(*makeDataWithSegment(nDataSegments - 1));
103 advanceClocks(io, time::nanoseconds(1), 1);
104 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
105
106 for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
107 face.receive(*makeDataWithSegment(i));
108 advanceClocks(io, time::nanoseconds(1), 1);
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400109 BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 2);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100110
111 if (i < nDataSegments - opt.maxPipelineSize - 1) {
112 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
113 // check if the interest for the segment i+1 is well formed
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500114 const auto& sentInterest = face.sentInterests[i];
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100115 BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
116 BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
117 BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
118 BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500119 BOOST_CHECK_EQUAL(getSegmentFromPacket(sentInterest), i);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100120 }
121 else {
122 // all the interests have been sent for all the segments
123 BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments - 1);
124 }
125 }
126
127 BOOST_CHECK_EQUAL(hasFailed, false);
128}
129
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400130BOOST_AUTO_TEST_CASE(TimeoutAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100131{
132 nDataSegments = 13;
133 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
134
135 runWithData(*makeDataWithSegment(nDataSegments - 1));
136 advanceClocks(io, time::nanoseconds(1), 1);
137 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
138
139 for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
140 advanceClocks(io, opt.interestLifetime, 1);
141 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400142 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100143
144 // A single retry for every pipeline element
145 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500146 const auto& interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
147 BOOST_CHECK_EQUAL(static_cast<size_t>(getSegmentFromPacket(interest)), j);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100148 }
149 }
150
151 advanceClocks(io, opt.interestLifetime, 1);
152 BOOST_CHECK_EQUAL(hasFailed, true);
153}
154
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400155BOOST_AUTO_TEST_CASE(TimeoutAfterFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100156{
157 // the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
158 // should fail
159
160 nDataSegments = 18;
161 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
162
163 runWithData(*makeDataWithSegment(nDataSegments - 1));
164 advanceClocks(io, time::nanoseconds(1), 1);
165 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
166
167 // send a single segment for each pipeline element but not the first element
168 advanceClocks(io, opt.interestLifetime, 1);
169 for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
170 face.receive(*makeDataWithSegment(i));
171 advanceClocks(io, time::nanoseconds(1), 1);
172 }
173
174 // send a single data packet for each pipeline element
175 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
176 for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
177 face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
178 advanceClocks(io, time::nanoseconds(1), 1);
179 }
180 advanceClocks(io, opt.interestLifetime, 1);
181
182 size_t interestAfterFailure = face.sentInterests.size();
183
184 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
185 BOOST_CHECK_EQUAL(hasFailed, true);
186
187 // these new segments should not generate new interests
188 advanceClocks(io, opt.interestLifetime, 1);
189 for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
190 face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
191 advanceClocks(io, time::nanoseconds(1), 1);
192 }
193
194 // no more interests after a failure
195 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
196 BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
197 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
198}
199
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400200BOOST_AUTO_TEST_CASE(TimeoutBeforeFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100201{
202 // the FinalBlockId is sent only with the last segment, all segments are sent except for the
203 // second one (segment #1); all segments are received correctly until the FinalBlockId is received
204
205 nDataSegments = 22;
206 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
207
208 runWithData(*makeDataWithSegment(nDataSegments - 1, false));
209 advanceClocks(io, time::nanoseconds(1), 1);
210 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
211
212 advanceClocks(io, opt.interestLifetime, 1);
213 for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
214 face.receive(*makeDataWithSegment(i, false));
215 advanceClocks(io, time::nanoseconds(1), 1);
216
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500217 const auto& lastInterest = face.sentInterests.back();
218 BOOST_CHECK_EQUAL(getSegmentFromPacket(lastInterest), opt.maxPipelineSize + i - 2);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100219 }
220 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
221
222 // nack for the first pipeline element (segment #0)
223 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
224 nack->setReason(lp::NackReason::DUPLICATE);
225 face.receive(*nack);
226
227 // all the pipeline elements are two retries near the timeout error, but not the
228 // second (segment #1) that is only one retry near the timeout
229 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
230 BOOST_CHECK_EQUAL(hasFailed, false);
231
232 // data for the first pipeline element (segment #0)
233 face.receive(*makeDataWithSegment(0, false));
234 BOOST_CHECK_EQUAL(hasFailed, false);
235
236 // data for all the pipeline element, but not the second (segment #1)
237 for (uint64_t i = opt.maxPipelineSize; i < nDataSegments - 1; ++i) {
238 if (i == nDataSegments - 2) {
239 face.receive(*makeDataWithSegment(i, true));
240 }
241 else {
242 face.receive(*makeDataWithSegment(i, false));
243 }
244 advanceClocks(io, time::nanoseconds(1), 1);
245 }
246 // timeout for the second pipeline element (segment #1), this should trigger an error
247 advanceClocks(io, opt.interestLifetime, 1);
248
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400249 BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100250 BOOST_CHECK_EQUAL(hasFailed, true);
251}
252
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400253BOOST_AUTO_TEST_CASE(SegmentReceivedAfterTimeout)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100254{
255 // the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
256 // segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
257
258 nDataSegments = 22;
259 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
260
261 runWithData(*makeDataWithSegment(nDataSegments - 1, false));
262 advanceClocks(io, time::nanoseconds(1), 1);
263 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
264
265 advanceClocks(io, opt.interestLifetime, 1);
266
267 // nack for the first pipeline element (segment #0)
268 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
269 nack->setReason(lp::NackReason::DUPLICATE);
270 face.receive(*nack);
271 BOOST_CHECK_EQUAL(hasFailed, false);
272
273 // timeout for all the pipeline elements, but not the first (segment #0)
274 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
275 BOOST_CHECK_EQUAL(hasFailed, false);
276
277 // data for the first pipeline element (segment #0), this should trigger an error because the
278 // others pipeline elements failed
279 face.receive(*makeDataWithSegment(0, false));
280 advanceClocks(io, time::nanoseconds(1), 1);
281
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400282 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 2);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100283 BOOST_CHECK_EQUAL(hasFailed, true);
284}
285
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400286BOOST_AUTO_TEST_CASE(CongestionAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100287{
288 nDataSegments = 13;
289 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
290
291 runWithData(*makeDataWithSegment(nDataSegments - 1));
292 advanceClocks(io, time::nanoseconds(1), 1);
293 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
294
295 // send nack for all the pipeline elements first interest
296 for (size_t j = 0; j < opt.maxPipelineSize; j++) {
297 auto nack = make_shared<lp::Nack>(face.sentInterests[j]);
298 nack->setReason(lp::NackReason::CONGESTION);
299 face.receive(*nack);
300 advanceClocks(io, time::nanoseconds(1), 1);
301 }
302
303 // send nack for all the pipeline elements interests after the first
304 for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
305 time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
306 if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
307 backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
308
309 advanceClocks(io, backoffTime, 1);
310 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
311
312 // A single retry for every pipeline element
313 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500314 const auto& interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
315 BOOST_CHECK_LT(static_cast<size_t>(getSegmentFromPacket(interest)), opt.maxPipelineSize);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100316 }
317
318 for (size_t j = 0; j < opt.maxPipelineSize; j++) {
319 auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
320 nack->setReason(lp::NackReason::CONGESTION);
321 face.receive(*nack);
322 advanceClocks(io, time::nanoseconds(1), 1);
323 }
324 }
325
326 BOOST_CHECK_EQUAL(hasFailed, true);
327}
328
329BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
330BOOST_AUTO_TEST_SUITE_END() // Chunks
331
332} // namespace tests
333} // namespace chunks
334} // namespace ndn