diff --git a/.gitignore b/.gitignore index f327f80446..e6e33092d3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ /_build /docs/_site -/mktree.* diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7fd3510d06..1f6bd698d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -71,40 +71,32 @@ if (nproc GREATER 1) set(JOBS -j${nproc}) endif() -# Detect suitable mktree backend -find_program(BWRAP bwrap) -mark_as_advanced(BWRAP) -find_program(PODMAN NAMES podman docker) -mark_as_advanced(PODMAN) -if ("${MKTREE_BACKEND}" STREQUAL "") - if (BWRAP AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/mktree.${OS_NAME}) - set(MKTREE_BACKEND ${OS_NAME}) - elseif (PODMAN) - set(MKTREE_BACKEND podman) - else() - message(WARNING - "No suitable mktree backend found for this platform. " - "Disabling test-suite.") - return() - endif() -endif() -message(STATUS "Using mktree backend: ${MKTREE_BACKEND}") - # Set up mktree -if ("${MKTREE_BACKEND}" STREQUAL "podman") +set(MKTREE_BACKEND podman CACHE STRING "Mktree backend to use") +if (MKTREE_BACKEND STREQUAL "podman") find_program(PODMAN NAMES podman docker REQUIRED) - configure_file(Dockerfile Dockerfile COPYONLY) -else() - find_program(BWRAP bwrap REQUIRED) - if (PODMAN) - get_filename_component(PODMAN ${PODMAN} NAME) + find_program(BUILDAH buildah) + get_filename_component(PODMAN_NAME ${PODMAN} NAME) + mark_as_advanced(PODMAN PODMAN_NAME BUILDAH) + if (PODMAN_NAME STREQUAL "podman" AND BUILDAH AND + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Dockerfile.${OS_NAME}) + set(MKTREE_NATIVE ON) + configure_file(Dockerfile.${OS_NAME} Dockerfile COPYONLY) add_custom_target(ci - COMMAND ./mktree.${PODMAN} build - COMMAND ./mktree.${PODMAN} check ${JOBS} $(TESTOPTS) + COMMAND ./mktree.podman build + COMMAND ./mktree.podman check --log ${JOBS} $(TESTOPTS) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + else() + set(MKTREE_NATIVE OFF) + configure_file(Dockerfile Dockerfile COPYONLY) endif() + set(MKTREE_MODE " (native: ${MKTREE_NATIVE})") +elseif(MKTREE_BACKEND STREQUAL "rootfs") + find_program(BWRAP bwrap REQUIRED) + mark_as_advanced(BWRAP) endif() +message(STATUS "Using mktree backend: ${MKTREE_BACKEND}${MKTREE_MODE}") configure_file(mktree.common mktree.common @ONLY) configure_file(mktree.${MKTREE_BACKEND} mktree @ONLY) diff --git a/tests/README.md b/tests/README.md index 96032ee0bb..3b08c4b20d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,8 +1,25 @@ -To run these tests, you need at least these dependencies on the host: +To run these tests, you need either of: -1. [bwrap](https://github.com/containers/bubblewrap/) -1. [gdb](https://www.gnu.org/software/gdb/) -1. [gnupg](https://www.gnupg.org/) >= 2.0 +1. [podman](https://github.com/containers/podman) +1. [docker](https://github.com/docker) + +Optionally, the following is also recommended (see below): + +1. [buildah](https://github.com/containers/buildah) + +The test suite runs in a Podman/Docker container and supports two modes: + +1. *Native* - Exercises the local build of RPM against a minimal image of the + host Linux distribution. Currently, only Fedora Linux is supported. This + mode is optimized for local RPM development and requires Podman and Buildah. +1. *Non-native* - Performs a fresh build of RPM (including cmake configuration) + from the local checkout as part of a Fedora-based image. This mode is + optimized for portability (CI environment) and works with both Podman and + Docker. + +The mode is selected automatically by cmake based on the host distribution and +the container tools installed, with the native mode being preferred whenever +possible. Then run the command @@ -32,16 +49,21 @@ For all available options, see the output of the command: By default, tests are executed in parallel using all available cores, pass a specific -jN value to limit. -To drop into an Autotest-like shell, run: +To drop into an interactive Autotest-like shell, run: make atshell -See the printed help for details on how to use it. +This is like a singular, empty `RPMTEST_CHECK()` with a shell running in it and +a writable tree available at the path stored in `$RPMTEST`. From this shell, +you can run the same commands as a normal test would, such as `runroot rpm`. +This can be used to quickly prototype (or debug) a test. -You can also run a containerized shell with your RPM checkout: +You can also drop straight into the `$RPMTEST` container like so: make shell -To factory-reset the container, run: +This is just a shorthand for `make atshell` followed by `runroot_other bash`. + +To factory-reset the `$RPMTEST` container, run: make reset diff --git a/tests/mktree.fedora b/tests/mktree.fedora deleted file mode 100755 index 0e7d52b001..0000000000 --- a/tests/mktree.fedora +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/bash -# -# Fedora-native mktree backend using DNF to bootstrap a minimal OS tree with -# the RPM runtime and test dependencies but no stock RPM preinstalled. -# Lightweight snapshotting built into the test-suite is used for isolation. - -source ./mktree.common - -# Obtain source dir (or common git-worktree(1) if one exists) -git() { command git -C "@CMAKE_SOURCE_DIR@" "$@"; } -if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - SOURCE_DIR=$(git rev-parse --path-format=absolute --git-common-dir | - xargs dirname) -else - SOURCE_DIR=@CMAKE_SOURCE_DIR@ -fi - -# Build-agnostic dirs, prefer those in source dir -[ -d "$SOURCE_DIR/mktree.output" ] || SOURCE_DIR=$PWD -BASE_DIR=$SOURCE_DIR/mktree.output/base -CACHE_DIR=$SOURCE_DIR/mktree.cache - -# Build-specific dirs -INST_DIR=$PWD/mktree.output/inst -SANDBOX_DIR=$PWD/mktree.sandbox - -RPM_MACROS=" -%_netsharedpath %{nil} -%__transaction_systemd_inhibit %{nil} -" - -ATSHELL_MOTD=" -Welcome to RPM test environment! - -This is like an interactive test with a writable \$RPMTEST -tree, but with full host integration so you can use your -native tools to inspect or modify the tree. - -The shell runs in a user namespace WITHOUT filesystem -isolation so be mindful when using destructive commands. -Treat it like any other shell on your host. - -The usual test commands are available, e.g. - - runroot rpm ... - -DNF is configured to operate on the tree, use it simply -like this: - - dnf install ... - -To factory-reset the tree, leave this shell and run: - - make reset -" - -CMD=$1; shift - -dnf() -{ - HOME=$CACHE_DIR command dnf \ - --installroot=$BASE_DIR \ - --releasever=@OS_VERSION@ \ - --setopt=cachedir=$CACHE_DIR/dnf \ - --setopt=keepcache=1 \ - --setopt=install_weak_deps=0 \ - --disablerepo=\* --enablerepo=fedora,updates \ - --exclude=rpm,systemd-udev "$@" -} - -mount_tree() -{ - local dir=$SANDBOX_DIR - if [ "$1" == "--read-only" ]; then - unset dir - fi - source ./atlocal - RPMTREE=$INST_DIR:$BASE_DIR - RPMTEST=$SANDBOX_DIR/tree - snapshot mount $dir -} - -clean_up() -{ - [ -n "$RPMTEST" ] && snapshot umount - chmod -Rf u+rwX $BASE_DIR $SANDBOX_DIR rpmtests.dir -} - -# Run CMD in a user namespace (if not root already) -if [ $(id -u) != 0 ]; then - if [ -f /run/.toolboxenv ]; then - # toolbox(1) support - UNSHARE="sudo --preserve-env" - else - UNSHARE="unshare -r --mount --map-auto" - fi - $UNSHARE $0 $CMD "$@" - exit -fi - -trap clean_up EXIT - -case $CMD in - build) - mkdir -p $CACHE_DIR - echo "$RPM_MACROS" > $CACHE_DIR/.rpmmacros - - dnf install -y \ - bash \ - binutils \ - bubblewrap \ - bzip2 \ - cmake \ - coreutils \ - cpio \ - curl \ - dbus-libs \ - debugedit \ - diffutils \ - elfutils-libelf \ - elfutils-libs \ - file \ - file-libs \ - findutils \ - gawk \ - gcc \ - gdb-minimal \ - glibc \ - gpg \ - grep \ - gzip \ - ima-evm-utils \ - libacl \ - libarchive \ - libcap \ - libfsverity \ - libgomp \ - libzstd \ - lua-libs \ - make \ - openssl-libs \ - patch \ - pkgconf-pkg-config \ - popt \ - python3 \ - rpm-sequoia \ - sed \ - shadow-utils \ - sqlite-libs \ - tar \ - unzip \ - util-linux-core \ - which \ - xz \ - xz-libs \ - zlib \ - zstd - - # Enable DNS resolution - cp /etc/resolv.conf $BASE_DIR/etc/ - - # Point RPM to newly created database - echo "%_dbpath $(rpm --eval '%_dbpath')" > $BASE_DIR/root/.rpmmacros - - # Configure default shell for root user - cp -r $BASE_DIR/{etc/skel/.,/root} - - # Add RPM installation layer - rm -rf "$INST_DIR" - make_install $INST_DIR - ;; - atshell) - set -a - mount_tree - - export CACHE_DIR - export BASE_DIR=$RPMTEST - export -f dnf - - echo "$ATSHELL_MOTD" - $SHELL - ;; - shell) - mount_tree - snapshot shell "$@" - ;; - check) - mount_tree --read-only - snapshot exec --tmpfs /tmp --bind $PWD $PWD --setenv RPMTREE $RPMTREE \ - rpmtests -C $PWD "$@" - ;; - reset) - rm -rf "$SANDBOX_DIR" - ;; -esac diff --git a/tests/mktree.podman b/tests/mktree.podman index 1454b9b304..85d53bca15 100755 --- a/tests/mktree.podman +++ b/tests/mktree.podman @@ -1,7 +1,15 @@ #!/bin/bash # -# Podman-based mktree backend using an OCI image to build and run RPM. -# Works standalone (outside of a build directory) too. +# Podman-based mktree backend using OCI images. +# +# If a Dockerfile matching the host distribution is found, it is built and then +# combined with the local RPM build to produce the final image ("native" mode). +# Otherwise, the default Dockerfile is used and RPM is built as part of the +# image ("non-native" mode). +# +# This script can also be invoked directly from the source directory, in which +# case it performs a non-native build (useful for CI purposes). If invoked via +# the mktree.docker symlink, docker is used instead of podman. PROGRAM=$(basename $0) if [ "$PROGRAM" == "mktree" ]; then