- delete GatewayHTTPServer/GatewayHandler, create_server, /healthz and /v1/channel; event_channel module removed - load_config now requires CREATOR_PLATFORM_URL + CREATOR_GATEWAY_KEY - run() wires Gateway into OutboundAgent; SIGINT/SIGTERM stop the agent - deploy env example, install script, systemd unit docs and deployment docs updated to the outbound model; NATIVE_GATEWAY_ENDPOINT dead dev config removed
107 lines
4.1 KiB
Python
107 lines
4.1 KiB
Python
"""Server entry tests: outbound-only config and run() wiring."""
|
||
from __future__ import annotations
|
||
|
||
import unittest
|
||
from importlib import import_module
|
||
from unittest.mock import Mock, patch
|
||
|
||
gateway_module = import_module(f"{__package__}.server.http")
|
||
|
||
load_config = gateway_module.load_config
|
||
|
||
|
||
class OutboundConfigTests(unittest.TestCase):
|
||
def test_platform_url_and_key_are_required(self) -> None:
|
||
config = load_config({
|
||
"CREATOR_PLATFORM_URL": "http://platform.example:8080",
|
||
"CREATOR_GATEWAY_KEY": "0123456789abcdef",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
self.assertEqual(config["platform_url"], "http://platform.example:8080")
|
||
self.assertEqual(config["access_key"], "0123456789abcdef")
|
||
self.assertNotIn("listen", config)
|
||
self.assertNotIn("token", config)
|
||
|
||
def test_platform_url_must_be_http(self) -> None:
|
||
with self.assertRaises(ValueError):
|
||
load_config({
|
||
"CREATOR_PLATFORM_URL": "ftp://platform.example",
|
||
"CREATOR_GATEWAY_KEY": "0123456789abcdef",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
|
||
def test_platform_url_must_not_embed_agent_path(self) -> None:
|
||
with self.assertRaises(ValueError):
|
||
load_config({
|
||
"CREATOR_PLATFORM_URL": "http://platform.example:8080/v1/agent",
|
||
"CREATOR_GATEWAY_KEY": "0123456789abcdef",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
|
||
def test_access_key_minimum_length(self) -> None:
|
||
with self.assertRaises(ValueError):
|
||
load_config({
|
||
"CREATOR_PLATFORM_URL": "http://platform.example:8080",
|
||
"CREATOR_GATEWAY_KEY": "short",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
|
||
def test_trailing_slash_platform_url_is_normalized(self) -> None:
|
||
config = load_config({
|
||
"CREATOR_PLATFORM_URL": "http://platform.example:8080/",
|
||
"CREATOR_GATEWAY_KEY": "0123456789abcdef",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
self.assertEqual(config["platform_url"], "http://platform.example:8080")
|
||
|
||
|
||
class RunWiringTests(unittest.TestCase):
|
||
def test_run_builds_agent_from_config_and_stops_on_signal(self) -> None:
|
||
config = load_config({
|
||
"CREATOR_PLATFORM_URL": "http://platform.example:8080",
|
||
"CREATOR_GATEWAY_KEY": "0123456789abcdef",
|
||
"BROWSER_PATH": "/bin/true",
|
||
})
|
||
agent_instances = []
|
||
|
||
class FakeAgent:
|
||
def __init__(self, gateway, agent_config) -> None:
|
||
self.gateway = gateway
|
||
self.config = agent_config
|
||
self.ran = False
|
||
self.stopped = False
|
||
agent_instances.append(self)
|
||
|
||
def run(self) -> None:
|
||
self.ran = True
|
||
|
||
def stop(self) -> None:
|
||
self.stopped = True
|
||
|
||
registered = {}
|
||
|
||
def record_signal(signum, handler):
|
||
registered[signum] = handler
|
||
|
||
with patch.object(gateway_module, "OutboundAgent", FakeAgent), \
|
||
patch.object(gateway_module, "NativeRuntimeManager", Mock()), \
|
||
patch.object(gateway_module.signal, "signal", record_signal):
|
||
exit_code = gateway_module.run(config)
|
||
self.assertEqual(exit_code, 0)
|
||
self.assertEqual(len(agent_instances), 1)
|
||
self.assertEqual(agent_instances[0].config.platform_url, config["platform_url"])
|
||
self.assertEqual(agent_instances[0].config.access_key, config["access_key"])
|
||
self.assertTrue(agent_instances[0].ran)
|
||
# SIGINT/SIGTERM 都注册了停止回调,触发后 agent 收到 stop
|
||
self.assertIn(gateway_module.signal.SIGINT, registered)
|
||
self.assertIn(gateway_module.signal.SIGTERM, registered)
|
||
registered[gateway_module.signal.SIGTERM](15, None)
|
||
registered[gateway_module.signal.SIGINT](2, None)
|
||
self.assertTrue(agent_instances[0].stopped)
|
||
# Gateway 的业务方法必须仍挂在 agent 上(agent.gateway)
|
||
self.assertIsNotNone(agent_instances[0].gateway.subscriptions)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|