This guide provides comprehensive instructions for testing the HexFeed WebSocket real-time notification system.
Ensure the backend is running:
cd hexfeed-backend
./mvnw spring-boot:runFirst, authenticate to get a JWT token:
# Login
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"email": "test@example.com"
}' | jq -r '.data.token'Save the token - you'll need it for WebSocket authentication!
-
Open the test client:
open hexfeed-backend/websocket-test-client.html # Or navigate to: file:///path/to/hexfeed-backend/websocket-test-client.html -
Follow the UI:
- Enter your JWT token
- Click "Connect"
- Enter latitude/longitude (e.g., 37.7749, -122.4194)
- Click "Subscribe to Location"
- Watch the message log for real-time updates!
// 1. Include libraries (paste in console)
var script1 = document.createElement('script');
script1.src = 'https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js';
document.head.appendChild(script1);
var script2 = document.createElement('script');
script2.src = 'https://cdn.jsdelivr.net/npm/@stomp/stompjs@7/bundles/stomp.umd.min.js';
document.head.appendChild(script2);
// 2. Wait a few seconds for libraries to load, then connect
var token = 'YOUR_JWT_TOKEN_HERE';
var socket = new SockJS('http://localhost:8080/ws');
var stompClient = new StompJs.Client();
stompClient.webSocketFactory = () => socket;
stompClient.connectHeaders = { 'Authorization': `Bearer ${token}` };
stompClient.onConnect = function(frame) {
console.log('β
Connected!');
// Subscribe to messages
stompClient.subscribe('/user/queue/feed', function(message) {
console.log('π¨ Received:', JSON.parse(message.body));
});
// Subscribe to location
stompClient.publish({
destination: '/app/subscribe',
body: JSON.stringify({ latitude: 37.7749, longitude: -122.4194 })
});
};
stompClient.onStompError = (error) => console.error('β Error:', error);
stompClient.activate();-
Create WebSocket Request:
- New β WebSocket Request
- URL:
ws://localhost:8080/ws
-
Add Authentication:
- In Headers tab, add:
Authorization: Bearer YOUR_JWT_TOKEN
- In Headers tab, add:
-
Connect and Subscribe:
- Click "Connect"
- Send message to
/app/subscribe:{ "destination": "/app/subscribe", "body": { "latitude": 37.7749, "longitude": -122.4194 } }
# Install wscat
npm install -g wscat
# Connect (note: wscat doesn't support SockJS, so this is basic)
wscat -c ws://localhost:8080/ws \
-H "Authorization: Bearer YOUR_JWT_TOKEN"# Install: pip install websocket-client
import websocket
import json
token = "YOUR_JWT_TOKEN"
def on_message(ws, message):
print(f"π¨ Received: {message}")
def on_open(ws):
print("β
Connected!")
# Subscribe
subscribe_msg = json.dumps({
"latitude": 37.7749,
"longitude": -122.4194
})
ws.send(f"SUBSCRIBE\ndestination:/app/subscribe\n\n{subscribe_msg}\x00")
ws = websocket.WebSocketApp(
"ws://localhost:8080/ws",
header={"Authorization": f"Bearer {token}"},
on_open=on_open,
on_message=on_message
)
ws.run_forever()Objective: Verify WebSocket connection establishment
Steps:
- Start backend
- Open HTML test client
- Enter JWT token
- Click "Connect"
Expected Result:
- Status changes to "Connected"
- Log shows: "β Connected to WebSocket successfully!"
- Log shows: "π‘ Subscribed to /user/queue/feed"
Pass Criteria: β Connection established without errors
Objective: Verify location-based subscription
Steps:
- Connect to WebSocket (Scenario 1)
- Enter coordinates:
- Latitude: 37.7749
- Longitude: -122.4194
- Click "Subscribe to Location"
Expected Result:
- Log shows: "π Subscribing to location: 37.7749, -122.4194"
- Receive subscription confirmation with:
{ "centerHexId": "872830828ffffff", "subscribedHexIds": ["872830828ffffff", "872830829ffffff", ...], "status": "success", "message": "Subscribed to 7 hex regions..." }
Pass Criteria: β Received 7 hex IDs in confirmation
Objective: Verify real-time post notifications
Steps:
- Connect and subscribe to location (Scenarios 1-2)
- In another terminal, create a post:
curl -X POST http://localhost:8080/api/v1/posts \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -d '{ "content": "Test post for WebSocket notification", "latitude": 37.7749, "longitude": -122.4194 }'
Expected Result:
- WebSocket client receives notification:
{ "type": "new_post", "hex_id": "872830828ffffff", "post": { "postId": "...", "content": "Test post...", "latitude": 37.7749, "longitude": -122.4194 } }
Pass Criteria: β Notification received within 1-2 seconds of post creation
Objective: Verify heartbeat mechanism
Steps:
- Connect to WebSocket
- Subscribe to location
- Wait and observe
Expected Result:
- Every 30 seconds, receive heartbeat:
{ "type": "heartbeat", "timestamp": "2024-01-15T10:30:00" } - Client automatically sends pong response
Pass Criteria: β Heartbeats received regularly, connection stays alive
Objective: Verify user can update subscription
Steps:
- Connect and subscribe to location A (37.7749, -122.4194)
- Subscribe to different location B (34.0522, -118.2437)
- Create posts in both locations
Expected Result:
- New subscription replaces old one
- Only receive notifications for location B
Pass Criteria: β Subscription updates correctly
Objective: Verify reconnection handling
Steps:
- Connect and subscribe
- Click "Disconnect"
- Wait 5 seconds
- Click "Connect" again
- Subscribe to same location
Expected Result:
- Clean disconnection
- Successful reconnection
- Subscription works after reconnect
Pass Criteria: β No errors, subscription restored
Objective: Verify authentication is enforced
Steps:
- Try to connect with invalid JWT token
- Try to connect without JWT token
Expected Result:
- Connection fails with error message
- Log shows: "β STOMP error" or "WebSocket authentication required"
Pass Criteria: β Connection rejected for invalid/missing auth
Objective: Verify unsubscribe functionality
Steps:
- Connect and subscribe to location
- Click "Unsubscribe"
- Create a post in that location
Expected Result:
- Receive unsubscribe confirmation
- Do NOT receive new post notification
Pass Criteria: β No notifications after unsubscribe
Objective: Verify system handles multiple users
Steps:
- Open 3 browser tabs with test client
- Login with different users in each tab
- Subscribe all to same location
- Create a post in that location
Expected Result:
- All 3 users receive the notification
- Each user sees their own userId in logs
Pass Criteria: β All users receive notifications independently
Objective: Verify system handles rapid messages
Steps:
- Connect and subscribe
- Create 10 posts rapidly in the same location:
for i in {1..10}; do curl -X POST http://localhost:8080/api/v1/posts \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{ "content": "Stress test post '$i'", "latitude": 37.7749, "longitude": -122.4194 }' & done
Expected Result:
- Receive all 10 notifications
- No dropped messages
- No connection errors
Pass Criteria: β All notifications received, no errors
Symptoms:
- "WebSocket connection error"
- "Connection refused"
Solutions:
- Verify backend is running:
curl http://localhost:8080/actuator/health - Check if port 8080 is available:
lsof -i :8080 - Check backend logs for errors
- Verify JWT token is valid (not expired)
Symptoms:
- "WebSocket authentication required"
- "Invalid JWT token"
Solutions:
- Get fresh JWT token from login API
- Ensure token includes "Bearer " prefix
- Check token expiration time
- Verify SecurityConfig allows WebSocket authentication
Symptoms:
- Connected and subscribed, but no messages when creating posts
Solutions:
- Check if Kafka is running:
docker ps | grep kafka - Verify subscription confirmation was received
- Check if post is in same location as subscription
- Check backend logs for Kafka consumer errors
- Verify WebSocketManagerService is broadcasting messages
Symptoms:
- Connection disconnects randomly
- "Disconnected" status after few minutes
Solutions:
- Check if heartbeat is working (should see "π Heartbeat received")
- Verify pong responses are being sent
- Check network stability
- Increase connection timeout in configuration
- Check for firewall/proxy issues
Symptoms:
- Receive same notification multiple times
Solutions:
- Check if multiple subscriptions are active
- Verify user isn't connected multiple times
- Check Kafka consumer group configuration
- Review WebSocketManagerService subscription logic
# Install Apache Bench WebSocket extension
npm install -g websocket-bench
# Run load test
wsbench -c 100 -n 1000 \
-H "Authorization: Bearer YOUR_TOKEN" \
ws://localhost:8080/ws- Connection Time: < 100ms
- Subscription Response: < 200ms
- Notification Latency: < 500ms from post creation
- Concurrent Connections: Support 1000+ users
- Memory Usage: Monitor with JProfiler or VisualVM
# Monitor active WebSocket connections
curl http://localhost:8080/actuator/metrics/websocket.connections
# Monitor message throughput
curl http://localhost:8080/actuator/metrics/websocket.messages
# Check backend logs
tail -f hexfeed-backend/logs/hexfeed-backend.log | grep WebSocketSave this as test-websocket.sh:
#!/bin/bash
echo "π§ͺ HexFeed WebSocket Automated Test"
echo "==================================="
# 1. Login and get token
echo "1οΈβ£ Getting JWT token..."
TOKEN=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"testuser","email":"test@example.com"}' \
| jq -r '.data.token')
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
echo "β Failed to get JWT token"
exit 1
fi
echo "β
Got JWT token: ${TOKEN:0:20}..."
# 2. Test WebSocket connection using HTML client
echo ""
echo "2οΈβ£ Opening WebSocket test client..."
open websocket-test-client.html
echo "π Token copied to clipboard:"
echo "$TOKEN" | pbcopy
echo "β
Paste the token in the browser and click Connect"
# 3. Wait for manual connection
read -p "Press Enter after connecting in browser..."
# 4. Create test post
echo ""
echo "3οΈβ£ Creating test post..."
POST_RESPONSE=$(curl -s -X POST http://localhost:8080/api/v1/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"content": "Automated test post - you should receive this via WebSocket!",
"latitude": 37.7749,
"longitude": -122.4194
}')
echo "β
Post created:"
echo "$POST_RESPONSE" | jq .
echo ""
echo "4οΈβ£ Check the browser - you should see a notification!"
echo ""
echo "Test complete! π"Make it executable:
chmod +x test-websocket.sh
./test-websocket.shUse this checklist to verify all functionality:
- β WebSocket connection establishes successfully
- β JWT authentication works
- β Location subscription returns 7 hex IDs
- β Real-time notifications received for new posts
- β Heartbeat mechanism works (pings every 30s)
- β Unsubscribe works correctly
- β Reconnection works after disconnect
- β Multiple concurrent users supported
- β No memory leaks with long connections
- β Proper cleanup on disconnect
- β Test endpoint (/app/test) works
- β Status endpoint (/app/status) works
- β Authentication failures handled gracefully
- β Invalid subscriptions handled with error messages
- β Performance acceptable under load
After completing WebSocket testing:
- β Integration Testing: Test complete flow (REST β Kafka β WebSocket)
- β Load Testing: Test with 1000+ concurrent connections
- β Frontend Integration: Connect React/Vue frontend
- β Production Setup: Configure external message broker (RabbitMQ/Redis)
- β Monitoring: Setup Grafana dashboards for WebSocket metrics
- Spring WebSocket Documentation
- STOMP Protocol Specification
- SockJS Documentation
- HexFeed Architecture Documentation
Need Help? Check the troubleshooting section or review backend logs in logs/hexfeed-backend.log