diff options
Diffstat (limited to 'tests/integration/test_client_hub_messaging.py')
| -rw-r--r-- | tests/integration/test_client_hub_messaging.py | 374 |
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" |
