From: Vasek Sraier Date: Tue, 9 Mar 2021 10:03:07 +0000 (+0100) Subject: integration: bind mounting repository and the test X-Git-Tag: v6.0.0a1~223 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3774ca9eed24dc05cc487ce4a7199ab628537a2;p=thirdparty%2Fknot-resolver.git integration: bind mounting repository and the test --- diff --git a/manager/integration/README.md b/manager/integration/README.md index eb482434c..d1f81bcaf 100644 --- a/manager/integration/README.md +++ b/manager/integration/README.md @@ -12,15 +12,17 @@ Install Podman and configure it so that it can run in a rootless mode. The tool ## What is a test? -A single test is a directory in `tests`. It has to contain `Dockerfile`. The container created by the `Dockerfile` has to have an executable called `/test` in its file system. The `Dockerfile` must be configured to execute systemd on container startup. The `/test` executable is then called manually by the testing tool. +A single test is a directory in `tests`. It has to contain `Dockerfile`, which defines the used system. The `Dockerfile` must be configured to execute systemd on container startup. -Exit code of the `/test` script determines the result of a test. 0 means test successfull, non-zero unsuccessful. +The test directory is mounted to `/test`, the root of the git repository is mounted to `/repo`. Both are read-only mounts. + +The test starts with the execution of `/test/run` executable. Its exit code determines the result of a test. 0 means test successfull, non-zero unsuccessful. ## How does the integration tool work? The tool launches a Podman subprocess which exposes a HTTP API. This API is then used to control the containers. -For each directory in `tests/`, the testing tool builds the container, starts it, exec's `/test` and observes its result. After that, it issues `systemctl poweroff` and waits until the container turns itself off. +For each directory in `tests/`, the testing tool builds the container, starts it, exec's `/test/run` and observes its result. After that, it issues `systemctl poweroff` and waits until the container turns itself off. Because building the container is slow (even with Podman's caching), we skip it if it's not needed. The testing tool creates a `.contentshash` file within each test directory, which contains a hash of all content. The container is rebuilt only when the hash changes (or the file is missing). diff --git a/manager/integration/runner.py b/manager/integration/runner.py index 3115f96fe..87020206e 100644 --- a/manager/integration/runner.py +++ b/manager/integration/runner.py @@ -1,7 +1,7 @@ import subprocess import signal import uuid -from typing import Optional, List, BinaryIO +from typing import Optional, List, BinaryIO, Dict import shutil import tarfile import os @@ -11,7 +11,7 @@ import requests import hashlib from _hashlib import HASH as Hash -from pathlib import Path +from pathlib import Path, PurePath from typing import Union @@ -143,10 +143,25 @@ class PodmanServiceManager: # create hashfile for future caching self._create_hashfile(context_dir, current_hash) - def _api_create_container(self, image: str) -> str: + def _api_create_container( + self, image: str, bind_mount_ro: Dict[PurePath, PurePath] = {} + ) -> str: response = requests.post( self._create_url("libpod/containers/create"), - json={"image": image, "remove": True, "systemd": "true"}, + json={ + "image": image, + "remove": True, + "systemd": "true", + "mounts": [ + { + "destination": str(destination), + "options": ["ro"], + "source": str(source), + "type": "bind", + } + for source, destination in bind_mount_ro.items() + ], + }, ) response.raise_for_status() return response.json()["Id"] @@ -192,9 +207,11 @@ class PodmanServiceManager: ) response.raise_for_status() - def start_temporary_and_wait(self, image: str, command: List[str]) -> int: + def start_temporary_and_wait( + self, image: str, command: List[str], bind_mount_ro: Dict[PurePath, PurePath] = {} + ) -> int: # start the container - container_id = self._api_create_container(image) + container_id = self._api_create_container(image, bind_mount_ro) self._api_start_container(container_id) # the container is booting, let's give it some time @@ -222,9 +239,13 @@ class Colors: RESET = "\033[0m" +def _get_git_root() -> PurePath: + result = subprocess.run("git rev-parse --show-toplevel", shell=True, capture_output=True) + return PurePath(str(result.stdout, encoding='utf8').strip()) + class TestRunner: _TEST_DIRECTORY = "tests" - _TEST_ENTRYPOINT = ["/test"] + _TEST_ENTRYPOINT = ["/test/run"] @staticmethod def _list_tests() -> List[Path]: @@ -248,7 +269,12 @@ class TestRunner: manager.build_image(test_path, image) print("\tRunning...") exit_code = manager.start_temporary_and_wait( - image, TestRunner._TEST_ENTRYPOINT + image, + TestRunner._TEST_ENTRYPOINT, + bind_mount_ro={ + _get_git_root(): PurePath('/repo'), + test_path.absolute(): '/test' + } ) if exit_code == 0: print(f"\t{Colors.GREEN}Test succeeded{Colors.RESET}") diff --git a/manager/integration/tests/dummy/Dockerfile b/manager/integration/tests/dummy/Dockerfile index 6f6c58301..05b007838 100644 --- a/manager/integration/tests/dummy/Dockerfile +++ b/manager/integration/tests/dummy/Dockerfile @@ -6,6 +6,4 @@ RUN useradd -m -s /bin/bash dev RUN echo "dev:password" | chpasswd RUN usermod -a -G sudo dev -COPY test /test - CMD ["/sbin/init"] diff --git a/manager/integration/tests/dummy/test b/manager/integration/tests/dummy/run similarity index 100% rename from manager/integration/tests/dummy/test rename to manager/integration/tests/dummy/run