veza/tools/tests/ws/ws_chat_matrix.sh
2025-12-03 22:56:50 +01:00

383 lines
No EOL
10 KiB
Bash

#!/bin/bash
# WebSocket Chat Matrix Tests
# Tests WebSocket functionality for Veza chat
set -euo pipefail
# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.."
# Load environment
if [ -f .env ]; then
source .env
else
echo "Error: .env file not found"
exit 1
fi
# Load assertion library
source http/http_assert.sh
# Check for WebSocket tools
if ! command -v wscat >/dev/null 2>&1 && ! command -v websocat >/dev/null 2>&1; then
echo "Error: Neither wscat nor websocat found. Install one:"
echo " npm install -g wscat"
echo " cargo install websocat"
exit 1
fi
# Prefer websocat if available (more features)
WS_TOOL="wscat"
if command -v websocat >/dev/null 2>&1; then
WS_TOOL="websocat"
fi
# Load session
SESSION_FILE="${SESSION_FILE:-.session.json}"
if [ ! -f "$SESSION_FILE" ]; then
echo "Error: No session file. Run http_matrix.sh first."
exit 1
fi
ACCESS_TOKEN=$(jq -r '.access_token' "$SESSION_FILE")
USER_ID=$(jq -r '.user_id' "$SESSION_FILE")
# Test WebSocket connection
test_ws_connect() {
log_info "Testing WebSocket connection..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
local connected=false
if [ "$WS_TOOL" = "websocat" ]; then
# Test connection with timeout
timeout 5s websocat -t "$ws_url" <<EOF > "$temp_file" 2>&1 &
{"type":"ping"}
EOF
local pid=$!
# Wait a bit for connection
sleep 2
# Check if still running (connected)
if kill -0 $pid 2>/dev/null; then
connected=true
kill $pid 2>/dev/null || true
fi
else
# wscat test
timeout 5s wscat -c "$ws_url" > "$temp_file" 2>&1 &
local pid=$!
sleep 2
if kill -0 $pid 2>/dev/null; then
connected=true
kill $pid 2>/dev/null || true
fi
fi
if [ "$connected" = true ]; then
pass "WebSocket connection established"
else
fail "WebSocket connection failed" "Check $temp_file for details"
cat "$temp_file" >&2
fi
rm -f "$temp_file"
}
test_ws_auth_invalid() {
log_info "Testing WebSocket with invalid token..."
local ws_url="${CHAT_ORIGIN}?token=invalid-token"
local temp_file=$(mktemp)
local rejected=false
if [ "$WS_TOOL" = "websocat" ]; then
timeout 3s websocat -t "$ws_url" > "$temp_file" 2>&1 || rejected=true
else
timeout 3s wscat -c "$ws_url" > "$temp_file" 2>&1 || rejected=true
fi
if [ "$rejected" = true ]; then
pass "Invalid token rejected"
else
fail "Invalid token was not rejected"
fi
rm -f "$temp_file"
}
test_ws_join_room() {
log_info "Testing room join..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
local success=false
# Create test script for interaction
cat > /tmp/ws_test_join.sh << 'EOF'
#!/bin/bash
sleep 1
echo '{"type":"join","room":"general"}'
sleep 2
echo '{"type":"ping"}'
sleep 1
EOF
chmod +x /tmp/ws_test_join.sh
if [ "$WS_TOOL" = "websocat" ]; then
timeout 5s bash /tmp/ws_test_join.sh | websocat -t "$ws_url" > "$temp_file" 2>&1
else
timeout 5s bash /tmp/ws_test_join.sh | wscat -c "$ws_url" > "$temp_file" 2>&1
fi
# Check for join confirmation
if grep -q "joined\|join_success\|room.*general" "$temp_file"; then
success=true
fi
if [ "$success" = true ]; then
pass "Room join successful"
else
fail "Room join failed" "Response: $(cat "$temp_file")"
fi
rm -f "$temp_file" /tmp/ws_test_join.sh
}
test_ws_send_message() {
log_info "Testing message send/receive..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
local message_id="test-$(date +%s)"
local test_message="Test message $message_id"
local success=false
# Create test script
cat > /tmp/ws_test_msg.sh << EOF
#!/bin/bash
sleep 1
echo '{"type":"join","room":"general"}'
sleep 1
echo '{"type":"message","room":"general","content":"$test_message"}'
sleep 2
EOF
chmod +x /tmp/ws_test_msg.sh
if [ "$WS_TOOL" = "websocat" ]; then
timeout 6s bash /tmp/ws_test_msg.sh | websocat -t "$ws_url" > "$temp_file" 2>&1
else
timeout 6s bash /tmp/ws_test_msg.sh | wscat -c "$ws_url" > "$temp_file" 2>&1
fi
# Check for message echo or broadcast
if grep -q "$test_message" "$temp_file"; then
success=true
fi
if [ "$success" = true ]; then
pass "Message send/receive working"
else
fail "Message send/receive failed" "Response: $(cat "$temp_file")"
fi
rm -f "$temp_file" /tmp/ws_test_msg.sh
}
test_ws_reconnection() {
log_info "Testing reconnection handling..."
# This test simulates connection drop and reconnect
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file1=$(mktemp)
local temp_file2=$(mktemp)
# First connection
if [ "$WS_TOOL" = "websocat" ]; then
timeout 3s websocat -t "$ws_url" <<< '{"type":"join","room":"general"}' > "$temp_file1" 2>&1
else
echo '{"type":"join","room":"general"}' | timeout 3s wscat -c "$ws_url" > "$temp_file1" 2>&1
fi
# Wait a bit
sleep 1
# Second connection (simulating reconnect)
if [ "$WS_TOOL" = "websocat" ]; then
timeout 3s websocat -t "$ws_url" <<< '{"type":"join","room":"general"}' > "$temp_file2" 2>&1
else
echo '{"type":"join","room":"general"}' | timeout 3s wscat -c "$ws_url" > "$temp_file2" 2>&1
fi
# Both connections should succeed
local conn1_ok=false
local conn2_ok=false
grep -q "joined\|connected" "$temp_file1" && conn1_ok=true
grep -q "joined\|connected" "$temp_file2" && conn2_ok=true
if [ "$conn1_ok" = true ] && [ "$conn2_ok" = true ]; then
pass "Reconnection handling works"
else
fail "Reconnection issues detected"
fi
rm -f "$temp_file1" "$temp_file2"
}
test_ws_slow_client() {
log_info "Testing slow client handling..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
local disconnected=false
# Create slow client script
cat > /tmp/ws_slow_client.sh << 'EOF'
#!/bin/bash
echo '{"type":"join","room":"general"}'
# Simulate slow client - send messages slowly
for i in {1..10}; do
sleep 2
echo "{\"type\":\"message\",\"room\":\"general\",\"content\":\"Slow message $i\"}"
done
EOF
chmod +x /tmp/ws_slow_client.sh
if [ "$WS_TOOL" = "websocat" ]; then
timeout 25s bash /tmp/ws_slow_client.sh | websocat -t "$ws_url" > "$temp_file" 2>&1 || disconnected=true
else
timeout 25s bash /tmp/ws_slow_client.sh | wscat -c "$ws_url" > "$temp_file" 2>&1 || disconnected=true
fi
# Check if client was disconnected (backpressure)
if grep -q "close\|disconnect\|timeout" "$temp_file"; then
log_warn "Slow client was disconnected (backpressure active)"
else
pass "Slow client handled gracefully"
fi
rm -f "$temp_file" /tmp/ws_slow_client.sh
}
test_ws_binary_data() {
log_info "Testing binary data handling..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
local binary_rejected=false
# Try to send binary data
if [ "$WS_TOOL" = "websocat" ]; then
echo -n -e '\x00\x01\x02\x03' | timeout 3s websocat -b -t "$ws_url" > "$temp_file" 2>&1 || binary_rejected=true
else
# wscat doesn't handle binary well, skip
log_warn "Skipping binary test with wscat"
return
fi
if [ "$binary_rejected" = true ] || grep -q "error\|close" "$temp_file"; then
pass "Binary data properly handled/rejected"
else
log_warn "Binary data might not be properly validated"
fi
rm -f "$temp_file"
}
test_ws_large_message() {
log_info "Testing large message handling..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local temp_file=$(mktemp)
# Generate large message (1MB)
local large_content=$(head -c 1048576 /dev/zero | tr '\0' 'A')
local large_message="{\"type\":\"message\",\"room\":\"general\",\"content\":\"$large_content\"}"
local rejected=false
if [ "$WS_TOOL" = "websocat" ]; then
echo "$large_message" | timeout 5s websocat -t "$ws_url" > "$temp_file" 2>&1 || rejected=true
else
echo "$large_message" | timeout 5s wscat -c "$ws_url" > "$temp_file" 2>&1 || rejected=true
fi
if [ "$rejected" = true ] || grep -q "too large\|size limit\|close" "$temp_file"; then
pass "Large messages properly limited"
else
log_warn "Large message limits might not be enforced"
fi
rm -f "$temp_file"
}
test_ws_concurrent_connections() {
log_info "Testing concurrent connections..."
local ws_url="${CHAT_ORIGIN}?token=${ACCESS_TOKEN}"
local pids=()
local temp_dir=$(mktemp -d)
# Start 5 concurrent connections
for i in {1..5}; do
(
if [ "$WS_TOOL" = "websocat" ]; then
timeout 5s websocat -t "$ws_url" <<< "{\"type\":\"join\",\"room\":\"test-$i\"}" > "$temp_dir/conn-$i.log" 2>&1
else
echo "{\"type\":\"join\",\"room\":\"test-$i\"}" | timeout 5s wscat -c "$ws_url" > "$temp_dir/conn-$i.log" 2>&1
fi
) &
pids+=($!)
done
# Wait for all connections
for pid in "${pids[@]}"; do
wait $pid
done
# Check results
local success_count=0
for i in {1..5}; do
if grep -q "joined\|connected" "$temp_dir/conn-$i.log" 2>/dev/null; then
success_count=$((success_count + 1))
fi
done
if [ "$success_count" -ge 4 ]; then
pass "Concurrent connections handled ($success_count/5 successful)"
else
fail "Concurrent connection issues" "Only $success_count/5 successful"
fi
rm -rf "$temp_dir"
}
# Main execution
main() {
log_info "Starting WebSocket Chat Matrix Tests"
log_info "Using tool: $WS_TOOL"
log_info "User ID: $USER_ID"
echo
# Run tests
test_ws_connect
test_ws_auth_invalid
test_ws_join_room
test_ws_send_message
test_ws_reconnection
test_ws_slow_client
test_ws_binary_data
test_ws_large_message
test_ws_concurrent_connections
# Print summary
print_test_summary
}
# Run tests
main "$@"