Files
ComfyUI-OpenClaw/tests/test_bridge_handshake.py

119 lines
4.0 KiB
Python

"""
Unit tests for R85 Bridge Handshake (N/N-1 Policy).
"""
import unittest
from services.bridge_handshake import verify_handshake
from services.sidecar.bridge_contract import BRIDGE_PROTOCOL_VERSION
class TestBridgeHandshake(unittest.TestCase):
def test_exact_match(self):
"""Current version (N) should pass."""
ok, msg, meta = verify_handshake(BRIDGE_PROTOCOL_VERSION)
self.assertTrue(ok)
# Handle cases where server_version might match client_version
self.assertEqual(meta["server_version"], BRIDGE_PROTOCOL_VERSION)
def test_n_minus_one(self):
"""Previous version (N-1) should pass."""
if BRIDGE_PROTOCOL_VERSION > 1:
prev_ver = BRIDGE_PROTOCOL_VERSION - 1
ok, msg, meta = verify_handshake(prev_ver)
self.assertTrue(ok)
self.assertEqual(meta["client_version"], prev_ver)
else:
# If version is 1, N-1 is 0 which might be rejected if min_supported is 1
# verify_handshake implementation uses max(1, server-1)
# So if server=1, min=1. Client 0 should fail.
pass
def test_too_old(self):
"""Version < N-1 should fail."""
# Force a drift scenario
server_ver = BRIDGE_PROTOCOL_VERSION
min_ver = max(1, server_ver - 1)
if min_ver > 1:
too_old = min_ver - 1
ok, msg, meta = verify_handshake(too_old)
self.assertFalse(ok)
self.assertIn("too old", msg)
def test_too_new(self):
"""Version > N should fail."""
future_ver = BRIDGE_PROTOCOL_VERSION + 1
ok, msg, meta = verify_handshake(future_ver)
self.assertFalse(ok)
self.assertIn("newer than server", msg)
import asyncio
from unittest.mock import AsyncMock, MagicMock, patch
class TestBridgeClient(unittest.TestCase):
def setUp(self):
self.client = MagicMock()
# We'll mock the internal machinery of BridgeClient for isolation
# But importing it is better to test the actual logic
pass
@patch("aiohttp.ClientSession.post")
def test_client_handshake_success(self, mock_post):
"""Test client handles specific 200 OK handshake."""
# Need to import BridgeClient locally to avoid import errors if deps missing
try:
from services.sidecar.bridge_client import BridgeClient
except ImportError:
self.skipTest("aiohttp or internal modules missing")
# Mock Response
mock_resp = AsyncMock()
mock_resp.status = 200
mock_resp.json.return_value = {"ok": True, "message": "Compatible"}
mock_post.return_value.__aenter__.return_value = mock_resp
client = BridgeClient("http://test", "token", "worker1")
client.session = MagicMock()
client.session.post.return_value.__aenter__.return_value = mock_resp
# Run async test
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
result = loop.run_until_complete(client.perform_handshake())
self.assertTrue(result)
finally:
loop.close()
@patch("aiohttp.ClientSession.post")
def test_client_handshake_fail(self, mock_post):
"""Test client raises error on 409 Conflict."""
try:
from services.sidecar.bridge_client import BridgeClient
except ImportError:
self.skipTest("aiohttp or internal modules missing")
mock_resp = AsyncMock()
mock_resp.status = 409
mock_resp.json.return_value = {"ok": False, "message": "Version mismatch"}
client = BridgeClient("http://test", "token", "worker1")
client.session = MagicMock()
client.session.post.return_value.__aenter__.return_value = mock_resp
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
with self.assertRaises(RuntimeError):
loop.run_until_complete(client.perform_handshake())
finally:
loop.close()
if __name__ == "__main__":
unittest.main()