]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Move test algorithm configuration to isctest
authorTom Krizek <tkrizek@isc.org>
Thu, 4 Jan 2024 16:27:32 +0000 (17:27 +0100)
committerNicki Křížek <nicki@isc.org>
Wed, 31 Jul 2024 08:50:09 +0000 (10:50 +0200)
Instead of invoking get_algorithms.py script repeatedly (which may yield
different results), move the algorithm configuration to an isctest
module. This ensures the variables are consistent across the entire test
run.

bin/tests/system/conf.sh
bin/tests/system/conftest.py
bin/tests/system/isctest/vars/__init__.py
bin/tests/system/isctest/vars/algorithms.py [moved from bin/tests/system/get_algorithms.py with 69% similarity, mode: 0644]
bin/tests/system/isctest/vars/all.py
bin/tests/system/mkeys/setup.sh
bin/tests/system/mkeys/tests.sh
bin/tests/system/mkeys/tests_sh_mkeys.py
bin/tests/system/pytest.ini

index e3e9a08fb938d84afa69ede5fbf8b86c8bb1d2f3..320cf647952213c6634fcdd8989224d1a05344b6 100644 (file)
@@ -99,42 +99,6 @@ send() {
   $PERL "$TOP_SRCDIR/bin/tests/system/send.pl" "$@"
 }
 
-#
-# Useful variables in test scripts
-#
-
-# The following script sets the following algorithm-related variables. These
-# are selected randomly at runtime from a list of supported algorithms. The
-# randomization is deterministic and remains stable for a period of time for a
-# given platform.
-#
-# Default algorithm for testing.
-# DEFAULT_ALGORITHM
-# DEFAULT_ALGORITHM_NUMBER
-# DEFAULT_BITS
-#
-# This is an alternative algorithm for test cases that require more than one
-# algorithm (for example algorithm rollover). Must be different from
-# DEFAULT_ALGORITHM.
-# ALTERNATIVE_ALGORITHM
-# ALTERNATIVE_ALGORITHM_NUMBER
-# ALTERNATIVE_BITS
-#
-# This is an algorithm that is used for tests against the "disable-algorithms"
-# configuration option. Must be different from above algorithms.
-# DISABLED_ALGORITHM
-# DISABLED_ALGORITHM_NUMBER
-# DISABLED_BITS
-#
-# There are multiple algoritms sets to choose from (see get_algorithms.py). To
-# override the default choice, set the ALGORITHM_SET env var (see mkeys system
-# test for example).
-eval "$($PYTHON "$TOP_SRCDIR/bin/tests/system/get_algorithms.py")"
-
-# Default HMAC algorithm.
-# also update _common/rndc.conf and _common/rndc.key when updating DEFAULT_HMAC
-export DEFAULT_HMAC=hmac-sha256
-
 #
 # Useful functions in test scripts
 #
index 5585d1e402ca0d3849cb07396f25059e4fd76baf..c578e4a8fdebfaadd9b2d1bdaaab2ea7860ba825 100644 (file)
@@ -277,6 +277,17 @@ def wait_for_zones_loaded(request, servers):
             watcher.wait_for_line("all zones loaded")
 
 
+@pytest.fixture(scope="module", autouse=True)
+def configure_algorithm_set(request):
+    """Configure the algorithm set to use in tests."""
+    mark = _get_marker(request.node, "algorithm_set")
+    if not mark:
+        name = None
+    else:
+        name = mark.args[0]
+    isctest.vars.set_algorithm_set(name)
+
+
 @pytest.fixture(autouse=True)
 def logger(request, system_test_name):
     """Sets up logging facility specific to a particular test."""
index 7c06a247a2d0316fdb3b47aab11f7a36a8aa18a2..6ed7020344ec1e8fcf21ea60ea874db92a6f96a3 100644 (file)
 import os
 
 from .all import ALL
+from .algorithms import set_algorithm_set
 from .openssl import parse_openssl_config
 from .. import log
 
 
 def init_vars():
     """Initializes the environment variables."""
+    set_algorithm_set(os.getenv("ALGORITHM_SET"))
     parse_openssl_config(ALL["OPENSSL_CONF"])
 
     os.environ.update(ALL)
old mode 100755 (executable)
new mode 100644 (file)
similarity index 69%
rename from bin/tests/system/get_algorithms.py
rename to bin/tests/system/isctest/vars/algorithms.py
index 663b986..4188864
@@ -1,5 +1,3 @@
-#!/usr/bin/python3
-
 # Copyright (C) Internet Systems Consortium, Inc. ("ISC")
 #
 # SPDX-License-Identifier: MPL-2.0
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
-# This script is a 'port' broker.  It keeps track of ports given to the
-# individual system subtests, so every test is given a unique port range.
-
-import logging
 import os
 from pathlib import Path
 import platform
 import random
 import subprocess
 import time
