Browse Source

More tests (and Python 3 changes)

master
Stephane Bortzmeyer 2 years ago
parent
commit
4a9e6fc082
  1. 14
      DNSLG/Formatter.py
  2. 5
      DNSLG/__init__.py
  3. 6
      README
  4. 9
      conftest.py
  5. 3
      test-my-resolver.py
  6. 23
      test-server-with-config-file.py
  7. 146
      test_service.py

14
DNSLG/Formatter.py

@ -1,7 +1,5 @@
#!/usr/bin/env python
from past.utils import old_div
import dns
import dns.version as dnspythonversion
import base64
@ -375,7 +373,7 @@ class JsonFormatter(Formatter):
except AttributeError: # total_seconds appeared only with Python 2.7
delay = querier.delay
duration = (delay.days*86400) + delay.seconds + \
(old_div(float(delay.microseconds),1000000.0))
(float(delay.microseconds)/1000000.0)
self.object['Query'] = {'Server': answer.nameserver,
'Time': time.strftime("%Y-%m-%d %H:%M:%SZ",
time.gmtime(time.time())),
@ -511,7 +509,7 @@ class XmlFormatter(Formatter):
except AttributeError: # total_seconds appeared only with Python 2.7
delay = querier.delay
duration = (delay.days*86400) + delay.seconds + \
(old_div(float(delay.microseconds),1000000.0))
(float(delay.microseconds),1000000.0)
self.context.addGlobal ("duration", duration)
self.context.addGlobal ("time", time.strftime("%Y-%m-%d %H:%M:%SZ",
time.gmtime(time.time())))
@ -834,10 +832,10 @@ class HtmlFormatter(Formatter):
def pretty_duration(self, duration):
""" duration is in seconds """
weeks = old_div(duration,(86400*7))
days = old_div((duration-(86400*7*weeks)),86400)
hours = old_div((duration-(86400*7*weeks)-(86400*days)),3600)
minutes = old_div((duration-(86400*7*weeks)-(86400*days)-(3600*hours)),60)
weeks = duration // (86400*7)
days = (duration-(86400*7*weeks)) // 86400
hours = (duration-(86400*7*weeks)-(86400*days)) // 3600
minutes = (duration-(86400*7*weeks)-(86400*days)-(3600*hours)) // 60
seconds = duration-(86400*7*weeks)-(86400*days)-(3600*hours)-(60*minutes)
result = ""
empty_result = True

5
DNSLG/__init__.py

@ -1,9 +1,6 @@
#!/usr/bin/env python3
# Standard library
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import str
from builtins import object
from cgi import escape
@ -32,7 +29,7 @@ from .LeakyBucket import LeakyBucket
from . import Answer
from . import Resolver
# If you need to change thse values, it is better to do it when
# If you need to change these values, it is better to do it when
# calling the Querier() constructor.
default_base_url = ""
default_edns_size = 4096

6
README

@ -185,6 +185,12 @@ To try it locally;
Then, from another window:
% curl http://localhost:8080/example.org/A
To test against running servers, see the script tests.sh. For
developer tests, see test_service.py, intended to be run from pytest
<https://pytest.org/>. By default, 'pytest' will run against
<http://localhost:8080/>, you can use another server with 'pytest
--url https://example.net/' (don't forget the trailing slash).
Other DNS looking glasses
*************************

9
conftest.py

@ -0,0 +1,9 @@
import pytest
def pytest_addoption(parser):
parser.addoption("--url", action="store", default='http://localhost:8080/',
help="URL of the server to test")
@pytest.fixture
def prefix(request):
return request.config.getoption("--url")

3
test-my-resolver.py

@ -1,6 +1,5 @@
#!/usr/bin/python
#!/usr/bin/env python3
from __future__ import print_function
import DNSLG
import sys

23
test-server-with-config-file.py

@ -1,8 +1,5 @@
#!/usr/bin/env python
#!/usr/bin/env python3
from __future__ import print_function
from future import standard_library
standard_library.install_aliases()
import wsgiref.simple_server as server
import os
import getopt
@ -14,19 +11,19 @@ config_file = os.path.expanduser("~/.dnslg.ini")
import DNSLG
default_values = {'email_administrator': None,
'url_documentation': None,
'url_css': None,
default_values = {'email_administrator': '',
'url_documentation': '',
'url_css': '',
'url_base_service': DNSLG.default_base_url,
'file_favicon': None,
'file_favicon': '',
'forbidden_suffixes': "",
'encoding': DNSLG.default_encoding,
'size_edns': '2048',
'bucket_size': '10',
'handle_wellknown_files': 'True',
'code_google_webmasters': None,
'description': None,
'description_html': None,
'code_google_webmasters': '',
'description': '',
'description_html': '',
'port': '8080'
}
@ -40,7 +37,7 @@ if len(sys.argv) != 1:
sys.exit(1)
SECTION = "DNS-LG"
config = configparser.SafeConfigParser(default_values)
config = configparser.ConfigParser(default_values)
try:
config_file = open(config_file)
except IOError:
@ -62,7 +59,7 @@ description_html = config.get(SECTION, 'description_html')
google_code = config.get(SECTION, 'code_google_webmasters')
edns_size = config.get(SECTION, 'size_edns')
forbidden_str = config.get(SECTION, 'forbidden_suffixes')
forbidden = string.split(forbidden_str, ':')
forbidden = forbidden_str.split(':')
if edns_size is None or edns_size == "":
edns_size = None
else:

146
test_service.py

@ -6,8 +6,6 @@
# https://requests.readthedocs.io/en/master/
import requests
PREFIX = 'https://dns.bortzmeyer.org/'
import re
formats = {'': 'text/html; charset=UTF-8', # Default
@ -36,90 +34,90 @@ def sstring(f):
except ValueError:
return formats[f]
def test_basic():
r = requests.get(PREFIX)
def test_basic(prefix):
r = requests.get(prefix)
assert r.status_code == 200 and r.headers['content-type'] == 'text/html; charset=UTF-8' and \
'No data was found' in r.text
def test_notexist():
r = requests.get(PREFIX + 'doesnotexistatall')
def test_notexist(prefix):
r = requests.get(prefix + 'doesnotexistatall')
assert r.status_code == 404 and 'does not exist' in r.text
def test_unknown_format():
r = requests.get(PREFIX + 'icann.org/?format=XXXX')
def test_unknown_format(prefix):
r = requests.get(prefix + 'icann.org/?format=XXXX')
assert r.status_code == 400 and 'Unsupported format "XXXX"' in r.text
def test_defaulttype(): # ADDR by default
def test_defaulttype(prefix): # ADDR by default
for format in formats:
r = requests.get(PREFIX + 'www.ietf.org/%s' % fstring(format))
r = requests.get(prefix + 'www.ietf.org/%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'104.20.0.85' in r.text, 'format is %s' % format
def test_addr():
def test_addr(prefix):
for format in formats:
r = requests.get(PREFIX + 'www.ietf.org/ADDR%s' % fstring(format))
r = requests.get(prefix + 'www.ietf.org/ADDR%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'104.20.0.85' in r.text, 'format is %s' % format
def test_addr_v4():
def test_addr_v4(prefix):
for format in formats:
r = requests.get(PREFIX + 'www.ietf.org/A%s' % fstring(format))
r = requests.get(prefix + 'www.ietf.org/A%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'104.20.0.85' in r.text, 'format is %s' % format
def test_addr_v6():
def test_addr_v6(prefix):
for format in formats:
r = requests.get(PREFIX + 'www.ietf.org/AAAA%s' % fstring(format))
r = requests.get(prefix + 'www.ietf.org/AAAA%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'2606:4700:10::6814:155' in r.text, 'format is %s' % format
def test_mx():
def test_mx(prefix):
for format in formats:
r = requests.get(PREFIX + 'framasoft.org/MX%s' % fstring(format))
r = requests.get(prefix + 'framasoft.org/MX%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'mail.framasoft.org' in r.text, 'format is %s' % format
def test_naptr():
def test_naptr(prefix):
for format in formats:
r = requests.get(PREFIX + 'canalplusoverseas.fr/NAPTR%s' % fstring(format))
r = requests.get(prefix + 'canalplusoverseas.fr/NAPTR%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'_sip._tcp.canalplusoverseas.fr' in r.text, 'format is %s' % format
def test_txt():
def test_txt(prefix):
for format in formats:
r = requests.get(PREFIX + 'fr/TXT%s' % fstring(format))
r = requests.get(prefix + 'fr/TXT%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'RRs processed' in r.text, 'format is %s' % format
def test_dnskey():
def test_dnskey(prefix):
for format in formats:
r = requests.get(PREFIX + 'paypal.com/DNSKEY%s' % fstring(format))
r = requests.get(prefix + 'paypal.com/DNSKEY%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'paypal.com' in r.text, 'format is %s' % format # Unfortunately,
# no text in the DNSKEY output, is available for all
# formats. Use one test per format, as in test_dnssec?
def test_loc():
def test_loc(prefix):
for format in formats:
r = requests.get(PREFIX + '52100.cp.bortzmeyer.fr/LOC%s' % fstring(format))
r = requests.get(prefix + '52100.cp.bortzmeyer.fr/LOC%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'48' in r.text, 'format is %s' % format
def test_ns():
def test_ns(prefix):
for format in formats:
r = requests.get(PREFIX + 'frmug.org/NS%s' % fstring(format))
r = requests.get(prefix + 'frmug.org/NS%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'ns.eu.org' in r.text, 'format is %s' % format
def test_srv():
def test_srv(prefix):
for format in formats:
r = requests.get(PREFIX + '_sipfederationtls._tcp.bretagne-ouest.cci.bzh/SRV%s' % fstring(format))
r = requests.get(prefix + '_sipfederationtls._tcp.bretagne-ouest.cci.bzh/SRV%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'sipfed.online.lync.com' in r.text, 'format is %s' % format
def test_ds():
def test_ds(prefix):
for format in formats:
r = requests.get(PREFIX + 'cyberstructure.fr/DS%s' % fstring(format))
r = requests.get(prefix + 'cyberstructure.fr/DS%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
((format == 'ZONE' and 'DS' in r.text) or
(format == 'TXT' and 'Delegation of signature:' in r.text) or
@ -127,9 +125,9 @@ def test_ds():
(format == 'XML' and '<RRSet type="DS"' in r.text ) or
('Secure Delegation:' in r.text)), 'format is %s' % format
def test_nsec3param():
def test_nsec3param(prefix):
for format in formats:
r = requests.get(PREFIX + 'pm/NSEC3PARAM%s' % fstring(format))
r = requests.get(prefix + 'pm/NSEC3PARAM%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'].startswith(formats[format]) and \
((format == 'ZONE' and 'NSEC3PARAM' in r.text) or
(format == 'TXT' and 'NSEC3PARAM:' in r.text) or
@ -137,37 +135,43 @@ def test_nsec3param():
(format == 'XML') or # Nothing in the XML output?
('NSEC3 parameters:' in r.text)), 'format is %s' % format
def test_uri():
def test_uri(prefix):
for format in formats:
r = requests.get(PREFIX + '78000.cp.bortzmeyer.fr/URI%s' % fstring(format))
r = requests.get(prefix + '78000.cp.bortzmeyer.fr/URI%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'https://www.openstreetmap.org/' in r.text, 'format is %s' % format
def test_cname(prefix):
for format in formats:
r = requests.get(prefix + 'www.elysee.fr/CNAME%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'incapdns.net' in r.text, 'format is %s' % format
# Once #40 is done, we'll have to use another type
def test_unformatted_type():
def test_unformatted_type(prefix):
for format in formats:
r = requests.get(PREFIX + '_443._tcp.doh.bortzmeyer.fr/TLSA%s' % fstring(format))
r = requests.get(prefix + '_443._tcp.doh.bortzmeyer.fr/TLSA%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
((format == 'ZONE' and 'TYPE52' in r.text) or
(format == 'JSON' and '"Type": "unknown 52"' in r.text) or
(format == 'XML' and '<binaryRR rtype="52"' in r.text) or
('Unknown record type' in r.text)), 'format is %s' % format
def test_rev_v4():
def test_rev_v4(prefix):
for format in formats:
r = requests.get(PREFIX + '194.0.9.1?reverse=1%s' % fstring(format, add=True))
r = requests.get(prefix + '194.0.9.1?reverse=1%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'nic.fr' in r.text, 'format is %s' % format
def test_rev_v6():
def test_rev_v6(prefix):
for format in formats:
r = requests.get(PREFIX + '2001:678:c::1?reverse=1%s' % fstring(format, add=True))
r = requests.get(prefix + '2001:678:c::1?reverse=1%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'nic.fr' in r.text, 'format is %s' % format
def test_dnssec():
def test_dnssec(prefix):
for format in formats:
r = requests.get(PREFIX + 'cyberstructure.fr?dodnssec=1%s' % fstring(format, add=True))
r = requests.get(prefix + 'cyberstructure.fr?dodnssec=1%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
(((format == 'HTML' or format == '' or format == 'TXT') and 'Authentic Data' in r.text) or
(format == 'ZONE' and 'Flags: ad' in r.text) or
@ -175,44 +179,62 @@ def test_dnssec():
(format == 'XML' and '<ad>1</ad>' in r.text) or
('Authentic data' in r.text)), 'format is %s' % format
def test_tcp():
# TODO test with cd=1
def test_tcp(prefix):
for format in formats:
r = requests.get(PREFIX + 'fr.wikipedia.org/A?tcp=1%s' % fstring(format, add=True))
r = requests.get(prefix + 'fr.wikipedia.org/A?tcp=1%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format]
def test_bufsize():
def test_bufsize(prefix):
for format in formats:
r = requests.get(PREFIX + 'fr.wikipedia.org/A?buffersize=512%s' % fstring(format, add=True))
r = requests.get(prefix + 'fr.wikipedia.org/A?buffersize=512%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format]
def test_both():
def test_both(prefix):
for format in formats:
r = requests.get(PREFIX + 'fr.wikipedia.org/A?tcp=1&buffersize=1024%s' % fstring(format, add=True))
r = requests.get(prefix + 'fr.wikipedia.org/A?tcp=1&buffersize=1024%s' % fstring(format, add=True))
assert r.status_code == 200 and r.headers['content-type'] == formats[format]
# TODO CNAME and DNAME types
def test_resolver(prefix):
for resolver in ['1.1.1.1', '9.9.9.9']:
for format in formats:
r = requests.get(prefix + 'fr.wikipedia.org/A?server=%s%s' % (resolver, fstring(format, add=True)))
assert r.status_code == 200 and r.headers['content-type'] == formats[format]
# TODO the root
# TODO DNAME types
# TODO other resolver
def test_root(prefix):
for format in formats:
r = requests.get(prefix + './NS%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'f.root-servers.net' in r.text, 'format is %s' % format
r = requests.get(prefix + 'root/NS%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'f.root-servers.net' in r.text, 'format is %s' % format
r = requests.get(prefix + '%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format], 'format is %s' % format # TODO content
# TODO other classes
# TODO broken DNSSEC domains
def test_dnssec(prefix):
for format in formats:
r = requests.get(prefix + 'servfail.nl%s' % fstring(format, add=True))
assert (r.status_code == 504 or r.status_code == 404) and r.headers['content-type'].startswith('text/plain')
# TODO special characters
# TODO other methods than GET
def test_no_such_qtype():
def test_no_such_qtype(prefix):
for format in formats:
r = requests.get(PREFIX + 'gouvernement.fr/XXXX%s' % fstring(format))
r = requests.get(prefix + 'gouvernement.fr/XXXX%s' % fstring(format))
assert r.status_code == 400 and r.headers['content-type'].startswith('text/plain') and \
'Record type XXXX does not exist\n' == r.text, 'format is %s' % format
def test_nodata():
def test_nodata(prefix):
for format in formats:
r = requests.get(PREFIX + 'com/AAAA%s' % fstring(format))
r = requests.get(prefix + 'com/AAAA%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
((format == 'TXT') or
(format == 'ZONE') or
@ -220,17 +242,17 @@ def test_nodata():
(format == 'XML') or
('No data was found' in r.text)), 'format is %s' % format
def test_idn():
def test_idn(prefix):
for format in formats:
r = requests.get(PREFIX + 'potamochère.fr/SOA%s' % fstring(format))
r = requests.get(prefix + 'potamochère.fr/SOA%s' % fstring(format))
assert r.status_code == 200 and r.headers['content-type'] == formats[format] and \
'hostmaster.gandi.net' in r.text, 'format is %s' % format
def test_content_negotiation():
def test_content_negotiation(prefix):
for format in formats:
if format == '':
continue
r = requests.get(PREFIX + 'www.ietf.org/ADDR', headers={'Accept': sstring(format)})
r = requests.get(prefix + 'www.ietf.org/ADDR', headers={'Accept': sstring(format)})
assert r.status_code == 200 and r.headers['content-type'].startswith(formats[format]) and \
'104.20.0.85' in r.text, 'format is %s' % format

Loading…
Cancel
Save