Commit 6aa6d7be authored by Ondřej Surý's avatar Ondřej Surý Committed by Ondřej Surý

Add tests for zone timers using the pytest testing framework

parent 72ffa194
......@@ -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__
############################################################################
# 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
############################################################################
# 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
; 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
/*
* 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
};
......
/*
* 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)
#!/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)
#!/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)
File mode changed from 100644 to 100755
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment