chunks: segmented file transfer
refs #3071
Change-Id: I88e4fc1a8e33a0d61a95e2291cccc7b998647489
diff --git a/tests/chunks/consumer.t.cpp b/tests/chunks/consumer.t.cpp
new file mode 100644
index 0000000..0ce7290
--- /dev/null
+++ b/tests/chunks/consumer.t.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#include "tools/chunks/catchunks/consumer.hpp"
+
+#include "tests/test-common.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include <ndn-cxx/security/validator-null.hpp>
+
+#include <boost/test/output_test_stream.hpp>
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+using namespace ndn::tests;
+using boost::test_tools::output_test_stream;
+
+BOOST_AUTO_TEST_SUITE(Chunks)
+BOOST_AUTO_TEST_SUITE(TestConsumer)
+
+BOOST_AUTO_TEST_CASE(OutputDataSequential)
+{
+ // Test sequential segments in the right order
+ // Segment order: 0 1 2
+
+ std::string name("/ndn/chunks/test");
+
+ std::vector<std::string> testStrings {
+ "",
+
+ "a1b2c3%^&(#$&%^$$/><",
+
+ "123456789123456789123456789123456789123456789123456789123456789"
+ "123456789123456789123456789123456789123456789123456789123456789",
+
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
+ "Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
+ "ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
+ "consequat massa Donec pede justo,"
+ };
+
+ util::DummyClientFace face;
+ ValidatorNull validator;
+ output_test_stream output("");
+ Consumer cons(face, validator, false, output);
+
+ auto interest = makeInterest(name);
+
+ for (size_t i = 0; i < testStrings.size(); ++i) {
+ output.flush();
+
+ auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
+ data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
+ testStrings[i].size());
+
+ cons.m_bufferedData[i] = data;
+ cons.writeInOrderData();
+
+ BOOST_CHECK(output.is_equal(testStrings[i]));
+ }
+}
+
+BOOST_AUTO_TEST_CASE(OutputDataUnordered)
+{
+ // Test unordered segments
+ // Segment order: 1 0 2
+
+ std::string name("/ndn/chunks/test");
+
+ std::vector<std::string> testStrings {
+ "a1b2c3%^&(#$&%^$$/><",
+
+ "123456789123456789123456789123456789123456789123456789123456789"
+ "123456789123456789123456789123456789123456789123456789123456789",
+
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
+ "Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
+ "ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
+ "consequat massa Donec pede justo,"
+ };;
+
+ util::DummyClientFace face;
+ ValidatorNull validator;
+ output_test_stream output("");
+ Consumer cons(face, validator, false, output);
+
+ auto interest = makeInterest(name);
+ std::vector<shared_ptr<Data>> dataStore;
+
+ for (size_t i = 0; i < testStrings.size(); ++i) {
+ auto data = makeData(Name(name).appendVersion(1).appendSegment(i));
+ data->setContent(reinterpret_cast<const uint8_t*>(testStrings[i].data()),
+ testStrings[i].size());
+
+ dataStore.push_back(data);
+ }
+
+ output.flush();
+ cons.m_bufferedData[1] = dataStore[1];
+ cons.writeInOrderData();
+ BOOST_CHECK(output.is_equal(""));
+
+ output.flush();
+ cons.m_bufferedData[0] = dataStore[0];
+ cons.writeInOrderData();
+ BOOST_CHECK(output.is_equal(testStrings[0] + testStrings[1]));
+
+ output.flush();
+ cons.m_bufferedData[2] = dataStore[2];
+ cons.writeInOrderData();
+ BOOST_CHECK(output.is_equal(testStrings[2]));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestConsumer
+BOOST_AUTO_TEST_SUITE_END() // Chunks
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn
diff --git a/tests/chunks/discover-version-fixed.t.cpp b/tests/chunks/discover-version-fixed.t.cpp
new file mode 100644
index 0000000..a57e5c8
--- /dev/null
+++ b/tests/chunks/discover-version-fixed.t.cpp
@@ -0,0 +1,147 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#include "tools/chunks/catchunks/discover-version-fixed.hpp"
+
+#include "discover-version-fixture.hpp"
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+using namespace ndn::tests;
+
+class DiscoverVersionFixedFixture : public DiscoverVersionFixture
+{
+public:
+ DiscoverVersionFixedFixture()
+ : DiscoverVersionFixture(makeOptions())
+ , version(1449227841747)
+ {
+ setDiscover(make_unique<DiscoverVersionFixed>(Name(name).appendVersion(version),
+ face, makeOptions()));
+ }
+
+protected:
+ uint64_t version; //Version to find
+};
+
+BOOST_AUTO_TEST_SUITE(Chunks)
+BOOST_AUTO_TEST_SUITE(TestDiscoverVersionFixed)
+
+BOOST_FIXTURE_TEST_CASE(RequestedVersionAvailable, DiscoverVersionFixedFixture)
+{
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+
+ face.receive(*makeDataWithVersion(version));
+
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ BOOST_CHECK_EQUAL(discoveredVersion, version);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+ auto lastInterest = face.sentInterests.back();
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+}
+
+BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionFixedFixture)
+{
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+
+ for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
+ }
+
+ for (const auto& lastInterest : face.sentInterests) {
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(Name(name).appendVersion(version)), true);
+ }
+
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ // check if discovered version is the default value
+ BOOST_CHECK_EQUAL(discoveredVersion, 0);
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
+}
+
+BOOST_FIXTURE_TEST_CASE(DataNotSegment, DiscoverVersionFixedFixture)
+{
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+
+ std::vector<std::string> randomStrings {
+ "",
+ "abcdefg",
+ "12345",
+ "qr%67a3%4e"
+ };
+
+ Exclude expectedExclude;
+ for (size_t retries = 0; retries < randomStrings.size(); ++retries) {
+ auto data = make_shared<Data>(Name(name).appendVersion(version).append(randomStrings[retries]));
+ data->setFinalBlockId(name::Component::fromSegment(0));
+ data = signData(data);
+
+ face.receive(*data);
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1 + retries);
+ auto lastInterest = face.sentInterests.back();
+ if (randomStrings[retries] != "")
+ expectedExclude.excludeOne(name::Component::fromEscapedString(randomStrings[retries]));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getMaxSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMinSuffixComponents(), 2);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ }
+
+ advanceClocks(io, interestLifetime, maxRetriesOnTimeoutOrNack + 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ // check if discovered version is the default value
+ BOOST_CHECK_EQUAL(discoveredVersion, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionFixed
+BOOST_AUTO_TEST_SUITE_END() // Chunks
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn
diff --git a/tests/chunks/discover-version-fixture.hpp b/tests/chunks/discover-version-fixture.hpp
new file mode 100644
index 0000000..9009301
--- /dev/null
+++ b/tests/chunks/discover-version-fixture.hpp
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#ifndef NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
+#define NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
+
+#include "tools/chunks/catchunks/discover-version.hpp"
+
+#include "tests/test-common.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+class DiscoverVersionFixture : public ndn::tests::UnitTestTimeFixture, virtual protected Options
+{
+public:
+ DiscoverVersionFixture(const Options& options)
+ : Options(options)
+ , face(io)
+ , name("/ndn/chunks/test")
+ , isDiscoveryFinished(false)
+ , discoveredVersion(0)
+ {
+ }
+
+protected:
+ void setDiscover(unique_ptr<DiscoverVersion> disc)
+ {
+ discover = std::move(disc);
+ discover->onDiscoverySuccess.connect(bind(&DiscoverVersionFixture::onSuccess, this, _1));
+ discover->onDiscoveryFailure.connect(bind(&DiscoverVersionFixture::onFailure, this, _1));
+ }
+
+ shared_ptr<Data>
+ makeDataWithVersion(uint64_t version)
+ {
+ auto data = make_shared<Data>(Name(name).appendVersion(version).appendSegment(0));
+ data->setFinalBlockId(name::Component::fromSegment(0));
+ return ndn::tests::signData(data);
+ }
+
+ static Options
+ makeOptions()
+ {
+ Options options;
+ options.isVerbose = false;
+ options.interestLifetime = time::seconds(1);
+ options.maxRetriesOnTimeoutOrNack = 3;
+ return options;
+ }
+
+ virtual void
+ onSuccess(const Data& data)
+ {
+ isDiscoveryFinished = true;
+
+ if (data.getName()[name.size()].isVersion())
+ discoveredVersion = data.getName()[name.size()].toVersion();
+ }
+
+ virtual void
+ onFailure(const std::string& reason)
+ {
+ isDiscoveryFinished = true;
+ }
+
+protected:
+ boost::asio::io_service io;
+ util::DummyClientFace face;
+ Name name;
+ unique_ptr<DiscoverVersion> discover;
+ bool isDiscoveryFinished;
+ uint64_t discoveredVersion;
+};
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn
+
+#endif // NDN_TOOLS_TESTS_CHUNKS_DISCOVER_VERSION_FIXTURE_HPP
diff --git a/tests/chunks/discover-version-iterative.t.cpp b/tests/chunks/discover-version-iterative.t.cpp
new file mode 100644
index 0000000..233f36c
--- /dev/null
+++ b/tests/chunks/discover-version-iterative.t.cpp
@@ -0,0 +1,235 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#include "tools/chunks/catchunks/discover-version-iterative.hpp"
+
+#include "discover-version-fixture.hpp"
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+using namespace ndn::tests;
+
+class DiscoverVersionIterativeFixture : public DiscoverVersionFixture,
+ protected DiscoverVersionIterativeOptions
+{
+public:
+ typedef DiscoverVersionIterativeOptions Options;
+
+public:
+ explicit
+ DiscoverVersionIterativeFixture(const Options& opt = makeOptionsIterative())
+ : chunks::Options(opt)
+ , DiscoverVersionFixture(opt)
+ , Options(opt)
+ {
+ setDiscover(make_unique<DiscoverVersionIterative>(Name(name), face, opt));
+ }
+
+protected:
+ static Options
+ makeOptionsIterative()
+ {
+ Options options;
+ options.isVerbose = false;
+ options.maxRetriesOnTimeoutOrNack = 3;
+ options.maxRetriesAfterVersionFound = 1;
+ return options;
+ }
+};
+
+
+BOOST_AUTO_TEST_SUITE(Chunks)
+BOOST_AUTO_TEST_SUITE(TestDiscoverVersionIterative)
+
+BOOST_FIXTURE_TEST_CASE(SingleVersionAvailable, DiscoverVersionIterativeFixture)
+{
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ uint64_t version = 1449241767037;
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+ auto lastInterest = face.sentInterests.back();
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+
+ // Send first segment for the right version
+ face.receive(*makeDataWithVersion(version));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
+ lastInterest = face.sentInterests.back();
+ Exclude expectedExclude;
+ expectedExclude.excludeBefore(name::Component::fromVersion(version));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+
+ // Generate the timeout
+ for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
+ advanceClocks(io, interestLifetime, 1);
+
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), retries + 3);
+ lastInterest = face.sentInterests.back();
+ Exclude expectedExclude;
+ expectedExclude.excludeBefore(name::Component::fromVersion(version));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+ }
+
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ BOOST_CHECK_EQUAL(discoveredVersion, version);
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
+}
+
+
+BOOST_FIXTURE_TEST_CASE(NoVersionsAvailable, DiscoverVersionIterativeFixture)
+{
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+
+ for (int retries = 0; retries < maxRetriesOnTimeoutOrNack; ++retries) {
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries);
+ }
+
+ for (auto& lastInterest : face.sentInterests) {
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+ }
+
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesOnTimeoutOrNack + 1);
+}
+
+BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailable, DiscoverVersionIterativeFixture)
+{
+ // nVersions must be positive
+ const uint64_t nVersions = 5;
+
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+ auto lastInterest = face.sentInterests.back();
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+
+ for (uint64_t nSentVersions = 0; nSentVersions < nVersions; ++nSentVersions) {
+ face.receive(*makeDataWithVersion(nSentVersions));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + nSentVersions);
+ lastInterest = face.sentInterests.back();
+ Exclude expectedExclude;
+ expectedExclude.excludeBefore(name::Component::fromVersion(nSentVersions));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+ }
+
+ for (int retries = 0; retries < maxRetriesAfterVersionFound; ++retries) {
+ advanceClocks(io, interestLifetime, 1);
+
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2 + retries + nVersions);
+ lastInterest = face.sentInterests.back();
+ Exclude expectedExclude;
+ expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+ }
+
+ advanceClocks(io, interestLifetime, 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), nVersions + maxRetriesAfterVersionFound + 1);
+}
+
+BOOST_FIXTURE_TEST_CASE(MultipleVersionsAvailableDescendent, DiscoverVersionIterativeFixture)
+{
+ // nVersions must be positive
+ const uint64_t nVersions = 5;
+
+ discover->run();
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 1);
+ auto lastInterest = face.sentInterests.back();
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+ BOOST_CHECK_EQUAL(lastInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+
+ for (uint64_t nVersionsToSend = nVersions; nVersionsToSend > 0; --nVersionsToSend) {
+ face.receive(*makeDataWithVersion(nVersionsToSend - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, false);
+
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), 2);
+ lastInterest = face.sentInterests.back();
+ Exclude expectedExclude;
+ expectedExclude.excludeBefore(name::Component::fromVersion(nVersions - 1));
+ BOOST_CHECK_EQUAL(lastInterest.getExclude(), expectedExclude);
+ BOOST_CHECK_EQUAL(lastInterest.getChildSelector(), 1);
+ BOOST_CHECK_EQUAL(lastInterest.getMustBeFresh(), mustBeFresh);
+ BOOST_CHECK_EQUAL(lastInterest.getName().equals(name), true);
+ }
+
+ advanceClocks(io, interestLifetime, maxRetriesAfterVersionFound + 1);
+ BOOST_CHECK_EQUAL(isDiscoveryFinished, true);
+ BOOST_CHECK_EQUAL(discoveredVersion, nVersions - 1);
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), maxRetriesAfterVersionFound + 2);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestDiscoverVersionIterative
+BOOST_AUTO_TEST_SUITE_END() // Chunks
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn
diff --git a/tests/chunks/pipeline-interests.t.cpp b/tests/chunks/pipeline-interests.t.cpp
new file mode 100644
index 0000000..98abfa4
--- /dev/null
+++ b/tests/chunks/pipeline-interests.t.cpp
@@ -0,0 +1,378 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#include "tools/chunks/catchunks/pipeline-interests.hpp"
+#include "tools/chunks/catchunks/data-fetcher.hpp"
+
+#include "tests/test-common.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+using namespace ndn::tests;
+
+class PipelineInterestsFixture : public UnitTestTimeFixture
+{
+public:
+ typedef PipelineInterestsOptions Options;
+
+public:
+ PipelineInterestsFixture()
+ : face(io)
+ , opt(makeOptions())
+ , name("/ndn/chunks/test")
+ , pipeline(face, opt)
+ , nDataSegments(0)
+ , nReceivedSegments(0)
+ , hasFailed(false)
+ {
+ }
+
+protected:
+ shared_ptr<Data>
+ makeDataWithSegment(uint64_t segmentNo, bool setFinalBlockId = true)
+ {
+ auto data = make_shared<Data>(Name(name).appendVersion(0).appendSegment(segmentNo));
+ if (setFinalBlockId)
+ data->setFinalBlockId(name::Component::fromSegment(nDataSegments - 1));
+ return signData(data);
+ }
+
+ void
+ runWithData(const Data& data)
+ {
+ pipeline.runWithExcludedSegment(data,
+ bind(&PipelineInterestsFixture::onData, this, _1, _2),
+ bind(&PipelineInterestsFixture::onFailure, this, _1));
+ }
+
+private:
+ void
+ onData(const Interest& interest, const Data& data)
+ {
+ nReceivedSegments++;
+ }
+
+ void
+ onFailure(const std::string& reason)
+ {
+ hasFailed = true;
+ }
+
+ static Options
+ makeOptions()
+ {
+ Options options;
+ options.isVerbose = false;
+ options.interestLifetime = time::seconds(1);
+ options.maxRetriesOnTimeoutOrNack = 3;
+ options.maxPipelineSize = 5;
+ return options;
+ }
+
+protected:
+ boost::asio::io_service io;
+ util::DummyClientFace face;
+ Options opt;
+ Name name;
+ PipelineInterests pipeline;
+ uint64_t nDataSegments;
+ uint64_t nReceivedSegments;
+ bool hasFailed;
+};
+
+BOOST_AUTO_TEST_SUITE(Chunks)
+BOOST_AUTO_TEST_SUITE(TestPipelineInterests)
+
+BOOST_FIXTURE_TEST_CASE(FewerSegmentsThanPipelineCapacity, PipelineInterestsFixture)
+{
+ nDataSegments = 3;
+ BOOST_ASSERT(nDataSegments <= opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(0));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
+
+ for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
+ face.receive(*makeDataWithSegment(i));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_CHECK_EQUAL(nReceivedSegments, i);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), nDataSegments - 1);
+ // check if the interest for the segment i+1 is well formed
+ auto sentInterest = face.sentInterests[i];
+ BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
+ BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
+ BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
+ BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i + 1);
+ }
+
+ BOOST_CHECK_EQUAL(hasFailed, false);
+
+ advanceClocks(io, ndn::DEFAULT_INTEREST_LIFETIME, opt.maxRetriesOnTimeoutOrNack + 1);
+ BOOST_CHECK_EQUAL(hasFailed, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(FullPipeline, PipelineInterestsFixture)
+{
+ nDataSegments = 13;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ for (uint64_t i = 0; i < nDataSegments - 1; ++i) {
+ face.receive(*makeDataWithSegment(i));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_CHECK_EQUAL(nReceivedSegments, i + 1);
+
+ if (i < nDataSegments - opt.maxPipelineSize - 1) {
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize + i + 1);
+ // check if the interest for the segment i+1 is well formed
+ auto sentInterest = face.sentInterests[i];
+ BOOST_CHECK_EQUAL(sentInterest.getExclude().size(), 0);
+ BOOST_CHECK_EQUAL(sentInterest.getMaxSuffixComponents(), 1);
+ BOOST_CHECK_EQUAL(sentInterest.getMustBeFresh(), opt.mustBeFresh);
+ BOOST_CHECK_EQUAL(Name(name).isPrefixOf(sentInterest.getName()), true);
+ BOOST_CHECK_EQUAL(sentInterest.getName()[-1].toSegment(), i);
+ }
+ else {
+ // all the interests have been sent for all the segments
+ BOOST_CHECK_EQUAL(face.sentInterests.size(), nDataSegments - 1);
+ }
+ }
+
+ BOOST_CHECK_EQUAL(hasFailed, false);
+}
+
+BOOST_FIXTURE_TEST_CASE(TimeoutAllSegments, PipelineInterestsFixture)
+{
+ nDataSegments = 13;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ for (int i = 0; i < opt.maxRetriesOnTimeoutOrNack; ++i) {
+ advanceClocks(io, opt.interestLifetime, 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i + 2));
+ BOOST_CHECK_EQUAL(nReceivedSegments, 0);
+
+ // A single retry for every pipeline element
+ for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
+ auto interest = face.sentInterests[(opt.maxPipelineSize * (i + 1)) + j];
+ BOOST_CHECK_EQUAL(static_cast<size_t>(interest.getName()[-1].toSegment()), j);
+ }
+ }
+
+ advanceClocks(io, opt.interestLifetime, 1);
+ BOOST_CHECK_EQUAL(hasFailed, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(TimeoutAfterFinalBlockIdReceived, PipelineInterestsFixture)
+{
+ // the FinalBlockId is sent with the first segment, after the first segment failure the pipeline
+ // should fail
+
+ nDataSegments = 18;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ // send a single segment for each pipeline element but not the first element
+ advanceClocks(io, opt.interestLifetime, 1);
+ for (uint64_t i = 1; i < opt.maxPipelineSize; ++i) {
+ face.receive(*makeDataWithSegment(i));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+
+ // send a single data packet for each pipeline element
+ advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
+ for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
+ face.receive(*makeDataWithSegment(opt.maxPipelineSize + i));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+ advanceClocks(io, opt.interestLifetime, 1);
+
+ size_t interestAfterFailure = face.sentInterests.size();
+
+ BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
+ BOOST_CHECK_EQUAL(hasFailed, true);
+
+ // these new segments should not generate new interests
+ advanceClocks(io, opt.interestLifetime, 1);
+ for (uint64_t i = 0; i < opt.maxPipelineSize - 1; ++i) {
+ face.receive(*makeDataWithSegment(opt.maxPipelineSize * 2 + i - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+
+ // no more interests after a failure
+ advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
+ BOOST_CHECK_EQUAL(interestAfterFailure, face.sentInterests.size());
+ BOOST_CHECK_EQUAL(face.getNPendingInterests(), 0);
+}
+
+BOOST_FIXTURE_TEST_CASE(TimeoutBeforeFinalBlockIdReceived, PipelineInterestsFixture)
+{
+ // the FinalBlockId is sent only with the last segment, all segments are sent except for the
+ // second one (segment #1); all segments are received correctly until the FinalBlockId is received
+
+ nDataSegments = 22;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1, false));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ advanceClocks(io, opt.interestLifetime, 1);
+ for (uint64_t i = 2; i < opt.maxPipelineSize; ++i) {
+ face.receive(*makeDataWithSegment(i, false));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ auto lastInterest = face.sentInterests.back();
+ BOOST_CHECK_EQUAL(lastInterest.getName()[-1].toSegment(), opt.maxPipelineSize + i - 2);
+ }
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * 3 - 2);
+
+ // nack for the first pipeline element (segment #0)
+ auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
+ nack->setReason(lp::NackReason::DUPLICATE);
+ face.receive(*nack);
+
+ // all the pipeline elements are two retries near the timeout error, but not the
+ // second (segment #1) that is only one retry near the timeout
+ advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack - 1);
+ BOOST_CHECK_EQUAL(hasFailed, false);
+
+ // data for the first pipeline element (segment #0)
+ face.receive(*makeDataWithSegment(0, false));
+ BOOST_CHECK_EQUAL(hasFailed, false);
+
+ // data for all the pipeline element, but not the second (segment #1)
+ for (uint64_t i = opt.maxPipelineSize; i < nDataSegments - 1; ++i) {
+ if (i == nDataSegments - 2) {
+ face.receive(*makeDataWithSegment(i, true));
+ }
+ else {
+ face.receive(*makeDataWithSegment(i, false));
+ }
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+ // timeout for the second pipeline element (segment #1), this should trigger an error
+ advanceClocks(io, opt.interestLifetime, 1);
+
+ BOOST_CHECK_EQUAL(nReceivedSegments, nDataSegments - 2);
+ BOOST_CHECK_EQUAL(hasFailed, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(SegmentReceivedAfterTimeout, PipelineInterestsFixture)
+{
+ // the FinalBlockId is never sent, all the pipeline elements with a segment number greater than
+ // segment #0 will fail, after this failure also segment #0 fail and this should trigger an error
+
+ nDataSegments = 22;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1, false));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ advanceClocks(io, opt.interestLifetime, 1);
+
+ // nack for the first pipeline element (segment #0)
+ auto nack = make_shared<lp::Nack>(face.sentInterests[opt.maxPipelineSize]);
+ nack->setReason(lp::NackReason::DUPLICATE);
+ face.receive(*nack);
+ BOOST_CHECK_EQUAL(hasFailed, false);
+
+ // timeout for all the pipeline elements, but not the first (segment #0)
+ advanceClocks(io, opt.interestLifetime, opt.maxRetriesOnTimeoutOrNack);
+ BOOST_CHECK_EQUAL(hasFailed, false);
+
+ // data for the first pipeline element (segment #0), this should trigger an error because the
+ // others pipeline elements failed
+ face.receive(*makeDataWithSegment(0, false));
+ advanceClocks(io, time::nanoseconds(1), 1);
+
+ BOOST_CHECK_EQUAL(nReceivedSegments, 1);
+ BOOST_CHECK_EQUAL(hasFailed, true);
+}
+
+BOOST_FIXTURE_TEST_CASE(CongestionAllSegments, PipelineInterestsFixture)
+{
+ nDataSegments = 13;
+ BOOST_ASSERT(nDataSegments > opt.maxPipelineSize);
+
+ runWithData(*makeDataWithSegment(nDataSegments - 1));
+ advanceClocks(io, time::nanoseconds(1), 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize);
+
+ // send nack for all the pipeline elements first interest
+ for (size_t j = 0; j < opt.maxPipelineSize; j++) {
+ auto nack = make_shared<lp::Nack>(face.sentInterests[j]);
+ nack->setReason(lp::NackReason::CONGESTION);
+ face.receive(*nack);
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+
+ // send nack for all the pipeline elements interests after the first
+ for (int i = 1; i <= opt.maxRetriesOnTimeoutOrNack; ++i) {
+ time::milliseconds backoffTime(static_cast<uint64_t>(std::pow(2, i)));
+ if (backoffTime > DataFetcher::MAX_CONGESTION_BACKOFF_TIME)
+ backoffTime = DataFetcher::MAX_CONGESTION_BACKOFF_TIME;
+
+ advanceClocks(io, backoffTime, 1);
+ BOOST_REQUIRE_EQUAL(face.sentInterests.size(), opt.maxPipelineSize * (i +1));
+
+ // A single retry for every pipeline element
+ for (size_t j = 0; j < opt.maxPipelineSize; ++j) {
+ auto interest = face.sentInterests[(opt.maxPipelineSize * i) + j];
+ BOOST_CHECK_LT(static_cast<size_t>(interest.getName()[-1].toSegment()), opt.maxPipelineSize);
+ }
+
+ for (size_t j = 0; j < opt.maxPipelineSize; j++) {
+ auto nack = make_shared<lp::Nack>(face.sentInterests[(opt.maxPipelineSize * i) + j]);
+ nack->setReason(lp::NackReason::CONGESTION);
+ face.receive(*nack);
+ advanceClocks(io, time::nanoseconds(1), 1);
+ }
+ }
+
+ BOOST_CHECK_EQUAL(hasFailed, true);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestPipelineInterests
+BOOST_AUTO_TEST_SUITE_END() // Chunks
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn
diff --git a/tests/chunks/producer.t.cpp b/tests/chunks/producer.t.cpp
new file mode 100644
index 0000000..dc5346f
--- /dev/null
+++ b/tests/chunks/producer.t.cpp
@@ -0,0 +1,233 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2016, Regents of the University of California,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University.
+ *
+ * This file is part of ndn-tools (Named Data Networking Essential Tools).
+ * See AUTHORS.md for complete list of ndn-tools authors and contributors.
+ *
+ * ndn-tools is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Andrea Tosatto
+ */
+
+#include "tools/chunks/putchunks/producer.hpp"
+
+#include "tests/test-common.hpp"
+#include <ndn-cxx/util/dummy-client-face.hpp>
+#include <ndn-cxx/security/validator-null.hpp>
+
+#include <cmath>
+
+namespace ndn {
+namespace chunks {
+namespace tests {
+
+using namespace ndn::tests;
+
+BOOST_AUTO_TEST_SUITE(Chunks)
+BOOST_AUTO_TEST_SUITE(TestProducer)
+
+BOOST_AUTO_TEST_CASE(InputData)
+{
+ util::DummyClientFace face;
+ KeyChain keyChain;
+ security::SigningInfo signingInfo;
+ Name prefix("/ndn/chunks/test");
+ int maxSegmentSize = 40;
+ std::vector<std::string> testStrings {
+ "",
+
+ "a1b2c3%^&(#$&%^$$/><",
+
+ "123456789123456789123456789123456789123456789123456789123456789"
+ "123456789123456789123456789123456789123456789123456789123456789",
+
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. "
+ "Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
+ "ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla "
+ "consequat massa Donec pede justo,"
+ };
+
+ for (size_t i = 0; i < testStrings.size(); ++i) {
+ std::istringstream str(testStrings[i]);
+ Producer prod(prefix, face, keyChain, signingInfo, time::seconds(4), maxSegmentSize, false,
+ false, str);
+
+ size_t expectedSize = std::ceil(static_cast<double>(testStrings[i].size()) / maxSegmentSize);
+ if (testStrings[i].size() == 0)
+ expectedSize = 1;
+
+ BOOST_CHECK_EQUAL(prod.m_store.size(), expectedSize);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(RequestSegmentUnspecifiedVersion)
+{
+ boost::asio::io_service io;
+ util::DummyClientFace face(io, {true, true});
+ KeyChain keyChain;
+ security::SigningInfo signingInfo;
+ Name prefix("/ndn/chunks/test");
+ time::milliseconds freshnessPeriod(time::seconds(10));
+ size_t maxSegmentSize(40);
+ std::istringstream testString(std::string(
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
+ "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
+ "sem. Nulla consequat massa Donec pede justo,"));
+
+ Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
+
+ Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
+ false, false, testString);
+ io.poll();
+
+ size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
+
+ // version request
+ face.receive(*makeInterest(prefix));
+ face.processEvents();
+
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
+ auto lastData = face.sentData.back();
+ BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
+ BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
+ BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
+ BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
+ BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
+
+ // segment request
+ Name nameWithVersion(prefix);
+ nameWithVersion.append(lastData.getName()[-2]);
+ size_t requestSegmentNo = 1;
+
+ face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
+ face.processEvents();
+
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
+ lastData = face.sentData.back();
+ BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
+ BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
+ BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
+ BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
+ BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
+}
+
+BOOST_AUTO_TEST_CASE(RequestSegmentSpecifiedVersion)
+{
+ boost::asio::io_service io;
+ util::DummyClientFace face(io, {true, true});
+ KeyChain keyChain;
+ security::SigningInfo signingInfo;
+ Name prefix("/ndn/chunks/test");
+ time::milliseconds freshnessPeriod(time::seconds(10));
+ size_t maxSegmentSize(40);
+ std::istringstream testString(std::string(
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
+ "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
+ "sem. Nulla consequat massa Donec pede justo,"));
+
+ uint64_t version = 1449227841747;
+ Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
+
+ Producer producer(prefix.appendVersion(version), face, keyChain, signingInfo, freshnessPeriod,
+ maxSegmentSize, false, false, testString);
+ io.poll();
+
+ size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
+
+ // version request
+ face.receive(*makeInterest(prefix));
+ face.processEvents();
+
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
+ auto lastData = face.sentData.back();
+ BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
+ BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
+ BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
+ BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
+ BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
+ BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
+
+ // segment request
+ Name nameWithVersion(prefix);
+ size_t requestSegmentNo = 1;
+
+ face.receive(*makeInterest(nameWithVersion.appendSegment(requestSegmentNo)));
+ face.processEvents();
+
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 2);
+ lastData = face.sentData.back();
+ BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 1);
+ BOOST_CHECK_EQUAL(lastData.getName()[-2].toVersion(), version);
+ BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), requestSegmentNo);
+ BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
+ BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
+ BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
+}
+
+BOOST_AUTO_TEST_CASE(RequestNotExistingSegment)
+{
+ boost::asio::io_service io;
+ util::DummyClientFace face(io, {true, true});
+ KeyChain keyChain;
+ security::SigningInfo signingInfo;
+ Name prefix("/ndn/chunks/test");
+ time::milliseconds freshnessPeriod(time::seconds(10));
+ size_t maxSegmentSize(40);
+ std::istringstream testString(std::string(
+ "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget "
+ "dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, "
+ "nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, "
+ "sem. Nulla consequat massa Donec pede justo,"));
+
+ Name keyLocatorName = keyChain.getDefaultCertificateName().getPrefix(-1);
+
+ Producer producer(prefix, face, keyChain, signingInfo, freshnessPeriod, maxSegmentSize,
+ false, false, testString);
+ io.poll();
+
+ size_t nSegments = std::ceil(static_cast<double>(testString.str().size()) / maxSegmentSize);
+
+ // version request
+ face.receive(*makeInterest(prefix));
+ face.processEvents();
+
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
+ auto lastData = face.sentData.back();
+ BOOST_REQUIRE_EQUAL(lastData.getName().size(), prefix.size() + 2);
+ BOOST_CHECK_EQUAL(lastData.getName()[-1].toSegment(), 0);
+ BOOST_REQUIRE(!lastData.getFinalBlockId().empty());
+ BOOST_CHECK_EQUAL(lastData.getFinalBlockId().toSegment(), nSegments - 1);
+ BOOST_CHECK_EQUAL(lastData.getSignature().getKeyLocator().getName(), keyLocatorName);
+
+ // segment request
+ Name nameWithVersion(prefix);
+ nameWithVersion.append(lastData.getName()[-2]);
+ face.receive(*makeInterest(nameWithVersion.appendSegment(nSegments)));
+ face.processEvents();
+
+ // no new data
+ BOOST_REQUIRE_EQUAL(face.sentData.size(), 1);
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestProducer
+BOOST_AUTO_TEST_SUITE_END() // Chunks
+
+} // namespace tests
+} // namespace chunks
+} // namespace ndn