]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
tests: pytest packaging tests for Debian 10 and Ubuntu Disco
authorLukáš Ježek <lukas.jezek@nic.cz>
Thu, 6 Feb 2020 15:12:11 +0000 (16:12 +0100)
committerTomas Krizek <tomas.krizek@nic.cz>
Wed, 27 May 2020 08:12:39 +0000 (10:12 +0200)
16 files changed:
client/packaging/test.sh
daemon/packaging/debian/10/builddeps
daemon/packaging/debian/10/post-build.sh [deleted file]
daemon/packaging/debian/10/post-run.sh [deleted file]
daemon/packaging/debian/10/pre-build.sh
daemon/packaging/debian/10/pre-run.sh
doc/packaging/debian/10/build.sh
doc/packaging/debian/10/install.sh [new file with mode: 0755]
doc/packaging/test.sh
modules/bogus_log/packaging/debian/10/rundeps [deleted file]
modules/etcd/packaging/debian/10/pre-test.sh [moved from modules/etcd/packaging/debian/10/install.sh with 100% similarity]
modules/etcd/packaging/debian/10/rundeps [moved from modules/etcd/packaging/debian/10/builddeps with 100% similarity]
scripts/packaging/debian/10/rundeps [deleted file]
tests/packaging-doc.py
tests/packaging/conftest.py [new file with mode: 0644]
tests/packaging/test_packaging.py [new file with mode: 0644]

index 21fa304dad402346cb294c166ff2d97eb8625d46..e1311c486a24c75ccde58c33ace834988025c9e7 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-3.0-or-later
-test -e /usr/sbin/kresc
-/usr/sbin/kresc  # command will fail because of invalid parameters
+test -e sbin/kresc
+sbin/kresc  # command will fail because of invalid parameters
 test "$?" -eq 1  # linker error would have different exit code
index 4f96c4438919f05a944b4dd8d9e6e394eb68ae41..604993c10f341f7ae6c52b55aed4b01cee8c295f 100644 (file)
@@ -10,7 +10,3 @@ libuv1-dev
 luajit
 pkg-config
 meson
-doxygen
-python3-breathe
-python3-sphinx
-python3-sphinx-rtd-theme
diff --git a/daemon/packaging/debian/10/post-build.sh b/daemon/packaging/debian/10/post-build.sh
deleted file mode 100755 (executable)
index e69de29..0000000
diff --git a/daemon/packaging/debian/10/post-run.sh b/daemon/packaging/debian/10/post-run.sh
deleted file mode 100755 (executable)
index e69de29..0000000
index ec7993d6fef280103062b3e94eda5a3146bc690c..dc3b8019c8b81528812f13f8b44dc66837646a9b 100755 (executable)
@@ -4,7 +4,7 @@
 apt-get update
 apt-get install -y wget gnupg apt-utils
 echo 'deb http://download.opensuse.org/repositories/home:/CZ-NIC:/knot-resolver-build/Debian_10/ /' > /etc/apt/sources.list.d/home:CZ-NIC:knot-resolver-build.list
-wget https://download.opensuse.org/repositories/home:CZ-NIC:knot-resolver-build/Debian_Next/Release.key -O Release.key
+wget -nv https://download.opensuse.org/repositories/home:CZ-NIC:knot-resolver-build/Debian_10/Release.key -O Release.key
 apt-key add - < Release.key
 
 apt-get update
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..01b4c5bf6c7226600b5833a1b164e136ee24606b 100755 (executable)
@@ -0,0 +1,7 @@
+apt-get update
+apt-get install -y wget gnupg apt-utils
+
+wget https://secure.nic.cz/files/knot-resolver/knot-resolver-release.deb
+dpkg -i knot-resolver-release.deb
+
+apt-get update
index 3422d6846c6a27fa5d202419be3e688490e5003e..e6084df48ce6dd002d6bed0ee03e21e2ae7ddb25 100755 (executable)
@@ -1,3 +1,19 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-3.0-or-later
-ninja -C build_packaging doc
+[ -d /root/kresd/build_packaging ] && rm -rf /root/kresd/build_packaging/;
+CFLAGS="$CFLAGS -Wall -pedantic -fno-omit-frame-pointer"
+LDFLAGS="$LDFLAGS -Wl,--as-needed"
+meson build_packaging \
+       --buildtype=plain \
+       --prefix=/root/kresd/install_packaging \
+       --libdir=lib \
+       --default-library=static \
+       -Ddoc=enabled \
+       -Dsystemd_files=enabled \
+       -Dclient=enabled \
+       -Dkeyfile_default=/usr/share/dns/root.key \
+       -Droot_hints=/usr/share/dns/root.hints \
+       -Dinstall_kresd_conf=enabled \
+       -Dunit_tests=enabled \
+       -Dc_args="${CFLAGS}" \
+       -Dc_link_args="${LDFLAGS}";
diff --git a/doc/packaging/debian/10/install.sh b/doc/packaging/debian/10/install.sh
new file mode 100755 (executable)
index 0000000..3422d68
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-3.0-or-later
+ninja -C build_packaging doc
index 491126ced8099c5946dd4a88abad2f716ce72fa3..33bf175d133fcedc717f3e28f232eb852e9be96f 100755 (executable)
@@ -1,3 +1,3 @@
 #!/bin/sh
 # SPDX-License-Identifier: GPL-3.0-or-later
