Current Dir: /snap/canonical-livepatch/418/resources/tests/
[FILE] 99-livepatch-kernel-upgrade-required.bats [ edit | delete | rename ]
[FILE] livepatch-kernel-installed.bats [ edit | delete | rename ]
[FILE] reboot-required-check.bats [ edit | delete | rename ]
Viewing: /snap/canonical-livepatch/418/resources/tests/reboot-required-check.bats
#!/usr/bin/env bats
#
# Tests for resources/reboot-required-check.
#
# Each test copies the script to a temp file and rewrites just the path
# variable assignments with sed before executing the copy. A stub
# canonical-livepatch logs each invocation's first argument to
# "$WORKDIR/calls" and its output/exit code are driven by env vars.
setup() {
ORIG_SCRIPT="${BATS_TEST_DIRNAME}/../reboot-required-check"
WORKDIR="$(mktemp -d)"
SCRIPT="${WORKDIR}/reboot-required-check"
NOTE="${WORKDIR}/canonical-livepatch-kernel-installed"
GRUB_CFG="${WORKDIR}/grub.cfg"
REBOOT_REQUIRED="${WORKDIR}/reboot-required"
REBOOT_REQUIRED_PKGS="${WORKDIR}/reboot-required.pkgs"
LIVEPATCH_STUB="${WORKDIR}/canonical-livepatch"
CALLS="${WORKDIR}/calls"
sed \
-e "s#^NOTE=.*#NOTE=\"${NOTE}\"#" \
-e "s#^GRUB_CFG=.*#GRUB_CFG=\"${GRUB_CFG}\"#" \
-e "s#^REBOOT_REQUIRED=.*#REBOOT_REQUIRED=\"${REBOOT_REQUIRED}\"#" \
-e "s#^REBOOT_REQUIRED_PKGS=.*#REBOOT_REQUIRED_PKGS=\"${REBOOT_REQUIRED_PKGS}\"#" \
-e "s#^LIVEPATCH=.*#LIVEPATCH=\"${LIVEPATCH_STUB}\"#" \
-e "s#^TIMEOUT_SECONDS=.*#TIMEOUT_SECONDS=1#" \
"$ORIG_SCRIPT" > "$SCRIPT"
chmod +x "$SCRIPT"
}
teardown() {
rm -rf "$WORKDIR"
}
# chmod-based permission tests are meaningless when run as root, since root
# bypasses DAC read/unlink checks.
skip_if_root() {
if [ "$(id -u)" -eq 0 ]; then
skip "permission checks are bypassed when running as root"
fi
}
livepatch_aware_policy='{"reboot-notification-policy":"livepatch-aware"}'
# Writes a stub canonical-livepatch that logs $1 to $CALLS, then answers
# "config"/"refresh"/"kernel-upgrade-required" per env vars:
# LP_CONFIG_OUT, LP_CONFIG_EXIT (default the aware policy, 0)
# LP_REFRESH_EXIT (default 0)
# LP_KUR_EXIT (default 2), LP_KUR_SLEEP (default 0, seconds to sleep first)
stub_livepatch() {
cat > "$LIVEPATCH_STUB" <<EOF
#!/bin/sh
printf '%s\n' "\$1" >> "$CALLS"
case "\$1" in
config)
printf '%s' '${LP_CONFIG_OUT:-$livepatch_aware_policy}'
exit "${LP_CONFIG_EXIT:-0}"
;;
refresh)
exit "${LP_REFRESH_EXIT:-0}"
;;
kernel-upgrade-required)
sleep "${LP_KUR_SLEEP:-0}"
exit "${LP_KUR_EXIT:-2}"
;;
esac
EOF
chmod +x "$LIVEPATCH_STUB"
}
@test "fast path: no note, no calls, no output" {
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -z "$output" ]
[ ! -f "$CALLS" ]
}
@test "note present, no grub.cfg: note removed, no calls" {
touch "$NOTE"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$NOTE" ]
[ ! -f "$CALLS" ]
}
@test "note newer than grub.cfg: note kept, no calls" {
touch "$GRUB_CFG"
touch -d '+1 min' "$NOTE"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$NOTE" ]
[ ! -f "$CALLS" ]
}
@test "equal mtimes count as fresh and proceed (note removed)" {
touch "$NOTE"
touch -r "$NOTE" "$GRUB_CFG"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$NOTE" ]
}
@test "marker absent: note removed, no snap calls" {
touch "$NOTE"
touch "$GRUB_CFG"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$NOTE" ]
[ ! -f "$CALLS" ]
}
@test "pkgs missing: marker kept, no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ ! -f "$CALLS" ]
}
@test "pkgs empty: marker kept, no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
: > "$REBOOT_REQUIRED_PKGS"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ ! -f "$CALLS" ]
}
@test "pkgs with only blank lines: marker kept, no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf '\n\n' > "$REBOOT_REQUIRED_PKGS"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
[ ! -f "$CALLS" ]
}
@test "pkgs containing libc6: marker kept, no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'libc6\n' > "$REBOOT_REQUIRED_PKGS"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ ! -f "$CALLS" ]
}
@test "blank lines and duplicate kernel lines are kernel-only: both files removed on KUR exit 1" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n\nlinux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=1
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$REBOOT_REQUIRED" ]
[ ! -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "linux-base next to kernel packages is still kernel-only: both files removed on KUR exit 1" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-base\nlinux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=1
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$REBOOT_REQUIRED" ]
[ ! -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "linux-base alone is not a kernel install: nothing removed, no calls" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-base\n' > "$REBOOT_REQUIRED_PKGS"
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ ! -f "$CALLS" ]
}
@test "LIVEPATCH not executable: no calls, marker kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
rm -f "$LIVEPATCH_STUB"
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ ! -f "$CALLS" ]
}
@test "policy livepatch-agnostic: no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_CONFIG_OUT='{"reboot-notification-policy":"livepatch-agnostic"}'
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ "$(cat "$CALLS")" = "config" ]
}
@test "malformed policy JSON: no refresh call" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_CONFIG_OUT='{"unexpected":"json"}'
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ "$(cat "$CALLS")" = "config" ]
}
@test "checking kernel coverage line printed only when refresh is called" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=1
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
case "$output" in
*"Livepatch: checking kernel coverage..."*) ;;
*) false ;;
esac
}
@test "no coverage line when policy check fails fast" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
rm -f "$LIVEPATCH_STUB"
run "$SCRIPT"
[ "$status" -eq 0 ]
case "$output" in
*"checking kernel coverage"*) false ;;
*) ;;
esac
}
@test "refresh exits 1: no KUR call, marker kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_REFRESH_EXIT=1
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ "$(cat "$CALLS")" = "$(printf 'config\nrefresh')" ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "KUR exit 0: marker and pkgs kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=0
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "KUR exit 2: marker and pkgs kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=2
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "KUR exit 3: marker and pkgs kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=3
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
}
@test "KUR exit 1: pkgs and marker removed, removal line printed" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_EXIT=1
stub_livepatch
run "$SCRIPT"
[ "$status" -eq 0 ]
[ ! -f "$REBOOT_REQUIRED" ]
[ ! -f "$REBOOT_REQUIRED_PKGS" ]
[ "$(cat "$CALLS")" = "$(printf 'config\nrefresh\nkernel-upgrade-required')" ]
case "$output" in
*"Livepatch: reboot-required notice removed; the running kernel is covered by Livepatch."*) ;;
*) false ;;
esac
}
@test "KUR times out (124): marker kept" {
touch "$NOTE"
touch "$GRUB_CFG"
touch "$REBOOT_REQUIRED"
printf 'linux-image-6.8.0-50-generic\n' > "$REBOOT_REQUIRED_PKGS"
LP_KUR_SLEEP=5
stub_livepatch
start=$(date +%s)
run "$SCRIPT"
elapsed=$(( $(date +%s) - start ))
[ "$status" -eq 0 ]
[ -f "$REBOOT_REQUIRED" ]
[ -f "$REBOOT_REQUIRED_PKGS" ]
[ "$elapsed" -lt 4 ]
}
@test "note cannot be removed: exits 0, no calls" {
skip_if_root
touch "$GRUB_CFG"
touch -r "$GRUB_CFG" "$NOTE"
chmod 555 "$WORKDIR"
run "$SCRIPT"
chmod 755 "$WORKDIR"
[ "$status" -eq 0 ]
[ -f "$NOTE" ]
[ ! -f "$CALLS" ]
}