mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 10:29:59 -04:00
Add tests for zone timers using the pytest testing framework
This commit is contained in:
parent
72ffa194e2
commit
6aa6d7be58
13 changed files with 437 additions and 10 deletions
2
bin/tests/system/statschannel/.gitignore
vendored
Normal file
2
bin/tests/system/statschannel/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/.cache/
|
||||
/__pycache__/
|
||||
|
|
@ -12,9 +12,9 @@
|
|||
rm -f traffic traffic.out.* traffic.json.* traffic.xml.*
|
||||
rm -f zones zones.out.* zones.json.* zones.xml.* zones.expect.*
|
||||
rm -f dig.out*
|
||||
rm -f */named.memstats
|
||||
rm -f */named.conf
|
||||
rm -f */named.run*
|
||||
rm -f ns*/named.memstats
|
||||
rm -f ns*/named.conf
|
||||
rm -f ns*/named.run*
|
||||
rm -f ns*/named.lock
|
||||
rm -f ns*/named.stats
|
||||
rm -f xml.*stats json.*stats
|
||||
|
|
@ -24,4 +24,6 @@ rm -f ns*/managed-keys.bind*
|
|||
rm -f ns2/Kdnssec* ns2/dnssec.*.id
|
||||
rm -f ns2/Kmanykeys* ns2/manykeys.*.id
|
||||
rm -f ns2/*.db.signed* ns2/dsset-*. ns2/*.jbk
|
||||
rm -f ns2/core
|
||||
rm -f ns2/dnssec.db.signed* ns2/dsset-dnssec.
|
||||
rm -f ns3/*.db
|
||||
rm -rf /.cache /__pycache__
|
||||
|
|
|
|||
74
bin/tests/system/statschannel/conftest.py
Normal file
74
bin/tests/system/statschannel/conftest.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
############################################################################
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
############################################################################
|
||||
|
||||
import pytest
|
||||
import os
|
||||
|
||||
def pytest_configure(config):
|
||||
config.addinivalue_line(
|
||||
"markers", "requests: mark tests that need requests to function"
|
||||
)
|
||||
config.addinivalue_line(
|
||||
"markers", "json: mark tests that need json to function"
|
||||
)
|
||||
config.addinivalue_line(
|
||||
"markers", "xml: mark tests that need xml.etree to function"
|
||||
)
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(config, items):
|
||||
# Test for requests module
|
||||
skip_requests = pytest.mark.skip(reason="need requests module to run")
|
||||
try:
|
||||
import requests # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
for item in items:
|
||||
if "requests" in item.keywords:
|
||||
item.add_marker(skip_requests)
|
||||
# Test for json module
|
||||
skip_json = pytest.mark.skip(reason="need json module to run")
|
||||
try:
|
||||
import json # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
for item in items:
|
||||
if "json" in item.keywords:
|
||||
item.add_marker(skip_json)
|
||||
# Test for xml module
|
||||
skip_xml = pytest.mark.skip(reason="need xml module to run")
|
||||
try:
|
||||
import xml # noqa: F401
|
||||
except ModuleNotFoundError:
|
||||
for item in items:
|
||||
if "xml" in item.keywords:
|
||||
item.add_marker(skip_xml)
|
||||
# Test if JSON statistics channel was enabled
|
||||
no_jsonstats = pytest.mark.skip(reason="need JSON statistics to be enabled")
|
||||
if os.getenv("HAVEJSONSTATS") is None:
|
||||
for item in items:
|
||||
if "json" in item.keywords:
|
||||
item.add_marker(no_jsonstats)
|
||||
# Test if XML statistics channel was enabled
|
||||
no_xmlstats = pytest.mark.skip(reason="need XML statistics to be enabled")
|
||||
if os.getenv("HAVEXMLSTATS") is None:
|
||||
for item in items:
|
||||
if "xml" in item.keywords:
|
||||
item.add_marker(no_xmlstats)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def statsport(request):
|
||||
port = os.getenv("EXTRAPORT1")
|
||||
if port is None:
|
||||
port = 5301
|
||||
else:
|
||||
port = int(port)
|
||||
|
||||
return port
|
||||
58
bin/tests/system/statschannel/helper.py
Normal file
58
bin/tests/system/statschannel/helper.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
############################################################################
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
############################################################################
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# ISO datetime format without msec
|
||||
fmt = '%Y-%m-%dT%H:%M:%SZ'
|
||||
|
||||
# The constants were taken from BIND 9 source code (lib/dns/zone.c)
|
||||
max_refresh = timedelta(seconds=2419200) # 4 weeks
|
||||
max_expires = timedelta(seconds=14515200) # 24 weeks
|
||||
now = datetime.utcnow().replace(microsecond=0)
|
||||
dayzero = datetime.utcfromtimestamp(0).replace(microsecond=0)
|
||||
|
||||
|
||||
# Generic helper functions
|
||||
def check_expires(expires, min, max):
|
||||
assert expires >= min
|
||||
assert expires <= max
|
||||
|
||||
|
||||
def check_refresh(refresh, min, max):
|
||||
assert refresh >= min
|
||||
assert refresh <= max
|
||||
|
||||
|
||||
def check_loaded(loaded, expected):
|
||||
# Sanity check the zone timers values
|
||||
assert loaded == expected
|
||||
assert loaded < now
|
||||
|
||||
|
||||
def check_zone_timers(loaded, expires, refresh, loaded_exp):
|
||||
# Sanity checks the zone timers values
|
||||
if expires is not None:
|
||||
check_expires(expires, now, now + max_expires)
|
||||
if refresh is not None:
|
||||
check_refresh(refresh, now, now + max_refresh)
|
||||
check_loaded(loaded, loaded_exp)
|
||||
|
||||
|
||||
def zone_mtime(zonedir, name):
|
||||
import os
|
||||
import os.path
|
||||
from datetime import datetime
|
||||
|
||||
si = os.stat(os.path.join(zonedir, "{}.db".format(name)))
|
||||
mtime = datetime.utcfromtimestamp(si.st_mtime).replace(microsecond=0)
|
||||
|
||||
return mtime
|
||||
47
bin/tests/system/statschannel/ns1/example.db
Normal file
47
bin/tests/system/statschannel/ns1/example.db
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
$ORIGIN .
|
||||
$TTL 300 ; 5 minutes
|
||||
example IN SOA mname1. . (
|
||||
1 ; serial
|
||||
20 ; refresh (20 seconds)
|
||||
20 ; retry (20 seconds)
|
||||
1814400 ; expire (3 weeks)
|
||||
3600 ; minimum (1 hour)
|
||||
)
|
||||
example. NS ns2.example.
|
||||
ns2.example. A 10.53.0.2
|
||||
|
||||
$ORIGIN example.
|
||||
a A 10.0.0.1
|
||||
MX 10 mail.example.
|
||||
short TXT "short text"
|
||||
long TXT (
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
"longlonglonglonglonglonglonglonglonglong"
|
||||
)
|
||||
|
||||
mail A 10.0.0.2
|
||||
41
bin/tests/system/statschannel/ns1/named.conf.in
Normal file
41
bin/tests/system/statschannel/ns1/named.conf.in
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.1;
|
||||
notify-source 10.53.0.1;
|
||||
transfer-source 10.53.0.1;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.1; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
notify explicit;
|
||||
minimal-responses no;
|
||||
version none; // make statistics independent of the version number
|
||||
};
|
||||
|
||||
statistics-channels { inet 10.53.0.1 port @EXTRAPORT1@ allow { localhost; }; };
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm hmac-sha256;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "example" {
|
||||
type master;
|
||||
file "example.db";
|
||||
allow-transfer { any; };
|
||||
};
|
||||
|
|
@ -18,7 +18,7 @@ options {
|
|||
listen-on { 10.53.0.2; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
notify yes;
|
||||
notify no;
|
||||
minimal-responses no;
|
||||
version none; // make statistics independent of the version number
|
||||
};
|
||||
|
|
|
|||
41
bin/tests/system/statschannel/ns3/named.conf.in
Normal file
41
bin/tests/system/statschannel/ns3/named.conf.in
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
options {
|
||||
query-source address 10.53.0.3;
|
||||
notify-source 10.53.0.3;
|
||||
transfer-source 10.53.0.3;
|
||||
port @PORT@;
|
||||
pid-file "named.pid";
|
||||
listen-on { 10.53.0.3; };
|
||||
listen-on-v6 { none; };
|
||||
recursion no;
|
||||
notify no;
|
||||
minimal-responses no;
|
||||
version none; // make statistics independent of the version number
|
||||
};
|
||||
|
||||
statistics-channels { inet 10.53.0.3 port @EXTRAPORT1@ allow { localhost; }; };
|
||||
|
||||
key rndc_key {
|
||||
secret "1234abcd8765";
|
||||
algorithm hmac-sha256;
|
||||
};
|
||||
|
||||
controls {
|
||||
inet 10.53.0.3 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
|
||||
};
|
||||
|
||||
zone "example" {
|
||||
type secondary;
|
||||
file "example.db";
|
||||
masters { 10.53.0.1; };
|
||||
};
|
||||
|
|
@ -12,9 +12,8 @@
|
|||
# shellcheck source=conf.sh
|
||||
. "$SYSTEMTESTTOP/conf.sh"
|
||||
|
||||
copy_setports ns2/named.conf.in ns2/named.conf
|
||||
for conf in ns*/named.conf.in; do
|
||||
copy_setports "$conf" "$(dirname "$conf")/$(basename "$conf" .in)"
|
||||
done
|
||||
|
||||
(
|
||||
cd ns2
|
||||
$SHELL sign.sh
|
||||
)
|
||||
(cd ns2 && $SHELL sign.sh)
|
||||
|
|
|
|||
75
bin/tests/system/statschannel/tests-json.py
Executable file
75
bin/tests/system/statschannel/tests-json.py
Executable file
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/python3
|
||||
############################################################################
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
############################################################################
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from helper import fmt, zone_mtime, check_zone_timers, dayzero
|
||||
|
||||
|
||||
# JSON helper functions
|
||||
def fetch_json(statsip, statsport):
|
||||
import requests
|
||||
|
||||
r = requests.get("http://{}:{}/json/v1/zones".format(statsip, statsport))
|
||||
assert r.status_code == 200
|
||||
|
||||
data = r.json()
|
||||
|
||||
return data["views"]["_default"]["zones"]
|
||||
|
||||
|
||||
def load_timers_from_json(zone, primary=True):
|
||||
name = zone['name']
|
||||
|
||||
# Check if the primary zone timer exists
|
||||
assert 'loaded' in zone
|
||||
loaded = datetime.strptime(zone['loaded'], fmt)
|
||||
|
||||
if primary:
|
||||
# Check if the secondary zone timers does not exist
|
||||
assert 'expires' not in zone
|
||||
assert 'refresh' not in zone
|
||||
expires = None
|
||||
refresh = None
|
||||
else:
|
||||
assert 'expires' in zone
|
||||
assert 'refresh' in zone
|
||||
expires = datetime.strptime(zone['expires'], fmt)
|
||||
refresh = datetime.strptime(zone['refresh'], fmt)
|
||||
|
||||
return (name, loaded, expires, refresh)
|
||||
|
||||
|
||||
@pytest.mark.json
|
||||
@pytest.mark.requests
|
||||
def test_zone_timers_primary_json(statsport):
|
||||
statsip = "10.53.0.1"
|
||||
zonedir = "ns1"
|
||||
|
||||
zones = fetch_json(statsip, statsport)
|
||||
|
||||
for zone in zones:
|
||||
(name, loaded, expires, refresh) = load_timers_from_json(zone, True)
|
||||
mtime = zone_mtime(zonedir, name)
|
||||
check_zone_timers(loaded, expires, refresh, mtime)
|
||||
|
||||
|
||||
@pytest.mark.json
|
||||
@pytest.mark.requests
|
||||
def test_zone_timers_secondary_json(statsport):
|
||||
statsip = "10.53.0.3"
|
||||
|
||||
zones = fetch_json(statsip, statsport)
|
||||
|
||||
for zone in zones:
|
||||
(name, loaded, expires, refresh) = load_timers_from_json(zone, False)
|
||||
check_zone_timers(loaded, expires, refresh, dayzero)
|
||||
84
bin/tests/system/statschannel/tests-xml.py
Executable file
84
bin/tests/system/statschannel/tests-xml.py
Executable file
|
|
@ -0,0 +1,84 @@
|
|||
#!/usr/bin/python3
|
||||
############################################################################
|
||||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
############################################################################
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from helper import fmt, zone_mtime, check_zone_timers, dayzero
|
||||
|
||||
|
||||
# XML helper functions
|
||||
def fetch_xml(statsip, statsport):
|
||||
import xml.etree.ElementTree as ET
|
||||
import requests
|
||||
|
||||
r = requests.get("http://{}:{}/xml/v3/zones".format(statsip, statsport))
|
||||
assert r.status_code == 200
|
||||
|
||||
root = ET.fromstring(r.text)
|
||||
|
||||
default_view = None
|
||||
for view in root.find('views').iter('view'):
|
||||
if view.attrib['name'] == "_default":
|
||||
default_view = view
|
||||
break
|
||||
assert default_view is not None
|
||||
|
||||
return default_view.find('zones').findall('zone')
|
||||
|
||||
|
||||
def load_timers_from_xml(zone, primary=True):
|
||||
name = zone.attrib['name']
|
||||
|
||||
loaded_el = zone.find('loaded')
|
||||
assert loaded_el is not None
|
||||
loaded = datetime.strptime(loaded_el.text, fmt)
|
||||
|
||||
expires_el = zone.find('expires')
|
||||
refresh_el = zone.find('refresh')
|
||||
if primary:
|
||||
assert expires_el is None
|
||||
assert refresh_el is None
|
||||
expires = None
|
||||
refresh = None
|
||||
else:
|
||||
assert expires_el is not None
|
||||
assert refresh_el is not None
|
||||
expires = datetime.strptime(expires_el.text, fmt)
|
||||
refresh = datetime.strptime(refresh_el.text, fmt)
|
||||
|
||||
return (name, loaded, expires, refresh)
|
||||
|
||||
|
||||
@pytest.mark.xml
|
||||
@pytest.mark.requests
|
||||
def test_zone_timers_primary_xml(statsport):
|
||||
statsip = "10.53.0.1"
|
||||
zonedir = "ns1"
|
||||
|
||||
zones = fetch_xml(statsip, statsport)
|
||||
|
||||
for zone in zones:
|
||||
(name, loaded, expires, refresh) = load_timers_from_xml(zone, True)
|
||||
mtime = zone_mtime(zonedir, name)
|
||||
check_zone_timers(loaded, expires, refresh, mtime)
|
||||
|
||||
|
||||
@pytest.mark.xml
|
||||
@pytest.mark.requests
|
||||
def test_zone_timers_secondary_xml(statsport):
|
||||
statsip = "10.53.0.3"
|
||||
|
||||
zones = fetch_xml(statsip, statsport)
|
||||
|
||||
for zone in zones:
|
||||
(name, loaded, expires, refresh) = load_timers_from_xml(zone, False)
|
||||
check_zone_timers(loaded, expires, refresh, dayzero)
|
||||
0
bin/tests/system/statschannel/tests.sh
Normal file → Executable file
0
bin/tests/system/statschannel/tests.sh
Normal file → Executable file
|
|
@ -808,12 +808,16 @@
|
|||
./bin/tests/system/statistics/setup.sh SH 2018,2019,2020
|
||||
./bin/tests/system/statistics/tests.sh SH 2012,2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/clean.sh SH 2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/conftest.py PYTHON 2020
|
||||
./bin/tests/system/statschannel/fetch.pl PERL 2015,2016,2018,2019,2020
|
||||
./bin/tests/system/statschannel/helper.py PYTHON 2020
|
||||
./bin/tests/system/statschannel/mem-xml.pl PERL 2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/ns2/sign.sh SH 2019,2020
|
||||
./bin/tests/system/statschannel/server-json.pl PERL 2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/server-xml.pl PERL 2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/setup.sh SH 2018,2019,2020
|
||||
./bin/tests/system/statschannel/tests-json.py PYTHON-BIN 2020
|
||||
./bin/tests/system/statschannel/tests-xml.py PYTHON-BIN 2020
|
||||
./bin/tests/system/statschannel/tests.sh SH 2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/traffic-json.pl PERL 2015,2016,2017,2018,2019,2020
|
||||
./bin/tests/system/statschannel/traffic-xml.pl PERL 2015,2016,2017,2018,2019,2020
|
||||
|
|
|
|||
Loading…
Reference in a new issue