-test -e doc/html/index.html
+test -e ../doc/html/index.html
diff --git a/modules/bogus_log/packaging/debian/10/rundeps b/modules/bogus_log/packaging/debian/10/rundeps
deleted file mode 100644 (file)
index c557cb2..0000000
+++ /dev/null
@@ -1 +0,0 @@
-lua-http
diff --git a/scripts/packaging/debian/10/rundeps b/scripts/packaging/debian/10/rundeps
deleted file mode 100644 (file)
index c3cd0e3..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-bash
-bsdmainutils
-coreutils
-gdb
-git
-luajit
-pkg-config
-sed
-tar
-xz-utils
index 67a6caa2ba3b51b53aaec027a8e36e5eed217310..40c6db092ea1f3f49d5402e5fa092a91e134b339 100644 (file)
@@ -133,6 +133,10 @@ def main():
 
             logging.debug('generating Dockerfile for %s', args)
             gen_dockerfile(args, tmpdir, srcdir)
+            from shutil import copyfile
+            copyfile(os.path.join(tmpdir, "Dockerfile"),
+                    "/tmp/Dockerfile_" + args[0] + args[1] + "_" + args[-1].replace('/', '-'))
+            continue
             logging.info('testing combination %s', args)
             docker_build(tmpdir, delete=not baseimg)
             baseimg = False
