From: Remi Gacogne Date: Mon, 11 Jan 2016 09:45:23 +0000 (+0100) Subject: dnsdist: More regression tests cleanups X-Git-Tag: dnsdist-1.0.0-alpha2~100^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F3207%2Fhead;p=thirdparty%2Fpdns.git dnsdist: More regression tests cleanups - Add a timeout on all queue operations - Give dnsdist more time to start in the DNSCrypt tests, since the key material has to be generated - Clear the response counters and the queues before every test - Add a one-line description for tests, displayed in verbose mode --- diff --git a/regression-tests.dnsdist/dnsdisttests.py b/regression-tests.dnsdist/dnsdisttests.py index f947359004..3afcded217 100644 --- a/regression-tests.dnsdist/dnsdisttests.py +++ b/regression-tests.dnsdist/dnsdisttests.py @@ -28,6 +28,8 @@ class DNSDistTest(unittest.TestCase): _testServerPort = 5350 _toResponderQueue = Queue.Queue() _fromResponderQueue = Queue.Queue() + _queueTimeout = 1 + _dnsdistStartupDelay = 2 _dnsdist = None _responsesCounter = {} _config_template = """ @@ -54,9 +56,6 @@ class DNSDistTest(unittest.TestCase): @classmethod def startResponders(cls): print("Launching responders..") - # clear counters - for key in cls._responsesCounter: - cls._responsesCounter[key] = 0 cls._UDPResponder = threading.Thread(name='UDP Responder', target=cls.UDPResponder, args=[cls._testServerPort]) cls._UDPResponder.setDaemon(True) @@ -90,7 +89,8 @@ class DNSDistTest(unittest.TestCase): if 'DNSDIST_FAST_TESTS' in os.environ: delay = 0.5 else: - delay = 2 + delay = cls._dnsdistStartupDelay + time.sleep(delay) if cls._dnsdist.poll() is not None: @@ -142,15 +142,19 @@ class DNSDistTest(unittest.TestCase): while True: data, addr = sock.recvfrom(4096) request = dns.message.from_wire(data) + answered = False if len(request.question) != 1: print("Skipping query with question count %d" % (len(request.question))) continue if str(request.question[0].name).endswith('tests.powerdns.com.') and not cls._toResponderQueue.empty(): - response = cls._toResponderQueue.get() - response.id = request.id - cls._fromResponderQueue.put(request) - cls.ResponderIncrementCounter() - else: + response = cls._toResponderQueue.get(True, cls._queueTimeout) + if response: + response.id = request.id + cls._fromResponderQueue.put(request, True, cls._queueTimeout) + cls.ResponderIncrementCounter() + answered = True + + if not answered: # unexpected query, or health check response = dns.message.make_response(request) if request.question[0].rdclass == dns.rdataclass.IN: @@ -186,6 +190,7 @@ class DNSDistTest(unittest.TestCase): sock.listen(100) while True: + answered = False (conn, address) = sock.accept() conn.settimeout(2.0) data = conn.recv(2) @@ -196,11 +201,14 @@ class DNSDistTest(unittest.TestCase): print("Skipping query with question count %d" % (len(request.question))) continue if str(request.question[0].name).endswith('tests.powerdns.com.') and not cls._toResponderQueue.empty(): - response = cls._toResponderQueue.get() - response.id = request.id - cls._fromResponderQueue.put(request) - cls.ResponderIncrementCounter() - else: + response = cls._toResponderQueue.get(True, cls._queueTimeout) + if response: + response.id = request.id + cls._fromResponderQueue.put(request, True, cls._queueTimeout) + cls.ResponderIncrementCounter() + answered = True + + if not answered: # unexpected query, or health check response = dns.message.make_response(request) if request.question[0].rdclass == dns.rdataclass.IN: @@ -228,7 +236,7 @@ class DNSDistTest(unittest.TestCase): @classmethod def sendUDPQuery(cls, query, response, useQueue=True, timeout=2.0): if useQueue: - cls._toResponderQueue.put(response) + cls._toResponderQueue.put(response, True, timeout) if timeout: cls._sock.settimeout(timeout) @@ -245,7 +253,7 @@ class DNSDistTest(unittest.TestCase): receivedQuery = None message = None if useQueue and not cls._fromResponderQueue.empty(): - receivedQuery = cls._fromResponderQueue.get(query) + receivedQuery = cls._fromResponderQueue.get(True, timeout) if data: message = dns.message.from_wire(data) return (receivedQuery, message) @@ -253,7 +261,7 @@ class DNSDistTest(unittest.TestCase): @classmethod def sendTCPQuery(cls, query, response, useQueue=True, timeout=2.0): if useQueue: - cls._toResponderQueue.put(response) + cls._toResponderQueue.put(response, True, timeout) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if timeout: sock.settimeout(timeout) @@ -280,7 +288,22 @@ class DNSDistTest(unittest.TestCase): receivedQuery = None message = None if useQueue and not cls._fromResponderQueue.empty(): - receivedQuery = cls._fromResponderQueue.get(query) + receivedQuery = cls._fromResponderQueue.get(True, timeout) if data: message = dns.message.from_wire(data) return (receivedQuery, message) + + def setUp(self): + # This function is called before every tests + + # Clear the responses counters + for key in self._responsesCounter: + self._responsesCounter[key] = 0 + + # Make sure the queues are empty, in case + # a previous test failed + while not self._toResponderQueue.empty(): + self._toResponderQueue.get(False) + + while not self._fromResponderQueue.empty(): + self._toResponderQueue.get(False) diff --git a/regression-tests.dnsdist/test_Advanced.py b/regression-tests.dnsdist/test_Advanced.py index 9376b81cb9..a951f2fdd4 100644 --- a/regression-tests.dnsdist/test_Advanced.py +++ b/regression-tests.dnsdist/test_Advanced.py @@ -18,6 +18,8 @@ class TestAdvancedFixupCase(DNSDistTest): def testAdvancedFixupCase(self): """ + Advanced: Fixup Case + Send a query with lower and upper chars, make the backend return a lowercase version, check that dnsdist fixes the response. @@ -61,6 +63,8 @@ class TestAdvancedRemoveRD(DNSDistTest): def testAdvancedNoRD(self): """ + Advanced: No RD + Send a query with RD, check that dnsdist clears the RD flag. """ @@ -95,6 +99,8 @@ class TestAdvancedRemoveRD(DNSDistTest): def testAdvancedKeepRD(self): """ + Advanced: No RD canary + Send a query with RD for a canary domain, check that dnsdist does not clear the RD flag. """ @@ -135,6 +141,8 @@ class TestAdvancedAddCD(DNSDistTest): def testAdvancedSetCD(self): """ + Advanced: Set CD + Send a query with CD cleared, check that dnsdist set the CD flag. """ @@ -169,6 +177,8 @@ class TestAdvancedAddCD(DNSDistTest): def testAdvancedKeepNoCD(self): """ + Advanced: Preserve CD canary + Send a query without CD for a canary domain, check that dnsdist does not set the CD flag. """ @@ -209,6 +219,8 @@ class TestAdvancedSpoof(DNSDistTest): def testSpoofA(self): """ + Advanced: Spoof A + Send an A query to "spoof.tests.powerdns.com.", check that dnsdist sends a spoofed result. """ @@ -236,6 +248,8 @@ class TestAdvancedSpoof(DNSDistTest): def testSpoofAAAA(self): """ + Advanced: Spoof AAAA + Send an AAAA query to "spoof.tests.powerdns.com.", check that dnsdist sends a spoofed result. """ @@ -263,6 +277,8 @@ class TestAdvancedSpoof(DNSDistTest): def testSpoofCNAME(self): """ + Advanced: Spoof CNAME + Send an A query for "cnamespoof.tests.powerdns.com.", check that dnsdist sends a spoofed result. """ @@ -297,6 +313,8 @@ class TestAdvancedPoolRouting(DNSDistTest): def testPolicyPool(self): """ + Advanced: Set pool by qname + Send an A query to "pool.tests.powerdns.com.", check that dnsdist routes the query to the "real" pool. """ @@ -324,6 +342,8 @@ class TestAdvancedPoolRouting(DNSDistTest): def testDefaultPool(self): """ + Advanced: Set pool by qname canary + Send an A query to "notpool.tests.powerdns.com.", check that dnsdist sends no response (no servers in the default pool). @@ -369,6 +389,8 @@ class TestAdvancedRoundRobinLB(DNSDistTest): def testRR(self): """ + Advanced: Round Robin + Send 100 A queries to "rr.tests.powerdns.com.", check that dnsdist routes half of it to each backend. """ @@ -383,10 +405,6 @@ class TestAdvancedRoundRobinLB(DNSDistTest): '192.0.2.1') response.answer.append(rrset) - # clear counters - for key in TestAdvancedRoundRobinLB._responsesCounter: - TestAdvancedRoundRobinLB._responsesCounter[key] = 0 - # the round robin counter is shared for UDP and TCP, # so we need to do UDP then TCP to have a clean count for idx in range(numberOfQueries): @@ -421,6 +439,8 @@ class TestAdvancedRoundRobinLBOneDown(DNSDistTest): def testRRWithOneDown(self): """ + Advanced: Round Robin with one server down + Send 100 A queries to "rr.tests.powerdns.com.", check that dnsdist routes all of it to the only backend up. """ @@ -468,6 +488,8 @@ class TestAdvancedACL(DNSDistTest): def testACLBlocked(self): """ + Advanced: ACL blocked + Send an A query to "tests.powerdns.com.", we expect no response since 127.0.0.1 is not on the ACL. @@ -490,6 +512,8 @@ class TestAdvancedDelay(DNSDistTest): def testDelayed(self): """ + Advanced: Delayed + Send an A query to "tests.powerdns.com.", check that the response delay is longer than 1000 ms over UDP, less than that over TCP. diff --git a/regression-tests.dnsdist/test_Basics.py b/regression-tests.dnsdist/test_Basics.py index c54d841435..286d7cad0c 100644 --- a/regression-tests.dnsdist/test_Basics.py +++ b/regression-tests.dnsdist/test_Basics.py @@ -8,6 +8,8 @@ class TestBasics(DNSDistTest): def testBlockedA(self): """ + Basics: Blocked A query + Send an A query for the powerdns.org domain, which is blocked by configuration. We expect no response. @@ -22,7 +24,7 @@ class TestBasics(DNSDistTest): def testAWithECS(self): """ - Send an A query with an ECS value. + Basics: A query with an ECS value """ name = 'awithecs.tests.powerdns.com.' ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4') @@ -50,7 +52,7 @@ class TestBasics(DNSDistTest): def testSimpleA(self): """ - Send a simple A query without EDNS. + Basics: A query without EDNS """ name = 'simplea.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN', use_edns=False) @@ -80,6 +82,8 @@ class TestBasics(DNSDistTest): def testAnyIsTruncated(self): """ + Basics: Truncate ANY query + dnsdist is configured to reply with TC to ANY queries, send an ANY query and check the result. """ @@ -98,6 +102,8 @@ class TestBasics(DNSDistTest): def testTruncateTC(self): """ + Basics: Truncate TC + dnsdist is configured to truncate TC (default), we make the backend send responses with TC set and additional content, @@ -128,6 +134,8 @@ class TestBasics(DNSDistTest): def testRegexReturnsRefused(self): """ + Basics: Refuse query matching regex + dnsdist is configured to reply 'refused' for query matching "evil[0-9]{4,}\\.regex\\.tests\\.powerdns\\.com$". We send a query for evil4242.powerdns.com @@ -148,6 +156,8 @@ class TestBasics(DNSDistTest): def testDomainAndQTypeReturnsNotImplemented(self): """ + Basics: NOTIMPL for specific name and qtype + dnsdist is configured to reply 'not implemented' for query matching "nameAndQtype.tests.powerdns.com." AND qtype TXT/ We send a TXT query for "nameAndQtype.powerdns.com." @@ -168,6 +178,8 @@ class TestBasics(DNSDistTest): def testDomainWithoutQTypeIsNotAffected(self): """ + Basics: NOTIMPL qtype canary + dnsdist is configured to reply 'not implemented' for query matching "nameAndQtype.tests.powerdns.com." AND qtype TXT/ We send a A query for "nameAndQtype.tests.powerdns.com." @@ -201,6 +213,8 @@ class TestBasics(DNSDistTest): def testOtherDomainANDQTypeIsNotAffected(self): """ + Basics: NOTIMPL qname canary + dnsdist is configured to reply 'not implemented' for query matching "nameAndQtype.tests.powerdns.com." AND qtype TXT/ We send a TXT query for "OtherNameAndQtype.tests.powerdns.com." diff --git a/regression-tests.dnsdist/test_DNSCrypt.py b/regression-tests.dnsdist/test_DNSCrypt.py index 3bb808f14e..1b754514f7 100644 --- a/regression-tests.dnsdist/test_DNSCrypt.py +++ b/regression-tests.dnsdist/test_DNSCrypt.py @@ -32,10 +32,11 @@ class TestDNSCrypt(DNSDistTest): _resolverCertificateValidFrom = time.time() - 60 _resolverCertificateValidUntil = time.time() + 7200 _config_params = ['_resolverCertificateSerial', '_resolverCertificateValidFrom', '_resolverCertificateValidUntil', '_dnsDistPortDNSCrypt', '_providerName', '_testServerPort'] + _dnsdistStartupDelay = 10 def testSimpleA(self): """ - Send an encrypted A query. + DNSCrypt: encrypted A query """ client = dnscrypt.DNSCryptClient(self._providerName, self._providerFingerprint, "127.0.0.1", 8443) name = 'a.dnscrypt.tests.powerdns.com.' @@ -64,6 +65,8 @@ class TestDNSCrypt(DNSDistTest): def testResponseLargerThanPaddedQuery(self): """ + DNSCrypt: response larger than query + Send a small encrypted query (don't forget to take the padding into account) and check that the response is truncated. diff --git a/regression-tests.dnsdist/test_EdnsClientSubnet.py b/regression-tests.dnsdist/test_EdnsClientSubnet.py index 7147bb9952..949edb7bba 100644 --- a/regression-tests.dnsdist/test_EdnsClientSubnet.py +++ b/regression-tests.dnsdist/test_EdnsClientSubnet.py @@ -30,6 +30,8 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest): def testWithoutEDNS(self): """ + ECS: No existing EDNS + Send a query without EDNS, check that the query received by the responder has the correct ECS value and that the response received from dnsdist does not @@ -67,6 +69,8 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest): def testWithEDNSNoECS(self): """ + ECS: Existing EDNS without ECS + Send a query with EDNS but no ECS value. Check that the query received by the responder has a valid ECS value and that the response @@ -104,6 +108,8 @@ class TestEdnsClientSubnetNoOverride(DNSDistTest): def testWithEDNSECS(self): """ + ECS: Existing EDNS with ECS + Send a query with EDNS and a crafted ECS value. Check that the query received by the responder has the initial ECS value (not overwritten) @@ -162,6 +168,8 @@ class TestEdnsClientSubnetOverride(DNSDistTest): def testWithoutEDNS(self): """ + ECS Override: No existing EDNS + Send a query without EDNS, check that the query received by the responder has the correct ECS value and that the response received from dnsdist does not @@ -199,6 +207,8 @@ class TestEdnsClientSubnetOverride(DNSDistTest): def testWithEDNSNoECS(self): """ + ECS Override: Existing EDNS without ECS + Send a query with EDNS but no ECS value. Check that the query received by the responder has a valid ECS value and that the response @@ -236,6 +246,8 @@ class TestEdnsClientSubnetOverride(DNSDistTest): def testWithEDNSShorterInitialECS(self): """ + ECS Override: Existing EDNS with ECS (short) + Send a query with EDNS and a crafted ECS value. Check that the query received by the responder has an overwritten ECS value (not the initial one) @@ -275,6 +287,8 @@ class TestEdnsClientSubnetOverride(DNSDistTest): def testWithEDNSLongerInitialECS(self): """ + ECS Override: Existing EDNS with ECS (long) + Send a query with EDNS and a crafted ECS value. Check that the query received by the responder has an overwritten ECS value (not the initial one) @@ -314,6 +328,8 @@ class TestEdnsClientSubnetOverride(DNSDistTest): def testWithEDNSSameSizeInitialECS(self): """ + ECS Override: Existing EDNS with ECS (same) + Send a query with EDNS and a crafted ECS value. Check that the query received by the responder has an overwritten ECS value (not the initial one)