feat: publish workphone SDK deployment and API docs

This commit is contained in:
Manus AI
2026-07-14 18:10:52 +08:00
commit 021d633cc1
534 changed files with 122391 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""
BIND-03 离线回归Agent 公网主服有序回退候选构建 + 健康探测。
不依赖真机/WS仅校验 _build_server_candidates 与 _probe_ws_base 纯逻辑。
真机寻服 E2E断 LAN 自动连公网)见 §八 V3仍须真机留痕。
"""
import os
import sys
import socket
import threading
import importlib.util
AGENT_PATH = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
"agent", "agent.py",
)
def _load_agent_module():
# 直接按文件路径加载,避免 import 触发 u2/websockets 之外的副作用
spec = importlib.util.spec_from_file_location("wp_agent_under_test", AGENT_PATH)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
def test_build_candidates_dedup_and_fill():
mod = _load_agent_module()
Agent = mod.WorkPhoneAgent
primary = "ws://192.168.110.251:8899/ws/device/dev1"
publics = [
"ws://sdk.quwanzhi.com:8899", # 缺 /ws/device + device_id
"ws://sdk.quwanzhi.com:8899/ws/device", # 缺 device_id
"ws://192.168.110.251:8899/ws/device/dev1", # 与主连接重复
"ws://backup.quwanzhi.com:8899/ws/device/dev1", # 已完整
]
cands = Agent._build_server_candidates(primary, publics, "dev1")
assert cands[0] == primary
assert "ws://sdk.quwanzhi.com:8899/ws/device/dev1" in cands
assert "ws://backup.quwanzhi.com:8899/ws/device/dev1" in cands
# 去重:主连接与重复公网只出现一次
assert cands.count(primary) == 1
assert len(cands) == 3, f"应去重为 3 个候选,实际 {cands}"
def test_build_candidates_empty_public():
mod = _load_agent_module()
Agent = mod.WorkPhoneAgent
primary = "ws://127.0.0.1:8899/ws/device/x"
assert Agent._build_server_candidates(primary, [], "x") == [primary]
assert Agent._build_server_candidates(primary, None, "x") == [primary]
def test_probe_unreachable():
mod = _load_agent_module()
Agent = mod.WorkPhoneAgent
# 保留端口 9discard本机通常不监听确定性不可达
assert Agent._probe_ws_base("ws://127.0.0.1:9/ws/device/x", timeout=0.5) is False
def test_probe_reachable_local_socket():
mod = _load_agent_module()
Agent = mod.WorkPhoneAgent
srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("127.0.0.1", 0))
srv.listen(1)
port = srv.getsockname()[1]
stop = threading.Event()
def _accept():
srv.settimeout(2)
try:
c, _ = srv.accept()
c.close()
except Exception:
pass
t = threading.Thread(target=_accept, daemon=True)
t.start()
try:
url = f"ws://127.0.0.1:{port}/ws/device/x"
assert Agent._probe_ws_base(url, timeout=1.0) is True
finally:
stop.set()
srv.close()
class _FakeAgent:
"""最小 duck-typed self避免重型构造u2/frida/anti_ban"""
VERSION = "test"
def __init__(self, stage):
self.d = None
self.connect_stage = stage
self.device_id = "dev1"
self.project_id = "cunkebao"
self.server_url = "ws://x:8899/ws/device/dev1"
self.server_candidates = ["ws://x:8899/ws/device/dev1", "ws://y:8899/ws/device/dev1"]
def test_quick_status_includes_connect_stage():
mod = _load_agent_module()
fake = _FakeAgent("public")
st = mod.WorkPhoneAgent._get_quick_status(fake)
assert st["online"] is True
assert st["connect_stage"] == "public", f"心跳须带 connect_stage实际 {st}"
def test_device_info_includes_connect_stage():
mod = _load_agent_module()
fake = _FakeAgent("retry")
info = mod.WorkPhoneAgent._get_device_info(fake)
assert info["connect_stage"] == "retry"
assert info["server_url"] == "ws://x:8899/ws/device/dev1"
assert info["server_candidate_count"] == 2
if __name__ == "__main__":
test_build_candidates_dedup_and_fill()
test_build_candidates_empty_public()
test_probe_unreachable()
test_probe_reachable_local_socket()
test_quick_status_includes_connect_stage()
test_device_info_includes_connect_stage()
print("✅ BIND-03/07 候选回退+寻服阶段上报离线回归全部通过")