diff --git a/_build/_c8.txt b/_build/_c8.txt new file mode 100644 index 0000000..118aabd --- /dev/null +++ b/_build/_c8.txt @@ -0,0 +1,17 @@ +修管理页测试的引号敏感 + 补 netPanel id + +重做管理页时把 HTML 从 class=pick(无引号)改成了 +class="pick"(标准写法),但测试里写死了无引号形式, +于是 5 个断言集体误报失败。 + +HTML 两种写法都合法,测试不该关心这个 —— +给两个测试加了 _has(),带不带引号都认。 + +另外给新管理页的体检卡补回 id=netPanel(语义合理, +也顺手让测试钩子还在)。 + +同时删掉 _build/_missing_tail.py(恢复事故时的临时文件, +静态检查把它当成真模块查,报了 8 个 undefined name)。 + +验证:管理页网络体检 15/15、中转批量删除 24/24、 +全局 32 个阶段全部通过。 diff --git a/_build/_missing_tail.py b/_build/_missing_tail.py deleted file mode 100644 index 50cd0af..0000000 --- a/_build/_missing_tail.py +++ /dev/null @@ -1,60 +0,0 @@ -def _esc(text) -> str: - return (str(text).replace("&", "&").replace("<", "<") - .replace(">", ">").replace('"', """)) - - -def _kb(value: int) -> str: - if value < 1024: - return f"{value} B" - if value < 1024 * 1024: - return f"{value / 1024:.1f} KB" - return f"{value / 1024 / 1024:.1f} MB" - - -def _uptime(seconds: int) -> str: - days, rest = divmod(int(seconds), 86400) - hours, rest = divmod(rest, 3600) - minutes = rest // 60 - if days: - return f"{days} 天 {hours} 小时" - if hours: - return f"{hours} 小时 {minutes} 分" - return f"{minutes} 分" - - -# ====================================================================== -# 启动 -# ====================================================================== - -class Server(ThreadingHTTPServer): - daemon_threads = True - allow_reuse_address = True - request_queue_size = 64 - - -def main() -> int: - DATA_DIR.mkdir(parents=True, exist_ok=True) - try: - server = Server((BIND, PORT), Handler) - except OSError as exc: - print(f"监听 {BIND}:{PORT} 失败:{exc}") - return 1 - - log(f"中转服务器 v{VERSION} 启动,监听 {BIND}:{PORT}") - log(f"长轮询 {POLL_SECONDS:.0f} 秒 · 队列上限 " - f"{MAX_QUEUE_BYTES // 1024} KB · 数据目录 {DATA_DIR}") - key = admin_key() - log(f"管理页:http://<本机>:{PORT}/?key={key}") - log(f"(钥匙也在 {DATA_DIR / 'admin_key.txt'})") - - try: - server.serve_forever() - except KeyboardInterrupt: - log("收到中断,退出") - finally: - server.server_close() - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/_build/fix_admin_tests_quotes.py b/_build/fix_admin_tests_quotes.py new file mode 100644 index 0000000..20becb5 --- /dev/null +++ b/_build/fix_admin_tests_quotes.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +r'''让管理页测试对"属性有没有引号"不敏感。 + +背景: + 旧版管理页的 HTML 是 `class=pick`(无引号), + 重做时改成了标准的 `class="pick"`(带引号)。 + 测试里写死了 `"class=pick" in html`,于是集体误报失败。 + + HTML 两种写法都合法,测试不该关心这个。 + 所以给测试加个 _has():两种写法都认。 +''' +from __future__ import annotations + +import ast +import re +import sys +from pathlib import Path + +TESTS = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote\_tests") + +# 要改的测试文件和里面的断言 +TARGETS = { + "test_admin_batch_delete.py": [ + ('check("有复选框(input.pick)", "class=pick" in html)', + 'check("有复选框(input.pick)", _has(html, "class=pick"))'), + ('check("有全选(pickAll)", "id=pickAll" in html)', + 'check("有全选(pickAll)", _has(html, "id=pickAll"))'), + ('check("有「删除选中」按钮", "id=delPicked" in html)', + 'check("有「删除选中」按钮", _has(html, "id=delPicked"))'), + ], + "test_admin_netcheck.py": [ + ('check("有网络体检面板", \'id=netPanel\' in html, "")', + 'check("有网络体检面板", _has(html, "id=netPanel"), "")'), + ('check("有「测一下」按钮", \'id=netBtn\' in html, "")', + 'check("有「测一下」按钮", _has(html, "id=netBtn"), "")'), + ], +} + +# 插到 check() 定义附近 +HELPER = ''' + +def _has(html: str, token: str) -> bool: + """判断 html 里有没有这个属性,**带不带引号都算**。 + + 旧版页面写的是 class=pick(无引号), + 重做后改成了标准的 class="pick"(带引号)。 + 测试不该因为引号差异就报失败 —— HTML 两种都合法。 + """ + if token in html: + return True + # class=pick -> class="pick" / id=netBtn -> id="netBtn" + match = re.match(r"^([A-Za-z-]+)=(.+)$", token) + if not match: + return False + attr, value = match.group(1), match.group(2) + return ('%s="%s"' % (attr, value)) in html +''' + + +def ensure_import_re(text: str) -> str: + if re.search(r"^import re$", text, re.M): + return text + # 插到第一个 import 之后 + match = re.search(r"^(import \w+|from \w+ import .+)$", text, re.M) + if match: + return (text[:match.end()] + "\nimport re" + text[match.end():]) + return "import re\n" + text + + +def main() -> int: + total = 0 + for name, replacements in TARGETS.items(): + path = TESTS / name + if not path.is_file(): + print(" [跳过] %s 不存在" % name) + continue + text = path.read_text(encoding="utf-8") + + if "_has(" in text and "def _has" in text: + print(" %s: 已经是新版" % name) + continue + + changed = 0 + for old, new in replacements: + if old in text: + text = text.replace(old, new, 1) + changed += 1 + if changed == 0: + print(" %s: 没找到要改的断言" % name) + continue + + text = ensure_import_re(text) + + # 把 _has 插到 "def check(" 前面 + marker = "def check(" + index = text.find(marker) + if index < 0: + print(" [失败] %s 找不到 check()" % name) + continue + text = text[:index] + HELPER.strip() + "\n\n\n" + text[index:] + + path.write_text(text, encoding="utf-8", newline="\n") + try: + ast.parse(text) + print(" %s: 改了 %d 处 + 加了 _has(),语法 OK" % (name, changed)) + total += changed + except SyntaxError as exc: + print(" [失败] %s 行 %s: %s" % (name, exc.lineno, exc.msg)) + + print() + print(" 共改 %d 处" % total) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/_tests/shots/1-屏幕中间.png b/_tests/shots/1-屏幕中间.png index 695c8db..04bcb0b 100644 Binary files a/_tests/shots/1-屏幕中间.png and b/_tests/shots/1-屏幕中间.png differ diff --git a/_tests/test_admin_batch_delete.py b/_tests/test_admin_batch_delete.py index 6fafece..5ddcb73 100644 --- a/_tests/test_admin_batch_delete.py +++ b/_tests/test_admin_batch_delete.py @@ -10,6 +10,7 @@ 6. 管理页上有复选框、全选、删除选中按钮 """ from __future__ import annotations +import re import http.cookiejar import json @@ -34,6 +35,23 @@ passed = 0 failed = 0 +def _has(html: str, token: str) -> bool: + """判断 html 里有没有这个属性,**带不带引号都算**。 + + 旧版页面写的是 class=pick(无引号), + 重做后改成了标准的 class="pick"(带引号)。 + 测试不该因为引号差异就报失败 —— HTML 两种都合法。 + """ + if token in html: + return True + # class=pick -> class="pick" / id=netBtn -> id="netBtn" + match = re.match(r"^([A-Za-z-]+)=(.+)$", token) + if not match: + return False + attr, value = match.group(1), match.group(2) + return ('%s="%s"' % (attr, value)) in html + + def check(name, ok, detail=""): global passed, failed if ok: @@ -120,9 +138,9 @@ def main() -> int: print("一、管理页上有批量删除的控件") html = opener.open(urllib.request.Request(BASE + "/zhongzhuanzhan", headers=_UA), timeout=15).read().decode("utf-8") - check("有复选框(input.pick)", "class=pick" in html) - check("有全选(pickAll)", "id=pickAll" in html) - check("有「删除选中」按钮", "id=delPicked" in html) + check("有复选框(input.pick)", _has(html, "class=pick")) + check("有全选(pickAll)", _has(html, "id=pickAll")) + check("有「删除选中」按钮", _has(html, "id=delPicked")) check("调的是 delete_many 接口", "/v1/admin/delete_many" in html) check("复选框的 value 是 deviceId", 'value="pc-1"' in html, "") diff --git a/_tests/test_admin_netcheck.py b/_tests/test_admin_netcheck.py index 4a30dc1..2ea7a3e 100644 --- a/_tests/test_admin_netcheck.py +++ b/_tests/test_admin_netcheck.py @@ -25,6 +25,23 @@ passed = 0 failed = 0 +def _has(html: str, token: str) -> bool: + """判断 html 里有没有这个属性,**带不带引号都算**。 + + 旧版页面写的是 class=pick(无引号), + 重做后改成了标准的 class="pick"(带引号)。 + 测试不该因为引号差异就报失败 —— HTML 两种都合法。 + """ + if token in html: + return True + # class=pick -> class="pick" / id=netBtn -> id="netBtn" + match = re.match(r"^([A-Za-z-]+)=(.+)$", token) + if not match: + return False + attr, value = match.group(1), match.group(2) + return ('%s="%s"' % (attr, value)) in html + + def check(name, ok, detail=""): global passed, failed if ok: @@ -127,8 +144,8 @@ def main() -> int: print("三、管理页上有这张卡片") html = opener.open(urllib.request.Request(BASE + "/zhongzhuanzhan", headers=UA), timeout=10).read().decode("utf-8") - check("有网络体检面板", 'id=netPanel' in html, "") - check("有「测一下」按钮", 'id=netBtn' in html, "") + check("有网络体检面板", _has(html, "id=netPanel"), "") + check("有「测一下」按钮", _has(html, "id=netBtn"), "") check("JS 里调 netcheck 接口", "/v1/admin/netcheck" in html, "") check("会显示隧道连接数", "tunnelConnections" in html, "") diff --git a/relay/admin.py b/relay/admin.py index 8fce63c..e7cb89d 100644 --- a/relay/admin.py +++ b/relay/admin.py @@ -601,7 +601,7 @@ def render_admin(snap: dict, public: str, admin_path: str, codes: int,
-
+

网络体检

看看这台机器是走局域网还是走隧道。
还没测过。