BOOST_AUTO_TEST_CASE_TEMPLATE(ChildSelector, T, InMemoryStorages)
{
  T ims;

  shared_ptr<Data> data = makeData("/a");
  ims.insert(*data);

  shared_ptr<Data> data2 = makeData("/b");
  ims.insert(*data2);

  shared_ptr<Data> data4 = makeData("/d");
  ims.insert(*data4);

  shared_ptr<Data> data5 = makeData("/c/c");
  ims.insert(*data5);

  shared_ptr<Data> data6 = makeData("/c/f");
  ims.insert(*data6);

  shared_ptr<Data> data7 = makeData("/c/n");
  ims.insert(*data7);

  shared_ptr<Interest> interest = makeInterest("/c");
  interest->setChildSelector(1);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK_EQUAL(found->getName(), "/c/n");

  shared_ptr<Interest> interest2 = makeInterest("/c");
  interest2->setChildSelector(0);

  shared_ptr<const Data> found2 = ims.find(*interest2);
  BOOST_CHECK_EQUAL(found2->getName(), "/c/c");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(ExcludeSelector, T, InMemoryStorages)
{
  T ims;

  shared_ptr<Data> data = makeData("/a");
  ims.insert(*data);

  shared_ptr<Data> data2 = makeData("/b");
  ims.insert(*data2);

  shared_ptr<Data> data3 = makeData("/c/a");
  ims.insert(*data3);

  shared_ptr<Data> data4 = makeData("/d");
  ims.insert(*data4);

  shared_ptr<Data> data5 = makeData("/c/c");
  ims.insert(*data5);

  shared_ptr<Data> data6 = makeData("/c/f");
  ims.insert(*data6);

  shared_ptr<Data> data7 = makeData("/c/n");
  ims.insert(*data7);

  shared_ptr<Interest> interest = makeInterest("/c");
  interest->setChildSelector(1);
  Exclude e;
  e.excludeOne (Name::Component("n"));
  interest->setExclude(e);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK_EQUAL(found->getName(), "/c/f");

  shared_ptr<Interest> interest2 = makeInterest("/c");
  interest2->setChildSelector(0);

  Exclude e2;
  e2.excludeOne (Name::Component("a"));
  interest2->setExclude(e2);

  shared_ptr<const Data> found2 = ims.find(*interest2);
  BOOST_CHECK_EQUAL(found2->getName(), "/c/c");

  shared_ptr<Interest> interest3 = makeInterest("/c");
  interest3->setChildSelector(0);

  Exclude e3;
  e3.excludeOne (Name::Component("c"));
  interest3->setExclude(e3);

  shared_ptr<const Data> found3 = ims.find(*interest3);
  BOOST_CHECK_EQUAL(found3->getName(), "/c/a");
}
BOOST_AUTO_TEST_CASE_TEMPLATE(CombineReasons, Combination, NackReasonCombinations)
{
  Combination combination;

  shared_ptr<fib::Entry> fibEntry = fib.insert(Name()).first;
  fibEntry->addNextHop(face3, 10);
  fibEntry->addNextHop(face4, 20);
  fibEntry->addNextHop(face5, 30);

  shared_ptr<Interest> interest1 = makeInterest("/F6sEwB24I", 282);
  shared_ptr<pit::Entry> pitEntry = pit.insert(*interest1).first;
  pitEntry->insertOrUpdateInRecord(face1, *interest1);
  pitEntry->insertOrUpdateOutRecord(face3, *interest1);
  pitEntry->insertOrUpdateOutRecord(face4, *interest1);

  lp::Nack nack3 = makeNack("/F6sEwB24I", 282, combination.getX());
  pitEntry->getOutRecord(*face3)->setIncomingNack(nack3);
  strategy.afterReceiveNack(*face3, nack3, fibEntry, pitEntry);

  BOOST_CHECK_EQUAL(strategy.sendNackHistory.size(), 0);

  lp::Nack nack4 = makeNack("/F6sEwB24I", 282, combination.getY());
  pitEntry->getOutRecord(*face4)->setIncomingNack(nack4);
  strategy.afterReceiveNack(*face4, nack4, fibEntry, pitEntry);

  BOOST_REQUIRE_EQUAL(strategy.sendNackHistory.size(), 1);
  BOOST_CHECK_EQUAL(strategy.sendNackHistory[0].pitEntry, pitEntry);
  BOOST_CHECK_EQUAL(strategy.sendNackHistory[0].outFaceId, face1->getId());
  BOOST_CHECK_EQUAL(strategy.sendNackHistory[0].header.getReason(), combination.getExpectedResult());
}
BOOST_AUTO_TEST_CASE_TEMPLATE(PublisherKeySelector2, T, InMemoryStorages)
{
  T ims;
  Name name("/insert/withkey");
  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  Name name2("/insert/withkey2");
  shared_ptr<Data> data2 = make_shared<Data>(name2);

  Name keyName("/somewhere/key");
  const ndn::KeyLocator locator(keyName);

  ndn::SignatureSha256WithRsa fakeSignature;
  fakeSignature.setValue(makeEmptyBlock(tlv::SignatureValue));

  fakeSignature.setKeyLocator(locator);
  data2->setSignature(fakeSignature);
  data2->wireEncode();

  ims.insert(*data2);

  shared_ptr<Interest> interest = makeInterest(name2);
  interest->setPublisherPublicKeyLocator(locator);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK(found != nullptr);
  BOOST_CHECK_EQUAL(found->getName(), data2->getName());
}
BOOST_AUTO_TEST_CASE_TEMPLATE(MinMaxComponentsSelector, T, InMemoryStorages)
{
  T ims;

  shared_ptr<Data> data = makeData("/a");
  ims.insert(*data);

  shared_ptr<Data> data2 = makeData("/b");
  ims.insert(*data2);

  shared_ptr<Data> data4 = makeData("/d");
  ims.insert(*data4);

  shared_ptr<Data> data5 = makeData("/c/c/1/2/3/4/5/6");
  ims.insert(*data5);

  shared_ptr<Data> data6 = makeData("/c/c/6/7/8/9");
  ims.insert(*data6);

  shared_ptr<Data> data7 = makeData("/c/c/1/2/3");
  ims.insert(*data7);

  shared_ptr<Data> data8 = makeData("/c/c/1");
  ims.insert(*data8);

  shared_ptr<Interest> interest = makeInterest("/c/c");
  interest->setMinSuffixComponents(3);
  interest->setChildSelector(0);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK_EQUAL(found->getName(), "/c/c/1/2/3");

  shared_ptr<Interest> interest2 = makeInterest("/c/c");
  interest2->setMinSuffixComponents(4);
  interest2->setChildSelector(1);

  shared_ptr<const Data> found2 = ims.find(*interest2);
  BOOST_CHECK_EQUAL(found2->getName(), "/c/c/6/7/8/9");

  shared_ptr<Interest> interest3 = makeInterest("/c/c");
  interest3->setMaxSuffixComponents(2);
  interest3->setChildSelector(1);

  shared_ptr<const Data> found3 = ims.find(*interest3);
  BOOST_CHECK_EQUAL(found3->getName(), "/c/c/1");
}
Beispiel #6
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestNack, TransportType, Transports, FaceFixture<TransportType>)
{
  int nNacks = 0;
  this->face.expressInterest(*makeInterest("/localhost/non-existent-should-nack"),
    [] (const Interest&, const Data&) { BOOST_ERROR("unexpected Data"); },
    [&] (const Interest&, const lp::Nack&) { ++nNacks; },
    [] (const Interest&) { BOOST_ERROR("unexpected timeout"); });

  this->face.processEvents();
  BOOST_CHECK_EQUAL(nNacks, 1);
}
Beispiel #7
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestData, TransportType, Transports, FaceFixture<TransportType>)
{
  int nData = 0;
  this->face.expressInterest(*makeInterest("/", true),
    [&] (const Interest&, const Data&) { ++nData; },
    [] (const Interest&, const lp::Nack&) { BOOST_ERROR("unexpected Nack"); },
    [] (const Interest&) { BOOST_ERROR("unexpected timeout"); });

  this->face.processEvents();
  BOOST_CHECK_EQUAL(nData, 1);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndFind, T, InMemoryStorages)
{
  T ims;

  Name name("/insert/and/find");

  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  shared_ptr<Interest> interest = makeInterest(name);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK(found != nullptr);
  BOOST_CHECK_EQUAL(data->getName(), found->getName());
}
Beispiel #9
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(ExpressInterestTimeout, TransportType, Transports, FaceFixture<TransportType>)
{
  // add route toward null face so Interest would timeout instead of getting Nacked
  executeCommand("nfdc route add /localhost/non-existent-should-timeout null://");
  std::this_thread::sleep_for(std::chrono::milliseconds(200)); // wait for FIB update to take effect

  int nTimeouts = 0;
  this->face.expressInterest(*makeInterest("/localhost/non-existent-should-timeout", false, 1_s),
    [] (const Interest&, const Data&) { BOOST_ERROR("unexpected Data"); },
    [] (const Interest&, const lp::Nack&) { BOOST_ERROR("unexpected Nack"); },
    [&] (const Interest&) { ++nTimeouts; });

  this->face.processEvents();
  BOOST_CHECK_EQUAL(nTimeouts, 1);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndNotFind, T, InMemoryStorages)
{
  T ims;

  Name name("/insert/and/find");
  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  Name name2("/not/find");
  shared_ptr<Interest> interest = makeInterest(name2);

  shared_ptr<const Data> found = ims.find(*interest);

  BOOST_CHECK_EQUAL(found.get(), static_cast<const Data*>(0));
}
BOOST_AUTO_TEST_CASE_TEMPLATE(ImplicitDigestSelector, T, InMemoryStorages)
{
  T ims;

  Name name("/digest/works");
  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  shared_ptr<Data> data2 = makeData("/a");
  ims.insert(*data2);

  shared_ptr<Data> data3 = makeData("/z/z/z");
  ims.insert(*data3);

  ndn::ConstBufferPtr digest1 = ndn::crypto::computeSha256Digest(data->wireEncode().wire(),
                                                                 data->wireEncode().size());

  shared_ptr<Interest> interest = makeInterest("");
  interest->setName(Name(name).appendImplicitSha256Digest(digest1->buf(), digest1->size()));
  interest->setMinSuffixComponents(0);
  interest->setMaxSuffixComponents(0);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_REQUIRE(found != nullptr);
  BOOST_CHECK_EQUAL(found->getName(), name);

  shared_ptr<Interest> interest2 = makeInterest("");
  uint8_t digest2[32] = {0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};
  interest2->setName(Name(name).appendImplicitSha256Digest(digest2, 32));
  interest2->setMinSuffixComponents(0);
  interest2->setMaxSuffixComponents(0);

  shared_ptr<const Data> notfound = ims.find(*interest2);
  BOOST_CHECK(notfound == nullptr);
}
Beispiel #12
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhostInterestToLocal,
                                 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
{
  fib::Entry* fibEntry = this->fib.insert("/localhost/A").first;
  fibEntry->addNextHop(*this->localFace4, 10);

  shared_ptr<Interest> interest = makeInterest("/localhost/A/1");
  shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
  pitEntry->insertOrUpdateInRecord(*this->localFace3, *interest);

  this->waitForStrategyAction(
    [&] { this->strategy.afterReceiveInterest(*this->localFace3, *interest, pitEntry); });

  BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 1);
  BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
  BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(PublisherKeySelector, T, InMemoryStorages)
{
  T ims;

  Name name("/insert/withkey");
  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  shared_ptr<Interest> interest = makeInterest(name);
  Name keyName("/somewhere/key");

  ndn::KeyLocator locator(keyName);
  interest->setPublisherPublicKeyLocator(locator);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK(found == nullptr);
}
BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocalAndLocal,
                                 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
{
  fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
  fibEntry->addOrUpdateNextHop(*this->nonLocalFace2, 0, 10);
  fibEntry->addOrUpdateNextHop(*this->localFace4, 0, 20);

  auto interest = makeInterest("/localhop/A/1");
  shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
  pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, 0, *interest);

  BOOST_REQUIRE(this->strategy.waitForAction(
    [&] { this->strategy.afterReceiveInterest(FaceEndpoint(*this->nonLocalFace1, 0), *interest, pitEntry); },
    this->limitedIo));

  BOOST_REQUIRE_EQUAL(this->strategy.sendInterestHistory.size(), 1);
  BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.back().outFaceId, this->localFace4->getId());
  BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
  BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.size(), 0);
}
Beispiel #15
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopInterestToNonLocal,
                                 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
{
  fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
  fibEntry->addNextHop(*this->nonLocalFace2, 10);

  shared_ptr<Interest> interest = makeInterest("/localhop/A/1");
  shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
  pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);

  this->waitForStrategyAction(
    [&] { this->strategy.afterReceiveInterest(*this->nonLocalFace1, *interest, pitEntry); },
    1 + T::willSendNackNoRoute());

  BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
  BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 1);
  if (T::willSendNackNoRoute()) {
    BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
    BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
  }
}
BOOST_AUTO_TEST_CASE_TEMPLATE(InsertAndEvict, T, InMemoryStoragesLimited)
{
  T ims(2);

  Name name("/insert/1");
  shared_ptr<Data> data = makeData(name);
  ims.insert(*data);

  Name name2("/insert/2");
  shared_ptr<Data> data2 = makeData(name2);
  ims.insert(*data2);

  Name name3("/insert/3");
  shared_ptr<Data> data3 = makeData(name3);
  ims.insert(*data3);

  BOOST_CHECK_EQUAL(ims.size(), 2);

  shared_ptr<Interest> interest = makeInterest(name);
  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK(found == nullptr);
}
BOOST_AUTO_TEST_CASE_TEMPLATE(ChildSelector2, T, InMemoryStorages)
{
  T ims;

  shared_ptr<Data> data = makeData("/a/b/1");
  ims.insert(*data);

  shared_ptr<Data> data2 = makeData("/a/b/2");
  ims.insert(*data2);

  shared_ptr<Data> data3 = makeData("/a/z/1");
  ims.insert(*data3);

  shared_ptr<Data> data4 = makeData("/a/z/2");
  ims.insert(*data4);

  shared_ptr<Interest> interest = makeInterest("/a");
  interest->setChildSelector(1);

  shared_ptr<const Data> found = ims.find(*interest);
  BOOST_CHECK_EQUAL(found->getName(), "/a/z/1");
}
Beispiel #18
0
BOOST_FIXTURE_TEST_CASE_TEMPLATE(LocalhopNackToNonLocal,
                                 T, Tests, StrategyScopeControlFixture<typename T::Strategy>)
{
  fib::Entry* fibEntry = this->fib.insert("/localhop/A").first;
  fibEntry->addNextHop(*this->localFace4, 10);
  fibEntry->addNextHop(*this->nonLocalFace2, 20);

  shared_ptr<Interest> interest = makeInterest("/localhop/A/1", 1377);
  shared_ptr<pit::Entry> pitEntry = this->pit.insert(*interest).first;
  pitEntry->insertOrUpdateInRecord(*this->nonLocalFace1, *interest);
  lp::Nack nack = makeNack("/localhop/A/1", 1377, lp::NackReason::NO_ROUTE);
  pitEntry->insertOrUpdateOutRecord(*this->localFace4, *interest)->setIncomingNack(nack);

  this->waitForStrategyAction(
    [&] { this->strategy.afterReceiveNack(*this->localFace4, nack, pitEntry); },
    T::canProcessNack());

  BOOST_CHECK_EQUAL(this->strategy.sendInterestHistory.size(), 0);
  BOOST_CHECK_EQUAL(this->strategy.rejectPendingInterestHistory.size(), 0);
  if (T::canProcessNack()) {
    BOOST_REQUIRE_EQUAL(this->strategy.sendNackHistory.size(), 1);
    BOOST_CHECK_EQUAL(this->strategy.sendNackHistory.back().header.getReason(), lp::NackReason::NO_ROUTE);
  }
}
Beispiel #19
0
  std::this_thread::sleep_for(std::chrono::milliseconds(200)); // wait for FIB update to take effect

  int nTimeouts = 0;
  this->face.expressInterest(*makeInterest("/localhost/non-existent-should-timeout", false, 1_s),
    [] (const Interest&, const Data&) { BOOST_ERROR("unexpected Data"); },
    [] (const Interest&, const lp::Nack&) { BOOST_ERROR("unexpected Nack"); },
    [&] (const Interest&) { ++nTimeouts; });

  this->face.processEvents();
  BOOST_CHECK_EQUAL(nTimeouts, 1);
}

