diff options
Diffstat (limited to 'tests')
| -rwxr-xr-x | tests/e2e.sh | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/tests/e2e.sh b/tests/e2e.sh index 29d900b..b79c748 100755 --- a/tests/e2e.sh +++ b/tests/e2e.sh @@ -37,7 +37,7 @@ cleanup() { [ -n "${DAEMON_PID:-}" ] && kill "$DAEMON_PID" 2>/dev/null [ -n "${DAEMON2_PID:-}" ] && kill "$DAEMON2_PID" 2>/dev/null t kill-server 2>/dev/null - tmux -L "$SOCK-restore" kill-server 2>/dev/null + tmux -L "$SOCK-restore-$$" kill-server 2>/dev/null rm -rf "$DIR" } trap cleanup EXIT @@ -226,6 +226,11 @@ t source-file "$ROOT/packaging/tmux/dingger.tmux" segment=$(t display -p -c "$CLIENT" '#{T:status-right}' | sed 's/#\[[^]]*\]//g') case "$segment" in *"×1"*"✓1"*) pass "segment shows ×1 ✓1 ($segment)";; *) fail "segment: [$segment]";; esac expect "mouse binding installed" "t list-keys -T root | grep MouseDown1StatusRight | grep -c 'dingger focus'" 1 +expect "clicking the restore offer runs restore" "t list-keys -T root | grep MouseDown1StatusRight | grep -c 'restore --report'" 1 +t set -g @dingger_restore 3 +segment=$(t display -p -c "$CLIENT" '#{T:status-right}' | sed 's/#\[[^]]*\]//g') +case "$segment" in "↺3 "*"×1"*) pass "segment offers to restore 3 sessions ($segment)";; *) fail "restore segment: [$segment]";; esac +t set -gu @dingger_restore # same run-shell + #{client_name} expansion as the mouse binding, via a key t bind -n F12 run-shell "DINGGER_TMUX_SOCKET=$SOCK $DINGGER focus --client '#{client_name}'" t send-keys -t viewer: F12 @@ -351,7 +356,7 @@ fi # A second server and daemon. "viewer" hosts a client the way a terminal # does: Ghostty runs `tmux new-session -As 0`. echo "16. restore" -R="$SOCK-restore" +R="$SOCK-restore-$$" STATE2="$DIR/state2" # tmux gives new windows the environment of the client that creates them: # both the test and restore run with the fake pi first on PATH. @@ -410,7 +415,10 @@ fingerprint() { | grep -E '^(0|work)\|' } BEFORE=$(fingerprint) -renv "$DINGGER" watch --interval-secs 1 --no-sounds --no-notifications >>"$DIR/daemon2.log" 2>&1 & +# Started directly, not through a function: $! must be the daemon itself. +env PATH="$DIR/rbin:$PATH" DINGGER_TMUX_SOCKET="$R" DINGGER_AGENT_SOCKET="$DIR/hook2.sock" \ + DINGGER_STATE_DIR="$STATE2" DINGGER_TMUX_CONFIG=/dev/null \ + "$DINGGER" watch --interval-secs 1 --no-sounds --no-notifications >>"$DIR/daemon2.log" 2>&1 & DAEMON2_PID=$! latest_snapshot() { ls "$STATE2"/snapshots/*.json 2>/dev/null | tail -1; } expect "a snapshot of both sessions" "grep -c '\"name\": \"work\"' \"\$(latest_snapshot)\" 2>/dev/null" 1 80 @@ -452,7 +460,16 @@ expect "the candidate survives the new server's snapshots" \ "python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))[\"snapshot\"][\"server\"] != json.load(open(sys.argv[2]))[\"server\"])' $STATE2/restore.json \"\$(latest_snapshot)\"" True 80 expect "dry run plans: replace 0, keep keep and viewer, create work" \ "renv \"$DINGGER\" restore --dry-run | grep -v '^ ' | cut -c1-14 | sort | tr '\n' ';'" "create work:;keep keep:;keep viewe;replace 0: 2 ;" -renv "$DINGGER" restore >"$DIR/restore.out" 2>&1 +mbr() { renv DINGGER_BIN="$DINGGER" DINGGER_RESTORE_DIRECT=1 \ + DINGGER_NOTIFIER="echo \"\$0|\$1\" >> $DIR/notes2" "$MENUBAR" "$@"; } +expect "the daemon offers to restore 0 and work" \ + "python3 -c 'import json,sys; o=json.load(open(sys.argv[1])); print([s[\"name\"] for s in o[\"sessions\"]], o[\"agents\"], o[\"interrupted\"])' $STATE2/offer.json 2>/dev/null" \ + "['0', 'work'] 2 1" 80 +expect "and tells the status line" "r show -gv @dingger_restore" 2 +expect "the panel offers it first" "mbr --print-panel | head -1 | cut -f1,3" "↺ Restore 2 sessions · 2 agents [Not now]" +expect "with what was interrupted" "mbr --print-panel | head -1 | cut -f2 | grep -o '1 was mid-turn'" "1 was mid-turn" +mbr --restore +cp "$STATE2/restore.log" "$DIR/restore.out" 2>/dev/null expect "restore succeeds" "grep -c FAILED $DIR/restore.out" 0 expect "agents resumed with their session files" "grep -- --session $DIR/pi-args | sort" "--session $W/sessions/a b.jsonl --session $W/sessions/gone.jsonl" @@ -463,6 +480,8 @@ expect "the interrupted turn is reported" "grep -c '^interrupted work:agent' $D typed_line() { r capture-pane -p -t "$1" | grep -v '^ *$' | tail -1; } expect "a command is retyped with its quoting" "typed_line '=work:cmd' | grep -o \"sh -c 'sleep 100000; :' 'two words'\$\"" "sh -c 'sleep 100000; :' 'two words'" expect "the zsh hook's text is retyped" "typed_line '=work:hooked' | grep -o 'slp 200000 | cat\$'" "slp 200000 | cat" +expect "a notification summarizes" "cat $DIR/notes2" "Restored 2 tmux sessions|resumed 2 of 2 agents · 1 was mid-turn · 2 commands typed, not run" +expect "the offer is gone" "ls $STATE2/offer.json 2>/dev/null; r show -gv @dingger_restore 2>/dev/null; mbr --print-panel | grep -c '↺'" "0" expect "neither runs: the shell waits for Enter" \ "r display -p -t '=work:cmd' '#{pane_current_command}'; r display -p -t '=work:hooked' '#{pane_current_command}'" "bash bash" @@ -480,6 +499,30 @@ expect "restoring again changes nothing" "fingerprint" "$BEFORE" expect "restoring again plans nothing" "grep -cvE '^keep ' $DIR/restore2.out" 0 [ "$FAILS" -gt 0 ] && { echo "--- restore output:"; cat "$DIR/restore.out"; echo "--- before:"; echo "$BEFORE"; echo "--- after:"; fingerprint; } +# Again, now with no tmux running at all (after a reboot, before a terminal +# opens): restoring starts the server. Then "Not now" stays dismissed. +names() { r list-panes -a -F '#{session_name}|#{window_index}|#{?automatic-rename,(auto),#{window_name}}|#{pane_index}|#{pane_current_path}' 2>/dev/null | grep "^$1|"; } +WORK_BEFORE=$(names work) +r kill-server +expect "a new offer: all four sessions, tmux is not running" \ + "python3 -c 'import json,sys; print(len(json.load(open(sys.argv[1]))[\"sessions\"]))' $STATE2/offer.json 2>/dev/null" 4 80 +mbr --restore work +expect "restoring with no server starts it and rebuilds the session" "names work" "$WORK_BEFORE" +expect "the offer shrinks to what is still missing" \ + "python3 -c 'import json,sys; print(sorted(s[\"name\"] for s in json.load(open(sys.argv[1]))[\"sessions\"]))' $STATE2/offer.json 2>/dev/null" \ + "['0', 'keep', 'viewer']" 80 +mbr --dismiss-offer >/dev/null +expect "Not now: the offer is gone" "ls $STATE2/offer.json 2>/dev/null | wc -l | tr -d ' '" 0 +expect "and the status line is told" "r show -gv @dingger_restore 2>/dev/null" "" +start_viewer +sleep 2 +expect "it stays dismissed when a terminal starts tmux" "ls $STATE2/offer.json 2>/dev/null | wc -l | tr -d ' '" 0 +expect "the layout can still be restored by hand" "renv \"$DINGGER\" restore --dry-run | grep -c '^create keep'" 1 + +# Every daemon this run started must stop with it. +kill "$DAEMON_PID" "$DAEMON2_PID" 2>/dev/null +expect "the test daemons stop" "ps -o pid= -p $DAEMON_PID,$DAEMON2_PID | wc -l | tr -d ' '" 0 + echo echo "$PASSES passed, $FAILS failed" [ "$FAILS" -eq 0 ] || { echo "--- daemon log tail"; tail -30 "$DIR/daemon.log"; exit 1; } |