diff --git a/tests/packaging/conftest.py b/tests/packaging/conftest.py
new file mode 100644 (file)
index 0000000..7279c15
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import pytest
+import os
+
+
+def pytest_configure():
+    pytest.KR_PYTESTS_DIR = os.path.dirname(os.path.realpath(__file__))
+    pytest.KR_ROOT_DIR = os.path.join(pytest.KR_PYTESTS_DIR, "..", "..")
+    pytest.KR_PREFIX = "kr-packaging-tests-"
diff --git a/tests/packaging/test_packaging.py b/tests/packaging/test_packaging.py
new file mode 100644 (file)
index 0000000..32d4e7a
--- /dev/null
@@ -0,0 +1,396 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import os
+import pytest
+import docker
+import logging
+from pathlib import Path
+from abc import ABC, abstractmethod
+
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.DEBUG)
+EXCLUDED_TEST_DIRS = ['tests/unit/packaging', 'tests/packaging',
+                      'tests/integration/deckard/contrib/libfaketime/packaging']
+client = docker.from_env()
+
+
+class DockerCmdError(Exception):
+    """ Raised when shell command in Docker container failed """
+    pass
+
+
+class ContainerHandler():
+    def __init__(self, image):
+        self.img_id = image
+        self.container = None
+
+    def run(self):
+        self.container = client.containers.run(self.img_id, network_mode='host',
+                                               tty=True, detach=True)
+        logger.info('Run container ID={}'.format(self.container))
+
+    def stop(self):
+        self.container.kill()
+
+    def exec_cmd(self, cmd, workdir):
+        rcode, out = self.container.exec_run('/bin/sh -c \'' + cmd + '\'', workdir=workdir)
+        if rcode != 0:
+            raise DockerCmdError(rcode, out)
+
+    def getFiles(self, output, path):
+        strm, stat = self.container.get_archive(path)
+        with open(output, 'wb') as ofile:
+            for data in strm:
+                ofile.write(data)
+
+
+class DockerImages(ABC):
+    def __init__(self, version):
+        self.version = version
+        self.module = None
+        self.distro = None
+        self.build_id = None
+        self.run_id = None
+
+    @abstractmethod
+    def cmd_kresd_install(self):
+        raise NotImplementedError
+
+    @abstractmethod
+    def cmd_kresd_build(self):
+        raise NotImplementedError
+
+    @abstractmethod
+    def cmd_pkgs_install(self):
+        raise NotImplementedError
+
+    def readDependencies(self, deps_file):
+        """Read dependencies from file"""
+        listf = None
+        try:
+            with open(deps_file, 'r') as f:
+                listf = f.read().splitlines()
+        except FileNotFoundError:
+            pass
+
+        return listf
+
+    def __genDockerFile(self, path, from_image=None):
+        """Generate Dockerfile for build image"""
+        if self.module is None:
+            raise AttributeError
+
+        if from_image is None:
+            from_image = '{0}:{1}'.format(self.distro, self.version)
+
+        distro_dir = os.path.join(self.module, self.distro, self.version)
+
+        dockerf = open(os.path.join(path, 'Dockerfile-build'), 'w')
+
+        dockerf.write('FROM {}\n'.format(from_image))
+        dockerf.write('WORKDIR /root/kresd\n')
+        if self.module == 'daemon/packaging':
+            dockerf.write('COPY . /root/kresd\n')
+        # when this file doesn't exists, tzdata needs user interaction
+        dockerf.write('RUN if [ ! -f /etc/localtime ];' +
+                      'then ln -fs /usr/share/zoneinfo/Europe/Prague /etc/localtime; fi\n')
+        if os.path.isfile(os.path.join(distro_dir, 'pre-build.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'pre-build.sh')))
+        if os.path.isfile(os.path.join(distro_dir, 'builddeps')):
+            dockerf.write('RUN {0} {1}\n'.format(self.cmd_pkgs_install(),
+                          ' '.join(self.readDependencies(os.path.join(distro_dir, 'builddeps')))))
+        if os.path.isfile(os.path.join(distro_dir, 'build.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'build.sh')))
+        else:
+            dockerf.write('RUN {}\n'.format(self.cmd_kresd_build()))
+        if os.path.isfile(os.path.join(distro_dir, 'install.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'install.sh')))
+        else:
+            dockerf.write('RUN {}\n'.format(self.cmd_kresd_install()))
+        if os.path.isfile(os.path.join(distro_dir, 'post-build.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'post-build.sh')))
+
+        dockerf.close()
+
+    def __genDockerFile_run(self, path, build_id, from_image=None):
+        """Generate Dockerfile for run image"""
+        if self.module is None:
+            raise AttributeError
+
+        if from_image is None:
+            from_image = '{0}:{1}'.format(self.distro, self.version)
+
+        distro_dir = os.path.join(self.module, self.distro, self.version)
+
+        dockerf = open(os.path.join(path, 'Dockerfile-run'), 'w')
+
+        dockerf.write('FROM {}\n'.format(from_image))
+        dockerf.write('COPY --from={} /root/kresd /root/kresd\n'.format(build_id))
+        dockerf.write('WORKDIR /root/kresd\n')
+        if os.path.isfile(os.path.join(distro_dir, 'pre-run.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'pre-run.sh')))
+        if os.path.isfile(os.path.join(distro_dir, 'rundeps')):
+            dockerf.write('RUN {0} {1}\n'.format(self.cmd_pkgs_install(),
+                          ' '.join(self.readDependencies(os.path.join(distro_dir, 'rundeps')))))
+        if os.path.isfile(os.path.join(distro_dir, 'pre-test.sh')):
+            dockerf.write('RUN {}\n'.format(os.path.join(distro_dir, 'pre-test.sh')))
+
+        dockerf.close()
+
+    def build(self, tmpdir, tag="", from_image=None):
+        self.__genDockerFile(tmpdir, from_image=from_image)
+
+        logger.debug('tmpdir={}'.format(tmpdir))
+        logger.debug('datadir={}'.format(pytest.KR_ROOT_DIR))
+        logger.debug('tag={}'.format(tag))
+        image = client.images.build(path=str(pytest.KR_ROOT_DIR),
+                                    dockerfile=os.path.join(tmpdir, 'Dockerfile-build'),
+                                    network_mode='host', tag=tag, rm=True)
+        logger.info('"Build image" ID={} created'.format(image[0].short_id))
+        self.build_id = image[0].short_id
+        return self.build_id
+
+    def build_run(self, tmpdir, build_id, from_image=None, tag=""):
+        self.__genDockerFile_run(tmpdir, build_id, from_image=from_image)
+
+        logger.debug('tmpdir={}'.format(tmpdir))
+        logger.debug('datadir={}'.format(tmpdir))
+        logger.debug('tag={}'.format(tag))
+        image = client.images.build(path=str(tmpdir),
+                                    dockerfile=os.path.join(tmpdir, 'Dockerfile-run'),
+                                    network_mode='host', tag=tag, rm=True)
+        logger.info('"Run image" ID={} created'.format(image[0].short_id))
+        self.run_id = image[0].short_id
+        return self.run_id
+
+
+class DebianImage(DockerImages):
+    def __init__(self, version):
+        super().__init__(version)
+        self.distro = 'debian'
+
+    def cmd_kresd_install(self):
+        # apt install
+        return 'ninja -C build_packaging install >/dev/null'
+
+    def cmd_kresd_build(self):
+        return """\\
+                [ -d /root/kresd/build_packaging ] && rm -rf /root/kresd/build_packaging/; \\
+                CFLAGS=\"$CFLAGS -Wall -pedantic -fno-omit-frame-pointer\"; \\
+                LDFLAGS=\"$LDFLAGS -Wl,--as-needed\"; \\
+                meson build_packaging \\
+                    --buildtype=plain \\
+                    --prefix=/root/kresd/install_packaging \\
+                    --libdir=lib \\
+                    --default-library=static \\
+                    -Dsystemd_files=enabled \\
+                    -Dclient=enabled \\
+                    -Dkeyfile_default=/usr/share/dns/root.key \\
+                    -Droot_hints=/usr/share/dns/root.hints \\
+                    -Dinstall_kresd_conf=enabled \\
+                    -Dunit_tests=enabled \\
+                    -Dc_args=\"${CFLAGS}\" \\
+                    -Dc_link_args=\"${LDFLAGS}\";
+                """
+
+    def cmd_pkgs_install(self):
+        return 'apt-get install -y '
+
+
+class UbuntuImage(DebianImage):
+    def __init__(self, version):
+        super().__init__(version)
+        self.distro = 'ubuntu'
+
+
+class CentosImage(DockerImages):
+    def __init__(self, version):
+        super().__init__(version)
+        self.distro = 'centos'
+
+    def cmd_kresd_install(self):
+        raise NotImplementedError
+        return ""
+
+    def cmd_kresd_build(self):
+        raise NotImplementedError
+        return ""
+
+    def cmd_pkgs_install(self):
+        raise NotImplementedError
+        return ""
+
+
+def create_distro_image(name, version):
+    img = None
+
+    if (name == 'debian'):
+        img = DebianImage(version)
+    elif (name == 'ubuntu'):
+        img = UbuntuImage(version)
+    elif (name == 'centos'):
+        img = CentosImage(version)
+    else:
+        img = None
+
+    return img
+
+
+def list_dirs(path, exclude=None):
+    """return all 'packaging' directories with full path"""
+    filtered_dirs = []
+
+    for rootpath, dirs, _ in os.walk(path):
+
+        if (os.path.basename(rootpath) == 'packaging'):
+            fdir = os.path.relpath(rootpath, path)
+            if exclude is not None:
+                if fdir not in exclude:
+                    filtered_dirs.append(fdir)
+            else:
+                filtered_dirs.append(fdir)
+
+    return filtered_dirs
+
+
+def list_tests_dirs():
+    """return all 'packaging' directories without directories included in EXCLUDED_TEST_DIRS"""
+    return list_dirs(pytest.KR_ROOT_DIR, EXCLUDED_TEST_DIRS)
+
+
+def list_distro_vers(distro_root):
+    """
+    return list of { 'name': distro_name, 'version': distro_version)
+    pairs found in distro_root
+    """
+    # transform list of paths like TOP/debian/10 into (debian, 10)
+    dist_ver = [{'name': p.parts[-2], 'version': p.parts[-1]} for p
+                in Path(distro_root).glob('*/*') if p.is_dir()]
+
+    return list(dist_ver)
+
+
+MODULES = list_tests_dirs()
+DISTROS = list_distro_vers(os.path.join(pytest.KR_ROOT_DIR, 'daemon/packaging'))
+DISTROS_NAMES = ['{0}_{1}'.format(distro['name'], distro['version']) for distro in DISTROS]
+
+
+@pytest.fixture(scope='session', params=DISTROS, ids=DISTROS_NAMES)
+def buildenv(request, tmpdir_factory):
+    distro = request.param
+
+    logger.debug('Creating main images for "{0} {1}"'.format(distro['name'], distro['version']))
+    img = create_distro_image(distro['name'], distro['version'])
+    if img is None:
+        logger.warning('Unknown distro {}'.format(distro['name']))
+    else:
+        img.module = 'daemon/packaging'
+        tmpdir = tmpdir_factory.mktemp(distro['name']+distro['version'])
+        img.build(tmpdir, tag=pytest.KR_PREFIX+distro['name']+distro['version']+'-build')
+        img.build_run(tmpdir, img.build_id,
+                      tag=pytest.KR_PREFIX+distro['name']+distro['version']+'-run',
+                      from_image=img.build_id)
+
+    yield img
+    client.images.remove(img.run_id)
+    client.images.remove(img.build_id)
+
+
+@pytest.mark.parametrize('module', MODULES)
+def test_collect(module, buildenv, tmp_path):
+    logger.info(' ### Run test {} ###'.format(module))
+
+    if buildenv is None:
+        logger.error('Distro "{0} {1}" isn\'t implemented'.format(buildenv.distro,
+                                                                  buildenv.version))
+        assert False
+
+    rcode = None
+    buildmod = None
+    module_dir = os.path.join(pytest.KR_ROOT_DIR, module)
+    distro_dir = os.path.join(module_dir, buildenv.distro, buildenv.version)
+
+    try:
+        if module == 'daemon/packaging':
+            # use main "run image" without changes
+            logging.info('Use main "run image"')
+            ch = ContainerHandler(buildenv.run_id)
+            ch.run()
+        elif buildenv is not None:
+            if os.path.isfile(os.path.join(distro_dir, 'pre-build.sh')) \
+                    or os.path.isfile(os.path.join(distro_dir, 'builddeps')):
+                # create module specific "build image"
+                logger.info('Create new "build image"')
+                buildmod = create_distro_image(buildenv.distro, buildenv.version)
+                buildmod.module = module
+                buildmod.build(tmp_path, from_image=buildenv.build_id,
+                               tag=pytest.KR_PREFIX+buildmod.distro+buildmod.version+'-' +
+                               module+'-build')
+
+            if buildmod is not None:
+                # new build image was made, create new module specific "run image"
+                logger.info('Create module specific "run image" from Dockerfile')
+                buildmod.build_run(tmp_path, buildmod.build_id,
+                                   tag=pytest.KR_PREFIX+buildmod.distro+buildmod.version+'-' +
+                                   module+'-run', from_image=buildenv.run_id)
+                ch = ContainerHandler(buildmod.run_id)
+                ch.run()
+            elif os.path.isfile(os.path.join(distro_dir, 'pre-run.sh')) \
+                    or os.path.isfile(os.path.join(distro_dir, 'rundeps')):
+                # use main "run image" and apply module specific changes
+                logger.info('Apply module specific changes to "run image"')
+                buildmod = buildenv
+                ch = ContainerHandler(buildmod.run_id)
+                ch.run()
+
+                if os.path.isfile(os.path.join(distro_dir, 'pre-run.sh')):
+                    ch.exec_cmd(os.path.join(module, buildenv.distro, buildenv.version,
+                                'pre-run.sh'), '/root/kresd/')
+
+                if os.path.isfile(os.path.join(distro_dir, 'rundeps')):
+                    ch.exec_cmd(buildenv.cmd_pkgs_install() + ' '.join(
+                                buildmod.readDependencies(os.path.join(distro_dir, 'rundeps'))),
+                                '/root/kresd/')
+
+                if os.path.isfile(os.path.join(distro_dir, 'pre-test.sh')):
+                    ch.exec_cmd(os.path.join(module, buildenv.distro, buildenv.version,
+                                'pre-test.sh'), '/root/kresd/')
+            else:
+                # use main "run image" without changes
+                logging.info('Use main "run image"')
+                ch = ContainerHandler(buildenv.run_id)
+                ch.run()
+
+        # run test
+        if os.path.isfile(os.path.join(module_dir, 'test.config')):
+            ch.exec_cmd('/root/kresd/install_packaging/sbin/kresd -n -c ' + os.path.join('..',
+                        module, 'test.config'), '/root/kresd/install_packaging')
+        elif os.path.isfile(os.path.join(module_dir, 'test.sh')):
+            ch.exec_cmd('/bin/sh -c ' + os.path.join('..', module, 'test.sh'),
+                        '/root/kresd/install_packaging/')
+        else:
+            ch.stop()
+            ch.container.remove()
+            logger.error('Test file (test.config or test.sh) not found')
+            assert False
+
+        rcode = 0
+
+        if os.path.isfile(os.path.join(distro_dir, 'post-run.sh')):
+            ch.exec_cmd(os.path.join(module, buildenv.distro, buildenv.version, 'post-run.sh'),
+                        '/root/kresd/')
+
+    except DockerCmdError as err:
+        rcode, out = err.args
+        logger.debug('rcode: {}'.format(rcode))
+        logger.error(out.decode('utf-8'))
+    finally:
+        ch.stop()
+        ch.container.remove()
+        if buildmod is not None and buildmod is not buildenv:
+            client.images.remove(buildmod.run_id)
+            client.images.remove(buildmod.build_id)
+
+    assert(rcode == 0)