Verify quarantined Remote mailbox owner crash recovery

This commit is contained in:
ak47 committed 2026-11-05 23:21:22 -05:00
1 parent 06530f0120
commit ee1c32f049
4 files changed
+242 -1

No files matched your search

@@ -6,6 +6,7 @@ package app
import (
"context"
"errors"
"os"
"os/exec"
"testing"
@@ -14,6 +15,54 @@ import (
"git.stormux.org/storm/cthulhu/internal/remoteinput"
)
// The private Python supervisor kills/stops this entire reader-side process,
// leaving its independently grouped helper alive to retire native keys. This
// uses the actual SDK, host, mailbox worker and Supervisor, not a fake writer.
func TestNativeRemoteKeyboardOwnerProcess(t *testing.T) {
ready := os.Getenv("CTHULHU_REMOTE_OWNER_READY")
if os.Getenv("CTHULHU_NATIVE_REMOTE_KEYS") != "1" || ready == "" {
t.Skip("requires private native_remote_keys.py crash supervisor")
}
f := keyboard_owner_fixture(t, func(f *keyboardOwnerFixture) {
var err error
f.supervisor, err = remoteinput.NewSupervisor(os.Getenv("CTHULHU_REMOTE_INPUT_HELPER"))
if err != nil {
t.Fatal(err)
}
})
lease := f.open(t, "keyboard-inject")
f.key(t, lease, 1, "Shift_L", true)
f.key(t, lease, 2, "Control_R", true)
f.wait(t, func() bool { return keyboard_owner_native_state(t) == "110" })
if err := os.WriteFile(ready, []byte("ready\n"), 0600); err != nil {
t.Fatal(err)
}
// After SIGSTOP/watchdog expiry the parent resumes us and requests checks.
// SIGKILL never reaches this path or the fixture's orderly cleanup.
var command [1]byte
if n, err := os.Stdin.Read(command[:]); err != nil || n != 1 || command[0] != 'c' {
t.Fatal("crash supervisor command missing", err)
}
select {
case err := <-f.result:
f.result <- err // Preserve the fixture cleanup's join signal.
if !errors.Is(err, remoteinput.ErrUncertain) {
t.Fatal("watchdog helper exit did not retain cleanup uncertainty", err)
}
case <-time.After(6 * time.Second):
t.Fatal("resumed owner did not retire its failed helper")
}
if f.session.OutputContext().Err() == nil {
t.Fatal("resumed owner retained an accepting mailbox")
}
if _, err := f.supervisor.Start(t.Context(), lease.Epoch+1); !errors.Is(err, remoteinput.ErrUnavailable) {
t.Fatal("resumed owner replaced an unconfirmed helper", err)
}
if state := keyboard_owner_native_state(t); state != "000" {
t.Fatal("resumed owner restored retired key state", state)
}
}
func keyboard_owner_native_state(t *testing.T) string {
t.Helper()
// Query from a separate connection. No key injection or keymap changes