-from typing import Dict, List, NamedTuple, Union
-
-# Uncomment to enable DEBUG logging
-# logging.basicConfig(
-#     format="get_algorithms.py %(levelname)s %(message)s", level=logging.DEBUG
-# )
+from typing import Dict, List, NamedTuple, Optional, Union
+
+from .basic import BASIC_VARS
+from .. import log
+
+# Algorithms are selected randomly at runtime from a list of supported
+# algorithms. The randomization is deterministic and remains stable for a
+# period of time for a given platform.
+ALG_VARS = {
+    # There are multiple algoritms sets to choose from (see ALGORITHM_SETS). To
+    # override the default choice, set the ALGORITHM_SET env var prior to
+    # loading this module or call set_algorithm_set().
+    "ALGORITHM_SET": "none",
+    "DEFAULT_ALGORITHM": "",
+    "DEFAULT_ALGORITHM_NUMBER": "",
+    "DEFAULT_BITS": "",
+    # Alternative algorithm for test cases that require more than one algorithm
+    # (for example algorithm rollover). Must be different from
+    # DEFAULT_ALGORITHM.
+    "ALTERNATIVE_ALGORITHM": "",
+    "ALTERNATIVE_ALGORITHM_NUMBER": "",
+    "ALTERNATIVE_BITS": "",
+    # Algorithm that is used for tests against the "disable-algorithms"
+    # configuration option. Must be different from above algorithms.
+    "DISABLED_ALGORITHM": "",
+    "DISABLED_ALGORITHM_NUMBER": "",
+    "DISABLED_BITS": "",
+    # Default HMAC algorithm. Must match the rndc configuration in
+    # bin/tests/system/_common (rndc.conf, rndc.key)
+    "DEFAULT_HMAC": "hmac-sha256",
+}
 
 STABLE_PERIOD = 3600 * 3
 """number of secs during which algorithm selection remains stable"""
@@ -93,57 +112,46 @@ ALGORITHM_SETS = {
     # ),
 }
 
-TESTCRYPTO = Path(__file__).resolve().parent / "testcrypto.sh"
-
-KEYGEN = os.getenv("KEYGEN", "")
-if not KEYGEN:
-    raise RuntimeError("KEYGEN environment variable has to be set")
+# TODO rewrite testcrypto.sh to python
+TESTCRYPTO = Path(__file__).resolve().parent.parent.parent / "testcrypto.sh"
 
-ALGORITHM_SET = os.getenv("ALGORITHM_SET", "stable")
-assert ALGORITHM_SET in ALGORITHM_SETS, f'ALGORITHM_SET "{ALGORITHM_SET}" unknown'
-logging.debug('choosing from ALGORITHM_SET "%s"', ALGORITHM_SET)
 
-
-def is_supported(alg: Algorithm) -> bool:
+def _is_supported(alg: Algorithm) -> bool:
     """Test whether a given algorithm is supported on the current platform."""
     try:
         subprocess.run(
             f"{TESTCRYPTO} -q {alg.name}",
             shell=True,
             check=True,
-            env={
-                "KEYGEN": KEYGEN,
-                "TMPDIR": os.getenv("TMPDIR", "/tmp"),
-            },
+            env=BASIC_VARS,
             stdout=subprocess.DEVNULL,
         )
     except subprocess.CalledProcessError as exc:
-        logging.debug(exc)
-        logging.info("algorithm %s not supported", alg.name)
+        log.debug(exc)
+        log.info("algorithm %s not supported", alg.name)
         return False
     return True
 
 
-def filter_supported(algs: AlgorithmSet) -> AlgorithmSet:
+def _filter_supported(algs: AlgorithmSet) -> AlgorithmSet:
     """Select supported algorithms from the set."""
     filtered = {}
     for alg_type in algs._fields:
         candidates = getattr(algs, alg_type)
         if isinstance(candidates, Algorithm):
             candidates = [candidates]
-        supported = list(filter(is_supported, candidates))
+        supported = list(filter(_is_supported, candidates))
         if len(supported) == 1:
             supported = supported.pop()
         elif not supported:
             raise RuntimeError(
-                f'no {alg_type.upper()} algorithm from "{ALGORITHM_SET}" set '
-                "supported on this platform"
+                f"no {alg_type.upper()} algorithm " "supported on this platform"
             )
         filtered[alg_type] = supported
     return AlgorithmSet(**filtered)
 
 
