mouse/src

Blob: scripts/check-c3.exp

Raw · Blame

#!/usr/bin/expect -f

if {$argc != 2} {
    puts stderr "usage: check-c3.exp RUNNER MODE"
    exit 2
}

set runner [file normalize [lindex $argv 0]]
set mode [lindex $argv 1]
if {$mode ni {enabled disabled recovery missing cycle}} {
    puts stderr "invalid C3 check mode: $mode"
    exit 2
}
set timeout 45

proc fail {message} {
    puts stderr "C3 check failed: $message"
    exit 1
}

proc await_exact {value description} {
    expect {
        -exact $value {
            return
        }
        timeout {
            fail "timed out waiting for $description"
        }
        eof {
            fail "QEMU exited while waiting for $description"
        }
    }
}

proc await_regexp {value description} {
    expect {
        -re $value {
            return
        }
        timeout {
            fail "timed out waiting for $description"
        }
        eof {
            fail "QEMU exited while waiting for $description"
        }
    }
}

proc await_prompt {} {
    send -- "\r"
    await_exact "mouse:~# " "the tcsh prompt"
}

proc sendline {line} {
    send -- $line
    send -- "\r"
}

proc await_clean_exit {action} {
    expect {
        eof {
            set result [wait]
            set status [lindex $result 3]
            if {$status != 0} {
                fail "QEMU exited with status $status after $action"
            }
        }
        timeout {
            fail "QEMU did not exit after $action"
        }
    }
}

proc poweroff {} {
    send -- "kill -TERM 1\r"
    await_exact "cheesed: received poweroff request" "the poweroff request"
    await_exact "cheesed: OpenRC shutdown transition complete" "the shutdown transition"
    await_clean_exit "poweroff"
}

log_user 0
spawn -noecho $runner
await_exact "cheesed: C3 bootstrap complete; cheesed is PID 1" "PID 1 confirmation"

if {$mode eq "recovery"} {
    await_regexp {required service console_login is not started: status command exited with status [0-9]+; entering recovery console} "the required-service failure"
    await_regexp {cheesed: started emergency shell as PID [0-9]+} "the recovery shell"
    await_exact "mouse:~# " "the recovery prompt"
    sendline {sh -c 'set -- `cat /proc/$PPID/stat`; cat /proc/$4/comm'}
    await_exact "cheesed\r" "the recovery shell parent"
    await_exact "mouse:~# " "the prompt after the recovery parent check"
    poweroff
    puts "C3 required-service recovery check passed"
    exit 0
}

if {$mode eq "disabled"} {
    await_exact "cheesed: enabled optional services: (none)" "disabled ports policy"
} else {
    await_exact "cheesed: enabled optional services: mouse_echo" "enabled ports policy"
}
if {$mode eq "missing"} {
    await_exact "Service 'mouse_echo' needs non existent service 'absent_port_dependency'" "the missing-dependency diagnostic"
}
await_exact "Starting console_login" "the required console service"
if {$mode eq "cycle"} {
    await_exact "ERROR: cannot start cycle_peer as mouse_echo would not start" "the dependency-cycle diagnostic"
}
await_exact "mouse login: root (automatic login)" "the automatic root login"
await_exact "MOUSE 0.1.0 (x86_64)" "the login banner"

if {$mode eq "enabled"} {
    await_exact "cheesed: OpenRC default transition complete" "the default transition"
} elseif {$mode eq "disabled"} {
    await_exact "cheesed: OpenRC default transition complete" "the default transition"
} else {
    await_exact "cheesed: OpenRC default transition complete" "the default transition after rejecting the optional service"
    await_regexp {optional service mouse_echo failed: status command exited with status [0-9]+} "the optional-service failure"
}
await_prompt

sendline {id}
await_exact "uid=0(root) gid=0(root) groups=0(root)\r" "the root login identity"
await_exact "mouse:~# " "the prompt after the identity check"
sendline {echo $LOGNAME $USER $SHELL}
await_exact "root root /bin/tcsh\r" "the login environment"
await_exact "mouse:~# " "the prompt after the environment check"
sendline {tty}
await_exact "/dev/ttyS0\r" "the serial login tty"
await_exact "mouse:~# " "the prompt after the tty check"
sendline {sh -c 'set -- `cat /proc/$PPID/stat`; cat /proc/$4/comm'}
await_exact "supervise-daemo\r" "the supervised login parent"
await_exact "mouse:~# " "the prompt after the login parent check"
sendline {sh -c 'test "$(cat /proc/1/comm)" = cheesed && ! command -v rc-update >/dev/null 2>&1'; echo BASE_$status}
await_exact "BASE_0\r" "cheesed as PID 1 with no rc-update command"
await_exact "mouse:~# " "the prompt after the base contract check"