BOOST_FIXTURE_TEST_CASE_TEMPLATE(OversizedInterest, TransportType, Transports, FaceFixture<TransportType>)
{
  BOOST_CHECK_THROW(do {
    this->face.expressInterest(*makeInterest(makeVeryLongName()), nullptr, nullptr, nullptr);
    this->face.processEvents();
  } while (false), Face::OversizedPacketError);
}

BOOST_AUTO_TEST_SUITE_END() // Consumer

BOOST_AUTO_TEST_SUITE(Producer)

BOOST_FIXTURE_TEST_CASE_TEMPLATE(RegisterUnregisterPrefix, TransportType, Transports, FaceFixture<TransportType>)
{
  this->terminateAfter(4_s);

  int nRegSuccess = 0, nUnregSuccess = 0;
  auto id = this->face.registerPrefix("/Hello/World",
    [&] (const Name&) { ++nRegSuccess; },
 Interest&
 startInterest(const Name& name)
 {
   m_interest = makeInterest(name);
   return *m_interest;
 }
Beispiel #21
0
BOOST_FIXTURE_TEST_CASE(StatusDataset, DispatcherFixture)
{
  static Block smallBlock("\x81\x01\0x01", 3);
  static Block largeBlock = [] () -> Block {
    EncodingBuffer encoder;
    for (size_t i = 0; i < 2500; ++i) {
      encoder.prependByte(1);
    }
    encoder.prependVarNumber(2500);
    encoder.prependVarNumber(129);
    return encoder.block();
  }();

  dispatcher.addStatusDataset("test/small",
                              makeTestAuthorization(),
                              [] (const Name& prefix, const Interest& interest,
                                  StatusDatasetContext& context) {
                                context.append(smallBlock);
                                context.append(smallBlock);
                                context.append(smallBlock);
                                context.end();
                              });

  dispatcher.addStatusDataset("test/large",
                              makeTestAuthorization(),
                              [] (const Name& prefix, const Interest& interest,
                                  StatusDatasetContext& context) {
                                context.append(largeBlock);
                                context.append(largeBlock);
                                context.append(largeBlock);
                                context.end();
                              });

  dispatcher.addStatusDataset("test/reject",
                              makeTestAuthorization(),
                              [] (const Name& prefix, const Interest& interest,
                                  StatusDatasetContext& context) {
                                context.reject();
                              });

  dispatcher.addTopPrefix("/root");
  advanceClocks(time::milliseconds(1));
  face.sentData.clear();

  face.receive(*makeInterest("/root/test/small/%80%00")); // returns 403
  face.receive(*makeInterest("/root/test/small/%80%00/invalid")); // returns 403
  face.receive(*makeInterest("/root/test/small/%80%00/silent")); // silently ignored
  advanceClocks(time::milliseconds(1), 20);
  BOOST_CHECK_EQUAL(face.sentData.size(), 2);

  BOOST_CHECK(face.sentData[0].getContentType() == tlv::ContentType_Blob);
  BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 403);
  BOOST_CHECK(face.sentData[1].getContentType() == tlv::ContentType_Blob);
  BOOST_CHECK_EQUAL(ControlResponse(face.sentData[1].getContent().blockFromValue()).getCode(), 403);

  face.sentData.clear();

  auto interestSmall = *makeInterest("/root/test/small/valid");
  face.receive(interestSmall);
  advanceClocks(time::milliseconds(1), 10);

  // one data packet is generated and sent to both places
  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
  BOOST_CHECK_EQUAL(storage.size(), 1);

  auto fetchedData = storage.find(interestSmall);
  BOOST_REQUIRE(fetchedData != nullptr);
  BOOST_CHECK(face.sentData[0].wireEncode() == fetchedData->wireEncode());

  face.receive(*makeInterest(Name("/root/test/small/valid").appendVersion(10))); // should be ignored
  face.receive(*makeInterest(Name("/root/test/small/valid").appendSegment(20))); // should be ignored
  advanceClocks(time::milliseconds(1), 10);
  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
  BOOST_CHECK_EQUAL(storage.size(), 1);

  Block content = face.sentData[0].getContent();
  BOOST_CHECK_NO_THROW(content.parse());

  BOOST_CHECK_EQUAL(content.elements().size(), 3);
  BOOST_CHECK(content.elements()[0] == smallBlock);
  BOOST_CHECK(content.elements()[1] == smallBlock);
  BOOST_CHECK(content.elements()[2] == smallBlock);

  storage.erase("/", true); // clear the storage
  face.sentData.clear();
  face.receive(*makeInterest("/root/test/large/valid"));
  advanceClocks(time::milliseconds(1), 10);

  // two data packets are generated, the first one will be sent to both places
  // while the second one will only be inserted into the in-memory storage
  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
  BOOST_CHECK_EQUAL(storage.size(), 2);

  // segment0 should be sent through the face
  const auto& component = face.sentData[0].getName().at(-1);
  BOOST_CHECK(component.isSegment());
  BOOST_CHECK_EQUAL(component.toSegment(), 0);

  std::vector<Data> dataInStorage;
  std::copy(storage.begin(), storage.end(), std::back_inserter(dataInStorage));

  // the Data sent through the face should be the same as the first Data in the storage
  BOOST_CHECK_EQUAL(face.sentData[0].getName(), dataInStorage[0].getName());
  BOOST_CHECK(face.sentData[0].getContent() == dataInStorage[0].getContent());

  content = [&dataInStorage] () -> Block {
    EncodingBuffer encoder;
    size_t valueLength = encoder.prependByteArray(dataInStorage[1].getContent().value(),
                                                  dataInStorage[1].getContent().value_size());
    valueLength += encoder.prependByteArray(dataInStorage[0].getContent().value(),
                                            dataInStorage[0].getContent().value_size());
    encoder.prependVarNumber(valueLength);
    encoder.prependVarNumber(tlv::Content);
    return encoder.block();
  }();

  BOOST_CHECK_NO_THROW(content.parse());
  BOOST_CHECK_EQUAL(content.elements().size(), 3);
  BOOST_CHECK(content.elements()[0] == largeBlock);
  BOOST_CHECK(content.elements()[1] == largeBlock);
  BOOST_CHECK(content.elements()[2] == largeBlock);

  storage.erase("/", true);// clear the storage
  face.sentData.clear();
  face.receive(*makeInterest("/root/test/reject/%80%00/valid")); // returns nack
  advanceClocks(time::milliseconds(1));
  BOOST_CHECK_EQUAL(face.sentData.size(), 1);
  BOOST_CHECK(face.sentData[0].getContentType() == tlv::ContentType_Nack);
  BOOST_CHECK_EQUAL(ControlResponse(face.sentData[0].getContent().blockFromValue()).getCode(), 400);
  BOOST_CHECK_EQUAL(storage.size(), 0); // the nack packet will not be inserted into the in-memory storage
}