1
0
mirror of https://gitlab.isc.org/isc-projects/bind9.git synced 2025-04-18 09:44:09 +03:00

Move test code that can be reused to isctest

This is the first step of converting the kasp system test to pytest.
Well, perhaps not the first, because earlier the ksr system test was
already converted to pytest and then the `isctest/kasp.py` library
was already introduced. Lots of this code can be reused for the kasp
pytest code.

First of all, 'check_file_contents_equal' is moved out of the ksr test
and into the 'check' library. This feels the most appropriate place
for this function to be reused in other tests. Then, 'keystr_to_keylist'
is moved to the 'kasp' library.

Introduce two new methods that are unused in this point of time, but
we are going to need them for the kasp system test. 'zone_contains'
will be used to check if a signature exists in the zonefile. This way
we can tell whether the signature has been reused or refreshed.
'file_contents_contain' will be used to check if the comment and public
DNSKEY record in the keyfile is correct.
This commit is contained in:
Matthijs Mekking 2025-03-13 15:46:39 +01:00
parent 21c7ec182a
commit ee8e9f1ded
4 changed files with 102 additions and 56 deletions

View File

@ -9,6 +9,7 @@
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
import difflib
import shutil
from typing import Optional
@ -128,3 +129,24 @@ def is_response_to(response: dns.message.Message, query: dns.message.Message) ->
single_question(response)
single_question(query)
assert query.is_response(response), str(response)
def file_contents_equal(file1, file2):
def normalize_line(line):
# remove trailing&leading whitespace and replace multiple whitespaces
return " ".join(line.split())
def read_lines(file_path):
with open(file_path, "r", encoding="utf-8") as file:
return [normalize_line(line) for line in file.readlines()]
lines1 = read_lines(file1)
lines2 = read_lines(file2)
differ = difflib.Differ()
diff = differ.compare(lines1, lines2)
for line in diff:
assert not line.startswith("+ ") and not line.startswith(
"- "
), f'file contents of "{file1}" and "{file2}" differ'

View File

@ -15,7 +15,7 @@ from pathlib import Path
import re
import subprocess
import time
from typing import Optional, Union
from typing import List, Optional, Union
from datetime import datetime, timedelta, timezone
@ -577,3 +577,7 @@ def check_subdomain(server, zone, ksks, zsks):
assert len(rrsigs) > 0
check_signatures(rrsigs, qtype, fqdn, ksks, zsks)
def keystr_to_keylist(keystr: str, keydir: Optional[str] = None) -> List[Key]:
return [Key(name, keydir) for name in keystr.split()]

View File

@ -0,0 +1,42 @@
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# 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 https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
import dns.zone
def zone_contains(
zone: dns.zone.Zone, rrset: dns.rrset.RRset, compare_ttl=False
) -> bool:
"""Check if a zone contains RRset"""
def compare_rrs(rr1, rrset):
rr2 = next((other_rr for other_rr in rrset if rr1 == other_rr), None)
if rr2 is None:
return False
if compare_ttl:
return rr1.ttl == rr2.ttl
return True
for _, node in zone.nodes.items():
for rdataset in node:
for rr in rdataset:
if compare_rrs(rr, rrset):
return True
return False
def file_contents_contain(file, substr):
with open(file, "r", encoding="utf-8") as fp:
for line in fp:
if f"{substr}" in line:
return True
return False

View File

