Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ on:
type: boolean
description: 'Should slow tests be run?'
default: true
registry-service:
required: false
type: string
description: 'registry service OCI image URI'
default: "ghcr.io/project-stacker/registry:2"

secrets:
codecov_token:
required: true
Expand All @@ -34,7 +40,7 @@ jobs:
build:
services:
registry:
image: ghcr.io/project-stacker/registry:2
image: ${{ inputs.registry-service }}
ports:
- 5000:5000
strategy:
Expand Down Expand Up @@ -88,6 +94,7 @@ jobs:
run: |
make stacker VERSION_FULL=${{ inputs.build-id }}
env:
REGISTRY_SERVICE: ${{ inputs.registry-service }}
REGISTRY_URL: localhost:5000
ZOT_HOST: localhost
ZOT_PORT: 8080
Expand All @@ -98,6 +105,7 @@ jobs:
run: |
make check VERSION_FULL=${{ inputs.build-id }} PRIVILEGE_LEVEL=${{ matrix.privilege-level }}
env:
REGISTRY_SERVICE: ${{ inputs.registry-service }}
REGISTRY_URL: localhost:5000
ZOT_HOST: localhost
ZOT_PORT: 8080
Expand All @@ -113,7 +121,7 @@ jobs:
make publish-stacker-bin
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: ${{ (matrix.privilege-level == 'priv') && (matrix.go-version == '1.23.x') }}
if: ${{ (matrix.privilege-level == 'priv') }}
with:
# if there is more than 1 go-version, we would need to account for that here.
name: stacker-${{ matrix.platform }}
Expand Down
11 changes: 9 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ on:
type: boolean
description: 'Should slow tests be run?'
default: true
registry-service:
required: false
type: string
description: 'registry service OCI image URI'
default: "ghcr.io/project-stacker/registry:2"

secrets:
codecov_token:
required: true
Expand All @@ -35,7 +41,7 @@ jobs:
runs-on: ubuntu-24.04
services:
registry:
image: ghcr.io/project-stacker/registry:2
image: ${{ inputs.registry-service }}
ports:
- 5000:5000
strategy:
Expand Down Expand Up @@ -91,6 +97,7 @@ jobs:
go tool covdata percent -i $GOCOVERDIR
ls -altR $GOCOVERDIR
env:
REGISTRY_SERVICE: ${{ inputs.registry-service }}
REGISTRY_URL: localhost:5000
ZOT_HOST: localhost
ZOT_PORT: 8080
Expand All @@ -104,7 +111,7 @@ jobs:
files: coverage-${{ matrix.privilege-level}}.txt
- name: Upload artifacts
uses: actions/upload-artifact@v4
if: ${{ (matrix.privilege-level == 'priv') && (matrix.go-version == '1.23.x') }}
if: ${{ (matrix.privilege-level == 'priv') }}
with:
# if there is more than 1 go-version, we would need to account for that here.
name: binary-cov
Expand Down
4 changes: 4 additions & 0 deletions install-build-deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ installdeps_ubuntu() {
lxc-utils
)

if ! command -v add-apt-repository; then
sudo apt-get -y install software-properties-common
fi

case "$VERSION_ID" in
22.04)
sudo add-apt-repository -y ppa:project-machine/squashfuse
Expand Down
1 change: 1 addition & 0 deletions test/bom.bats
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function teardown() {

@test "all container contents must be accounted for" {
skip_slow_test
skip_broken_tests
cat > stacker.yaml <<"EOF"
bom-parent:
from:
Expand Down
8 changes: 8 additions & 0 deletions test/convert.bats
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
load helpers

function setup_file() {
start_registry
}

function teardown_file() {
stop_registry
}

function setup() {
stacker_setup
}
Expand Down
126 changes: 116 additions & 10 deletions test/helpers.bash
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ function skip_slow_test {
esac
}

function skip_broken_tests {
case "${BROKEN_TESTS:-false}" in
true) return;;
false) skip "${BATS_TEST_NAME} is broken. Set BROKEN_TESTS=true to run.";;
*) stderr "BROKEN_TESTS variable must be 'true' or 'false'" \
"found '${BROKEN_TESTS}'"
return 1;;
esac
}

