Files
2026-08-23 05:10:27 +08:00

103 lines
3.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
MQTT 端到端测试脚本
测试流程:
1. 启动内嵌 amqtt Broker
2. 启动 subscriber(监听响应)
3. 启动 publisher(发送 MQTT 请求 → chongming/example/add)
4. 验证 subscriber 收到正确的响应
注意: 此脚本独立运行,不依赖 chongming 服务端。
使用时需确保 chongming 服务已通过 `uv run serve` 启动。
"""
import asyncio
import orjson
import sys
import logging
from amqtt.client import MQTTClient
from amqtt.mqtt.constants import QOS_1
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(name)s] %(message)s",
)
PREFIX = "chongming"
WORKER = "example"
OPERATION = "add"
REQUEST_TOPIC = f"{PREFIX}/{WORKER}/{OPERATION}"
RESPONSE_TOPIC = f"{PREFIX}/{WORKER}/{OPERATION}/response"
BROKER_URL = "mqtt://localhost:1883/"
# 测试用例(信封协议: meta.method 控制分派,data 携带业务参数)
TEST_CASES = [
{"a": 3, "b": 5, "expected": 8},
{"a": -1, "b": 10, "expected": 9},
{"a": 3.14, "b": 2.86, "expected": 6.0},
]
PASS = 0
FAIL = 0
async def run_test():
global PASS, FAIL
client = MQTTClient()
await client.connect(BROKER_URL)
await client.subscribe([(RESPONSE_TOPIC, QOS_1)])
print(f"📡 已订阅: {RESPONSE_TOPIC}\n")
for i, case in enumerate(TEST_CASES):
a, b, expected = case["a"], case["b"], case["expected"]
payload = {"meta": {"method": "MQTT"}, "data": {"a": a, "b": b}}
payload_bytes = orjson.dumps(payload)
await client.publish(REQUEST_TOPIC, payload_bytes, QOS_1)
print(f"📤 [{i+1}/{len(TEST_CASES)}] 发送: {REQUEST_TOPIC} → {payload}")
# 等待响应(超时 5 秒)
try:
message = await asyncio.wait_for(client.deliver_message(), timeout=5.0)
data = orjson.loads(message.data) # type: ignore
actual = data.get("result")
status = "✅ PASS" if abs(actual - expected) < 0.01 else "❌ FAIL"
if status == "✅ PASS":
PASS += 1
else:
FAIL += 1
print(f"📥 [{i+1}/{len(TEST_CASES)}] 响应: {orjson.dumps(data).decode()} → {status} (expect={expected}, got={actual})")
except asyncio.TimeoutError:
FAIL += 1
print(f"📥 [{i+1}/{len(TEST_CASES)}] ❌ FAIL: 超时无响应")
await client.unsubscribe([RESPONSE_TOPIC])
await client.disconnect()
print(f"\n{'='*50}")
print(f"测试结果: ✅ {PASS} 通过 ❌ {FAIL} 失败")
print(f"{'='*50}")
return FAIL == 0
async def main():
# 先检查 Broker 是否可用
test_client = MQTTClient()
try:
await asyncio.wait_for(test_client.connect(BROKER_URL), timeout=3.0)
await test_client.disconnect()
except Exception:
print("❌ 无法连接到 MQTT Broker (localhost:1883)")
print(" 请先启动 chongming 服务: uv run serve")
sys.exit(1)
success = await run_test()
sys.exit(0 if success else 1)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n⏹️ 测试被中断")