-def select_random(algs: AlgorithmSet, stable_period=STABLE_PERIOD) -> AlgorithmSet:
+def _select_random(algs: AlgorithmSet, stable_period=STABLE_PERIOD) -> AlgorithmSet:
     """Select random DEFAULT, ALTERNATIVE and DISABLED algorithms from the set.
 
     The algorithm selection is deterministic for a given time period and
@@ -200,9 +208,11 @@ def select_random(algs: AlgorithmSet, stable_period=STABLE_PERIOD) -> AlgorithmS
     return AlgorithmSet(default, alternative, disabled)
 
 
-def algorithms_env(algs: AlgorithmSet) -> Dict[str, str]:
+def _algorithms_env(algs: AlgorithmSet, name: str) -> Dict[str, str]:
     """Return environment variables with selected algorithms as a dict."""
-    algs_env: Dict[str, str] = {}
+    algs_env = {
+        "ALGORITHM_SET": name,
+    }
 
     def set_alg_env(alg: Algorithm, prefix):
         algs_env[f"{prefix}_ALGORITHM"] = alg.name
@@ -217,25 +227,23 @@ def algorithms_env(algs: AlgorithmSet) -> Dict[str, str]:
     set_alg_env(algs.alternative, "ALTERNATIVE")
     set_alg_env(algs.disabled, "DISABLED")
 
-    logging.info("selected algorithms: %s", algs_env)
+    log.info("selected algorithms: %s", algs_env)
     return algs_env
 
 
-def main():
-    try:
-        algs = ALGORITHM_SETS[ALGORITHM_SET]
-        algs = filter_supported(algs)
-        algs = select_random(algs)
-        algs_env = algorithms_env(algs)
-    except Exception:
-        # if anything goes wrong, the conf.sh ignores error codes, so make sure
-        # we set an environment variable to an error value that can be checked
-        # later by the test runner and/or tests themselves
-        print("export ALGORITHM_SET=error")
-        raise
-    for name, value in algs_env.items():
-        print(f"export {name}={value}")
-
-
-if __name__ == "__main__":
-    main()
+def set_algorithm_set(name: Optional[str]):
+    if name is None:
+        name = "stable"
+    assert name in ALGORITHM_SETS, f'ALGORITHM_SET "{name}" unknown'
+    if name == ALG_VARS["ALGORITHM_SET"]:
+        log.debug('algorithm set already configured: "%s"', name)
+        return
+    log.debug('choosing from ALGORITHM_SET "%s"', name)
+
+    algs = ALGORITHM_SETS[name]
+    algs = _filter_supported(algs)
+    algs = _select_random(algs)
+    algs_env = _algorithms_env(algs, name)
+
+    ALG_VARS.update(algs_env)
+    os.environ.update(algs_env)
index 3e6d49dc749f237f58f076ed41f997fd20969dee..3478a84a545ab9cf826586fd9424183b0f3f897d 100644 (file)
@@ -15,6 +15,7 @@ from collections import ChainMap
 from .autoconf import AC_VARS  # type: ignore
 
 # pylint: enable=import-error
+from .algorithms import ALG_VARS
 from .basic import BASIC_VARS
 from .dirs import DIR_VARS
 from .openssl import OPENSSL_VARS
@@ -52,4 +53,4 @@ class VarLookup(ChainMap):
         return iter(self.keys())
 
 
-ALL = VarLookup(AC_VARS, BASIC_VARS, OPENSSL_VARS, PORT_VARS, DIR_VARS)
+ALL = VarLookup(AC_VARS, BASIC_VARS, OPENSSL_VARS, PORT_VARS, DIR_VARS, ALG_VARS)
index 7251e30f17a4e1f82669e57913a7b6d51b255b54..4b5e752afd52211717163756cb4427cb13990e38 100644 (file)
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
+# Explicitly setting ALGORITHM_SET is only needed is the script is executed
+# standalone without the pytest runner (e.g. for debugging).
 export ALGORITHM_SET="ecc_default"
-. ../conf.sh
 
-# Ensure the selected algorithm set is okay.
-if [ "$ALGORITHM_SET" = "error" ]; then
-  echofail "Algorithm selection failed." >&2
-  exit 1
-fi
+. ../conf.sh
 
 copy_setports ns1/named1.conf.in ns1/named.conf
 copy_setports ns2/named.conf.in ns2/named.conf
index 40248f96d985bd64e021a49082cabbeb6c624ecc..b460121b04112ea21b5c60ef727e309bbf789caf 100644 (file)
@@ -13,7 +13,6 @@
 
 set -e
 
-export ALGORITHM_SET="ecc_default"
 #shellcheck source=conf.sh
 . ../conf.sh
 
index 141ee838aa7f33b52aa4b0cc5671420d95a4b279..48d79acf28b39f3529249c4da95d9a7c73158f5f 100644 (file)
@@ -9,6 +9,10 @@
 # See the COPYRIGHT file distributed with this work for additional
 # information regarding copyright ownership.
 
+import pytest
+
+pytestmark = pytest.mark.algorithm_set("ecc_default")
+
 
 def test_mkeys(run_tests_sh):
     run_tests_sh()
index ff17998e3523afecc034a39bf4f36b178e18ff15..766b3dad2ea73675a35d7c4fcc457996080bfbb1 100644 (file)
@@ -20,3 +20,4 @@ junit_logging = log
 junit_log_passing_tests = 0
 markers =
     requires_zones_loaded: ensures the test does not start until the specified named instances load all configured zones
+    algorithm_set: use to select desired algorithms from isctest/vars/algorithms.py