]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Add unit tests for the NegCache
authorPieter Lexis <pieter.lexis@powerdns.com>
Thu, 6 Apr 2017 11:41:40 +0000 (13:41 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Fri, 7 Apr 2017 10:49:07 +0000 (12:49 +0200)
pdns/recursordist/Makefile.am
pdns/recursordist/test-negcache_cc.cc [new file with mode: 0644]

index 9344db76122398053981929d3b567e095e9d2a0c..c6e16a1055271e16ff6bae58570843d90e1ff403 100644 (file)
@@ -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 (file)
index 0000000..a2566f1
--- /dev/null
@@ -0,0 +1,303 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#include <boost/test/unit_test.hpp>
+
+#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>(DNSRecordContent::mastermake(qtype, QClass::IN, content));
+
+  ret.records.push_back(rec);
+
+  if (sigs) {
+    rec.d_type = QType::RRSIG;
+    rec.d_content = std::make_shared<RRSIGRecordContent>(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<string> 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()