aboutsummaryrefslogtreecommitdiff
path: root/scripts/tests/agent-text.bats
blob: d4c5f9b0720b2250f1a6fba59c87c6b77aaf11a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env bats
# agent-text — the runtime-neutral Signal phone messenger ("text me"). Reaches
# Craig over Signal from any machine on the tailnet: sends directly wherever the
# account is registered locally (any machine holding it, as primary or as a
# linked device), and otherwise ssh-relays to the first relay host that holds
# it. These tests stub ssh/signal-cli/uname on PATH to verify command
# construction without a network or a phone. The signal-cli stub answers
# `listAccounts` to control which branch the dispatch takes; the uname stub
# fixes the machine identity, so the self-relay skip is exercised deterministically
# rather than depending on which machine runs the suite. The final test covers
# the deprecated agent-page shim.

setup() {
    REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
    PAGE="$REPO_ROOT/claude-templates/bin/agent-text"
    SHIM="$REPO_ROOT/claude-templates/bin/agent-page"
    STUBS="$(mktemp -d)"
    LOG="$STUBS/calls.log"
    cat > "$STUBS/ssh" <<EOF
#!/bin/bash
echo "ssh \$*" >> "$LOG"
exit 0
EOF
    # HAS_ACCOUNT controls the listAccounts answer: "1" → the account is
    # local (send direct), unset/"0" → not local (relay).
    cat > "$STUBS/signal-cli" <<EOF
#!/bin/bash
if [ "\$1" = "listAccounts" ]; then
  [ "\${HAS_ACCOUNT:-0}" = "1" ] && echo "Number: +15045173983"
  exit 0
fi
echo "signal-cli \$*" >> "$LOG"
exit 0
EOF
    # SELF_HOST fixes what the script sees as this machine. Defaults to a name
    # in neither relay list, so the plain relay tests reach the first host.
    cat > "$STUBS/uname" <<EOF
#!/bin/bash
[ "\$1" = "-n" ] && { echo "\${SELF_HOST:-somewhere-else}"; exit 0; }
exec /usr/bin/uname "\$@"
EOF
    chmod +x "$STUBS/ssh" "$STUBS/signal-cli" "$STUBS/uname"
}

teardown() {
    rm -rf "$STUBS"
}

@test "no message exits 2 with usage" {
    run bash "$PAGE"
    [ "$status" -eq 2 ]
    [[ "$output" == *"usage"* ]]
}

@test "relays to the first relay host when the account is not local" {
    HAS_ACCOUNT=0 PATH="$STUBS:$PATH" run bash "$PAGE" build finished
    [ "$status" -eq 0 ]
    grep -q "^ssh .*ratio" "$LOG"
    grep -q "15045173983" "$LOG"
    grep -q "b1b5601e-6126-47f8-afaa-0a59f5188fde" "$LOG"
    # printf %q escapes the space, so the relayed message reads build\ finished.
    grep -qF 'build\ finished' "$LOG"
    # First host answered, so the second is never tried.
    ! grep -q "^ssh .*velox" "$LOG"
}

@test "never relays to this machine — the self host is skipped" {
    # On ratio, relaying to ratio cannot work: reaching this branch means the
    # account is not local, so the round trip lands on the same empty store.
    SELF_HOST=ratio HAS_ACCOUNT=0 PATH="$STUBS:$PATH" run bash "$PAGE" hello
    [ "$status" -eq 0 ]
    ! grep -q "^ssh .*ratio" "$LOG"
    grep -q "^ssh .*velox" "$LOG"
}

@test "the self skip survives an FQDN nodename on either side" {
    # uname -n returns whatever /etc/hostname holds, which may be fully
    # qualified. Both sides are stripped, so the guard must still fire -- if it
    # compares a stripped candidate against an unqualified self, an FQDN
    # nodename silently restores the self-relay bug on the away channel.
    SELF_HOST=ratio.tailf3bb8c.ts.net HAS_ACCOUNT=0 PATH="$STUBS:$PATH" \
        run bash "$PAGE" hi
    [ "$status" -eq 0 ]
    ! grep -q "^ssh .*ratio" "$LOG"
    grep -q "^ssh .*velox" "$LOG"
}

@test "falls through to the next host when the first relay fails" {
    cat > "$STUBS/ssh" <<EOF
#!/bin/bash
echo "ssh \$*" >> "$LOG"
case "\$*" in *ratio*) exit 255 ;; esac
exit 0
EOF
    chmod +x "$STUBS/ssh"
    HAS_ACCOUNT=0 PATH="$STUBS:$PATH" run bash "$PAGE" retry me
    [ "$status" -eq 0 ]
    grep -q "^ssh .*ratio" "$LOG"
    grep -q "^ssh .*velox" "$LOG"
}

@test "AGENT_TEXT_RELAYS overrides the default relay list" {
    AGENT_TEXT_RELAYS="spare.example.net" HAS_ACCOUNT=0 PATH="$STUBS:$PATH" \
        run bash "$PAGE" custom
    [ "$status" -eq 0 ]
    grep -q "^ssh .*spare.example.net" "$LOG"
    ! grep -q "^ssh .*ratio" "$LOG"
}

@test "sends directly (no ssh) when the pager account is registered locally" {
    HAS_ACCOUNT=1 PATH="$STUBS:$PATH" run bash "$PAGE" hello
    [ "$status" -eq 0 ]
    grep -q "^signal-cli -a +15045173983 send " "$LOG"
    ! grep -q "^ssh " "$LOG"
}

@test "every relay failing reports the desktop fallback and propagates failure" {
    cat > "$STUBS/ssh" <<'EOF'
#!/bin/bash
exit 255
EOF
    chmod +x "$STUBS/ssh"
    HAS_ACCOUNT=0 PATH="$STUBS:$PATH" run bash "$PAGE" urgent thing
    [ "$status" -ne 0 ]
    [[ "$output" == *"notify"* ]]
}

@test "no reachable relay at all still fails rather than reporting success" {
    # Every candidate is this machine, so the loop body never runs. rc must stay
    # at its non-zero seed: a skipped loop is not a delivered message.
    AGENT_TEXT_RELAYS="ratio.tailf3bb8c.ts.net" SELF_HOST=ratio HAS_ACCOUNT=0 \
        PATH="$STUBS:$PATH" run bash "$PAGE" nowhere to go
    [ "$status" -ne 0 ]
    [[ "$output" == *"notify"* ]]
    ! grep -q "^ssh " "$LOG"
}

@test "a local send failure blames the local send, not the relay list" {
    # On the machine that holds the account, no relay is ever consulted. A
    # message naming the relay list sends whoever is debugging it off chasing
    # the tailnet while the fault is on the box in front of them.
    cat > "$STUBS/signal-cli" <<EOF
#!/bin/bash
if [ "\$1" = "listAccounts" ]; then echo "Number: +15045173983"; exit 0; fi
exit 1
EOF
    chmod +x "$STUBS/signal-cli"
    # This stub reports the account unconditionally, so it drives the direct
    # branch on its own -- HAS_ACCOUNT would be decorative here.
    PATH="$STUBS:$PATH" run bash "$PAGE" boom
    [ "$status" -ne 0 ]
    [[ "$output" == *"local signal-cli send failed"* ]]
    [[ "$output" != *"no relay reachable"* ]]
}

@test "the deprecated agent-page shim delegates to agent-text" {
    HAS_ACCOUNT=1 PATH="$STUBS:$PATH" run bash "$SHIM" via shim
    [ "$status" -eq 0 ]
    # Reaches the same direct-send path as agent-text.
    grep -q "^signal-cli -a +15045173983 send " "$LOG"
}