ops-jrz1/tests/test-learner-env.sh
Dan d387b0b910 Add learner environment integration tests
- test-learner-env.sh: SSH, nix-ld, Slack tokens, Python, API connectivity
- test-slack-bolt.py: Socket Mode connection test
- Makefile: test runner with env/slack-bolt/vscode targets
- Add python3 + uv to system packages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-02 12:16:58 -08:00

198 lines
5.2 KiB
Bash
Executable file

#!/usr/bin/env bash
# test-learner-env.sh - Integration tests for learner dev environment
# Run from local machine: ./tests/test-learner-env.sh [username] [ssh-key]
# Default username: dantest
set -euo pipefail
SERVER="45.77.205.49"
USER="${1:-dantest}"
SSH_KEY="${2:-}"
# Build SSH options
SSH_OPTS="-o ConnectTimeout=5"
if [ -n "$SSH_KEY" ]; then
SSH_OPTS="$SSH_OPTS -i $SSH_KEY"
fi
ssh_cmd() {
ssh $SSH_OPTS "${USER}@${SERVER}" "$@"
}
PASS=0
FAIL=0
red() { echo -e "\033[0;31m$1\033[0m"; }
green() { echo -e "\033[0;32m$1\033[0m"; }
yellow() { echo -e "\033[1;33m$1\033[0m"; }
pass() { PASS=$((PASS + 1)); green " PASS: $1"; }
fail() { FAIL=$((FAIL + 1)); red " FAIL: $1"; }
skip() { yellow " SKIP: $1"; }
echo "=========================================="
echo "Learner Environment Tests"
echo "Server: $SERVER"
echo "User: $USER"
echo "=========================================="
echo ""
# ---------------------------------------------
echo "## 1. SSH Connectivity"
# ---------------------------------------------
if ssh_cmd 'echo ok' &>/dev/null; then
pass "SSH connection as $USER"
else
fail "SSH connection as $USER"
echo " Hint: Check SSH key is configured for $USER"
echo " Usage: $0 <user> [/path/to/key]"
exit 1
fi
# ---------------------------------------------
echo ""
echo "## 2. nix-ld (VS Code Remote-SSH support)"
# ---------------------------------------------
if ssh_cmd 'test -L /lib64/ld-linux-x86-64.so.2' &>/dev/null; then
pass "nix-ld symlink exists"
else
fail "nix-ld symlink missing"
fi
# Test with a simple pre-compiled binary (curl is dynamically linked)
if ssh_cmd 'file /run/current-system/sw/bin/curl | grep -q "dynamically linked"' &>/dev/null; then
pass "Dynamic binaries available"
else
skip "Could not verify dynamic binary support"
fi
# ---------------------------------------------
echo ""
echo "## 3. Learners group membership"
# ---------------------------------------------
if ssh_cmd 'groups' | grep -q learners; then
pass "User in learners group"
else
fail "User NOT in learners group"
fi
# ---------------------------------------------
echo ""
echo "## 4. Slack tokens accessible"
# ---------------------------------------------
if ssh_cmd 'test -r /etc/slack-learner.env'; then
pass "Slack env file readable"
else
fail "Slack env file NOT readable (check group permissions)"
fi
if ssh_cmd 'source /etc/slack-learner.env && test -n "$SLACK_BOT_TOKEN"' &>/dev/null; then
pass "SLACK_BOT_TOKEN set"
else
fail "SLACK_BOT_TOKEN not set"
fi
if ssh_cmd 'source /etc/slack-learner.env && test -n "$SLACK_APP_TOKEN"' &>/dev/null; then
pass "SLACK_APP_TOKEN set"
else
fail "SLACK_APP_TOKEN not set"
fi
# ---------------------------------------------
echo ""
echo "## 5. Python environment"
# ---------------------------------------------
if ssh_cmd 'which python3' &>/dev/null; then
pass "python3 available"
PY_VERSION=$(ssh_cmd 'python3 --version 2>&1')
echo " $PY_VERSION"
else
fail "python3 not found"
fi
if ssh_cmd 'uv --version' &>/dev/null; then
UV_VERSION=$(ssh_cmd 'uv --version 2>&1')
pass "uv available ($UV_VERSION)"
else
fail "uv not available"
fi
# ---------------------------------------------
echo ""
echo "## 6. Home directory structure"
# ---------------------------------------------
if ssh_cmd 'test -d ~/plugins'; then
pass "~/plugins directory exists"
else
fail "~/plugins directory missing"
fi
if ssh_cmd 'test -d ~/plugins/hello-*' &>/dev/null; then
pass "Starter plugin exists"
else
skip "No starter plugin (may be expected)"
fi
# ---------------------------------------------
echo ""
echo "## 7. Slack API connectivity"
# ---------------------------------------------
echo " Testing Slack API auth (this may take a moment)..."
SLACK_TEST=$(ssh_cmd 'source /etc/slack-learner.env && python3 -c "
import urllib.request
import urllib.error
import json
import os
token = os.environ.get(\"SLACK_BOT_TOKEN\", \"\")
if not token:
print(\"NO_TOKEN\")
exit(1)
req = urllib.request.Request(
\"https://slack.com/api/auth.test\",
headers={\"Authorization\": f\"Bearer {token}\"}
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
if data.get(\"ok\"):
user = data.get(\"user\", \"unknown\")
team = data.get(\"team\", \"unknown\")
print(f\"OK:{user}@{team}\")
else:
err = data.get(\"error\", \"unknown\")
print(f\"API_ERROR:{err}\")
except Exception as e:
print(f\"NET_ERROR:{e}\")
" 2>&1' || echo "EXEC_ERROR")
case "$SLACK_TEST" in
OK:*)
pass "Slack API auth successful"
echo " Authenticated as: ${SLACK_TEST#OK:}"
;;
API_ERROR:*)
fail "Slack API error: ${SLACK_TEST#API_ERROR:}"
;;
NET_ERROR:*)
fail "Network error: ${SLACK_TEST#NET_ERROR:}"
;;
NO_TOKEN)
fail "No SLACK_BOT_TOKEN available"
;;
*)
fail "Unexpected result: $SLACK_TEST"
;;
esac
# ---------------------------------------------
echo ""
echo "=========================================="
echo "Results: $PASS passed, $FAIL failed"
echo "=========================================="
if [ "$FAIL" -gt 0 ]; then
exit 1
fi