blob: 12610be2c91357d5b8d6e44a50f570f43f68af45 [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/*
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -08003 * Copyright (c) 2016-2019, Regents of the University of California,
Davide Pesaventobf1c0692017-01-15 19:15:09 -05004 * 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
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080024 * @author Chavoosh Ghasemi
Andrea Tosatto672b9a72016-01-05 16:18:20 +010025 */
26
schneiderklausd8197df2019-03-16 11:31:40 -070027#include "tools/chunks/catchunks/pipeline-interests-fixed.hpp"
Andrea Tosatto672b9a72016-01-05 16:18:20 +010028#include "tools/chunks/catchunks/data-fetcher.hpp"
29
Weiwei Liue4765012016-06-01 00:10:29 -070030#include "pipeline-interests-fixture.hpp"
Andrea Tosatto672b9a72016-01-05 16:18:20 +010031
32namespace ndn {
33namespace chunks {
34namespace tests {
35
schneiderklausd8197df2019-03-16 11:31:40 -070036class PipelineInterestFixedFixture : public PipelineInterestsFixture
Andrea Tosatto672b9a72016-01-05 16:18:20 +010037{
38public:
schneiderklausd8197df2019-03-16 11:31:40 -070039 PipelineInterestFixedFixture()
Davide Pesaventof6991e12018-01-08 20:58:50 -050040 : opt(makeOptions())
Andrea Tosatto672b9a72016-01-05 16:18:20 +010041 {
schneiderklausd8197df2019-03-16 11:31:40 -070042 createPipeline();
43 }
44
45 void
46 createPipeline()
47 {
48 auto pline = make_unique<PipelineInterestsFixed>(face, opt);
49 pipeline = pline.get();
50 setPipeline(std::move(pline));
Andrea Tosatto672b9a72016-01-05 16:18:20 +010051 }
Davide Pesaventoe9c69852017-11-04 18:08:37 -040052
Andrea Tosatto672b9a72016-01-05 16:18:20 +010053private:
schneiderklausd8197df2019-03-16 11:31:40 -070054 static PipelineInterestsFixed::Options
Andrea Tosatto672b9a72016-01-05 16:18:20 +010055 makeOptions()
56 {
schneiderklausd8197df2019-03-16 11:31:40 -070057 PipelineInterestsFixed::Options options;
Davide Pesaventof6991e12018-01-08 20:58:50 -050058 options.isQuiet = true;
Andrea Tosatto672b9a72016-01-05 16:18:20 +010059 options.isVerbose = false;
60 options.interestLifetime = time::seconds(1);
61 options.maxRetriesOnTimeoutOrNack = 3;
62 options.maxPipelineSize = 5;
63 return options;
64 }
Davide Pesaventof6991e12018-01-08 20:58:50 -050065
66protected:
schneiderklausd8197df2019-03-16 11:31:40 -070067 PipelineInterestsFixed::Options opt;
68 PipelineInterestsFixed* pipeline;
Andrea Tosatto672b9a72016-01-05 16:18:20 +010069};
70
71BOOST_AUTO_TEST_SUITE(Chunks)
schneiderklausd8197df2019-03-16 11:31:40 -070072BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsFixed, PipelineInterestFixedFixture)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010073
Davide Pesaventoe9c69852017-11-04 18:08:37 -040074BOOST_AUTO_TEST_CASE(FullPipeline)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010075{
76 nDataSegments = 13;
77 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
78
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080079 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010080 advanceClocks(io, time::nanoseconds(1), 1);
81 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
82
83 for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
84 face.receive(*makeDataWithSegment(i));
85 advanceClocks(io, time::nanoseconds(1), 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080086 BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010087
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080088 if (i < nDataSegments - opt.maxPipelineSize) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +010089 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080090 // check if the interest for the segment i is well formed
Davide Pesaventobf1c0692017-01-15 19:15:09 -050091 const auto& sentInterest = face.sentInterests[i];
Davide Pesavento84d84772019-04-07 14:40:07 -040092 BOOST_CHECK_EQUAL(sentInterest.getCanBePrefix(), false);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010093 BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
94 BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
Davide Pesaventobf1c0692017-01-15 19:15:09 -050095 BOOST_CHECK_EQUAL(getSegmentFromPacket(sentInterest), i);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010096 }
97 else {
98 // all the interests have been sent for all the segments
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080099 BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100100 }
101 }
102
103 BOOST_CHECK_EQUAL(hasFailed, false);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800104
105 advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
106 BOOST_CHECK_EQUAL(hasFailed, true);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100107}
108
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400109BOOST_AUTO_TEST_CASE(TimeoutAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100110{
111 nDataSegments = 13;
112 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
113
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800114 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100115 advanceClocks(io, time::nanoseconds(1), 1);
116 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
117
118 for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
119 advanceClocks(io, opt.interestLifetime, 1);
120 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800121 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 0);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100122
123 // A single retry for every pipeline element
124 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500125 const auto& interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
126 BOOST_CHECK_EQUAL(static_cast<size_t>(getSegmentFromPacket(interest)), j);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100127 }
128 }
129
130 advanceClocks(io, opt.interestLifetime, 1);
131 BOOST_CHECK_EQUAL(hasFailed, true);
132}
133
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400134BOOST_AUTO_TEST_CASE(TimeoutAfterFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100135{
136 // the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
137 // should fail
138
139 nDataSegments = 18;
140 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
141
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800142 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100143 advanceClocks(io, time::nanoseconds(1), 1);
144 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
145
146 // send a single segment for each pipeline element but not the first element
147 advanceClocks(io, opt.interestLifetime, 1);
148 for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
149 face.receive(*makeDataWithSegment(i));
150 advanceClocks(io, time::nanoseconds(1), 1);
151 }
152
153 // send a single data packet for each pipeline element
154 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800155 for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100156 face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
157 advanceClocks(io, time::nanoseconds(1), 1);
158 }
159 advanceClocks(io, opt.interestLifetime, 1);
160
161 size_t interestAfterFailure = face.sentInterests.size();
162
163 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
164 BOOST_CHECK_EQUAL(hasFailed, true);
165
166 // these new segments should not generate new interests
167 advanceClocks(io, opt.interestLifetime, 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800168 for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100169 face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
170 advanceClocks(io, time::nanoseconds(1), 1);
171 }
172
173 // no more interests after a failure
174 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
175 BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
176 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
177}
178
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400179BOOST_AUTO_TEST_CASE(TimeoutBeforeFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100180{
181 // the FinalBlockId is sent only with the last segment, all segments are sent except for the
182 // second one (segment #1); all segments are received correctly until the FinalBlockId is received
183
184 nDataSegments = 22;
185 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
186
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800187 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100188 advanceClocks(io, time::nanoseconds(1), 1);
189 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
190
191 advanceClocks(io, opt.interestLifetime, 1);
192 for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
193 face.receive(*makeDataWithSegment(i, false));
194 advanceClocks(io, time::nanoseconds(1), 1);
195
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500196 const auto& lastInterest = face.sentInterests.back();
197 BOOST_CHECK_EQUAL(getSegmentFromPacket(lastInterest), opt.maxPipelineSize + i - 2);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100198 }
199 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
200
201 // nack for the first pipeline element (segment #0)
202 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
203 nack->setReason(lp::NackReason::DUPLICATE);
204 face.receive(*nack);
205
206 // all the pipeline elements are two retries near the timeout error, but not the
207 // second (segment #1) that is only one retry near the timeout
208 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
209 BOOST_CHECK_EQUAL(hasFailed, false);
210
211 // data for the first pipeline element (segment #0)
212 face.receive(*makeDataWithSegment(0, false));
213 BOOST_CHECK_EQUAL(hasFailed, false);
214
215 // data for all the pipeline element, but not the second (segment #1)
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800216 for (uint64_t i = opt.maxPipelineSize; i < nDataSegments; ++i) {
217 if (i == nDataSegments - 1) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100218 face.receive(*makeDataWithSegment(i, true));
219 }
220 else {
221 face.receive(*makeDataWithSegment(i, false));
222 }
223 advanceClocks(io, time::nanoseconds(1), 1);
224 }
225 // timeout for the second pipeline element (segment #1), this should trigger an error
226 advanceClocks(io, opt.interestLifetime, 1);
227
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400228 BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100229 BOOST_CHECK_EQUAL(hasFailed, true);
230}
231
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400232BOOST_AUTO_TEST_CASE(SegmentReceivedAfterTimeout)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100233{
234 // the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
235 // segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
236
237 nDataSegments = 22;
238 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
239
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800240 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100241 advanceClocks(io, time::nanoseconds(1), 1);
242 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
243
244 advanceClocks(io, opt.interestLifetime, 1);
245
246 // nack for the first pipeline element (segment #0)
247 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
248 nack->setReason(lp::NackReason::DUPLICATE);
249 face.receive(*nack);
250 BOOST_CHECK_EQUAL(hasFailed, false);
251
252 // timeout for all the pipeline elements, but not the first (segment #0)
253 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
254 BOOST_CHECK_EQUAL(hasFailed, false);
255
256 // data for the first pipeline element (segment #0), this should trigger an error because the
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800257 // other pipeline elements failed
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100258 face.receive(*makeDataWithSegment(0, false));
259 advanceClocks(io, time::nanoseconds(1), 1);
260
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800261 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100262 BOOST_CHECK_EQUAL(hasFailed, true);
263}
264
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400265BOOST_AUTO_TEST_CASE(CongestionAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100266{
267 nDataSegments = 13;
268 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
269
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800270 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100271 advanceClocks(io, time::nanoseconds(1), 1);
272 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
273
274 // send nack for all the pipeline elements first interest
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800275 for (size_t i = 0; i < opt.maxPipelineSize; i++) {
276 auto nack = make_shared<lp::Nack>(face.sentInterests[i]);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100277 nack->setReason(lp::NackReason::CONGESTION);
278 face.receive(*nack);
279 advanceClocks(io, time::nanoseconds(1), 1);
280 }
281
282 // send nack for all the pipeline elements interests after the first
283 for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
284 time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
285 if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
286 backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
287
288 advanceClocks(io, backoffTime, 1);
289 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
290
291 // A single retry for every pipeline element
292 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500293 const auto& interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
294 BOOST_CHECK_LT(static_cast<size_t>(getSegmentFromPacket(interest)), opt.maxPipelineSize);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100295 }
296
297 for (size_t j = 0; j < opt.maxPipelineSize; j++) {
298 auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
299 nack->setReason(lp::NackReason::CONGESTION);
300 face.receive(*nack);
301 advanceClocks(io, time::nanoseconds(1), 1);
302 }
303 }
304
305 BOOST_CHECK_EQUAL(hasFailed, true);
306}
307
308BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
309BOOST_AUTO_TEST_SUITE_END() // Chunks
310
311} // namespace tests
312} // namespace chunks
313} // namespace ndn