diff --git a/.gitignore b/.gitignore index 7456785..0d378a3 100644 --- a/.gitignore +++ b/.gitignore @@ -163,4 +163,6 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -manifest-entry.json \ No newline at end of file +manifest-entry.json +digest +tests/data/gardenlinux \ No newline at end of file diff --git a/tests/cert/gencert.sh b/tests/cert/gencert.sh new file mode 100755 index 0000000..7918236 --- /dev/null +++ b/tests/cert/gencert.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +CERT_NAME="$SCRIPT_DIR/oci-sign" + +openssl req -x509 -newkey rsa -pkeyopt rsa_keygen_bits:4096 -days 3650 -nodes -keyout $CERT_NAME.key -out $CERT_NAME.crt -subj "/CN=Garden Linux test signing key for oci" \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..a6b2629 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,39 @@ +from helper import call_command, spawn_background_process +import os +import sys +import shutil +import pytest + + +@pytest.fixture(autouse=False, scope="function") +def zot_session(): + print("Starting zot session") + zot_config = "tests/zot/config.json" + print(f"Spawning zot registry with config {zot_config}") + zot_process = spawn_background_process( + f"zot serve {zot_config}", + stdout=sys.stdout, + stderr=sys.stderr, + ) + + yield zot_process + print("Clean up zot session") + + zot_process.terminate() + + if os.path.isdir("./output"): + shutil.rmtree("./output") + + +def pytest_sessionstart(session): + call_command("./tests/cert/gencert.sh") + print("pytest session started") + call_command("./tests/data/build-test-data.sh --dummy") + + +def pytest_sessionfinish(session): + print(" pytest session finished") + if os.path.isfile("./tests/cert/oci-sign.crt"): + os.remove("./tests/cert/oci-sign.crt") + if os.path.isfile("./tests/cert/oci-sign.key"): + os.remove("./tests/cert/oci-sign.key") diff --git a/tests/data/build-test-data.sh b/tests/data/build-test-data.sh new file mode 100755 index 0000000..8cfd1de --- /dev/null +++ b/tests/data/build-test-data.sh @@ -0,0 +1,85 @@ +#!/bin/bash +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +echo "This will take a while. Building for the following targets:" + +test_targets=( + "aws-gardener_prod" + "azure-gardener_prod" + "gcp-gardener_prod" + "openstack-gardener_prod" + "openstackbaremetal-gardener_prod" + "metal-kvm_dev" +) +test_arch=("amd64") +pushd $script_dir/gardenlinux +commit=$(git rev-parse --short=8 HEAD) +popd +fake_artifacts=( + "aws-gardener_prod-today-amd64-$commit.raw" + "aws-gardener_prod-today-arm64-$commit.raw" + "aws-gardener_prod-today-amd64-$commit.tar" + "aws-gardener_prod-today-arm64-$commit.tar" + "gcp-gardener_prod-today-amd64-$commit.tar.gz" + "gcp-gardener_prod-today-arm64-$commit.tar.gz" + "gcp-gardener_prod-today-amd64-$commit.gcpimage.tar.gz" + "gcp-gardener_prod-today-arm64-$commit.gcpimage.tar.gz" + "azure-gardener_prod-today-amd64-$commit.vhd" + "azure-gardener_prod-today-arm64-$commit.vhd" + "azure-gardener_prod-today-amd64-$commit.tar" + "azure-gardener_prod-today-arm64-$commit.tar" + "openstack-gardener_prod-today-amd64-$commit.qcow2" + "openstack-gardener_prod-today-arm64-$commit.qcow2" + "openstack-gardener_prod-today-amd64-$commit.vmdk" + "openstack-gardener_prod-today-arm64-$commit.vmdk" + "openstack-gardener_prod-today-amd64-$commit.tar" + "openstack-gardener_prod-today-arm64-$commit.tar" + "openstackbaremetal-gardener_prod-today-amd64-$commit.raw" + "openstackbaremetal-gardener_prod-today-arm64-$commit.raw" + "openstackbaremetal-gardener_prod-today-amd64-$commit.tar" + "openstackbaremetal-gardener_prod-today-arm64-$commit.tar" + "openstackbaremetal-gardener_prod-today-amd64-$commit.qcow2" + "openstackbaremetal-gardener_prod-today-arm64-$commit.qcow2" + "openstackbaremetal-gardener_prod-today-amd64-$commit.vmdk" + "openstackbaremetal-gardener_prod-today-arm64-$commit.vmdk" + "metal-kvm_dev-today-amd64-$commit.raw" + "metal-kvm_dev-today-arm64-$commit.raw" + "metal-kvm_dev-today-amd64-$commit.tar" + "metal-kvm_dev-today-arm64-$commit.tar" + ) + + +# Check if the --dummy flag is set +dummy_mode=false +if [[ "$1" == "--dummy" ]]; then + dummy_mode=true + echo "Dummy mode enabled. No actual builds will be performed." + for target in "${test_targets[@]}"; do + echo "$target (amd64 and arm64)" + done + else + read -p "Build targets listed above? (y/n): " confirm + if [[ "$confirm" != [yY] ]]; then + exit 1 + fi +fi + + + +if [ "$dummy_mode" = true ]; then + echo "Creating fake artifacts..." + mkdir -p $script_dir/gardenlinux/.build + for artifact in "${fake_artifacts[@]}"; do + echo "Creating fake artifact: $artifact" + touch "$script_dir/gardenlinux/.build/$artifact" # This simulates creating a fake artifact file + done + echo "Fake artifacts created." +else + pushd $script_dir/gardenlinux + for target in "${test_targets[@]}"; do + for arch in "${test_arch[@]}"; do + echo "Building $target-$arch..." + ./build "$target-$arch" + done + done + popd +fi diff --git a/tests/helper.py b/tests/helper.py new file mode 100644 index 0000000..be7a4a1 --- /dev/null +++ b/tests/helper.py @@ -0,0 +1,22 @@ +import subprocess +import shlex + + +def spawn_background_process(cmd, stdout=None, stderr=None): + args = shlex.split(cmd) + process = subprocess.Popen(args, shell=False, stdout=stdout, stderr=stderr) + return process + + +def call_command(cmd): + try: + args = shlex.split(cmd) + result = subprocess.run( + args, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + output = result.stdout.decode("utf-8") + return output + + except subprocess.CalledProcessError as e: + error_message = e.stderr.decode("utf-8") + return f"An error occurred: {error_message}" diff --git a/tests/test_e2e.py b/tests/test_e2e.py new file mode 100644 index 0000000..e64652f --- /dev/null +++ b/tests/test_e2e.py @@ -0,0 +1,84 @@ +import pytest +from click.testing import CliRunner +import sys +import logging + +sys.path.append("src") + +from glcli import cli + + +CONTAINER_NAME_ZOT_EXAMPLE = "localhost:5000/gardenlinux" +GARDENLINUX_ROOT_DIR_EXAMPLE = "tests/data/gardenlinux/.build" + + +@pytest.mark.usefixtures("zot_session") +@pytest.mark.parametrize( + "version, cname, arch", + [ + ("today", "aws-gardener_prod", "arm64"), + ("today", "aws-gardener_prod", "amd64"), + ], +) +def test_push_manifest_and_index(version, arch, cname): + logger = logging.getLogger(__name__) + runner = CliRunner() + result = runner.invoke( + cli, + [ + "push-manifest", + "--container", + CONTAINER_NAME_ZOT_EXAMPLE, + "--version", + version, + "--arch", + arch, + "--cname", + cname, + "--dir", + GARDENLINUX_ROOT_DIR_EXAMPLE, + "--insecure", + "True", + "--cosign_file", + "digest", + ], + catch_exceptions=False, + ) + print(f"Output: {result.output}") + if result.exit_code != 0: + print(f"Exit Code: {result.exit_code}") + if result.exception: + print(result.exception) + try: + print(f"Output: {result.stderr}") + except ValueError: + print("No stderr captured.") + assert result.exit_code == 0 + + logger.info("Pushed manifests") + + result = runner.invoke( + cli, + [ + "update-index", + "--container", + CONTAINER_NAME_ZOT_EXAMPLE, + "--version", + version, + "--insecure", + "True", + "--manifest_file", + "manifest-entry.json", + ], + catch_exceptions=False, + ) + print(f"Output: {result.output}") + if result.exit_code != 0: + print(f"Exit Code: {result.exit_code}") + if result.exception: + print(result.exception) + try: + print(f"Output: {result.stderr}") + except ValueError: + print("No stderr captured.") + assert result.exit_code == 0 diff --git a/tests/zot/config.json b/tests/zot/config.json new file mode 100644 index 0000000..be931bf --- /dev/null +++ b/tests/zot/config.json @@ -0,0 +1,21 @@ +{ + "distSpecVersion": "1.1.0", + "storage": { + "rootDirectory": "output/registry/zot" + }, + "http": { + "address": "localhost", + "port": "5000" + }, + "log": { + "level": "warn" + }, + "extensions": { + "search": { + "enable": true + }, + "ui": { + "enable": true + } + } +}