383 lines
No EOL
10 KiB
Bash
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 "$@" |