aboutsummaryrefslogtreecommitdiff
path: root/tests/integration/test_client_hub_messaging.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration/test_client_hub_messaging.py')
-rw-r--r--tests/integration/test_client_hub_messaging.py374
1 files changed, 374 insertions, 0 deletions
diff --git a/tests/integration/test_client_hub_messaging.py b/tests/integration/test_client_hub_messaging.py
new file mode 100644
index 0000000..f5765cf
--- /dev/null
+++ b/tests/integration/test_client_hub_messaging.py
@@ -0,0 +1,374 @@
+"""
+Integration tests for client-hub messaging using Selenium.
+Tests that client doesn't receive its own Join message back.
+"""
+import pytest
+import time
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions as EC
+
+pytestmark = [pytest.mark.nondestructive]
+
+
+@pytest.mark.integration
+def test_client_does_not_receive_own_join_message(ready_app, wait):
+ """
+ Test that when a client sends a Join message to the hub,
+ it doesn't receive it back through its own message handler.
+
+ This test:
+ 1. Clicks "Host" to create a hub and connect host client
+ 2. Injects JS to monitor if the host client receives a Join message
+ 3. Verifies the host client does NOT receive its own Join message
+ """
+ driver = ready_app
+
+ # Inject monitoring script before clicking Host
+ driver.execute_script("""
+ // Track if client receives Join message
+ window.clientReceivedOwnJoin = false;
+
+ // Monkey-patch Client.handle_message to detect Join messages
+ (function() {
+ // Wait for modules to load
+ var checkInterval = setInterval(function() {
+ try {
+ var clientModule = require('client');
+ var Client = clientModule.Client;
+
+ if (Client && Client.prototype && Client.prototype.handle_message) {
+ var originalHandleMessage = Client.prototype.handle_message;
+
+ Client.prototype.handle_message = function(callback_id, message_data) {
+ // Check if this is a Join message
+ if (message_data && Array.isArray(message_data) && message_data[0] === 'Join') {
+ console.log('[TEST] Client received Join message!');
+ window.clientReceivedOwnJoin = true;
+ }
+
+ // Call original method
+ return originalHandleMessage.call(this, callback_id, message_data);
+ };
+
+ console.log('[TEST] Successfully patched Client.handle_message');
+ clearInterval(checkInterval);
+ }
+ } catch (e) {
+ // Modules not loaded yet, keep trying
+ }
+ }, 100);
+
+ // Give up after 10 seconds
+ setTimeout(function() {
+ clearInterval(checkInterval);
+ }, 10000);
+ })();
+ """)
+
+ # Wait for Host button to be available
+ time.sleep(1)
+
+ # Click Host button
+ try:
+ # Try to find and click Host button via JavaScript
+ clicked = driver.execute_script("""
+ // Look for Host button in the UI
+ var buttons = document.querySelectorAll('canvas');
+ if (buttons.length > 0) {
+ // Simulate click on canvas where Host button would be
+ var canvas = buttons[0];
+ var event = new MouseEvent('click', {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ clientX: canvas.width / 2,
+ clientY: canvas.height / 2 - 64 // Approximate position of Host button
+ });
+ canvas.dispatchEvent(event);
+ return true;
+ }
+ return false;
+ """)
+
+ if not clicked:
+ # Fallback: Try clicking the canvas directly
+ canvas = driver.find_element(By.ID, "canvas")
+ canvas.click()
+ except Exception as e:
+ pytest.fail(f"Failed to click Host button: {e}")
+
+ # Wait for connection to establish
+ time.sleep(3)
+
+ # Check if client received its own Join message
+ received_own_join = driver.execute_script("return window.clientReceivedOwnJoin || false;")
+
+ # Get console logs for debugging
+ logs = driver.get_log("browser")
+ test_logs = [log['message'] for log in logs if '[TEST]' in log.get('message', '')]
+
+ print(f"\n=== Test Debug Info ===")
+ print(f"Client received own Join: {received_own_join}")
+ print(f"Test logs: {test_logs}")
+
+ # Assert client did NOT receive its own Join message
+ assert not received_own_join, "Client should not receive its own Join message back from hub"
+
+
+@pytest.mark.integration
+def test_hub_receives_join_message(ready_app, wait):
+ """
+ Test that the hub correctly receives the Join message from a connecting client.
+
+ This test:
+ 1. Clicks "Host" to create a hub
+ 2. Monitors hub.handle_message for Join messages
+ 3. Verifies the hub receives the Join message
+ """
+ driver = ready_app
+
+ # Inject monitoring script
+ driver.execute_script("""
+ // Track if hub receives Join message
+ window.hubReceivedJoin = false;
+ window.joinMessageData = null;
+
+ // Monkey-patch Hub.handle_message to detect Join messages
+ (function() {
+ var checkInterval = setInterval(function() {
+ try {
+ var hubModule = require('hub');
+ var Hub = hubModule.Hub;
+
+ if (Hub && Hub.prototype && Hub.prototype.handle_message) {
+ var originalHandleMessage = Hub.prototype.handle_message;
+
+ Hub.prototype.handle_message = function(from_client, msgname, data) {
+ // Normalise arguments: depending on the Lua/JS bridge,
+ // the message array may arrive as `msgname` or `data`,
+ // and may be 0- or 1-indexed from JS.
+ var message = null;
+ if (Array.isArray(msgname)) {
+ message = msgname;
+ } else if (Array.isArray(data)) {
+ message = data;
+ }
+ var msg_type = null;
+ var msg_data = null;
+ if (message) {
+ msg_type = message[0] || message[1] || null;
+ msg_data = message[1] || message[2] || null;
+ }
+ if (msg_type === 'Join') {
+ console.log('[TEST] Hub received Join message from:', from_client);
+ window.hubReceivedJoin = true;
+ window.joinMessageData = msg_data;
+ }
+
+ // Call original method
+ return originalHandleMessage.call(this, from_client, msgname, data);
+ };
+
+ console.log('[TEST] Successfully patched Hub.handle_message');
+ clearInterval(checkInterval);
+ }
+ } catch (e) {
+ // Modules not loaded yet, keep trying
+ }
+ }, 100);
+
+ setTimeout(function() {
+ clearInterval(checkInterval);
+ }, 10000);
+ })();
+ """)
+
+ # Wait for modules to load
+ time.sleep(1)
+
+ # Click Host button (same approach as previous test)
+ try:
+ clicked = driver.execute_script("""
+ var canvas = document.getElementById('canvas');
+ if (canvas) {
+ var event = new MouseEvent('click', {
+ view: window,
+ bubbles: true,
+ cancelable: true,
+ clientX: canvas.width / 2,
+ clientY: canvas.height / 2 - 64
+ });
+ canvas.dispatchEvent(event);
+ return true;
+ }
+ return false;
+ """)
+
+ if not clicked:
+ canvas = driver.find_element(By.ID, "canvas")
+ canvas.click()
+ except Exception as e:
+ pytest.fail(f"Failed to click Host button: {e}")
+
+ # Wait for connection and message processing
+ time.sleep(3)
+
+ # Debug world/hub state before assertions
+ world_debug = driver.execute_script("""
+ try {
+ var world = typeof require === 'function' ? require('world') : null;
+ return {
+ hasWorld: !!world,
+ hasHub: !!(world && world.hub),
+ hasNetwork: !!(world && world.network)
+ };
+ } catch (e) {
+ return { error: String(e) };
+ }
+ """)
+ print(f"World debug: {world_debug}")
+ js_flags = driver.execute_script("""
+ return {
+ clientConnected: !!window._clientConnectedToHub,
+ clientJoinPayload: window._clientJoinPayload || null,
+ hubJoinReceived: !!window._hubJoinReceived,
+ hubJoinData: window._hubJoinData || null
+ };
+ """)
+ print(f"JS flags: {js_flags}")
+
+ # Check if hub received Join message (Lua side exposes this via js_bridge)
+ hub_received_join = driver.execute_script("return (window.hubReceivedJoin || window._hubJoinReceived) || false;")
+ join_data = driver.execute_script("return window.joinMessageData || window._hubJoinData || null;")
+
+ # Get console logs for debugging
+ logs = driver.get_log("browser")
+ test_logs = [log['message'] for log in logs if '[TEST]' in log.get('message', '')]
+
+ print(f"\n=== Test Debug Info ===")
+ print(f"Hub received Join: {hub_received_join}")
+ print(f"Join data: {join_data}")
+ print(f"Test logs: {test_logs}")
+
+ # Assert hub received the Join message
+ assert hub_received_join, "Hub should receive Join message from connecting client"
+ assert join_data is not None, "Join message should contain data"
+ # Check that join data has a 'name' field
+ if join_data:
+ assert 'name' in join_data, "Join message data should contain 'name' field"
+
+
+@pytest.mark.integration
+def test_message_flow_integrity(ready_app, wait):
+ """
+ End-to-end test of message flow: client sends, hub receives, but client doesn't get echo.
+
+ This combines both previous tests to verify the complete message flow.
+ """
+ driver = ready_app
+
+ # Inject comprehensive monitoring
+ driver.execute_script("""
+ window.testResults = {
+ clientReceivedJoin: false,
+ hubReceivedJoin: false,
+ joinData: null
+ };
+
+ (function() {
+ var checkInterval = setInterval(function() {
+ try {
+ // Patch Client
+ var clientModule = require('client');
+ var hubModule = require('hub');
+
+ if (clientModule && clientModule.Client &&
+ hubModule && hubModule.Hub) {
+
+ var Client = clientModule.Client;
+ var Hub = hubModule.Hub;
+
+ // Patch client
+ if (Client.prototype.handle_message) {
+ var origClientHandle = Client.prototype.handle_message;
+ Client.prototype.handle_message = function(cid, mdata) {
+ if (mdata && mdata[0] === 'Join') {
+ console.log('[TEST] CLIENT RECEIVED JOIN - THIS IS THE BUG!');
+ window.testResults.clientReceivedJoin = true;
+ }
+ return origClientHandle.call(this, cid, mdata);
+ };
+ }
+
+ // Patch hub
+ if (Hub.prototype.handle_message) {
+ var origHubHandle = Hub.prototype.handle_message;
+ Hub.prototype.handle_message = function(from, msgname, data) {
+ // Normalise message array from Lua/JS bridge.
+ var message = null;
+ if (Array.isArray(msgname)) {
+ message = msgname;
+ } else if (Array.isArray(data)) {
+ message = data;
+ }
+ var msg_type = null;
+ var msg_data = null;
+ if (message) {
+ msg_type = message[0] || message[1] || null;
+ msg_data = message[1] || message[2] || null;
+ }
+ if (msg_type === 'Join') {
+ console.log('[TEST] Hub received Join - CORRECT!');
+ window.testResults.hubReceivedJoin = true;
+ window.testResults.joinData = msg_data;
+ }
+ return origHubHandle.call(this, from, msgname, data);
+ };
+ }
+
+ console.log('[TEST] Patching complete');
+ clearInterval(checkInterval);
+ }
+ } catch (e) {
+ // Keep trying
+ }
+ }, 100);
+
+ setTimeout(function() { clearInterval(checkInterval); }, 10000);
+ })();
+ """)
+
+ time.sleep(1)
+
+ # Click Host
+ canvas = driver.find_element(By.ID, "canvas")
+ canvas.click()
+
+ # Wait for messages to flow
+ time.sleep(3)
+
+ # Get results, augmenting from Lua-side hub instrumentation if present
+ results = driver.execute_script("""
+ if (typeof window.testResults === 'undefined') {
+ window.testResults = {
+ clientReceivedJoin: false,
+ hubReceivedJoin: false,
+ joinData: null
+ };
+ }
+ if (window._hubJoinReceived) {
+ window.testResults.hubReceivedJoin = true;
+ }
+ if (window._hubJoinData) {
+ window.testResults.joinData = window._hubJoinData;
+ }
+ return window.testResults;
+ """)
+
+ print(f"\n=== Complete Test Results ===")
+ print(f"Results: {results}")
+
+ # Assertions
+ assert results['hubReceivedJoin'], "Hub must receive Join message"
+ assert not results['clientReceivedJoin'], "Client must NOT receive its own Join message (bug fixed!)"
+ assert results['joinData'] is not None, "Join message must have data"