146 lines
4.5 KiB
Python
146 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import ssl
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from proto_socket.communicator import type_name_of
|
|
from proto_socket.packets.message_common_pb2 import TestData
|
|
from proto_socket.ws_server import WsServer
|
|
|
|
HOST = "127.0.0.1"
|
|
WS_PORT = 29698
|
|
WSS_PORT = 29699
|
|
WS_PATH = "/"
|
|
PROCESS_TIMEOUT = 60.0
|
|
SERVER_OBSERVATION_WINDOW = 0.5
|
|
CERT_PATH = Path(__file__).resolve().parents[1] / "test" / "certs" / "server.crt"
|
|
KEY_PATH = Path(__file__).resolve().parents[1] / "test" / "certs" / "server.key"
|
|
|
|
|
|
def parser_map():
|
|
return {type_name_of(TestData): TestData.FromString}
|
|
|
|
|
|
async def main() -> None:
|
|
print(f"INFO typeName python={type_name_of(TestData)}")
|
|
try:
|
|
await run_web_suites()
|
|
except Exception as exc:
|
|
print(f"FAIL crosstest error={exc}", file=sys.stderr)
|
|
raise SystemExit(1) from exc
|
|
print("PASS scenario=ws-send-push")
|
|
print("PASS scenario=ws-request-response")
|
|
print("PASS scenario=wss-send-push")
|
|
print("PASS scenario=wss-request-response")
|
|
print("PASS all python-server/dart-web-client crosstests passed")
|
|
|
|
|
|
async def run_web_suites() -> None:
|
|
loop = asyncio.get_running_loop()
|
|
ws_received = loop.create_future()
|
|
wss_received = loop.create_future()
|
|
ws_server = make_web_server(WS_PORT, None, ws_received)
|
|
wss_server = make_web_server(WSS_PORT, make_server_ssl_context(), wss_received)
|
|
|
|
await ws_server.start()
|
|
await wss_server.start()
|
|
try:
|
|
await run_dart_browser_test("test/browser_ws_python_test.dart")
|
|
await expect_received("WS", ws_received)
|
|
await expect_received("WSS", wss_received)
|
|
finally:
|
|
await wss_server.stop()
|
|
await ws_server.stop()
|
|
|
|
|
|
def make_web_server(
|
|
port: int,
|
|
ssl_context: ssl.SSLContext | None,
|
|
received: asyncio.Future[bool],
|
|
) -> WsServer:
|
|
server = WsServer(
|
|
HOST,
|
|
port,
|
|
WS_PATH,
|
|
interval_sec=0,
|
|
wait_sec=0,
|
|
parser_map=parser_map(),
|
|
ssl_context=ssl_context,
|
|
)
|
|
|
|
def on_connected(client):
|
|
def on_request(req):
|
|
print(f"SERVER_RECEIVED index={req.index} message={req.message}")
|
|
if req.index == 101 and req.message == "fire from dart web client":
|
|
if not received.done():
|
|
received.set_result(True)
|
|
asyncio.create_task(
|
|
client.communicator.send(
|
|
TestData(index=200, message="push from python server")
|
|
)
|
|
)
|
|
return TestData(index=req.index * 2, message="echo: " + req.message)
|
|
|
|
client.communicator.add_request_listener(type_name_of(TestData), on_request)
|
|
|
|
server.on_client_connected = on_connected
|
|
return server
|
|
|
|
|
|
def make_server_ssl_context() -> ssl.SSLContext:
|
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
ctx.load_cert_chain(CERT_PATH, KEY_PATH)
|
|
return ctx
|
|
|
|
|
|
async def expect_received(transport: str, received: asyncio.Future[bool]) -> None:
|
|
try:
|
|
ok = await asyncio.wait_for(received, SERVER_OBSERVATION_WINDOW)
|
|
except TimeoutError as exc:
|
|
raise RuntimeError(
|
|
f"{transport} web send-push server did not receive expected data"
|
|
) from exc
|
|
if not ok:
|
|
raise RuntimeError(f"{transport} web send-push server received unexpected data")
|
|
|
|
|
|
async def run_dart_browser_test(test_path: str) -> None:
|
|
dart_dir = dart_package_dir()
|
|
process = await asyncio.create_subprocess_exec(
|
|
"dart",
|
|
"test",
|
|
"-p",
|
|
"chrome",
|
|
test_path,
|
|
cwd=dart_dir,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE,
|
|
)
|
|
try:
|
|
stdout, stderr = await asyncio.wait_for(process.communicate(), PROCESS_TIMEOUT)
|
|
except TimeoutError as exc:
|
|
process.kill()
|
|
await process.wait()
|
|
raise TimeoutError("dart browser test timed out") from exc
|
|
for line in stdout.decode().splitlines():
|
|
print(line)
|
|
for line in stderr.decode().splitlines():
|
|
print(line, file=sys.stderr)
|
|
if process.returncode != 0:
|
|
raise RuntimeError(f"dart browser test failed exitCode={process.returncode}")
|
|
|
|
|
|
def dart_package_dir() -> Path:
|
|
repo_root = Path(__file__).resolve().parents[2]
|
|
candidate = repo_root / "dart"
|
|
if (candidate / "pubspec.yaml").is_file():
|
|
return candidate
|
|
raise RuntimeError(f"cannot resolve dart package directory from {candidate}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|