Adding basic test for socket.io

This commit is contained in:
dgtlmoon
2025-05-16 11:20:04 +02:00
parent cc484f07be
commit f7d576a920
4 changed files with 122 additions and 7 deletions

View File

@@ -34,7 +34,6 @@
<script src="{{url_for('static_content', group='js', filename='jquery-3.6.0.min.js')}}"></script>
<script src="{{url_for('static_content', group='js', filename='csrf.js')}}" defer></script>
<script src="https://cdn.socket.io/4.6.0/socket.io.min.js" integrity="sha384-c79GN5VsunZvi+Q/WObgk2in0CbZsHnjEqvFxC5DxHn9lTfNce2WW6h2pH6u/kF+" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/timeago.js/4.0.2/timeago.min.js" integrity="sha512-SVDh1zH5N9ChofSlNAK43lcNS7lWze6DTVx1JCXH1Tmno+0/1jMpdbR8YDgDUfcUrPp1xyE53G42GFrcM0CMVg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="{{url_for('static_content', group='js', filename='socket.js')}}" defer></script>
<script src="{{url_for('static_content', group='js', filename='timeago-init.js')}}" defer></script>
</head>

View File

@@ -2,9 +2,9 @@ import asyncio
import socketio
from aiohttp import web
SOCKETIO_URL = "http://localhost:5000"
SOCKETIO_URL = 'ws://localhost.localdomain:5005'
SOCKETIO_PATH = "/socket.io"
NUM_CLIENTS = 100
NUM_CLIENTS = 1
clients = []
shutdown_event = asyncio.Event()
@@ -13,7 +13,7 @@ class WatchClient:
def __init__(self, client_id: int):
self.client_id = client_id
self.i_got_watch_update_event = False
self.sio = socketio.AsyncClient(reconnection_attempts=5, reconnection_delay=1)
self.sio = socketio.AsyncClient(reconnection_attempts=50, reconnection_delay=1)
@self.sio.event
async def connect():
@@ -51,7 +51,7 @@ async def start_http_server():
await site.start()
async def main():
await start_http_server()
#await start_http_server()
for i in range(NUM_CLIENTS):
client = WatchClient(i)

View File

@@ -0,0 +1,115 @@
#!/usr/bin/env python3
import time
from flask import url_for
from .util import (
set_original_response,
set_modified_response,
live_server_setup,
wait_for_all_checks
)
class TestSocketIO:
"""Test class for Socket.IO functionality"""
def test_socketio_watch_update(self, client, live_server):
"""Test that the socketio emits a watch update event when content changes"""
# Set up the test server
set_original_response()
live_server_setup(live_server)
# Get the SocketIO instance from the app
from changedetectionio.flask_app import app
socketio = app.extensions['socketio']
# Create a test client for SocketIO
socketio_test_client = socketio.test_client(app, flask_test_client=client)
assert socketio_test_client.is_connected(), "Failed to connect to Socket.IO server"
print("Successfully connected to Socket.IO server")
# Add our URL to the import page
res = client.post(
url_for("imports.import_page"),
data={"urls": url_for('test_endpoint', _external=True)},
follow_redirects=True
)
assert b"1 Imported" in res.data
res = client.get(url_for("watchlist.index"))
assert url_for('test_endpoint', _external=True).encode() in res.data
# Wait for initial check to complete
wait_for_all_checks(client)
# Clear any initial messages
socketio_test_client.get_received()
# Make a change to trigger an update
set_modified_response()
# Force recheck
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
# Wait for the watch to be checked
wait_for_all_checks(client)
# Wait for events to be emitted and received (up to 20 seconds)
max_wait = 20
has_watch_update = False
has_unviewed_update = False
for i in range(max_wait):
# Get received events
received = socketio_test_client.get_received()
if received:
print(f"Received {len(received)} events after {i+1} seconds")
# Check for watch_update events with unviewed=True
for event in received:
if event['name'] == 'watch_update':
has_watch_update = True
if event['args'][0].get('unviewed', False):
has_unviewed_update = True
print("Found unviewed update event!")
break
if has_unviewed_update:
break
# Force a recheck every 5 seconds to ensure events are emitted
if i > 0 and i % 5 == 0:
print(f"Still waiting for events, forcing another recheck...")
res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
assert b'Queued 1 watch for rechecking.' in res.data
wait_for_all_checks(client)
print(f"Waiting for unviewed update event... {i+1}/{max_wait}")
time.sleep(1)
# Verify we received watch_update events
assert has_watch_update, "No watch_update events received"
# Verify we received an unviewed event
assert has_unviewed_update, "No watch_update event with unviewed=True received"
# Alternatively, check directly if the watch in the datastore is marked as unviewed
from changedetectionio.flask_app import app
datastore = app.config.get('DATASTORE')
# Extract the watch UUID from the watchlist page
res = client.get(url_for("watchlist.index"))
import re
m = re.search('edit/(.+?)[#"]', str(res.data))
assert m, "Could not find watch UUID in page"
watch_uuid = m.group(1).strip()
# Get the watch from the datastore
watch = datastore.data['watching'].get(watch_uuid)
assert watch, f"Watch {watch_uuid} not found in datastore"
assert watch.has_unviewed, "The watch was not marked as unviewed after content change"
# Clean up
client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)

View File

@@ -139,8 +139,7 @@ def wait_for_all_checks(client=None):
attempt = 0
i=0
max_attempts = 60
wait_between_attempts = 2
required_empty_duration = 2
required_empty_duration = 0.8
logger = logging.getLogger()
time.sleep(1.2)
@@ -329,6 +328,8 @@ def live_server_setup(live_server):
live_server.start()
def get_index(client):
import inspect
# Get the caller's frame (parent function)