You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ja...@apache.org on 2016/06/14 18:43:11 UTC
[trafficserver] branch master updated: TS-4407 tsqa tests for
hostdb (#710)
This is an automated email from the ASF dual-hosted git repository.
jacksontj pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 80213e3 TS-4407 tsqa tests for hostdb (#710)
80213e3 is described below
commit 80213e3669b2bcfa839a2ebc8fa686a8b707ede0
Author: Thomas Jackson <ja...@gmail.com>
AuthorDate: Tue Jun 14 11:43:05 2016 -0700
TS-4407 tsqa tests for hostdb (#710)
This includes a resolver that you can control from within the test
This closes #710
---
ci/tsqa/requirements.txt | 1 +
ci/tsqa/tests/test_hostdb.py | 185 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+)
diff --git a/ci/tsqa/requirements.txt b/ci/tsqa/requirements.txt
index 01a8816..0aa7ecf 100644
--- a/ci/tsqa/requirements.txt
+++ b/ci/tsqa/requirements.txt
@@ -6,3 +6,4 @@ pyyaml
pyOpenSSL
# TODO: can't do python_version in requirements.txt files
#hyper; python_version >= '2.7'
+dnslib
diff --git a/ci/tsqa/tests/test_hostdb.py b/ci/tsqa/tests/test_hostdb.py
index 3a9b800..614a238 100644
--- a/ci/tsqa/tests/test_hostdb.py
+++ b/ci/tsqa/tests/test_hostdb.py
@@ -22,14 +22,61 @@ import os
import requests
import time
import logging
+import socket
import SocketServer
+import contextlib
+import dnslib
+import dnslib.server
+
import tsqa.test_cases
import helpers
log = logging.getLogger(__name__)
+@contextlib.contextmanager
+def kill_dns(dns_server):
+ ''' Temporarily kill the dns server
+ '''
+ dns_server.stop()
+ yield
+ dns_server.start_thread()
+
+
+class StubDNSResolver(object):
+ '''Resolver to serve defined responses from `response_dict` or return SOA
+ '''
+ def __init__(self, responses):
+ self.responses = responses
+ self.resp_headers = {}
+
+ def resolve(self, request, handler):
+ reply = request.reply()
+ for q in request.questions:
+ qname = str(q.get_qname())
+ if qname in self.responses:
+ for resp in self.responses[qname]:
+ reply.add_answer(resp)
+ else:
+ reply.add_answer(dnslib.server.RR(
+ q.get_qname(),
+ rtype=dnslib.QTYPE.SOA,
+ ttl=1,
+ rdata=dnslib.dns.SOA(
+ 'nameserver.local',
+ q.get_qname(),
+ ),
+ ))
+ for k, v in self.resp_headers.iteritems():
+ if k == 'rcode':
+ reply.header.set_rcode(v)
+ print 'setting rcode'
+ else:
+ log.warning('Unsupported header sent to StubDNSResolver %s' % k)
+ return reply
+
+
class EchoServerIpHandler(SocketServer.BaseRequestHandler):
"""
A subclass of RequestHandler which will return a connection uuid
@@ -214,3 +261,141 @@ class TestHostDBHostsFile(helpers.EnvironmentCase, tsqa.test_cases.HTTPBinCase):
)
self.assertEqual(ret.status_code, 200)
self.assertEqual('127.0.0.3', ret.headers['X-Server-Ip'])
+
+
+class TestHostDB(helpers.EnvironmentCase, tsqa.test_cases.HTTPBinCase):
+ @classmethod
+ def setUpEnv(cls, env):
+ cls.dns_sock = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
+ cls.dns_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ cls.dns_sock.bind(('', 0)) # bind to all interfaces on an ephemeral port
+ dns_port = cls.dns_sock.getsockname()[1]
+
+ # set up dns resolver
+ cls.responses = {
+ 'www.foo.com.': dnslib.server.RR.fromZone("foo.com. 1 A 127.0.0.1"),
+ 'www.stale_for.com.': dnslib.server.RR.fromZone("foo.com. 1 A 127.0.0.1"),
+ }
+
+ cls.dns_server = dnslib.server.DNSServer(
+ StubDNSResolver(cls.responses),
+ port=dns_port,
+ address="localhost",
+ )
+ cls.dns_server.start_thread()
+
+ cls.hosts_file_path = os.path.join(env.layout.prefix, 'resolv')
+ with open(cls.hosts_file_path, 'w') as fh:
+ fh.write('nameserver 127.0.0.1:{0}\n'.format(dns_port))
+
+ cls.configs['records.config']['CONFIG'].update({
+ 'proxy.config.http.response_server_enabled': 2, # only add server headers when there weren't any
+ 'proxy.config.hostdb.lookup_timeout': 1,
+ 'proxy.config.url_remap.remap_required': 0,
+ 'proxy.config.http.connect_attempts_max_retries': 1,
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags': 'hostdb',
+ 'proxy.config.dns.resolv_conf': os.path.join(env.layout.prefix, 'resolv'),
+ 'proxy.config.hostdb.serve_stale_for': 2,
+ 'proxy.config.hostdb.ttl_mode': 0,
+ 'proxy.config.http_ui_enabled': 3,
+ })
+
+ cls.configs['remap.config'].add_line('map /_hostdb/ http://{hostdb}')
+
+ def _hostdb_entries(self):
+ # mapping of name -> entries
+ ret = {}
+ showall_ret = requests.get('http://127.0.0.1:{0}/_hostdb/showall?format=json'.format(
+ self.configs['records.config']['CONFIG']['proxy.config.http.server_ports']
+ ), timeout=1).json()
+
+ for item in showall_ret:
+ ret[item['hostname']] = item
+
+ return ret
+
+ def test_dns(self):
+ '''Test that DNS lookups end up in hostdb as we expect
+ '''
+ # TODO: remove
+ self.test_basic()
+ print self._hostdb_entries()
+
+ # test something with a LARGE number of entries
+ zone_parts = []
+ # TODO: fix this, right now there is `#define DNS_MAX_ADDRS 35` which
+ # controls how many work-- we should make this configurable
+ # 30 works, once you pass 35 some records are missing, and at some point
+ # you start getting garbage (50 for example) and at some point (100) it
+ # seems to crash
+ NUM_RECORDS = 2
+ for x in xrange(0, NUM_RECORDS):
+ zone_parts.append("www.huge.com. 1 A 127.0.0.{0}".format(x + 1))
+ self.responses['www.huge.com.'] = dnslib.server.RR.fromZone('\n'.join(zone_parts))
+
+ ret = requests.get(
+ 'http://www.huge.com:{0}/get'.format(self.http_endpoint.address[1]),
+ proxies=self.proxies,
+ )
+ #self.assertEqual(ret.status_code, 200)
+
+ for item in self._hostdb_entries()['www.huge.com']['rr_records']:
+ print item['ip']
+
+ self.assertEqual(len(self._hostdb_entries()['www.huge.com']['rr_records']), NUM_RECORDS)
+
+
+ def test_basic(self):
+ '''
+ Test basic fnctionality of resolver
+ '''
+
+ # test one that works
+ ret = requests.get(
+ 'http://www.foo.com:{0}/get'.format(self.http_endpoint.address[1]),
+ proxies=self.proxies,
+ )
+ self.assertEqual(ret.status_code, 200)
+
+ # check one that doesn't exist
+ ret = requests.get(
+ 'http://www.bar.com:{0}/get'.format(self.http_endpoint.address[1]),
+ proxies=self.proxies,
+ )
+ self.assertEqual(ret.status_code, 502)
+
+ def test_serve_stail_for(self):
+ start = time.time()
+ ret = requests.get(
+ 'http://www.stale_for.com:{0}/get'.format(self.http_endpoint.address[1]),
+ proxies=self.proxies,
+ )
+ self.assertEqual(ret.status_code, 200)
+ # mark the DNSServer down
+ with kill_dns(self.dns_server):
+ timeout_at = time.time() + 10
+ end_working = None
+ end = None
+ count = 0
+
+ while time.time() < timeout_at:
+ ret = requests.get(
+ 'http://www.stale_for.com:{0}/get'.format(self.http_endpoint.address[1]),
+ proxies=self.proxies,
+ )
+ count += 1
+ if ret.status_code != 200:
+ end = time.time()
+ break
+ else:
+ end_working = time.time()
+ time.sleep(0.5)
+ # ensure that it was for at least 2 seconds
+ print end_working - start
+ self.assertTrue(end_working - start >= 2)
+ # TODO: Fix this!
+ # for whatever reason the failed DNS response is taking ~3.5s to timeout
+ # even though the hostdb.lookup_timeout is set to 1 (meaning it should be ~1s)
+ #print end - end_working
+ #self.assertTrue(end - start >= 2)
--
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].