From 959d9770bcc93f84bc3371af1def4cdd5460466f Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 4 Dec 2023 17:30:03 +0100 Subject: [PATCH] tests: add basic integration testing This commit adds basic integration testing for the project. It is pytest based and can run both locally or via `tmt` [0] which will spin up a clean VM and run the tests inside. [0] https://github.com/teemtee/tmt --- .fmf/version | 1 + .github/workflows/tests.yml | 16 +++++++++ plans/all.fmf | 12 +++++++ test/README.md | 14 ++++++++ test/test_flake8.py | 11 ++++++ test/test_smoke.py | 67 +++++++++++++++++++++++++++++++++++++ test/testutil.py | 17 ++++++++++ 7 files changed, 138 insertions(+) create mode 100644 .fmf/version create mode 100644 plans/all.fmf create mode 100644 test/README.md create mode 100644 test/test_flake8.py create mode 100644 test/test_smoke.py create mode 100644 test/testutil.py diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0bdcfad66..8932ce068 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,3 +56,19 @@ jobs: # don't check /etc/os-release sourcing, allow useless cats to live inside our codebase, and # allow seemingly unreachable commands SHELLCHECK_OPTS: -e SC1091 -e SC2002 -e SC2317 + + integration: + # TODO: run this also via tmt/testing-farm + name: "Integration" + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Setup up python + uses: actions/setup-python@v4 + - name: Install test dependencies + run: | + sudo apt install -y podman python3-pytest + - name: Run tests + run: sudo pytest-3 -s -vv diff --git a/plans/all.fmf b/plans/all.fmf new file mode 100644 index 000000000..8e1f9b784 --- /dev/null +++ b/plans/all.fmf @@ -0,0 +1,12 @@ +summary: Run all tests inside a VM environment +provision: + how: virtual + image: fedora:39 +prepare: + how: install + package: + - podman + - pytest +execute: + how: tmt + script: pytest -s -vv diff --git a/test/README.md b/test/README.md new file mode 100644 index 000000000..b3e82e773 --- /dev/null +++ b/test/README.md @@ -0,0 +1,14 @@ +Integration tests for osbuild-deploy-container +---------------------------------------------- + +This directory contans integration tests for osbuild-deploy-container. +They can be run in two ways: +1. On the local machine by just running `pytest` +2. Via `tmt` [0] which will spin up a clean VM and run the tests inside: + + tmt run -vvv + + + + +[0] https://github.com/teemtee/tmt diff --git a/test/test_flake8.py b/test/test_flake8.py new file mode 100644 index 000000000..5cb61a7b1 --- /dev/null +++ b/test/test_flake8.py @@ -0,0 +1,11 @@ +import os +import pathlib +import subprocess + + +def test_flake8(): + p = pathlib.Path(__file__).parent + # TODO: use all static checks from osbuild instead + subprocess.check_call( + ["flake8", "--ignore=E402", "--max-line-length=120", + os.fspath(p)]) diff --git a/test/test_smoke.py b/test/test_smoke.py new file mode 100644 index 000000000..e3fc9e780 --- /dev/null +++ b/test/test_smoke.py @@ -0,0 +1,67 @@ +import json +import os +import pathlib +import subprocess + +import pytest + +# local test utils +import testutil + + +@pytest.fixture(name="output_path") +def output_path_fixture(tmp_path): + output_path = tmp_path / "output" + output_path.mkdir(exist_ok=True) + return output_path + + +@pytest.fixture(name="config_json") +def config_json_fixture(output_path): + CFG = { + "blueprint": { + "customizations": { + "user": [ + { + "name": "test", + "password": "password", + "groups": ["wheel"], + }, + ], + }, + }, + } + config_json_path = output_path / "config.json" + config_json_path.write_text(json.dumps(CFG), encoding="utf-8") + return config_json_path + + +@pytest.mark.skipif(os.getuid() != 0, reason="needs root") +@pytest.mark.skipif(not testutil.has_executable("podman"), reason="need podman") +def test_smoke(output_path, config_json): + # build local container + subprocess.check_call([ + "podman", "build", + "-f", "Containerfile", + "-t", "osbuild-deploy-container-test", + ]) + cursor = testutil.journal_cursor() + # and run container to deploy an image into output/disk.qcow2 + subprocess.check_call([ + "podman", "run", "--rm", + "--privileged", + "--security-opt", "label=type:unconfined_t", + "-v", f"{output_path}:/output", + "osbuild-deploy-container-test", + "quay.io/centos-boot/fedora-tier-1:eln", + "--config", "/output/config.json", + ]) + # check that there are no denials + journal_output = testutil.journal_after_cursor(cursor) + assert journal_output != "" + # TODO: actually check this once https://github.com/osbuild/images/pull/287 + # is merged + generated_img = pathlib.Path(output_path) / "output/disk.qcow2" + assert generated_img.exists() + # TODO: boot and do basic checks, see + # https://github.com/osbuild/osbuild-deploy-container/compare/main...mvo5:integration-test?expand=1 diff --git a/test/testutil.py b/test/testutil.py new file mode 100644 index 000000000..47da18e03 --- /dev/null +++ b/test/testutil.py @@ -0,0 +1,17 @@ +import shutil +import subprocess + + +def journal_cursor(): + output = subprocess.check_output(["journalctl", "-n0", "--show-cursor"], encoding="utf-8").strip() + cursor = output.split("\n")[-1] + return cursor.split("cursor: ")[-1] + + +def journal_after_cursor(cursor): + output = subprocess.check_output(["journalctl", f"--after-cursor={cursor}"]) + return output + + +def has_executable(name): + return shutil.which(name) is not None