]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: make chain test more robust and fix max chain size accounting 14669/head
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 13 Sep 2024 09:00:14 +0000 (11:00 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 13 Sep 2024 12:07:49 +0000 (14:07 +0200)
pdns/recursordist/pdns_recursor.cc
regression-tests.recursor-dnssec/recursortests.py
regression-tests.recursor-dnssec/test_Chain.py

index 01d2ecea565f8477d764c3522ea73350407107a9..d39fcd6d7d91d3fab56b555adfcbc7c1b359078a 100644 (file)
@@ -313,8 +313,8 @@ LWResult::Result asendto(const void* data, size_t len, int /* flags */,
         }
         chain.first->key->authReqChain.emplace(*fileDesc, qid); // we can chain
         auto maxLength = t_Counters.at(rec::Counter::maxChainLength);
-        if (currentChainSize > maxLength) {
-          t_Counters.at(rec::Counter::maxChainLength) = currentChainSize;
+        if (currentChainSize + 1 > maxLength) {
+          t_Counters.at(rec::Counter::maxChainLength) = currentChainSize + 1;
         }
         return LWResult::Result::Success;
       }
index 63fa230eade8d53635540b727308b2b4371db549..bb97883624fce73549da1d5123ef57f7899d6343 100644 (file)
@@ -12,6 +12,7 @@ import time
 import unittest
 import dns
 import dns.message
+import requests
 
 from proxyprotocol import ProxyProtocol
 
@@ -1197,3 +1198,23 @@ distributor-threads={threads}""".format(confdir=confdir,
         if data:
             message = dns.message.from_wire(data)
         return message
+
+    def checkMetrics(self, map):
+        self.waitForTCPSocket("127.0.0.1", self._wsPort)
+        headers = {'x-api-key': self._apiKey}
+        url = 'http://127.0.0.1:' + str(self._wsPort) + '/api/v1/servers/localhost/statistics'
+        r = requests.get(url, headers=headers, timeout=self._wsTimeout)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        count = 0
+        for entry in content:
+            for key, expected in map.items():
+                if entry['name'] == key:
+                    value = int(entry['value'])
+                    if callable(expected):
+                        self.assertTrue(expected(value))
+                    else:
+                        self.assertEqual(value, expected)
+                    count += 1
+        self.assertEqual(count, len(map))
index e962e1395af9264c9c9b23bb87b43ba4d9197d1d..6c20937b31e32a1691d47d5f093717a3bf523cd4 100644 (file)
@@ -8,29 +8,47 @@ class ChainTest(RecursorTest):
     These regression tests test the chaining of outgoing requests.
     """
     _confdir = 'Chain'
+    _wsPort = 8042
+    _wsTimeout = 2
+    _wsPassword = 'secretpassword'
+    _apiKey = 'secretapikey'
 
     _config_template = """dnssec=validate
     trace=no
-"""
+    devonly-regression-test-mode
+    webserver=yes
+    webserver-port=%d
+    webserver-address=127.0.0.1
+    webserver-password=%s
+    api-key=%s
+""" % (_wsPort, _wsPassword, _apiKey)
 
     def testBasic(self):
         """
         Tests the case of #14624. Sending many equal requests could lead to ServFail because of clashing
         waiter ids.
         """
+        # We actually do not check all responses, as experience show that packets may be dropped by the OS
+        # Instead, we check if a few counters in rec have the expected values.
         count = 200
-        name = '1.delay1.example.'
+        name = '9.delay1.example.'
         exp = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'TXT', 'a')
         for i in range(count):
             query = dns.message.make_query(name, 'TXT', want_dnssec=True)
             query.flags |= dns.flags.AD
             self._sock.send(query.to_wire())
 
-        for i in range(count):
-            data = self._sock.recv(4096)
-            res = dns.message.from_wire(data)
-            self.assertRcodeEqual(res, dns.rcode.NOERROR)
-            self.assertMessageIsAuthenticated(res)
-            self.assertRRsetInAnswer(res, exp)
-            self.assertMatchingRRSIGInAnswer(res, exp)
-        self._sock.settimeout(None)
+        # Just check one, as OS emptying of socket buffers can work against us
+        data = self._sock.recv(4096)
+        res = dns.message.from_wire(data)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageIsAuthenticated(res)
+        self.assertRRsetInAnswer(res, exp)
+        self.assertMatchingRRSIGInAnswer(res, exp)
+        time.sleep(1)
+
+        self.checkMetrics({
+            'max-chain-length': (lambda x: x <= count-1), # first request has count - 1 requests chained to it
+            'servfail-answers': 0,
+            'noerror-answers': (lambda x: x <= count),
+        })