]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add tests for zone timers using the pytest testing framework
authorOndřej Surý <ondrej@sury.org>
Fri, 27 Mar 2020 09:13:31 +0000 (10:13 +0100)
committerOndřej Surý <ondrej@isc.org>
Tue, 12 May 2020 06:48:01 +0000 (08:48 +0200)
13 files changed:
bin/tests/system/statschannel/.gitignore [new file with mode: 0644]
bin/tests/system/statschannel/clean.sh
bin/tests/system/statschannel/conftest.py [new file with mode: 0644]
bin/tests/system/statschannel/helper.py [new file with mode: 0644]
bin/tests/system/statschannel/ns1/example.db [new file with mode: 0644]
bin/tests/system/statschannel/ns1/named.conf.in [new file with mode: 0644]
bin/tests/system/statschannel/ns2/named.conf.in
bin/tests/system/statschannel/ns3/named.conf.in [new file with mode: 0644]
bin/tests/system/statschannel/setup.sh
bin/tests/system/statschannel/tests-json.py [new file with mode: 0755]
bin/tests/system/statschannel/tests-xml.py [new file with mode: 0755]
bin/tests/system/statschannel/tests.sh [changed mode: 0644->0755]
util/copyrights

diff --git a/bin/tests/system/statschannel/.gitignore b/bin/tests/system/statschannel/.gitignore
new file mode 100644 (file)
index 0000000..44fb46c
--- /dev/null
@@ -0,0 +1,2 @@
+/.cache/
+/__pycache__/
index c9edbde9ee3f29be4bf4edebbab5019459dc981c..243a90612cb3c3ce62cf3155c0852227dfcca650 100644 (file)
@@ -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__
diff --git a/bin/tests/system/statschannel/conftest.py b/bin/tests/system/statschannel/conftest.py
new file mode 100644 (file)
index 0000000..d62b6af
--- /dev/null
@@ -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
diff --git a/bin/tests/system/statschannel/helper.py b/bin/tests/system/statschannel/helper.py
new file mode 100644 (file)
index 0000000..0865b30
--- /dev/null
@@ -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
diff --git a/bin/tests/system/statschannel/ns1/example.db b/bin/tests/system/statschannel/ns1/example.db
new file mode 100644 (file)
index 0000000..b65651a
--- /dev/null
@@ -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
diff --git a/bin/tests/system/statschannel/ns1/named.conf.in b/bin/tests/system/statschannel/ns1/named.conf.in
new file mode 100644 (file)
index 0000000..fa1cd57
--- /dev/null
@@ -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; };
+};
index 70aadf8b283c649ad11522ea13644221920f031d..9eebe560d38b1215746454c224995ea7edce2ae8 100644 (file)
@@ -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
 };
diff --git a/bin/tests/system/statschannel/ns3/named.conf.in b/bin/tests/system/statschannel/ns3/named.conf.in
new file mode 100644 (file)
index 0000000..e78cff9
--- /dev/null
@@ -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; };
+};
index 3a8577eb72a1c1257cf9c68bd4297fb30c69d316..2ce6fde81d3d4406c9cbf111f692dae428ebb9c1 100644 (file)
@@ -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)
diff --git a/bin/tests/system/statschannel/tests-json.py b/bin/tests/system/statschannel/tests-json.py
new file mode 100755 (executable)
index 0000000..f9bd5ec
--- /dev/null
@@ -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)
diff --git a/bin/tests/system/statschannel/tests-xml.py b/bin/tests/system/statschannel/tests-xml.py
new file mode 100755 (executable)
index 0000000..dcd2d76
--- /dev/null
@@ -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)
old mode 100644 (file)
new mode 100755 (executable)
index 91a31b2ea54b6ca6a8dee78da77ecc66fd38f913..40db450438d165f22404bdd1e6dd5aa45573823c 100644 (file)
 ./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