Files

103 lines
3.1 KiB
Python
Raw Permalink Normal View History

2026-07-24 16:33:23 +08:00
"""
MQTT 端到端测试脚本
测试流程:
1. 启动内嵌 amqtt Broker
2. 启动 subscriber(监听响应)
3. 启动 publisher(发送 MQTT 请求 → chongming/example/add)
4. 验证 subscriber 收到正确的响应
注意: 此脚本独立运行,不依赖 chongming 服务端。
使用时需确保 chongming 服务已通过 `uv run serve` 启动。
"""
import asyncio
2026-08-23 04:34:05 +08:00
import orjson
2026-07-24 16:33:23 +08:00
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/"
2026-08-14 16:03:49 +08:00
# 测试用例(信封协议: meta.method 控制分派,data 携带业务参数)
2026-07-24 16:33:23 +08:00
TEST_CASES = [
2026-08-14 16:03:49 +08:00
{"a": 3, "b": 5, "expected": 8},
{"a": -1, "b": 10, "expected": 9},
{"a": 3.14, "b": 2.86, "expected": 6.0},
2026-07-24 16:33:23 +08:00
]
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"]
2026-08-14 16:03:49 +08:00
payload = {"meta": {"method": "MQTT"}, "data": {"a": a, "b": b}}
2026-08-23 04:34:05 +08:00
payload_bytes = orjson.dumps(payload)
2026-07-24 16:33:23 +08:00
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)
2026-08-23 04:34:05 +08:00
data = orjson.loads(message.data) # type: ignore
2026-07-24 16:33:23 +08:00
actual = data.get("result")
status = "✅ PASS" if abs(actual - expected) < 0.01 else "❌ FAIL"
if status == "✅ PASS":
PASS += 1
else:
FAIL += 1
2026-08-23 04:34:05 +08:00
print(f"📥 [{i+1}/{len(TEST_CASES)}] 响应: {orjson.dumps(data).decode()} → {status} (expect={expected}, got={actual})")
2026-07-24 16:33:23 +08:00
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⏹️ 测试被中断")