main
sh 92 lines 3.81 KB
Raw
1 #!/bin/bash
2 # Copyright 2026 Google LLC
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 #
16 # Integration Test: Piped console exits cleanly on EOF
17 # Verifies that `echo cmd | colab console -s s` runs the command on the remote
18 # /colab/tty endpoint and then exits within a few seconds.
19 #
20 # Regression: prior to 2026-05-07 this hung indefinitely because the EOF
21 # handler sent \x04 (Ctrl-D), which the remote tmux-wrapped bash treated as a
22 # literal character rather than a session terminator. The fix sends "exit\n"
23 # and closes the websocket from the client side after a short grace period.
24
25 set -e
26
27 TMP_DIR=$(mktemp -d)
28 SESSION_FILE="$TMP_DIR/sessions.json"
29 SESSION_NAME="test-piped-console"
30
31 # Auth selection (same priority order as repro_keep_alive).
32 if [ -f "$HOME/.config/colab-cli/token.json" ]; then
33 AUTH_FLAGS="--auth=oauth2"
34 elif command -v gcloud > /dev/null && gcloud auth application-default print-access-token > /dev/null 2>&1; then
35 ADC_TOKEN=$(gcloud auth application-default print-access-token 2>/dev/null)
36 ADC_SCOPES=$(curl -s "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=$ADC_TOKEN" | python3 -c "import json,sys; print(json.load(sys.stdin).get('scope',''))" 2>/dev/null)
37 if echo "$ADC_SCOPES" | grep -q "userinfo.email"; then
38 AUTH_FLAGS="--auth=adc"
39 else
40 echo "Error: ADC token lacks the userinfo.email scope."
41 exit 1
42 fi
43 else
44 echo "Error: No usable auth provider found." >&2
45 exit 1
46 fi
47
48 cleanup_session() {
49 uv run colab $AUTH_FLAGS --config "$SESSION_FILE" stop -s "$SESSION_NAME" 2>/dev/null || true
50 }
51 trap "cleanup_session; rm -rf $TMP_DIR" EXIT
52
53 echo "[*] Creating session for piped-console test using $AUTH_FLAGS..."
54 uv run colab $AUTH_FLAGS --config "$SESSION_FILE" new -s "$SESSION_NAME"
55
56 # Marker string we'll grep for in the captured output. Made unique enough that
57 # accidental matches in tmux status lines or shell prompts are impossible.
58 MARKER="PIPED-CONSOLE-OK-$(date +%s)-$$"
59
60 OUTPUT_FILE="$TMP_DIR/console-output.txt"
61
62 echo "[*] Running: echo 'echo $MARKER' | colab console (must exit within 30s)..."
63 START=$(date +%s)
64 # 30s upper bound guards against the prior hang regression. The fix typically
65 # completes in ~1-2s; anything beyond that means the EOF/close path broke.
66 if ! timeout 30 bash -c "echo 'echo $MARKER' | uv run colab $AUTH_FLAGS --config '$SESSION_FILE' console -s '$SESSION_NAME'" > "$OUTPUT_FILE" 2>&1; then
67 EXIT=$?
68 if [ $EXIT -eq 124 ]; then
69 echo "[FAILURE] Piped console hung past the 30s timeout (regression — was the EOF handler reverted?)."
70 else
71 echo "[FAILURE] Piped console exited non-zero: $EXIT"
72 fi
73 cat "$OUTPUT_FILE"
74 exit 1
75 fi
76 ELAPSED=$(($(date +%s) - START))
77 echo "[*] Piped console returned in ${ELAPSED}s."
78
79 if ! grep -q "$MARKER" "$OUTPUT_FILE"; then
80 echo "[FAILURE] Marker '$MARKER' not found in console output (the command did not actually execute on the VM)."
81 cat "$OUTPUT_FILE"
82 exit 1
83 fi
84 echo "[*] Confirmed: the piped command actually ran on the remote VM."
85
86 # Sanity: the doc claims ~1.2s round-trip. Anything > 10s is suspicious even
87 # if it eventually exited (probably means the grace window was bumped wildly).
88 if [ "$ELAPSED" -gt 10 ]; then
89 echo "[WARNING] Piped console took ${ELAPSED}s — slow, but not a hang."
90 fi
91
92 echo "[SUCCESS] Piped console integration test passed (elapsed=${ELAPSED}s)."