mirror of
https://github.com/rookiestar28/ComfyUI-OpenClaw.git
synced 2026-08-14 08:52:45 +00:00
156 lines
5.9 KiB
Python
156 lines
5.9 KiB
Python
"""
|
|
Unit tests for R13 Sidecar Bridge Contract.
|
|
"""
|
|
|
|
import unittest
|
|
|
|
from services.sidecar.bridge_client import BridgeClient, BridgeClientConfig
|
|
from services.sidecar.bridge_contract import (
|
|
BRIDGE_ENDPOINTS,
|
|
REQUIRED_WORKER_SCOPES,
|
|
BridgeDeliveryRequest,
|
|
BridgeHealthResponse,
|
|
BridgeJobRequest,
|
|
BridgeScope,
|
|
DeviceToken,
|
|
)
|
|
|
|
|
|
class TestBridgeContract(unittest.TestCase):
|
|
"""Tests for R13 sidecar bridge contract."""
|
|
|
|
def test_bridge_scopes(self):
|
|
"""Test bridge scope enum values."""
|
|
self.assertEqual(BridgeScope.JOB_SUBMIT.value, "job:submit")
|
|
self.assertEqual(BridgeScope.DELIVERY.value, "delivery:send")
|
|
|
|
def test_device_token_dataclass(self):
|
|
"""Test DeviceToken dataclass."""
|
|
token = DeviceToken(
|
|
device_id="dev123", device_token="secret", scopes=[BridgeScope.JOB_SUBMIT]
|
|
)
|
|
self.assertEqual(token.device_id, "dev123")
|
|
self.assertIn(BridgeScope.JOB_SUBMIT, token.scopes)
|
|
|
|
def test_job_request_dataclass(self):
|
|
"""Test BridgeJobRequest dataclass."""
|
|
req = BridgeJobRequest(
|
|
template_id="text2img", inputs={"prompt": "test"}, idempotency_key="key123"
|
|
)
|
|
self.assertEqual(req.template_id, "text2img")
|
|
self.assertEqual(req.timeout_sec, 300) # Default
|
|
|
|
def test_delivery_request_dataclass(self):
|
|
"""Test BridgeDeliveryRequest dataclass."""
|
|
req = BridgeDeliveryRequest(
|
|
target="discord:123456", text="Hello", idempotency_key="del123"
|
|
)
|
|
self.assertEqual(req.target, "discord:123456")
|
|
|
|
def test_health_response_dataclass(self):
|
|
"""Test BridgeHealthResponse dataclass."""
|
|
resp = BridgeHealthResponse(ok=True, version="1.0.0", uptime_sec=3600)
|
|
self.assertTrue(resp.ok)
|
|
self.assertEqual(resp.uptime_sec, 3600)
|
|
|
|
def test_endpoints_defined(self):
|
|
"""Test bridge endpoints are properly defined."""
|
|
self.assertIn("submit", BRIDGE_ENDPOINTS)
|
|
self.assertIn("deliver", BRIDGE_ENDPOINTS)
|
|
self.assertIn("health", BRIDGE_ENDPOINTS)
|
|
|
|
# Check submit endpoint structure
|
|
submit = BRIDGE_ENDPOINTS["submit"]
|
|
self.assertEqual(submit["method"], "POST")
|
|
self.assertEqual(submit["path"], "/bridge/submit")
|
|
self.assertEqual(submit["scope"], BridgeScope.JOB_SUBMIT)
|
|
|
|
# --- F46 contract alignment ---
|
|
|
|
def test_worker_endpoints_defined(self):
|
|
"""F46: Worker-facing endpoints must exist in contract."""
|
|
for key in ("worker_poll", "worker_result", "worker_heartbeat"):
|
|
self.assertIn(key, BRIDGE_ENDPOINTS, f"Missing worker endpoint: {key}")
|
|
|
|
def test_worker_endpoint_paths(self):
|
|
"""F46: Worker endpoints use /bridge/worker/* path convention."""
|
|
self.assertEqual(BRIDGE_ENDPOINTS["worker_poll"]["path"], "/bridge/worker/poll")
|
|
self.assertEqual(
|
|
BRIDGE_ENDPOINTS["worker_result"]["path"], "/bridge/worker/result"
|
|
)
|
|
self.assertEqual(
|
|
BRIDGE_ENDPOINTS["worker_heartbeat"]["path"], "/bridge/worker/heartbeat"
|
|
)
|
|
|
|
def test_worker_endpoint_methods(self):
|
|
"""F46: Worker endpoints use correct HTTP methods."""
|
|
self.assertEqual(BRIDGE_ENDPOINTS["worker_poll"]["method"], "GET")
|
|
self.assertEqual(BRIDGE_ENDPOINTS["worker_result"]["method"], "POST")
|
|
self.assertEqual(BRIDGE_ENDPOINTS["worker_heartbeat"]["method"], "POST")
|
|
|
|
def test_required_worker_scopes(self):
|
|
"""F46: Required scopes for sidecar startup are defined."""
|
|
self.assertIn(BridgeScope.JOB_SUBMIT, REQUIRED_WORKER_SCOPES)
|
|
self.assertIn(BridgeScope.JOB_STATUS, REQUIRED_WORKER_SCOPES)
|
|
|
|
|
|
class TestBridgeClient(unittest.TestCase):
|
|
"""Tests for R13 sidecar bridge client."""
|
|
|
|
def test_client_config_defaults(self):
|
|
"""Test client config defaults."""
|
|
config = BridgeClientConfig("http://bridge", "token", "worker1")
|
|
self.assertEqual(config.url, "http://bridge")
|
|
self.assertEqual(config.token, "token")
|
|
self.assertEqual(config.worker_id, "worker1")
|
|
|
|
def test_client_not_connected_by_default(self):
|
|
"""Test client starts disconnected."""
|
|
client = BridgeClient("http://bridge", "token", "worker1")
|
|
self.assertIsNone(client.session)
|
|
|
|
def test_idempotency_key_propagation(self):
|
|
"""Test idempotency key is required in requests."""
|
|
req = BridgeJobRequest(template_id="test", inputs={}, idempotency_key="key123")
|
|
# Key should be accessible
|
|
self.assertEqual(req.idempotency_key, "key123")
|
|
|
|
def test_device_token_in_request_context(self):
|
|
"""Test device_id can be passed in requests."""
|
|
req = BridgeJobRequest(
|
|
template_id="test", inputs={}, idempotency_key="key123", device_id="dev456"
|
|
)
|
|
self.assertEqual(req.device_id, "dev456")
|
|
|
|
# --- F46 client endpoint alignment ---
|
|
|
|
def test_endpoint_resolver(self):
|
|
"""F46: Client resolves contract paths correctly."""
|
|
client = BridgeClient("https://bridge.example.com", "t", "w")
|
|
self.assertEqual(
|
|
client._endpoint("worker_poll"),
|
|
"https://bridge.example.com/bridge/worker/poll",
|
|
)
|
|
self.assertEqual(
|
|
client._endpoint("health"),
|
|
"https://bridge.example.com/bridge/health",
|
|
)
|
|
|
|
def test_endpoint_resolver_strips_trailing_slash(self):
|
|
"""F46: Client strips trailing slash from base URL."""
|
|
client = BridgeClient("https://bridge.example.com/", "t", "w")
|
|
self.assertEqual(
|
|
client._endpoint("health"),
|
|
"https://bridge.example.com/bridge/health",
|
|
)
|
|
|
|
def test_endpoint_resolver_unknown_raises(self):
|
|
"""F46: Unknown endpoint name raises ValueError."""
|
|
client = BridgeClient("https://bridge.example.com", "t", "w")
|
|
with self.assertRaises(ValueError):
|
|
client._endpoint("nonexistent")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|