#!/bin/bash # Shared helper functions for e2e tests. # shellcheck disable=SC2312 # Run buildah build with --skip-unused-stages=false and workarounds for older buildah versions. buildah_build() { local tmp_args=() local version min_version version=$(${BUILDAH:-buildah} version --json | jq -r '.version') min_version=$(echo -e "${version}\n1.44" | sort -V | head -n1) if [[ "${min_version}" != "1.44" ]]; then tmp_args+=(-v "${PWD}:/run/src" --security-opt=label=disable) fi ${BUILDAH:-buildah} build --skip-unused-stages=false "${tmp_args[@]}" "$@" rm -f "${PWD}/out.ociarchive" } # Get layer annotations for an image. get_layer_annotations() { local image="${1}" skopeo inspect "containers-storage:${image}" | \ jq -r '.LayersData[].Annotations["org.chunkah.component"] // empty' } # Assert that an image has the expected components in its layer annotations. assert_has_components() { local image="${1}"; shift local annotations annotations=$(get_layer_annotations "${image}") for component in "$@"; do if ! grep -q "${component}" <<< "${annotations}"; then echo "ERROR: Expected component '${component}' not found in ${image}" return 1 fi done } # Assert that an image has exactly the expected number of layers. assert_layer_count() { local image="${1}"; shift local expected="${1}"; shift local count count=$(skopeo inspect "containers-storage:${image}" | jq '.LayersData | length') if [[ ${count} -ne ${expected} ]]; then echo "ERROR: Expected ${expected} layers, got ${count} in ${image}" return 1 fi } # Get digest of layer with specific component name in image get_image_component_digest() { local component="$1" local image="$2" local digest digest="$(skopeo inspect -n "containers-storage:${image}" \ | jq -r --arg component "${component}" ' .LayersData[] | select(.Annotations."org.chunkah.component" == $component) | .Digest ')" if [[ -z "${digest}" ]]; then echo "ERROR: Layer with component '${component}' not found in image ${image}" >&2 exit 1 fi printf '%s' "${digest}" } # Assert layer with given component name is unmodified between images assert_layer_unmodified() { local component="$1" local image1="$2" local image2="$3" local digest1 digest2 digest1=$(get_image_component_digest "${component}" "${image1}") || exit 1 digest2=$(get_image_component_digest "${component}" "${image2}") || exit 1 if [[ "${digest1}" != "${digest2}" ]]; then echo "ERROR: Digests of layer with component '${component}' differ between ${image1} and ${image2}:" >&2 printf '%s != %s\n' "${digest1}" "${digest2}" >&2 exit 1 fi } # Assert that a path exists in an image. assert_path_exists() { local image="${1}"; shift local path="${1}"; shift if ! podman run --rm "${image}" test -e "${path}"; then echo "ERROR: ${path} should exist in ${image}" return 1 fi } # Assert that a path in an image has the given mtime (epoch seconds). assert_path_mtime() { local image="${1}"; shift local path="${1}"; shift local expected="${1}"; shift local actual actual=$(podman run --rm "${image}" stat -c '%Y' "${path}") if [[ "${actual}" != "${expected}" ]]; then echo "ERROR: mtime of ${path} in ${image} is ${actual}, expected ${expected}" >&2 return 1 fi } # Assert that a path does not exist in an image. assert_path_not_exists() { local image="${1}"; shift local path="${1}"; shift if podman run --rm "${image}" test -e "${path}"; then echo "ERROR: ${path} should not exist in ${image}" return 1 fi } # Assert that two images have no filesystem differences (ignoring timestamps). # Additional arguments are passed through to chunkah-differ (e.g. --skip /sysroot/). assert_no_diff() { local repo_root repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" just -f "${repo_root}/Justfile" diff "$@" } # Remove images, ignoring errors. cleanup_images() { for image in "$@"; do podman rmi -f "${image}" 2>/dev/null || true done }