From: Pieter Lexis Date: Thu, 6 Apr 2017 11:41:40 +0000 (+0200) Subject: rec: Add unit tests for the NegCache X-Git-Tag: rec-4.1.0-alpha1~166^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8cb955a8d05cb7324da553e6d8b41a88ec535e4;p=thirdparty%2Fpdns.git rec: Add unit tests for the NegCache --- diff --git a/pdns/recursordist/Makefile.am b/pdns/recursordist/Makefile.am index 9344db7612..c6e16a1055 100644 --- a/pdns/recursordist/Makefile.am +++ b/pdns/recursordist/Makefile.am @@ -226,6 +226,7 @@ testrunner_SOURCES = \ test-iputils_hh.cc \ test-misc_hh.cc \ test-nmtree.cc \ + test-negcache_cc.cc \ test-rcpgenerator_cc.cc \ test-recpacketcache_cc.cc \ test-syncres_cc.cc \ diff --git a/pdns/recursordist/test-negcache_cc.cc b/pdns/recursordist/test-negcache_cc.cc new file mode 100644 index 0000000000..a2566f1aa5 --- /dev/null +++ b/pdns/recursordist/test-negcache_cc.cc @@ -0,0 +1,303 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN +#include + +#include "negcache.hh" +#include "dnsrecords.hh" +#include "utility.hh" + +static recordsAndSignatures genRecsAndSigs(const DNSName& name, const uint16_t qtype, const string& content, bool sigs) { + recordsAndSignatures ret; + + DNSRecord rec; + rec.d_name = name; + rec.d_type = qtype; + rec.d_ttl = 600; + rec.d_place = DNSResourceRecord::AUTHORITY; + rec.d_content = shared_ptr(DNSRecordContent::mastermake(qtype, QClass::IN, content)); + + ret.records.push_back(rec); + + if (sigs) { + rec.d_type = QType::RRSIG; + rec.d_content = std::make_shared(QType(qtype).getName() + " 5 3 600 2100010100000000 2100010100000000 24567 dummy data"); + ret.signatures.push_back(rec); + } + + return ret; +} + +static NegCache::NegCacheEntry genNegCacheEntry(const DNSName& name, const DNSName& auth, const struct timeval& now, const uint16_t qtype=0) { + NegCache::NegCacheEntry ret; + + ret.d_name = name; + ret.d_qtype = QType(qtype); + ret.d_auth = auth; + ret.d_ttd = now.tv_sec + 600; + ret.authoritySOA = genRecsAndSigs(auth, QType::SOA, "ns1 hostmaster 1 2 3 4 5", true); + ret.DNSSECRecords = genRecsAndSigs(auth, QType::NSEC, "deadbeef", true); + + return ret; +} + +BOOST_AUTO_TEST_SUITE(negcache_cc) + +BOOST_AUTO_TEST_CASE(test_get_entry) { + /* Add a full name negative entry to the cache and attempt to get an entry for + * the A record. Should yield the full name does not exist entry + */ + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(0).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); +} + +BOOST_AUTO_TEST_CASE(test_get_NODATA_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now, 1)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(1).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); + + NegCache::NegCacheEntry ne2; + ret = cache.get(qname, QType(16), now, ne2); + BOOST_CHECK_EQUAL(ret, false); +} + +BOOST_AUTO_TEST_CASE(test_getRootNXTrust_entry) { + DNSName qname("com"); + DNSName auth("."); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + bool ret = cache.getRootNXTrust(qname, now, ne); + + BOOST_CHECK(ret); + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_qtype.getName(), QType(0).getName()); + BOOST_CHECK_EQUAL(ne.d_auth, auth); +} + +BOOST_AUTO_TEST_CASE(test_add_and_get_expired_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + now.tv_sec -= 1000; + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + + now.tv_sec += 1000; + bool ret = cache.get(qname, QType(1), now, ne); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne.d_name, DNSName()); + BOOST_CHECK_EQUAL(ne.d_auth, DNSName()); + BOOST_CHECK(ne.authoritySOA.records.empty()); +} + +BOOST_AUTO_TEST_CASE(test_add_updated_entry) { + DNSName qname("www2.powerdns.com"); + DNSName auth("powerdns.com"); + DNSName auth2("com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + cache.add(genNegCacheEntry(qname, auth, now)); + // Should override the existing entry for www2.powerdns.com + cache.add(genNegCacheEntry(qname, auth2, now)); + + BOOST_CHECK_EQUAL(cache.size(), 1); + + NegCache::NegCacheEntry ne; + cache.get(qname, QType(1), now, ne); + + BOOST_CHECK_EQUAL(ne.d_name, qname); + BOOST_CHECK_EQUAL(ne.d_auth, auth2); +} + +BOOST_AUTO_TEST_CASE(test_prune) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 400); + + cache.prune(100); + + BOOST_CHECK_EQUAL(cache.size(), 100); +} + +BOOST_AUTO_TEST_CASE(test_wipe_single) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + ne = genNegCacheEntry(auth, auth, now); + cache.add(ne); + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 401); + + // Should only wipe the powerdns.com entry + cache.wipe(auth); + BOOST_CHECK_EQUAL(cache.size(), 400); + + NegCache::NegCacheEntry ne2; + bool ret = cache.get(auth, QType(1), now, ne2); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne2.d_auth, DNSName()); + BOOST_CHECK_EQUAL(ne2.d_name, DNSName()); + + cache.wipe(DNSName("1.powerdns.com")); + BOOST_CHECK_EQUAL(cache.size(), 399); + + NegCache::NegCacheEntry ne3; + ret = cache.get(auth, QType(1), now, ne3); + + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ne3.d_auth, DNSName()); + BOOST_CHECK_EQUAL(ne3.d_name, DNSName()); +} + +BOOST_AUTO_TEST_CASE(test_wipe_subtree) { + string qname(".powerdns.com"); + string qname2("powerdns.org"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + ne = genNegCacheEntry(auth, auth, now); + cache.add(ne); + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname2), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 801); + + // Should wipe all the *.powerdns.com and powerdns.com entries + cache.wipe(auth, true); + BOOST_CHECK_EQUAL(cache.size(), 400); +} + +BOOST_AUTO_TEST_CASE(test_clear) { + string qname(".powerdns.com"); + DNSName auth("powerdns.com"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + NegCache cache; + NegCache::NegCacheEntry ne; + + for(int i = 0; i < 400; i++) { + ne = genNegCacheEntry(DNSName(std::to_string(i) + qname), auth, now); + cache.add(ne); + } + + BOOST_CHECK_EQUAL(cache.size(), 400); + cache.clear(); + BOOST_CHECK_EQUAL(cache.size(), 0); +} + +BOOST_AUTO_TEST_CASE(test_dumpToFile) { + NegCache cache; + vector expected; + expected.push_back("www1.powerdns.com. 600 IN TYPE0 VIA powerdns.com.\n"); + expected.push_back("www2.powerdns.com. 600 IN TYPE0 VIA powerdns.com.\n"); + + struct timeval now; + Utility::gettimeofday(&now, 0); + + cache.add(genNegCacheEntry(DNSName("www1.powerdns.com"), DNSName("powerdns.com"), now)); + cache.add(genNegCacheEntry(DNSName("www2.powerdns.com"), DNSName("powerdns.com"), now)); + + FILE* fp; + fp = tmpfile(); + if (!fp) + BOOST_FAIL("Temporary file could not be opened"); + + cache.dumpToFile(fp); + + rewind(fp); + char *line = nullptr; + size_t len = 0; + ssize_t read; + + for (const auto& str : expected) { + read = getline(&line, &len, fp); + if (read == -1) + BOOST_FAIL("Unable to read a line from the temp file"); + BOOST_CHECK_EQUAL(line, str); + } + fclose(fp); +} + +BOOST_AUTO_TEST_SUITE_END()