blob: f4979a204ce83f055e955cae8144f10ad130d837 [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()
Andrea Tosatto672b9a72016-01-05 16:18:20 +010040 {
Davide Pesavento97a33b22019-10-17 22:10:47 -040041 opt.interestLifetime = 1_s;
42 opt.maxRetriesOnTimeoutOrNack = 3;
43 opt.isQuiet = true;
44 opt.maxPipelineSize = 5;
schneiderklausd8197df2019-03-16 11:31:40 -070045 createPipeline();
46 }
47
48 void
49 createPipeline()
50 {
51 auto pline = make_unique<PipelineInterestsFixed>(face, opt);
52 pipeline = pline.get();
53 setPipeline(std::move(pline));
Andrea Tosatto672b9a72016-01-05 16:18:20 +010054 }
Davide Pesaventoe9c69852017-11-04 18:08:37 -040055
Davide Pesaventof6991e12018-01-08 20:58:50 -050056protected:
Davide Pesavento97a33b22019-10-17 22:10:47 -040057 Options opt;
schneiderklausd8197df2019-03-16 11:31:40 -070058 PipelineInterestsFixed* pipeline;
Andrea Tosatto672b9a72016-01-05 16:18:20 +010059};
60
61BOOST_AUTO_TEST_SUITE(Chunks)
schneiderklausd8197df2019-03-16 11:31:40 -070062BOOST_FIXTURE_TEST_SUITE(TestPipelineInterestsFixed, PipelineInterestFixedFixture)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010063
Davide Pesaventoe9c69852017-11-04 18:08:37 -040064BOOST_AUTO_TEST_CASE(FullPipeline)
Andrea Tosatto672b9a72016-01-05 16:18:20 +010065{
66 nDataSegments = 13;
67 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
68
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080069 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010070 advanceClocks(io, time::nanoseconds(1), 1);
71 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
72
73 for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
74 face.receive(*makeDataWithSegment(i));
75 advanceClocks(io, time::nanoseconds(1), 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080076 BOOST_CHECK_EQUAL(pipeline->m_nReceived, i + 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010077
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080078 if (i < nDataSegments - opt.maxPipelineSize) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +010079 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080080 // check if the interest for the segment i is well formed
Davide Pesaventobf1c0692017-01-15 19:15:09 -050081 const auto& sentInterest = face.sentInterests[i];
Davide Pesavento84d84772019-04-07 14:40:07 -040082 BOOST_CHECK_EQUAL(sentInterest.getCanBePrefix(), false);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010083 BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
84 BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
Davide Pesaventobf1c0692017-01-15 19:15:09 -050085 BOOST_CHECK_EQUAL(getSegmentFromPacket(sentInterest), i);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010086 }
87 else {
88 // all the interests have been sent for all the segments
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080089 BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010090 }
91 }
92
93 BOOST_CHECK_EQUAL(hasFailed, false);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -080094
95 advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
96 BOOST_CHECK_EQUAL(hasFailed, true);
Andrea Tosatto672b9a72016-01-05 16:18:20 +010097}
98
Davide Pesaventoe9c69852017-11-04 18:08:37 -040099BOOST_AUTO_TEST_CASE(TimeoutAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100100{
101 nDataSegments = 13;
102 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
103
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800104 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100105 advanceClocks(io, time::nanoseconds(1), 1);
106 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
107
108 for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
109 advanceClocks(io, opt.interestLifetime, 1);
110 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800111 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 0);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100112
113 // A single retry for every pipeline element
114 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500115 const auto& interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
116 BOOST_CHECK_EQUAL(static_cast<size_t>(getSegmentFromPacket(interest)), j);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100117 }
118 }
119
120 advanceClocks(io, opt.interestLifetime, 1);
121 BOOST_CHECK_EQUAL(hasFailed, true);
122}
123
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400124BOOST_AUTO_TEST_CASE(TimeoutAfterFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100125{
126 // the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
127 // should fail
128
129 nDataSegments = 18;
130 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
131
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800132 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100133 advanceClocks(io, time::nanoseconds(1), 1);
134 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
135
136 // send a single segment for each pipeline element but not the first element
137 advanceClocks(io, opt.interestLifetime, 1);
138 for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
139 face.receive(*makeDataWithSegment(i));
140 advanceClocks(io, time::nanoseconds(1), 1);
141 }
142
143 // send a single data packet for each pipeline element
144 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800145 for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100146 face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
147 advanceClocks(io, time::nanoseconds(1), 1);
148 }
149 advanceClocks(io, opt.interestLifetime, 1);
150
151 size_t interestAfterFailure = face.sentInterests.size();
152
153 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
154 BOOST_CHECK_EQUAL(hasFailed, true);
155
156 // these new segments should not generate new interests
157 advanceClocks(io, opt.interestLifetime, 1);
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800158 for (uint64_t i = 0; i < opt.maxPipelineSize; ++i) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100159 face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
160 advanceClocks(io, time::nanoseconds(1), 1);
161 }
162
163 // no more interests after a failure
164 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
165 BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
166 BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
167}
168
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400169BOOST_AUTO_TEST_CASE(TimeoutBeforeFinalBlockIdReceived)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100170{
171 // the FinalBlockId is sent only with the last segment, all segments are sent except for the
172 // second one (segment #1); all segments are received correctly until the FinalBlockId is received
173
174 nDataSegments = 22;
175 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
176
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800177 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100178 advanceClocks(io, time::nanoseconds(1), 1);
179 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
180
181 advanceClocks(io, opt.interestLifetime, 1);
182 for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
183 face.receive(*makeDataWithSegment(i, false));
184 advanceClocks(io, time::nanoseconds(1), 1);
185
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500186 const auto& lastInterest = face.sentInterests.back();
187 BOOST_CHECK_EQUAL(getSegmentFromPacket(lastInterest), opt.maxPipelineSize + i - 2);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100188 }
189 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
190
191 // nack for the first pipeline element (segment #0)
192 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
193 nack->setReason(lp::NackReason::DUPLICATE);
194 face.receive(*nack);
195
196 // all the pipeline elements are two retries near the timeout error, but not the
197 // second (segment #1) that is only one retry near the timeout
198 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
199 BOOST_CHECK_EQUAL(hasFailed, false);
200
201 // data for the first pipeline element (segment #0)
202 face.receive(*makeDataWithSegment(0, false));
203 BOOST_CHECK_EQUAL(hasFailed, false);
204
205 // data for all the pipeline element, but not the second (segment #1)
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800206 for (uint64_t i = opt.maxPipelineSize; i < nDataSegments; ++i) {
207 if (i == nDataSegments - 1) {
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100208 face.receive(*makeDataWithSegment(i, true));
209 }
210 else {
211 face.receive(*makeDataWithSegment(i, false));
212 }
213 advanceClocks(io, time::nanoseconds(1), 1);
214 }
215 // timeout for the second pipeline element (segment #1), this should trigger an error
216 advanceClocks(io, opt.interestLifetime, 1);
217
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400218 BOOST_CHECK_EQUAL(pipeline->m_nReceived, nDataSegments - 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100219 BOOST_CHECK_EQUAL(hasFailed, true);
220}
221
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400222BOOST_AUTO_TEST_CASE(SegmentReceivedAfterTimeout)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100223{
224 // the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
225 // segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
226
227 nDataSegments = 22;
228 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
229
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800230 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100231 advanceClocks(io, time::nanoseconds(1), 1);
232 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
233
234 advanceClocks(io, opt.interestLifetime, 1);
235
236 // nack for the first pipeline element (segment #0)
237 auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
238 nack->setReason(lp::NackReason::DUPLICATE);
239 face.receive(*nack);
240 BOOST_CHECK_EQUAL(hasFailed, false);
241
242 // timeout for all the pipeline elements, but not the first (segment #0)
243 advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
244 BOOST_CHECK_EQUAL(hasFailed, false);
245
246 // data for the first pipeline element (segment #0), this should trigger an error because the
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800247 // other pipeline elements failed
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100248 face.receive(*makeDataWithSegment(0, false));
249 advanceClocks(io, time::nanoseconds(1), 1);
250
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800251 BOOST_CHECK_EQUAL(pipeline->m_nReceived, 1);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100252 BOOST_CHECK_EQUAL(hasFailed, true);
253}
254
Davide Pesaventoe9c69852017-11-04 18:08:37 -0400255BOOST_AUTO_TEST_CASE(CongestionAllSegments)
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100256{
257 nDataSegments = 13;
258 BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
259
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800260 run(name);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100261 advanceClocks(io, time::nanoseconds(1), 1);
262 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
263
264 // send nack for all the pipeline elements first interest
Chavoosh Ghasemi5cb67012019-02-15 09:56:57 -0800265 for (size_t i = 0; i < opt.maxPipelineSize; i++) {
266 auto nack = make_shared<lp::Nack>(face.sentInterests[i]);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100267 nack->setReason(lp::NackReason::CONGESTION);
268 face.receive(*nack);
269 advanceClocks(io, time::nanoseconds(1), 1);
270 }
271
272 // send nack for all the pipeline elements interests after the first
273 for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
274 time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
275 if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
276 backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
277
278 advanceClocks(io, backoffTime, 1);
279 BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
280
281 // A single retry for every pipeline element
282 for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500283 const auto& interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
284 BOOST_CHECK_LT(static_cast<size_t>(getSegmentFromPacket(interest)), opt.maxPipelineSize);
Andrea Tosatto672b9a72016-01-05 16:18:20 +0100285 }
286
287 for (size_t j = 0; j < opt.maxPipelineSize; j++) {
288 auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
289 nack->setReason(lp::NackReason::CONGESTION);
290 face.receive(*nack);
291 advanceClocks(io, time::nanoseconds(1), 1);
292 }
293 }
294
295 BOOST_CHECK_EQUAL(hasFailed, true);
296}
297
298BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
299BOOST_AUTO_TEST_SUITE_END() // Chunks
300
301} // namespace tests
302} // namespace chunks
303} // namespace ndn