@ -10,19 +10,14 @@
# information regarding copyright ownership.
from datetime import timedelta
import difflib
import os
import shutil
import time
from typing import List, Optional
import pytest
import isctest
from isctest.kasp import (
Key,
KeyTimingMetadata,
)
from isctest.kasp import KeyTimingMetadata
pytestmark = pytest.mark.extra_artifacts(
[
@ -89,31 +84,6 @@ def between(value, start, end):
return start < value < end
def check_file_contents_equal(file1, file2):
def normalize_line(line):
# remove trailing&leading whitespace and replace multiple whitespaces
return " ".join(line.split())
def read_lines(file_path):
with open(file_path, "r", encoding="utf-8") as file:
return [normalize_line(line) for line in file.readlines()]
lines1 = read_lines(file1)
lines2 = read_lines(file2)
differ = difflib.Differ()
diff = differ.compare(lines1, lines2)
for line in diff:
assert not line.startswith("+ ") and not line.startswith(
"- "
), f'file contents of "{file1}" and "{file2}" differ'
def keystr_to_keylist(keystr: str, keydir: Optional[str] = None) -> List[Key]:
return [Key(name, keydir) for name in keystr.split()]
def ksr(zone, policy, action, options="", raise_on_exception=True):
ksr_command = [
os.environ.get("KSR"),
@ -515,14 +485,14 @@ def test_ksr_common(servers):
# create ksk
kskdir = "ns1/offline"
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 1
check_keys(ksks, None)
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
out, _ = ksr(zone, policy, "keygen", options="-i now -e +1y")
zsks = keystr_to_keylist(out)
zsks = isctest.kasp.keystr_to_keylist(out)
assert len(zsks) == 2
lifetime = timedelta(days=31 * 6)
@ -532,7 +502,7 @@ def test_ksr_common(servers):
# in the given key directory
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 2
lifetime = timedelta(days=31 * 6)
@ -575,18 +545,22 @@ def test_ksr_common(servers):
# check that 'dnssec-ksr keygen' selects pregenerated keys for
# the same time bundle
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +1y")
selected_zsks = keystr_to_keylist(out, zskdir)
selected_zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(selected_zsks) == 2
for index, key in enumerate(selected_zsks):
assert zsks[index] == key
check_file_contents_equal(f"{key.path}.private", f"{key.path}.private.backup")
check_file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
check_file_contents_equal(f"{key.path}.state", f"{key.path}.state.backup")
isctest.check.file_contents_equal(
f"{key.path}.private", f"{key.path}.private.backup"
)
isctest.check.file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
isctest.check.file_contents_equal(
f"{key.path}.state", f"{key.path}.state.backup"
)
# check that 'dnssec-ksr keygen' generates only necessary keys for
# overlapping time bundle
out, err = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +2y -v 1")
overlapping_zsks = keystr_to_keylist(out, zskdir)
overlapping_zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(overlapping_zsks) == 4
verbose = err.split()
@ -606,15 +580,19 @@ def test_ksr_common(servers):
for index, key in enumerate(overlapping_zsks):
if index < 2:
assert zsks[index] == key
check_file_contents_equal(
isctest.check.file_contents_equal(
f"{key.path}.private", f"{key.path}.private.backup"
)
check_file_contents_equal(f"{key.path}.key", f"{key.path}.key.backup")
check_file_contents_equal(f"{key.path}.state", f"{key.path}.state.backup")
isctest.check.file_contents_equal(
f"{key.path}.key", f"{key.path}.key.backup"
)
isctest.check.file_contents_equal(
f"{key.path}.state", f"{key.path}.state.backup"
)
# run 'dnssec-ksr keygen' again with verbosity 0
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {now} -e +2y")
overlapping_zsks2 = keystr_to_keylist(out, zskdir)
overlapping_zsks2 = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(overlapping_zsks2) == 4
check_keys(overlapping_zsks2, lifetime)
for index, key in enumerate(overlapping_zsks2):
@ -709,7 +687,7 @@ def test_ksr_lastbundle(servers):
kskdir = "ns1/offline"
offset = -timedelta(days=365)
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1d -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 1
check_keys(ksks, None, offset=offset)
@ -717,7 +695,7 @@ def test_ksr_lastbundle(servers):
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1d")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 2
lifetime = timedelta(days=31 * 6)
@ -788,7 +766,7 @@ def test_ksr_inthemiddle(servers):
kskdir = "ns1/offline"
offset = -timedelta(days=365)
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i -1y -e +1y -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 1
check_keys(ksks, None, offset=offset)
@ -796,7 +774,7 @@ def test_ksr_inthemiddle(servers):
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i -1y -e +1y")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 4
lifetime = timedelta(days=31 * 6)
@ -868,13 +846,13 @@ def check_ksr_rekey_logs_error(server, zone, policy, offset, end):
then = now + offset
until = now + end
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i {then} -e {until} -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 1
# key generation
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i {then} -e {until}")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 2
# create request
@ -941,7 +919,7 @@ def test_ksr_unlimited(servers):
# create ksk
kskdir = "ns1/offline"
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +2y -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 1
check_keys(ksks, None)
@ -949,7 +927,7 @@ def test_ksr_unlimited(servers):
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +2y")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 1
lifetime = None
@ -1058,7 +1036,7 @@ def test_ksr_twotone(servers):
# create ksk
kskdir = "ns1/offline"
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 2
ksks_defalg = []
@ -1082,7 +1060,7 @@ def test_ksr_twotone(servers):
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
# First algorithm keys have a lifetime of 3 months, so there should
# be 4 created keys. Second algorithm keys have a lifetime of 5
# months, so there should be 3 created keys. While only two time
@ -1176,7 +1154,7 @@ def test_ksr_kskroll(servers):
# create ksk
kskdir = "ns1/offline"
out, _ = ksr(zone, policy, "keygen", options=f"-K {kskdir} -i now -e +1y -o")
ksks = keystr_to_keylist(out, kskdir)
ksks = isctest.kasp.keystr_to_keylist(out, kskdir)
assert len(ksks) == 2
lifetime = timedelta(days=31 * 6)
@ -1185,7 +1163,7 @@ def test_ksr_kskroll(servers):
# check that 'dnssec-ksr keygen' pregenerates right amount of keys
zskdir = "ns1"
out, _ = ksr(zone, policy, "keygen", options=f"-K {zskdir} -i now -e +1y")
zsks = keystr_to_keylist(out, zskdir)
zsks = isctest.kasp.keystr_to_keylist(out, zskdir)
assert len(zsks) == 1
check_keys(zsks, None)