if {$mode eq "missing"} {
    sendline {sh -c 'test ! -e /run/mouse-echo.unexpected'; echo ORDERED_$status}
    await_exact "ORDERED_0\r" "no partial start after a missing dependency"
    await_exact "mouse:~# " "the prompt after the missing-dependency check"
    poweroff
    puts "C3 missing-dependency check passed"
    exit 0
}

if {$mode eq "cycle"} {
    sendline {sh -c 'test ! -e /run/mouse-echo.unexpected && test ! -e /run/cycle-peer.unexpected'; echo ORDERED_$status}
    await_exact "ORDERED_0\r" "no partial start after a dependency cycle"
    await_exact "mouse:~# " "the prompt after the dependency-cycle check"
    poweroff
    puts "C3 dependency-cycle check passed"
    exit 0
}

sendline {service console_login status}
await_exact "status: started" "the required console service status"
await_exact "mouse:~# " "the prompt after the console status"

if {$mode eq "disabled"} {
    sendline {sh -c 'test ! -e /run/openrc/runlevels/current/default/mouse_echo'; echo DISABLED_$status}
    await_exact "DISABLED_0\r" "the absent ports runlevel member"
    await_exact "mouse:~# " "the prompt after the disabled membership check"
    sendline {sh -c 'cksum /etc/rc.conf > /run/rc.conf.cksum'; service mouse_echo start}
    await_exact "Starting mouse_echo" "the runtime-only ports service start"
    await_exact "mouse:~# " "the prompt after the runtime start"
    sendline {sh -c 'test "$(cksum /etc/rc.conf)" = "$(cat /run/rc.conf.cksum)"'; echo POLICY_$status}
    await_exact "POLICY_0\r" "unchanged persistent policy"
    await_exact "mouse:~# " "the prompt after the persistent-policy check"
    sendline {service mouse_echo stop}
    await_exact "Stopping mouse_echo" "the runtime-only ports service stop"
    await_exact "mouse:~# " "the prompt after the runtime stop"
    poweroff
    puts "C3 disabled ports-service check passed"
    exit 0
}

sendline {sh -c 'test -L /run/openrc/runlevels/current/default/mouse_echo'; echo ENABLED_$status}
await_exact "ENABLED_0\r" "the generated ports runlevel member"
await_exact "mouse:~# " "the prompt after the enabled membership check"
sendline {sh -c 'i=0; while [ "$i" -lt 4 ]; do child=`cat /run/openrc/options/mouse_echo/child_pid`; kill -KILL "$child"; i=$((i + 1)); sleep 1; done'; echo EXHAUST_$status}
await_exact "EXHAUST_0\r" "four supervised ports-service crashes"
await_exact "mouse:~# " "the prompt after exhausting respawns"
sendline {service mouse_echo status; echo FAILED_STATUS_$status}
await_exact "status: failed" "the failed ports-service status"
await_exact "FAILED_STATUS_32\r" "the failed status exit code"
await_exact "mouse:~# " "the prompt after failed status"
sendline {service mouse_echo restart}
await_exact "Starting mouse_echo" "administrative ports-service recovery"
await_exact "mouse:~# " "the prompt after administrative recovery"
sendline {set stubborn=`cat /run/openrc/options/mouse_echo/child_pid`; service mouse_echo stop}
await_exact "Stopping mouse_echo" "the forced ports-service stop"
await_exact "mouse:~# " "the prompt after the forced stop"
sendline {sh -c 'test -f /run/mouse-echo.term'; echo TERM_SEEN_$status}
await_exact "TERM_SEEN_0\r" "the ports daemon observing SIGTERM"
await_exact "mouse:~# " "the prompt after the SIGTERM check"
sendline {sh -c '! kill -0 "$1" 2>/dev/null' sh "$stubborn"; echo FORCED_GONE_$status}
await_exact "FORCED_GONE_0\r" "SIGKILL escalation for the ports daemon"
await_exact "mouse:~# " "the prompt after forced termination"
sendline {service mouse_echo start}
await_exact "Starting mouse_echo" "the final ports-service start"
await_exact "mouse:~# " "the prompt after the final start"

sendline {exit}
await_exact "logout\r" "the first login session ending"
await_exact "mouse login: root (automatic login)" "the respawned console login"
await_exact "MOUSE 0.1.0 (x86_64)" "the respawned login banner"
await_exact "mouse:~# " "the respawned tcsh prompt"
sendline {sh -c 'for stat in /proc/[0-9]*/stat; do set -- $(cat "$stat"); test "$3" != Z || exit 1; done'; echo ZOMBIES_$status}
await_exact "ZOMBIES_0\r" "the absence of zombie processes"
await_exact "mouse:~# " "the prompt after the zombie check"

sendline {kill -TERM 1}
await_exact "cheesed: received poweroff request" "the poweroff request"
await_exact "Stopping mouse_echo" "the ports service stopping first"
await_exact "Stopping console_login" "the console service stopping after its dependent"
await_exact "cheesed: OpenRC shutdown transition complete" "the shutdown transition"
await_clean_exit "poweroff"

puts "C3 enabled base-integration check passed"