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"); }
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); }
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()); }
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); }
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); }
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"); }
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); } }
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; }
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 }