465 lines
19 KiB
Bash
465 lines
19 KiB
Bash
#!/usr/bin/env bats -*- bats -*-
|
|
#
|
|
# Tests generated configurations for systemd.
|
|
#
|
|
|
|
load helpers
|
|
load helpers.network
|
|
load helpers.registry
|
|
load helpers.systemd
|
|
|
|
function setup() {
|
|
skip_if_remote "podman quadlet is not implemented for remote setup yet"
|
|
skip_if_rootless_cgroupsv1 "Can't use --cgroups=split w/ CGv1 (issue 17456, wontfix)"
|
|
skip_if_journald_unavailable "Needed for RHEL. FIXME: we might be able to re-enable a subset of tests."
|
|
|
|
test -x "$QUADLET" || die "Cannot run quadlet tests without executable \$QUADLET ($QUADLET)"
|
|
|
|
basic_setup
|
|
}
|
|
|
|
function teardown() {
|
|
systemctl daemon-reload
|
|
basic_teardown
|
|
}
|
|
|
|
# Helper function to get the systemd install directory based on rootless/root mode
|
|
function get_quadlet_install_dir() {
|
|
if is_rootless; then
|
|
# For rootless: $XDG_CONFIG_HOME/containers/systemd or ~/.config/containers/systemd
|
|
local config_home=${XDG_CONFIG_HOME:-$HOME/.config}
|
|
echo "$config_home/containers/systemd"
|
|
else
|
|
# For root: /etc/containers/systemd
|
|
echo "/etc/containers/systemd"
|
|
fi
|
|
}
|
|
|
|
@test "quadlet verb - install, list, rm" {
|
|
# Determine the install directory path based on rootless/root
|
|
local install_dir=$(get_quadlet_install_dir)
|
|
# Create a test quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/alpine-quadlet.container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
# Test quadlet install
|
|
run_podman quadlet install $quadlet_file
|
|
# Verify install output contains the quadlet name on a single line
|
|
assert "$output" =~ "alpine-quadlet.container" "install output should contain quadlet name"
|
|
|
|
# Count lines in output (should be 1 line with the quadlet name)
|
|
assert "${#lines[@]}" -eq 1 "install output should contain exactly one line"
|
|
|
|
# Test quadlet list
|
|
run_podman quadlet list
|
|
assert "$output" =~ "alpine-quadlet.container" "list should contain alpine-quadlet.container"
|
|
assert "$output" =~ "alpine-quadlet.service" "UNIT NAME should be alpine-quadlet.service"
|
|
|
|
# Loaded status should be inactive/dead
|
|
assert "$output" =~ "inactive/dead" "loaded status should be 'inactive/dead'"
|
|
|
|
assert "$output" =~ "$install_dir/alpine-quadlet.container" "PATH ON DISK must be set and must belong to"
|
|
|
|
# Test quadlet list with filter
|
|
run_podman quadlet list --filter name=something*
|
|
assert "$output" !~ "alpine-quadlet.container" "filtered list should not contain alpine-quadlet.container"
|
|
|
|
# Test quadlet list with matching filter
|
|
run_podman quadlet list --filter name=alpine*
|
|
assert "$output" =~ "alpine-quadlet.container" "matching filter should contain alpine-quadlet.container"
|
|
|
|
# Test quadlet print
|
|
run_podman quadlet print alpine-quadlet.container
|
|
assert "$output" == "$(<$quadlet_file)" "print output matches quadlet file"
|
|
|
|
# Test quadlet rm
|
|
run_podman quadlet rm alpine-quadlet.container
|
|
# Verify remove output contains the quadlet name on a single line
|
|
assert "$output" =~ "alpine-quadlet.container" "remove output should contain quadlet name"
|
|
|
|
# Count lines in output (should be 1 line with the quadlet name)
|
|
assert "${#lines[@]}" -eq 1 "remove output should contain exactly one line"
|
|
|
|
# Verify removal
|
|
run_podman quadlet list
|
|
assert "$output" !~ "alpine-quadlet.container" "list should not contain removed container"
|
|
}
|
|
|
|
@test "quadlet verb - install multiple files from directory and remove by app name" {
|
|
# Create a directory for multiple quadlet files
|
|
local app_name="test-app-$(safe_name)"
|
|
local quadlet_dir="$PODMAN_TMPDIR/$app_name"
|
|
mkdir -p $quadlet_dir
|
|
|
|
# Create multiple quadlet files with different configurations
|
|
cat > $quadlet_dir/alpine1.container <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER 1; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
cat > $quadlet_dir/alpine2.container <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER 2; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
cat > $quadlet_dir/nginx.container <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Environment=FOO1=foo1
|
|
Exec=sh -c "echo STARTED NGINX; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
# Test quadlet install with directory
|
|
run_podman quadlet install $quadlet_dir
|
|
|
|
# Test quadlet list to verify all containers were installed
|
|
run_podman quadlet list
|
|
assert "$output" =~ "alpine1.container" "list should contain alpine1.container"
|
|
assert "$output" =~ "alpine2.container" "list should contain alpine2.container"
|
|
assert "$output" =~ "nginx.container" "list should contain nginx.container"
|
|
|
|
# Test quadlet list with filter for alpine containers
|
|
run_podman quadlet list --filter name=alpine*
|
|
assert "$output" =~ "alpine1.container" "filtered list should contain alpine1.container"
|
|
assert "$output" =~ "alpine2.container" "filtered list should contain alpine2.container"
|
|
assert "$output" !~ "nginx.container" "filtered list should not contain nginx.container"
|
|
|
|
# Test quadlet print for each container
|
|
run_podman quadlet print alpine1.container
|
|
assert "$output" =~ "Image=$IMAGE" "print should show correct image for alpine1"
|
|
|
|
run_podman quadlet print alpine2.container
|
|
assert "$output" =~ "Image=$IMAGE" "print should show correct image for alpine2"
|
|
|
|
run_podman quadlet print nginx.container
|
|
assert "$output" =~ "Environment=FOO1=foo1" "print should contain environment for nginx container"
|
|
|
|
# Test quadlet rm for all containers
|
|
run_podman quadlet rm ".$app_name.app"
|
|
|
|
# Verify all containers were removed
|
|
run_podman quadlet list
|
|
assert "$output" == "NAME UNIT NAME PATH ON DISK STATUS APPLICATION" "output should be blank"
|
|
}
|
|
|
|
@test "quadlet verb - install from URL" {
|
|
# Create a directory for multiple quadlet files
|
|
echo READY > $PODMAN_TMPDIR/ready
|
|
local quadlet_dir="$PODMAN_TMPDIR/quadlet_diri_$(safe_name)"
|
|
mkdir -p $quadlet_dir
|
|
|
|
cat > $quadlet_dir/basic.container <<EOF
|
|
[Container]
|
|
Image=$Image
|
|
EOF
|
|
|
|
HOST_PORT=$(random_free_port)
|
|
SERVER=http://127.0.0.1:$HOST_PORT
|
|
|
|
serverctr="quadletserver-$(safename)"
|
|
run_podman run -d --name $serverctr -p "$HOST_PORT:80" \
|
|
-v $quadlet_dir/basic.container:/var/www/basic.container:Z \
|
|
-v $PODMAN_TMPDIR/ready:/var/www/ready:Z \
|
|
-w /var/www \
|
|
$IMAGE /bin/busybox-extras httpd -f -p 80
|
|
|
|
wait_for_port 127.0.0.1 $HOST_PORT
|
|
wait_for_command_output "curl -s -S $SERVER/ready" "READY"
|
|
# Test quadlet install from URL and capture the output
|
|
run_podman quadlet install $SERVER/basic.container
|
|
# Extract just the basename from the full path
|
|
quadlet_name=$(basename "$output")
|
|
|
|
# Test quadlet list to verify the container was installed
|
|
run_podman quadlet list
|
|
assert "$output" =~ "$quadlet_name" "list should contain $quadlet_name"
|
|
|
|
# Test quadlet print to verify the configuration
|
|
run_podman quadlet print "$quadlet_name"
|
|
assert "$output" == "$(<$quadlet_dir/basic.container)" "print output matches quadlet file"
|
|
|
|
# Test quadlet rm
|
|
run_podman quadlet rm "$quadlet_name"
|
|
|
|
# Verify removal
|
|
run_podman quadlet list
|
|
assert "$output" !~ "$quadlet_name" "list should not contain removed container"
|
|
|
|
run_podman rm -f -t0 $serverctr
|
|
}
|
|
|
|
@test "quadlet verb - install with external file mount" {
|
|
# Create a test.txt file with content
|
|
local test_file=$PODMAN_TMPDIR/test.txt
|
|
mount_content="This is a test file for quadlet mount testing $(random_string)"
|
|
echo $mount_content > $test_file
|
|
|
|
# Create a quadlet directory for installation
|
|
local quadlet_dir=$PODMAN_TMPDIR/quadlet-mount-test
|
|
mkdir -p $quadlet_dir
|
|
|
|
# Create quadlet file that mounts the external test.txt file
|
|
local quadlet_file=$quadlet_dir/mount-test.container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER WITH MOUNT; cat /mounted/test.txt; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
Mount=type=bind,source=./test.txt,destination=/test.txt:z
|
|
EOF
|
|
|
|
# Determine the install directory path based on rootless/root
|
|
local install_dir=$(get_quadlet_install_dir)
|
|
|
|
# Test quadlet install with the directory containing the quadlet and test file
|
|
run_podman quadlet install $quadlet_dir $test_file
|
|
|
|
# Verify the content of the installed test.txt file
|
|
run -0 cat "$install_dir/test.txt"
|
|
assert "$output" == "$mount_content" "installed test.txt should have correct content"
|
|
|
|
# Test quadlet list to verify the container was installed
|
|
run_podman quadlet list
|
|
assert "$output" =~ "mount-test.container" "list should contain mount-test.container"
|
|
|
|
# Test quadlet print to verify the configuration includes the volume mount
|
|
run_podman quadlet print mount-test.container
|
|
assert "$output" == "$(<$quadlet_file)" "print output matches quadlet file"
|
|
|
|
# Test quadlet rm
|
|
run_podman quadlet rm mount-test.container
|
|
|
|
# Verify the test.txt file should not exists in $install_dir
|
|
if [[ -f "$install_dir/test.txt" ]]; then
|
|
die "test.txt file should not exist in install directory $install_dir after removal"
|
|
fi
|
|
|
|
# Verify removal
|
|
run_podman quadlet list
|
|
assert "$output" !~ "mount-test.container" "list should not contain removed container"
|
|
}
|
|
|
|
@test "quadlet verb - install with --reload-systemd option" {
|
|
# Create a test quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/reload-test-install.container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER FOR RELOAD TEST; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
# Get the expected service name for the quadlet
|
|
local service_name=$(quadlet_to_service_name "reload-test-install.container")
|
|
|
|
# Test quadlet install with --reload-systemd=true (should succeed)
|
|
run_podman quadlet install --reload-systemd=true $quadlet_file
|
|
assert $status -eq 0 "install with --reload-systemd=true should succeed"
|
|
|
|
# Verify the quadlet was installed in podman
|
|
run_podman quadlet list
|
|
assert "$output" =~ "reload-test-install.container" "list should contain reload-test-install.container"
|
|
|
|
# Verify the systemd unit exists and is loaded after reload
|
|
run systemctl status "$service_name"
|
|
assert $status -eq 3 "systemd unit should exist (inactive/loaded state)"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit should be loaded"
|
|
|
|
# Verify unit can be listed by systemctl
|
|
run systemctl list-unit-files "$service_name"
|
|
assert $status -eq 0 "systemctl should be able to list the unit file"
|
|
assert "$output" =~ "$service_name" "unit file should be listed by systemctl"
|
|
|
|
# Remove the quadlet for next test
|
|
run_podman quadlet rm reload-test-install.container
|
|
|
|
# Verify systemd unit is removed after quadlet removal
|
|
run systemctl status "$service_name"
|
|
assert $status -eq 4 "systemd unit should not exist after removal"
|
|
|
|
# Test quadlet install with --reload-systemd=false (should succeed but systemd may not see it immediately)
|
|
run_podman quadlet install --reload-systemd=false $quadlet_file
|
|
assert $status -eq 0 "install with --reload-systemd=false should succeed"
|
|
|
|
# Verify the quadlet was installed in podman
|
|
run_podman quadlet list
|
|
assert "$output" =~ "reload-test-install.container" "list should contain reload-test-install.container after install with --reload-systemd=false"
|
|
|
|
# When --reload-systemd=false, systemd might not see the unit immediately
|
|
# But after manual reload, it should be visible
|
|
run systemctl daemon-reload
|
|
run systemctl status "$service_name"
|
|
assert $status -eq 3 "systemd unit should exist after manual daemon-reload"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit should be loaded after manual reload"
|
|
|
|
# Clean up
|
|
run_podman quadlet rm reload-test-install.container
|
|
}
|
|
|
|
|
|
@test "quadlet verb - remove with --reload-systemd option" {
|
|
# Create a test quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/reload-test-remove.container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER FOR RELOAD TEST; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
# Get the expected service name for the quadlet
|
|
local service_name=$(quadlet_to_service_name "reload-test-remove.container")
|
|
|
|
# Install the quadlet
|
|
run_podman quadlet install $quadlet_file
|
|
|
|
# Verify the quadlet was installed in podman
|
|
run_podman quadlet list
|
|
assert "$output" =~ "reload-test-remove.container" "list should contain reload-test-remove.container"
|
|
|
|
# Verify the systemd unit exists after installation
|
|
run systemctl status "$service_name"
|
|
assert $status -eq 3 "systemd unit should exist (inactive/loaded state)"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit should be loaded"
|
|
|
|
# Test quadlet remove with --reload-systemd (should succeed and reload systemd)
|
|
run_podman quadlet rm --reload-systemd reload-test-remove.container
|
|
assert $status -eq 0 "remove with --reload-systemd should succeed"
|
|
|
|
# Verify the quadlet was removed from podman
|
|
run_podman quadlet list
|
|
assert "$output" !~ "reload-test-remove.container" "list should not contain reload-test-remove.container after removal"
|
|
|
|
# Verify the systemd unit is removed after removal with --reload-systemd
|
|
run systemctl status "$service_name"
|
|
assert $status -eq 4 "systemd unit should not exist after removal with --reload-systemd"
|
|
}
|
|
|
|
@test "quadlet verb - list with --format option" {
|
|
# Create a test quadlet file
|
|
local quadlet_file=$PODMAN_TMPDIR/format-test.container
|
|
cat > $quadlet_file <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER FOR FORMAT TEST; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
# Install the quadlet
|
|
run_podman quadlet install $quadlet_file
|
|
|
|
# Test default format (should show tabular output)
|
|
run_podman quadlet list
|
|
assert $status -eq 0 "quadlet list should succeed"
|
|
assert "$output" =~ "format-test.container" "default format should contain quadlet name"
|
|
|
|
# Test JSON format
|
|
run_podman quadlet list --format json
|
|
assert $status -eq 0 "quadlet list --format json should succeed"
|
|
assert "$output" =~ '"Name".*"format-test.container"' "JSON format should contain name field"
|
|
assert "$output" =~ '"Path"' "JSON format should contain path field"
|
|
assert "$output" =~ '"Status"' "JSON format should contain status field"
|
|
|
|
# Test custom Go template format - extract only names
|
|
run_podman quadlet list --format '{{range .}}{{.Name}}{{"\n"}}{{end}}'
|
|
assert $status -eq 0 "quadlet list with custom format should succeed"
|
|
assert "$output" = $'NAME\nformat-test.container' "custom format should show only the name"
|
|
|
|
# Test custom Go template format - extract multiple fields
|
|
run_podman quadlet list --format '{{range .}}Name:{{.Name}} Status:{{.Status}}{{"\n"}}{{end}}'
|
|
assert $status -eq 0 "quadlet list with multi-field format should succeed"
|
|
assert "$output" =~ "Name:format-test.container" "multi-field format should show name"
|
|
assert "$output" =~ "Status:" "multi-field format should show status"
|
|
|
|
# Test format with specific field extraction
|
|
run_podman quadlet list --format '{{.Name}}'
|
|
assert $status -eq 0 "quadlet list with field format should succeed"
|
|
assert "$output" = $'NAME\nformat-test.container' "field format should extract just the name"
|
|
|
|
# Clean up
|
|
run_podman quadlet rm format-test.container
|
|
}
|
|
|
|
@test "quadlet verb - rm --all and --ignore options" {
|
|
# Create multiple test quadlet files
|
|
local quadlet_file1=$PODMAN_TMPDIR/rm-all-test1.container
|
|
cat > $quadlet_file1 <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER 1; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
local quadlet_file2=$PODMAN_TMPDIR/rm-all-test2.container
|
|
cat > $quadlet_file2 <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER 2; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
local quadlet_file3=$PODMAN_TMPDIR/rm-all-test3.container
|
|
cat > $quadlet_file3 <<EOF
|
|
[Container]
|
|
Image=$IMAGE
|
|
Exec=sh -c "echo STARTED CONTAINER 3; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
|
EOF
|
|
|
|
# Install all three quadlets
|
|
run_podman quadlet install $quadlet_file1 $quadlet_file2 $quadlet_file3
|
|
assert $status -eq 0 "quadlet install should succeed for all files"
|
|
|
|
# Verify all quadlets were installed
|
|
run_podman quadlet list
|
|
assert "$output" =~ "rm-all-test1.container" "list should contain rm-all-test1.container"
|
|
assert "$output" =~ "rm-all-test2.container" "list should contain rm-all-test2.container"
|
|
assert "$output" =~ "rm-all-test3.container" "list should contain rm-all-test3.container"
|
|
|
|
# Get the expected service names for systemd verification
|
|
local service_name1=$(quadlet_to_service_name "rm-all-test1.container")
|
|
local service_name2=$(quadlet_to_service_name "rm-all-test2.container")
|
|
local service_name3=$(quadlet_to_service_name "rm-all-test3.container")
|
|
|
|
# Verify systemd units exist for all quadlets
|
|
run systemctl status "$service_name1"
|
|
assert $status -eq 3 "systemd unit 1 should exist (inactive/loaded state)"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit 1 should be loaded"
|
|
|
|
run systemctl status "$service_name2"
|
|
assert $status -eq 3 "systemd unit 2 should exist (inactive/loaded state)"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit 2 should be loaded"
|
|
|
|
run systemctl status "$service_name3"
|
|
assert $status -eq 3 "systemd unit 3 should exist (inactive/loaded state)"
|
|
assert "$output" =~ "Loaded: loaded" "systemd unit 3 should be loaded"
|
|
|
|
# Test quadlet rm --all (should remove all quadlets)
|
|
run_podman quadlet rm --all
|
|
assert $status -eq 0 "quadlet rm --all should succeed"
|
|
|
|
# Verify all quadlets were removed from podman
|
|
run_podman quadlet list
|
|
assert "$output" !~ "rm-all-test1.container" "list should not contain rm-all-test1.container after --all removal"
|
|
assert "$output" !~ "rm-all-test2.container" "list should not contain rm-all-test2.container after --all removal"
|
|
assert "$output" !~ "rm-all-test3.container" "list should not contain rm-all-test3.container after --all removal"
|
|
|
|
# Verify all systemd units are removed
|
|
run systemctl status "$service_name1"
|
|
assert $status -eq 4 "systemd unit 1 should not exist after --all removal"
|
|
|
|
run systemctl status "$service_name2"
|
|
assert $status -eq 4 "systemd unit 2 should not exist after --all removal"
|
|
|
|
run systemctl status "$service_name3"
|
|
assert $status -eq 4 "systemd unit 3 should not exist after --all removal"
|
|
|
|
# Test quadlet rm --ignore behavior
|
|
# Try to remove non-existent quadlets without --ignore (should fail)
|
|
run_podman 125 quadlet rm non-existent.container
|
|
assert "$output" =~ "could not locate quadlet" "should fail to remove non-existent quadlet without --ignore"
|
|
|
|
# Try to remove non-existent quadlets with --ignore (should succeed)
|
|
run_podman quadlet rm --ignore non-existent1.container non-existent2.container
|
|
assert $status -eq 0 "quadlet rm --ignore should succeed even for non-existent quadlets"
|
|
}
|
|
|
|
# vim: filetype=sh
|