From: Joerg Behrmann Date: Fri, 1 Dec 2023 13:30:05 +0000 (+0100) Subject: tests: add pytest CLI args for distribution and release X-Git-Tag: v20~56 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4ad47d01d1a527177ca8f7f023ccddfa0215cde1;p=thirdparty%2Fmkosi.git tests: add pytest CLI args for distribution and release Pass them to test functions via a fixture and the new Config subclass of Image. Also move pytest.ini into pyproject.toml while we're at it. --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c5f8fb5e..5cd11f0e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,6 +133,4 @@ jobs: EOF - name: Run integration tests - run: sudo --preserve-env timeout -k 30 1h python3 -m pytest --tb=no -sv -m integration tests/ - env: - MKOSI_TEST_DISTRIBUTION: ${{ matrix.distro }} + run: sudo --preserve-env timeout -k 30 1h python3 -m pytest --tb=no -sv -m integration -D ${{ matrix.distro }} tests/ diff --git a/pyproject.toml b/pyproject.toml index 8f46a9ebd..2c93e8a6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -73,3 +73,9 @@ ignore_missing_imports = true target-version = "py39" line-length = 119 select = ["E", "F", "I", "UP"] + +[tool.pytest.ini_options] +markers = [ + "integration: mark a test as an integration test." +] +addopts = "-m \"not integration\"" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index c24ad4606..000000000 --- a/pytest.ini +++ /dev/null @@ -1,4 +0,0 @@ -[pytest] -markers = - integration: mark a test as an integration test. -addopts = -m "not integration" diff --git a/tests/__init__.py b/tests/__init__.py index 74de5c4bc..df9bd345d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -6,32 +6,24 @@ import sys import tempfile from collections.abc import Iterator, Sequence from types import TracebackType -from typing import Any, Optional +from typing import Any, NamedTuple, Optional import pytest -from mkosi.distributions import Distribution, detect_distribution -from mkosi.log import die +from mkosi.distributions import Distribution from mkosi.run import run from mkosi.types import _FILE, CompletedProcess, PathString from mkosi.util import INVOKING_USER class Image: - def __init__(self, options: Sequence[PathString] = []) -> None: - self.options = options - - if d := os.getenv("MKOSI_TEST_DISTRIBUTION"): - self.distribution = Distribution(d) - elif detected := detect_distribution()[0]: - self.distribution = detected - else: - die("Cannot detect host distribution, please set $MKOSI_TEST_DISTRIBUTION to be able to run the tests") + class Config(NamedTuple): + distribution: Distribution + release: str - if r := os.getenv("MKOSI_TEST_RELEASE"): - self.release = r - else: - self.release = self.distribution.default_release() + def __init__(self, config: Config, options: Sequence[PathString] = []) -> None: + self.options = options + self.config = config def __enter__(self) -> "Image": self.output_dir = tempfile.TemporaryDirectory(dir="/var/tmp") @@ -71,8 +63,8 @@ class Image: return run([ "python3", "-m", "mkosi", - "--distribution", str(self.distribution), - "--release", self.release, + "--distribution", str(self.config.distribution), + "--release", self.config.release, *self.options, *options, "--output-dir", self.output_dir.name, @@ -118,7 +110,10 @@ class Image: check=False, ) - rc = 0 if self.distribution == Distribution.ubuntu or self.distribution.is_centos_variant() else 123 + if self.config.distribution == Distribution.ubuntu or self.config.distribution.is_centos_variant(): + rc = 0 + else: + rc = 123 if result.returncode != rc: raise subprocess.CalledProcessError(result.returncode, result.args, result.stdout, result.stderr) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..22d374130 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: LGPL-2.1+ +from typing import Any, Optional, cast + +import pytest + +from mkosi.distributions import Distribution, detect_distribution + +from . import Image + + +def pytest_addoption(parser: Any) -> None: + parser.addoption( + "-D", + "--distribution", + metavar="DISTRIBUTION", + help="Run the integration tests for the given distribution.", + default=detect_distribution()[0], + type=Distribution, + choices=[Distribution(d) for d in Distribution.values()], + ) + parser.addoption( + "-R", + "--release", + metavar="RELEASE", + help="Run the integration tests for the given release.", + ) + + +@pytest.fixture(scope="session") +def config(request: Any) -> Image.Config: + distribution = cast(Distribution, request.config.getoption("--distribution")) + release = cast(Optional[str], request.config.getoption("--release")) + if release is None: + release = distribution.default_release() + + return Image.Config(distribution=distribution, release=release) diff --git a/tests/test_boot.py b/tests/test_boot.py index 61f481af4..66f002779 100644 --- a/tests/test_boot.py +++ b/tests/test_boot.py @@ -14,15 +14,16 @@ pytestmark = pytest.mark.integration @pytest.mark.parametrize("format", OutputFormat) -def test_boot(format: OutputFormat) -> None: +def test_boot(config: Image.Config, format: OutputFormat) -> None: with Image( + config, options=[ "--kernel-command-line=systemd.unit=mkosi-check-and-shutdown.service", "--incremental", "--ephemeral", ], ) as image: - if image.distribution == Distribution.rhel_ubi and format in (OutputFormat.esp, OutputFormat.uki): + if image.config.distribution == Distribution.rhel_ubi and format in (OutputFormat.esp, OutputFormat.uki): pytest.skip("Cannot build RHEL-UBI images with format 'esp' or 'uki'") options = ["--format", str(format)] @@ -40,13 +41,13 @@ def test_boot(format: OutputFormat) -> None: image.boot(options=options, args=args) if ( - image.distribution == Distribution.ubuntu and + image.config.distribution == Distribution.ubuntu and format in (OutputFormat.cpio, OutputFormat.uki, OutputFormat.esp) ): # https://bugs.launchpad.net/ubuntu/+source/linux-kvm/+bug/2045561 pytest.skip("Cannot boot Ubuntu UKI/cpio images in qemu until we switch back to linux-kvm") - if image.distribution == Distribution.rhel_ubi: + if image.config.distribution == Distribution.rhel_ubi: return if format in (OutputFormat.tar, OutputFormat.none) or format.is_extension_image(): diff --git a/tests/test_initrd.py b/tests/test_initrd.py index f2730ce27..cc53ac9fa 100644 --- a/tests/test_initrd.py +++ b/tests/test_initrd.py @@ -35,15 +35,16 @@ def passphrase() -> Iterator[Path]: @pytest.fixture(scope="module") -def initrd(passphrase: Path) -> Iterator[Image]: +def initrd(config: Image.Config, passphrase: Path) -> Iterator[Image]: with Image( + config, options=[ "--directory", "", "--include=mkosi-initrd/", "--extra-tree", passphrase, ], ) as initrd: - if initrd.distribution == Distribution.rhel_ubi: + if initrd.config.distribution == Distribution.rhel_ubi: pytest.skip("Cannot build RHEL-UBI initrds") initrd.build() @@ -52,6 +53,7 @@ def initrd(passphrase: Path) -> Iterator[Image]: def test_initrd(initrd: Image) -> None: with Image( + initrd.config, options=[ "--initrd", Path(initrd.output_dir.name) / "initrd", "--kernel-command-line=systemd.unit=mkosi-check-and-shutdown.service", @@ -67,6 +69,7 @@ def test_initrd(initrd: Image) -> None: @pytest.mark.skipif(os.getuid() != 0, reason="mkosi-initrd LVM test can only be executed as root") def test_initrd_lvm(initrd: Image) -> None: with Image( + initrd.config, options=[ "--initrd", Path(initrd.output_dir.name) / "initrd", "--kernel-command-line=systemd.unit=mkosi-check-and-shutdown.service", @@ -95,7 +98,7 @@ def test_initrd_lvm(initrd: Image) -> None: run(["lvm", "lvcreate", "-l", "100%FREE", "-n", "lv0", "vg_mkosi"]) run(["lvm", "lvs"]) run(["udevadm", "wait", "/dev/vg_mkosi/lv0"]) - run([f"mkfs.{image.distribution.filesystem()}", "-L", "root", "/dev/vg_mkosi/lv0"]) + run([f"mkfs.{image.config.distribution.filesystem()}", "-L", "root", "/dev/vg_mkosi/lv0"]) with tempfile.TemporaryDirectory() as mnt, mount(Path("/dev/vg_mkosi/lv0"), Path(mnt)): # The image might have been built unprivileged so we need to fix the file ownership. Making all the @@ -143,7 +146,7 @@ def test_initrd_luks(initrd: Image, passphrase: Path) -> None: f"""\ [Partition] Type=root - Format={initrd.distribution.filesystem()} + Format={initrd.config.distribution.filesystem()} Minimize=guess Encrypt=key-file CopyFiles=/ @@ -152,6 +155,7 @@ def test_initrd_luks(initrd: Image, passphrase: Path) -> None: ) with Image( + initrd.config, options=[ "--initrd", Path(initrd.output_dir.name) / "initrd", "--repart-dir", repartd, @@ -168,8 +172,9 @@ def test_initrd_luks(initrd: Image, passphrase: Path) -> None: @pytest.mark.skipif(os.getuid() != 0, reason="mkosi-initrd LUKS+LVM test can only be executed as root") -def test_initrd_luks_lvm(initrd: Image, passphrase: Path) -> None: +def test_initrd_luks_lvm(config: Image.Config, initrd: Image, passphrase: Path) -> None: with Image( + config, options=[ "--initrd", Path(initrd.output_dir.name) / "initrd", "--kernel-command-line=systemd.unit=mkosi-check-and-shutdown.service", @@ -213,7 +218,7 @@ def test_initrd_luks_lvm(initrd: Image, passphrase: Path) -> None: run(["lvm", "lvcreate", "-l", "100%FREE", "-n", "lv0", "vg_mkosi"]) run(["lvm", "lvs"]) run(["udevadm", "wait", "/dev/vg_mkosi/lv0"]) - run([f"mkfs.{image.distribution.filesystem()}", "-L", "root", "/dev/vg_mkosi/lv0"]) + run([f"mkfs.{image.config.distribution.filesystem()}", "-L", "root", "/dev/vg_mkosi/lv0"]) with tempfile.TemporaryDirectory() as mnt, mount(Path("/dev/vg_mkosi/lv0"), Path(mnt)): # The image might have been built unprivileged so we need to fix the file ownership. Making all the @@ -236,6 +241,6 @@ def test_initrd_size(initrd: Image) -> None: Distribution.ubuntu: 32, Distribution.arch: 47, Distribution.opensuse: 36, - }.get(initrd.distribution, 48) + }.get(initrd.config.distribution, 48) assert (Path(initrd.output_dir.name) / "initrd").stat().st_size <= maxsize diff --git a/tests/test_sysext.py b/tests/test_sysext.py index b7f3cf6aa..39ecec036 100644 --- a/tests/test_sysext.py +++ b/tests/test_sysext.py @@ -9,8 +9,9 @@ from . import Image pytestmark = pytest.mark.integration -def test_sysext() -> None: +def test_sysext(config: Image.Config) -> None: with Image( + config, options=[ "--incremental", "--clean-package-metadata=no", @@ -20,6 +21,7 @@ def test_sysext() -> None: image.build() with Image( + image.config, options=[ "--directory", "", "--base-tree", Path(image.output_dir.name) / "image",