@furongjun1999/dsh-memory 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +552 -465
- package/docs/README.md +1 -0
- package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
- package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
- package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
- package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +100 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +197 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v1.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v10.md +210 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v11.md +227 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v12.md +203 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v13.md +233 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v14.md +191 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v15.md +213 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v16.md +214 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v17.md +199 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v2.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v3.md +152 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v4.md +128 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v5.md +114 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v6.md +192 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v7.md +187 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v8.md +207 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v9.md +203 -0
- package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +19 -3
- package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
- package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
- package/docs/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
- package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
- package/lib/bridge.d.ts +9 -0
- package/lib/bridge.js +35 -0
- package/lib/index.js +7 -1
- package/lib/lib/roleplay_web.js +530 -443
- package/lib/lib/token_store.d.ts +7 -1
- package/lib/lib/token_store.js +12 -3
- package/md_cg/audit.py +12 -1
- package/md_cg/backfill.py +16 -15
- package/md_cg/backfill_bucket_zh.py +35 -0
- package/md_cg/bench_e2e_judge.py +532 -0
- package/md_cg/bench_e2e_locomo_qa.py +368 -0
- package/md_cg/bench_e2e_qa.py +256 -0
- package/md_cg/branches.py +18 -2
- package/md_cg/ccgc.py +3 -2
- package/md_cg/chain.py +19 -4
- package/md_cg/consolidate.py +7 -6
- package/md_cg/crosscheck.py +4 -3
- package/md_cg/crypto.py +439 -437
- package/md_cg/datapath.py +395 -335
- package/md_cg/evidence.py +582 -580
- package/md_cg/export.py +3 -1
- package/md_cg/forgetting.py +2 -2
- package/md_cg/fsutil.py +48 -0
- package/md_cg/hotcache.py +255 -238
- package/md_cg/interop.py +161 -22
- package/md_cg/judgment_manifest.py +177 -0
- package/md_cg/links.py +655 -622
- package/md_cg/mcp_server.py +280 -29
- package/md_cg/mdcg.py +616 -125
- package/md_cg/mdcos.py +430 -66
- package/md_cg/mreview/govern.py +5 -4
- package/md_cg/postings.py +4 -2
- package/md_cg/readcache.py +76 -18
- package/md_cg/reconcile.py +228 -0
- package/md_cg/review_cli.py +170 -0
- package/md_cg/routing.py +28 -0
- package/md_cg/run_tests.py +211 -0
- package/md_cg/scrub.py +862 -852
- package/md_cg/security.py +385 -275
- package/md_cg/selfreport.py +3 -2
- package/md_cg/signer.py +565 -562
- package/md_cg/sources.py +3 -2
- package/md_cg/stg.py +6 -0
- package/md_cg/sustain.py +1168 -1138
- package/md_cg/test_access_hints.py +147 -0
- package/md_cg/test_branch_discard_tombstone.py +136 -0
- package/md_cg/test_branches.py +259 -249
- package/md_cg/test_chain_read_isolate.py +168 -0
- package/md_cg/test_datapath_device_name.py +203 -0
- package/md_cg/test_emit_negtail_cache.py +156 -0
- package/md_cg/test_en_pipeline.py +186 -166
- package/md_cg/test_govern_directread.py +421 -0
- package/md_cg/test_i32_hotcache_env_key.py +218 -0
- package/md_cg/test_identity_attribution.py +228 -147
- package/md_cg/test_index_durability.py +238 -224
- package/md_cg/test_interop.py +4 -2
- package/md_cg/test_interop_judgment.py +228 -0
- package/md_cg/test_issue39_utf8_stdio.py +273 -0
- package/md_cg/test_links_concurrent_write.py +188 -0
- package/md_cg/test_merge_upsert.py +168 -0
- package/md_cg/test_n123_derive_expiry_chain.py +205 -0
- package/md_cg/test_n130_verify_falsified_protect.py +185 -0
- package/md_cg/test_n131_merge_gate.py +205 -0
- package/md_cg/test_p1x_ref_root.py +160 -0
- package/md_cg/test_p27_docindex.py +774 -765
- package/md_cg/test_p2_mcp.py +3 -0
- package/md_cg/test_p32_backfill.py +304 -298
- package/md_cg/test_p39_verify_flow.py +90 -50
- package/md_cg/test_p47_session_view.py +60 -25
- package/md_cg/test_propose_tail_index.py +157 -0
- package/md_cg/test_read_scope_b27.py +277 -0
- package/md_cg/test_readcache_default_on.py +168 -0
- package/md_cg/test_readcache_precise_inval.py +270 -0
- package/md_cg/test_readcache_prodpath.py +55 -7
- package/md_cg/test_reconcile_v0.py +294 -0
- package/md_cg/test_retr_s1.py +6 -2
- package/md_cg/test_retr_s1b.py +67 -0
- package/md_cg/test_retr_s7.py +8 -0
- package/md_cg/test_retr_s9_entity_ctx.py +181 -175
- package/md_cg/test_retr_score_once.py +208 -0
- package/md_cg/test_review_onepass.py +170 -0
- package/md_cg/test_rrf_graph_seed_cache.py +154 -0
- package/md_cg/test_security_audit.py +155 -0
- package/md_cg/test_security_audit_b26.py +161 -0
- package/md_cg/test_security_audit_v21.py +250 -0
- package/md_cg/test_semantic_canonical.py +255 -241
- package/md_cg/test_session_isolation.py +168 -0
- package/md_cg/test_snapshot_autoclose.py +187 -0
- package/md_cg/test_tail_watermark_race.py +208 -0
- package/md_cg/test_tenant_env_override_warn.py +139 -0
- package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
- package/md_cg/test_v14_fixes.py +415 -397
- package/md_cg/test_verify_dirty_reconcile.py +157 -0
- package/md_cg/theory.py +276 -273
- package/md_cg/tokens.py +734 -677
- package/md_cg/units.py +3 -2
- package/md_cg/vision_evidence.py +4 -3
- package/md_cg/whitebox_kb/wisdom/code_solidified.json +6195 -6195
- package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
- package/md_cg/writepipe.py +554 -550
- package/package.json +6 -2
- package/src/bridge.ts +434 -401
- package/src/index.ts +526 -518
- package/src/lib/roleplay_web.ts +1019 -932
- package/src/lib/token_store.ts +202 -192
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""run_tests.py · 测试一键入口(固化 `python -m` 运行约定)。
|
|
3
|
+
|
|
4
|
+
背景(2026-09-13 全面分析报告建议 #3):md_cg 包内测试普遍使用**相对导入**,
|
|
5
|
+
必须以模块方式从仓库根运行——`python -m md_cg.test_xxx`;直接
|
|
6
|
+
`python md_cg/test_xxx.py` 会因相对导入 ImportError(59/61 踩坑实测)。
|
|
7
|
+
本脚本把该约定固化为唯一入口,杜绝逐文件手敲与跑法漂移。
|
|
8
|
+
|
|
9
|
+
**本模块是包内入口**(2026-09-24 修复):原入口只在 `scripts/run_tests.py`,
|
|
10
|
+
而出货包 `files` 不含 `scripts/` —— README 写的门禁命令在安装态不存在。
|
|
11
|
+
现在 `python -m md_cg.run_tests` 恒可用;源码树里 `scripts/run_tests.py`
|
|
12
|
+
可继续作为薄封装(同一约定)。
|
|
13
|
+
|
|
14
|
+
与 scripts/ 版的两点差异(都是为了在受限宿主里可跑):
|
|
15
|
+
① 子进程输出**重定向到文件**,不用 capture_output(管道):DSH 文件沙箱
|
|
16
|
+
禁 CreatePipe(WinError 5),旧写法在受限环境里每个用例都 PermissionError
|
|
17
|
+
——表现为「全部失败」,与代码无关。日志落在 `<testlogs>/` 便于事后查。
|
|
18
|
+
② 组集合按**存在性**发现:compiler / swarm / scripts / hive 不在(安装态)
|
|
19
|
+
就自然没有目标,不报错。
|
|
20
|
+
|
|
21
|
+
用法(任意 cwd 均可,内部以本包所在仓根为 subprocess cwd):
|
|
22
|
+
python -m md_cg.run_tests # 全量(存在的组)
|
|
23
|
+
python -m md_cg.run_tests md_cg # 只跑一组:md_cg | compiler | swarm | scripts | hive
|
|
24
|
+
python -m md_cg.run_tests -k p44 # 按关键字过滤模块名
|
|
25
|
+
python -m md_cg.run_tests --jobs 1 # 串行(默认并发 4)
|
|
26
|
+
python -m md_cg.run_tests --list # 只列出目标不执行
|
|
27
|
+
|
|
28
|
+
退出码:全部通过 0,存在失败 1(可直接接 CI / 提交前门禁)。
|
|
29
|
+
"""
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import argparse
|
|
33
|
+
import concurrent.futures
|
|
34
|
+
import glob
|
|
35
|
+
import os
|
|
36
|
+
import subprocess
|
|
37
|
+
import sys
|
|
38
|
+
import tempfile
|
|
39
|
+
import time
|
|
40
|
+
|
|
41
|
+
_REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
42
|
+
#: 逐用例日志目录(重定向目标;默认临时目录,避免污染仓)
|
|
43
|
+
_LOG_DIR = os.environ.get("MDCG_TESTLOG_DIR") or os.path.join(
|
|
44
|
+
tempfile.gettempdir(), "md_cg_testlogs")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _discover():
|
|
48
|
+
"""返回 [(组名, 显示名, argv 候选列表)];argv 依次尝试直到成功启动。"""
|
|
49
|
+
out = []
|
|
50
|
+
for f in sorted(glob.glob(os.path.join(_REPO, "md_cg", "test_*.py"))):
|
|
51
|
+
stem = os.path.splitext(os.path.basename(f))[0]
|
|
52
|
+
out.append(("md_cg", f"md_cg.{stem}",
|
|
53
|
+
[[sys.executable, "-X", "utf8", "-m", f"md_cg.{stem}"]]))
|
|
54
|
+
for pkg in ("compiler", "swarm"):
|
|
55
|
+
for f in sorted(glob.glob(os.path.join(_REPO, pkg, "tests", "*.py"))):
|
|
56
|
+
if os.path.basename(f).startswith("_"):
|
|
57
|
+
continue
|
|
58
|
+
stem = os.path.splitext(os.path.basename(f))[0]
|
|
59
|
+
out.append((pkg, f"{pkg}.tests.{stem}",
|
|
60
|
+
[[sys.executable, "-X", "utf8", "-m",
|
|
61
|
+
f"{pkg}.tests.{stem}"],
|
|
62
|
+
[sys.executable, "-X", "utf8", f]]))
|
|
63
|
+
# scripts/ 不是包(无 __init__.py)→ 只能直跑;脚本内自带 sys.path 注入
|
|
64
|
+
for f in sorted(glob.glob(os.path.join(_REPO, "scripts", "test_*.py"))):
|
|
65
|
+
stem = os.path.splitext(os.path.basename(f))[0]
|
|
66
|
+
out.append(("scripts", f"scripts.{stem}",
|
|
67
|
+
[[sys.executable, "-X", "utf8", f]]))
|
|
68
|
+
# hive/ 是包 → -m 优先;测试内用 importlib 直载,故回退直跑同样可用。
|
|
69
|
+
for f in sorted(glob.glob(os.path.join(_REPO, "hive", "test_*.py"))):
|
|
70
|
+
stem = os.path.splitext(os.path.basename(f))[0]
|
|
71
|
+
out.append(("hive", f"hive.{stem}",
|
|
72
|
+
[[sys.executable, "-X", "utf8", "-m", f"hive.{stem}"],
|
|
73
|
+
[sys.executable, "-X", "utf8", f]]))
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# 生效条件:name/argvs/timeout 就绪时逐个 argv 尝试运行(cwd=_REPO,stdout+stderr 重定向到 _LOG_DIR/<name>.log,无管道),返回 (name, 是否通过, 日志尾部最多 800 字符);超时返回 (name, False, "超时(>Ns)");首个成功启动(非「No module named」回退)的尝试决定结果。
|
|
78
|
+
def _run_one(name, argvs, timeout):
|
|
79
|
+
"""跑一个用例;输出**重定向到文件**(不用管道——沙箱禁 CreatePipe)。"""
|
|
80
|
+
os.makedirs(_LOG_DIR, exist_ok=True)
|
|
81
|
+
env = dict(os.environ, PYTHONUTF8="1", PYTHONIOENCODING="utf-8")
|
|
82
|
+
last = ""
|
|
83
|
+
for argv in argvs: # -m 优先;No module named 时回退直跑
|
|
84
|
+
log = os.path.join(_LOG_DIR, name.replace(".", "_") + ".log")
|
|
85
|
+
t0 = time.time()
|
|
86
|
+
try:
|
|
87
|
+
with open(log, "wb") as fh:
|
|
88
|
+
p = subprocess.run(argv, cwd=_REPO, stdout=fh,
|
|
89
|
+
stderr=subprocess.STDOUT,
|
|
90
|
+
stdin=subprocess.DEVNULL, env=env,
|
|
91
|
+
shell=False, timeout=timeout)
|
|
92
|
+
rc = p.returncode
|
|
93
|
+
except subprocess.TimeoutExpired:
|
|
94
|
+
return name, False, f"超时(>{timeout}s)—— 日志 {log}"
|
|
95
|
+
except OSError as exc:
|
|
96
|
+
return name, False, f"无法启动子进程:{exc!r}(日志 {log})"
|
|
97
|
+
try:
|
|
98
|
+
with open(log, encoding="utf-8", errors="replace") as fh:
|
|
99
|
+
text = fh.read()
|
|
100
|
+
except OSError:
|
|
101
|
+
text = ""
|
|
102
|
+
if rc != 0 and "No module named" in text and len(argvs) > 1:
|
|
103
|
+
last = text[-300:]
|
|
104
|
+
continue
|
|
105
|
+
tail = text[-800:]
|
|
106
|
+
return name, rc == 0, f"[{time.time() - t0:.1f}s] " + tail
|
|
107
|
+
return name, False, last
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _dep_db():
|
|
111
|
+
p = os.path.join(_REPO, "md_cg", "whitebox_kb", "wisdom",
|
|
112
|
+
"wisdom-book-cloud.db")
|
|
113
|
+
return (None if os.path.exists(p)
|
|
114
|
+
else "依赖白箱库 whitebox_kb/wisdom/wisdom-book-cloud.db"
|
|
115
|
+
"(.gitignore 忽略,需本地生成)")
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _dep_mdroot():
|
|
119
|
+
"""md 语料真源依赖:目录存在**且含 .md** 才算就绪。
|
|
120
|
+
|
|
121
|
+
空壳目录不算(v14 缺陷 F:旁路执行造出的空 `_md_cg_wisdom_graph/` 曾把
|
|
122
|
+
runner 从 SKIP 翻成 FAIL)——判据必须与 test_md_access_parity 同口径。
|
|
123
|
+
"""
|
|
124
|
+
p = os.path.join(_REPO, "_md_cg_wisdom_graph")
|
|
125
|
+
if not os.path.isdir(p):
|
|
126
|
+
return ("依赖 md 语料真源 _md_cg_wisdom_graph/(.gitignore 忽略,"
|
|
127
|
+
"组 D 需本地真源)")
|
|
128
|
+
for _dirpath, _dirs, names in os.walk(p):
|
|
129
|
+
if any(n.endswith(".md") for n in names):
|
|
130
|
+
return None
|
|
131
|
+
return ("依赖 md 语料真源 _md_cg_wisdom_graph/(目录在但零 .md:"
|
|
132
|
+
"空壳目录不算依赖就绪)")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# 裸 clone 环境 SKIP 探测(2026-09-14 外部复核建议 #3):
|
|
136
|
+
# 依赖 gitignored 本地数据或特定平台的测试,依赖缺失时标 SKIP(附原因)
|
|
137
|
+
# 不计入失败——避免裸 clone 用户第一眼看到虚假 FAIL(复核实测 83/87 根因)。
|
|
138
|
+
_SKIPS = {
|
|
139
|
+
"md_cg.test_p44_md_whitebox": _dep_db,
|
|
140
|
+
"md_cg.test_md_access_parity": _dep_db,
|
|
141
|
+
"md_cg.test_wisdom_md_store": _dep_mdroot,
|
|
142
|
+
"swarm.tests.test_swarm_fault": (
|
|
143
|
+
lambda: None if os.name == "nt"
|
|
144
|
+
else "Windows 专用(powershell/taskkill)"),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# 生效条件:argv 就绪时解析组/-k/--jobs/--timeout/--list 参数,按 _discover() 与 _SKIPS 过滤后并发执行,打印 PASS/FAIL/SKIP 与汇总;全部通过返回 0、有失败返回 1、--list 恒返回 0。
|
|
149
|
+
def main(argv=None):
|
|
150
|
+
ap = argparse.ArgumentParser(
|
|
151
|
+
prog="python -m md_cg.run_tests",
|
|
152
|
+
description="灵枢测试入口(python -m 约定;输出重定向,沙箱安全)")
|
|
153
|
+
# 注:不用 argparse choices——部分 Python 版本对 nargs="*" 无值时
|
|
154
|
+
# 以空列表过 choices 校验会误报 invalid choice(bpo-27227 老行为)。
|
|
155
|
+
ap.add_argument("group", nargs="*", default=None,
|
|
156
|
+
help="只跑指定组,可多选:md_cg compiler swarm scripts hive"
|
|
157
|
+
"(缺省全量)")
|
|
158
|
+
ap.add_argument("-k", default="", help="按关键字过滤模块名")
|
|
159
|
+
ap.add_argument("--jobs", type=int, default=4, help="并发数(默认 4)")
|
|
160
|
+
ap.add_argument("--timeout", type=int, default=900, help="单测超时秒数")
|
|
161
|
+
ap.add_argument("--list", action="store_true", help="只列出目标不执行")
|
|
162
|
+
args = ap.parse_args(argv)
|
|
163
|
+
|
|
164
|
+
_known = ("md_cg", "compiler", "swarm", "scripts", "hive")
|
|
165
|
+
_bad = [g for g in (args.group or ()) if g not in _known]
|
|
166
|
+
if _bad:
|
|
167
|
+
ap.error(f"invalid group: {', '.join(_bad)}(可选:{'/'.join(_known)})")
|
|
168
|
+
groups = set(args.group or ()) or set(_known)
|
|
169
|
+
targets = [(g, n, a) for g, n, a in _discover()
|
|
170
|
+
if g in groups and (not args.k or args.k in n)]
|
|
171
|
+
if args.list:
|
|
172
|
+
for g, n, _a in targets:
|
|
173
|
+
print(f"{g:<9}{n}")
|
|
174
|
+
print(f"共 {len(targets)} 个")
|
|
175
|
+
return 0
|
|
176
|
+
|
|
177
|
+
# SKIP 探测:依赖缺失/平台不符的测试不执行(外部复核建议 #3,裸 clone 友好)
|
|
178
|
+
skipped, runnable = [], []
|
|
179
|
+
for g, n, a in targets:
|
|
180
|
+
probe = _SKIPS.get(n)
|
|
181
|
+
reason = probe() if probe else None
|
|
182
|
+
if reason:
|
|
183
|
+
skipped.append((n, reason))
|
|
184
|
+
print(f"SKIP {n} ({reason})", flush=True)
|
|
185
|
+
else:
|
|
186
|
+
runnable.append((g, n, a))
|
|
187
|
+
|
|
188
|
+
bad = []
|
|
189
|
+
with concurrent.futures.ThreadPoolExecutor(
|
|
190
|
+
max_workers=max(1, args.jobs)) as ex:
|
|
191
|
+
futs = {ex.submit(_run_one, n, a, args.timeout): (g, n)
|
|
192
|
+
for g, n, a in runnable}
|
|
193
|
+
for fu in concurrent.futures.as_completed(futs):
|
|
194
|
+
name, ok, tail = fu.result()
|
|
195
|
+
print(("PASS " if ok else "FAIL ") + name, flush=True)
|
|
196
|
+
if not ok:
|
|
197
|
+
bad.append(name)
|
|
198
|
+
for ln in tail.splitlines()[-6:]:
|
|
199
|
+
print(" " + ln, flush=True)
|
|
200
|
+
|
|
201
|
+
print(f"\n===== SUMMARY {len(runnable) - len(bad)}/{len(runnable)} 通过,"
|
|
202
|
+
f"{len(skipped)} 跳过(依赖缺失/平台不符) =====")
|
|
203
|
+
print(f"逐用例日志:{_LOG_DIR}")
|
|
204
|
+
if bad:
|
|
205
|
+
print("失败:" + ", ".join(bad))
|
|
206
|
+
return 1
|
|
207
|
+
return 0
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
if __name__ == "__main__":
|
|
211
|
+
sys.exit(main())
|