function tmpd() {
mktemp -d "${PWD}/stackertest${1:+-$1}.XXXXXX"
}
Expand Down Expand Up @@ -221,10 +231,15 @@ EOF
}

function write_auth_zot_config {
if ! check_env_zot; then
echo "ERROR: invalid zot env values"
return 1
fi

htpasswd -Bbn iam careful >> $TEST_TMPDIR/htpasswd

cat > $TEST_TMPDIR/zot-config.json << EOF
zotcfg=$TEST_TMPDIR/zot-config.json
cat > "$zotcfg" << EOF
{
"distSpecVersion": "1.1.0-dev",
"storage": {
Expand Down Expand Up @@ -262,15 +277,18 @@ function write_auth_zot_config {
}
}
EOF

echo "zot config:"
cat "$zotcfg"
}

function zot_setup {
zot_teardown
write_plain_zot_config
start_zot
}

function zot_setup_auth {
zot_teardown
write_auth_zot_config
start_zot USE_TLS
}
Expand All @@ -279,12 +297,18 @@ function start_zot {
ZOT_USE_TLS=$1
echo "# starting zot at $ZOT_HOST:$ZOT_PORT" >&3
# start as a background task
zot verify $TEST_TMPDIR/zot-config.json
zot serve $TEST_TMPDIR/zot-config.json &
zotcfg="$TEST_TMPDIR/zot-config.json"
if ! zot verify "$zotcfg"; then
echo "zot failed to verify zot config:"
cat "$zotcfg"
return 1
fi
zot serve "$TEST_TMPDIR/zot-config.json" &
pid=$!
echo "$pid" > "${TEST_TMPDIR}/zot.pid"

echo "zot is running at pid $pid"
cat $TEST_TMPDIR/zot.log
cat "$TEST_TMPDIR/zot.log"
# wait until service is up
count=5
up=0
Expand All @@ -295,6 +319,14 @@ function start_zot {
exit 1
fi
up=1
# check if correct port is open
if ! nc -v -z "${ZOT_HOST}" "${ZOT_PORT}"; then
echo "no response from host:${ZOT_HOST} port:${ZOT_PORT}" >&3
sleep 1
count=$((count - 1))
continue
fi
echo "Got response from host:${ZOT_HOST} on port:${ZOT_PORT}" >&3
if [[ -n $ZOT_USE_TLS ]]; then
echo "testing zot at https://$ZOT_HOST:$ZOT_PORT"
curl -v --cacert $BATS_SUITE_TMPDIR/ca.crt -u "iam:careful" -f https://$ZOT_HOST:$ZOT_PORT/v2/ || up=0
Expand Down Expand Up @@ -323,11 +355,14 @@ function start_zot {
}

function zot_teardown {
echo "# stopping zot" >&3
killall zot
killall -KILL zot || true
rm -f $TEST_TMPDIR/zot-config.json
rm -rf $TEST_TMPDIR/zot
zotpid="${TEST_TMPDIR}/zot.pid"
if [ -s "$zotpid" ]; then
echo "# stopping zot" >&3
pkill --pidfile "$zotpid"
echo "# stopped zot" >&3
fi
rm -f "$TEST_TMPDIR/zot-config.json"
rm -rf "$TEST_TMPDIR/zot"
}

function _skopeo() {
Expand All @@ -348,6 +383,77 @@ function _skopeo() {
HOME="$home" skopeo "$@"
}

function start_registry() {
if [ -z "${REGISTRY_URL}" ]; then
echo "Missing REGISTRY_URL env value"
return 1
fi
if [ -z "${REGISTRY_SERVICE}" ]; then
echo "Missing REGISTRY_SERVICE env value"
return 1
fi
rhost=${REGISTRY_URL%:*} # trim from right until colon, localhost
rport=${REGISTRY_URL#*:} # trim from left until colon , 5000
if nc -v -z "${rhost}" "${rport}"; then
echo "# skipping start, registry service ${REGISTRY_SERVICE} already active for REGISTRY_URL=${REGISTRY_URL}" >&3
return 0
fi
echo "# no registry service ${REGISTRY_SERVICE} active for REGISTRY_URL=${REGISTRY_URL}" >&3
echo "# Starting registry service ${REGISTRY_SERVICE}" >&3


imgname=$(basename "${REGISTRY_SERVICE}") # registry:tag
if ! _skopeo copy "docker://${REGISTRY_SERVICE}" "oci:${TEST_TMPDIR}/ocid:${imgname}"; then
echo "# skopeo copy of '${REGISTRY_SERVICE}' to local directory failed" >&3
return 1
fi

# unpack the image
unpackdir="${TEST_TMPDIR}/unpacked-reg"
if [ ! -d "${unpackdir}" ]; then
if ! umoci unpack --keep-dirlinks --image "${TEST_TMPDIR}/ocid:${imgname}" "${unpackdir}"; then
echo "failed to unpack registry service image ${imgname} to ${unpackdir}"
return 1
fi
else
echo "# reusing existing unpacked registry service OCI image" >&3
fi

# start up registry in the background
reglog="${TEST_TMPDIR}/registry.log"
chroot "${unpackdir}/rootfs" "/entrypoint.sh" "/etc/docker/registry/config.yml" "2>&1" "1>${reglog}" &
REGISTRY_PID=$!
echo "$REGISTRY_PID" > "${TEST_TMPDIR}/registry.pid"

regup=0
for ((x=1;x<=5;x++)); do
sleep "$x"
if ! nc -v -z "${rhost}" "${rport}"; then
echo "# local registry service not ready" >&3
sleep "$x"
continue
fi
regup=1
break
done

if [ "$regup" != "1" ]; then
echo "failed to bring up local registry service"
fi

echo "local registry service up on ${REGISTRY_URL} PID=$(cat "${TEST_TMPDIR}/registry.pid")"
return 0
}

function stop_registry() {
regpid="${TEST_TMPDIR}/registry.pid"
if [ -s "$regpid" ]; then
echo "# stopping local registry" >&3
pkill --pidfile "$regpid"
echo "# stopped local registry" >&3
fi
}

function dir_has_only() {
local d="$1" oifs="$IFS" unexpected="" f=""
shift
Expand Down
40 changes: 37 additions & 3 deletions test/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/python3
"""
test harness for stacker
"""

import argparse
import glob
Expand All @@ -7,7 +10,24 @@
import subprocess
import sys

priv_levels=("priv", "unpriv")

def check_env(env_to_check):
"""
check for required env variables
"""
required_vars = ["ZOT_HOST", "ZOT_PORT", "REGISTRY_SERVICE", "REGISTRY_URL"]
errors = []
for req_var in required_vars:
if req_var not in env_to_check:
errors.append(f"missing env variable '{req_var}'")
if not env_to_check.get(req_var):
errors.append(f"env variable '{req_var}' is empyty")

if len(errors) > 0:
raise RuntimeError(f"EnvCheckFailures: {errors}")


priv_levels = ("priv", "unpriv")

parser = argparse.ArgumentParser()
parser.add_argument("--privilege-level", choices=priv_levels)
Expand All @@ -16,17 +36,31 @@

options = parser.parse_args()

priv_to_test=priv_levels
priv_to_test = priv_levels

if options.privilege_level is not None:
priv_to_test = [options.privilege_level]

for priv in priv_to_test:
cmd = ["bats", "--setup-suite-file", "./test/setup_suite.bash", "--jobs", str(options.jobs), "--tap", "--timing"]
cmd = [
"bats",
"--setup-suite-file",
"./test/setup_suite.bash",
"--jobs",
str(options.jobs),
"--tap",
"--timing",
"--verbose-run",
]
cmd.extend(options.tests)

env = os.environ.copy()
env["PRIVILEGE_LEVEL"] = priv
try:
check_env
except RuntimeError as err:
print(f"Failed environment variable check: {err}")
sys.exit(1)

print("running tests in modes:", priv)
try:
Expand Down
8 changes: 8 additions & 0 deletions test/publish.bats
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
load helpers

function setup_file() {
start_registry
}

function teardown_file() {
stop_registry
}

function setup() {
stacker_setup
mkdir -p ocibuilds/sub1
Expand Down
Loading