Spaces:
Running
Running
stouchinglhh
Claude
sync processor from GitLab c697b6e: 版本 1.19.4 / 前端 1.12.4 —— 服务端 i18n(首屏不再闪英文)、推理模块并入模型页、前端抽出 shared/、缓存键改用前端号
bb59211 Download processor/tests/test_cleaning_glove.py from Stouching-Robotics/DataFlowing: direct link, hf CLI and curl.
- Browser
- Download file 8.8 kB
-
https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/tests/test_cleaning_glove.py
- Command line
-
hf download hf://spaces/Stouching-Robotics/DataFlowing/processor/tests/test_cleaning_glove.py
-
curl -L -o test_cleaning_glove.py https://huggingface.co/spaces/Stouching-Robotics/DataFlowing/resolve/main/processor/tests/test_cleaning_glove.py
8.8 kB
| """手套检查项 —— 每一项都必须**被证明能抓到失败**。 | |
| 真实数据上 5 项全绿(6 集、左右手各 5-6 条流、零误报)。但"全绿"证明不了什么: | |
| **检查项从来没触发过,和检查项根本跑不起来,报告长得一模一样。** 所以这里每条 | |
| 都构造一份明确的坏数据,断言它被抓到;再造一份好数据,断言不误报。 | |
| 阈值全部来自实测: | |
| * 阵列 16×16 = 256 维 | |
| * 取值门限 500(0 到 500 之间没有值) | |
| * 设备更新 ~7.5Hz → 受压时静止**恰好 4 帧**(正常,不是卡死) | |
| * 整集最低有 11.4% 的帧有压力 | |
| pytest tests/test_cleaning_glove.py | |
| python3 tests/test_cleaning_glove.py | |
| """ | |
| import sys | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # noqa: E402 | |
| from app.processing.cleaning.checks import ( # noqa: E402 | |
| CheckContext, StreamEvidence, applicable_checks, get_check, | |
| PASS, WARN, FAIL, | |
| ) | |
| SIZE = 256 | |
| # ── 构造 ──────────────────────────────────────────────────── | |
| def _frame(value: float = 0.0, size: int = SIZE) -> tuple: | |
| return tuple([value] * size) | |
| def _context(series: dict, *, channel="tactile", key="left_glove", | |
| fps=30.0) -> CheckContext: | |
| stream = StreamEvidence(key=key, channel=channel, series=series) | |
| return CheckContext(batch_dir=Path("/nonexistent"), fps=fps, streams=(stream,)) | |
| def _run(slug: str, ctx: CheckContext, params: dict | None = None): | |
| ctx.params = params or {} | |
| findings = get_check(slug).run(ctx) | |
| assert findings, f"{slug} 一条结论都没产出 —— 报告会显示为『没问题』" | |
| return findings | |
| def _only(slug, ctx, params=None): | |
| findings = _run(slug, ctx, params) | |
| statuses = {f.status for f in findings} | |
| assert len(statuses) == 1, f"期望单一结论,得到 {statuses}" | |
| return findings[0] | |
| # ── 可达性:检查项必须真的会被选中 ─────────────────────────── | |
| def test_glove_checks_are_applicable(): | |
| """★ 防"检查项静默不跑"—— 声明与闸门对不上时它们一条都不会执行。""" | |
| slugs = {c.slug for c in applicable_checks( | |
| channels={"tactile", "device_status", "time"}, | |
| modalities={"glove_sensor"})} | |
| for expected in ("glove.array_shape", "glove.device_status", | |
| "glove.frozen_array", "glove.gate_floor", | |
| "glove.no_contact"): | |
| assert expected in slugs, f"{expected} 在手套数据上不可达" | |
| def test_glove_checks_skip_other_devices(): | |
| """UMI 夹爪上不该跑手套检查 —— 设备卡片闸门要生效。""" | |
| slugs = {c.slug for c in applicable_checks( | |
| channels={"tactile", "slam", "time"}, modalities={"gripper_device"})} | |
| assert not any(s.startswith("glove.") for s in slugs) | |
| def test_device_status_check_needs_its_channel(): | |
| """没有状态列(老批次)时不该跑 —— 跑起来只会报"没数据"。""" | |
| slugs = {c.slug for c in applicable_checks( | |
| channels={"tactile", "time"}, modalities={"glove_sensor"})} | |
| assert "glove.device_status" not in slugs | |
| assert "glove.frozen_array" in slugs | |
| # ── 1. 连接状态 ───────────────────────────────────────────── | |
| def test_status_constant_connected_passes(): | |
| ctx = _context({"device_status": tuple(["connected"] * 100)}, channel="device_status") | |
| assert _only("glove.device_status", ctx).status is PASS | |
| def test_status_change_mid_recording_fails(): | |
| """★ 从"连着"变成别的 = 掉线,与状态词表无关,见到即拦。""" | |
| values = tuple(["connected"] * 50 + ["disconnected"] * 50) | |
| ctx = _context({"device_status": values}, channel="device_status") | |
| finding = _only("glove.device_status", ctx) | |
| assert finding.status is FAIL | |
| assert finding.metrics["first_change_frame"] == 50 | |
| def test_status_unknown_constant_only_warns(): | |
| """词表只见过 connected;别的取值不拦批次(拦错了比不拦更糟)。""" | |
| ctx = _context({"device_status": tuple(["ok"] * 100)}, channel="device_status") | |
| assert _only("glove.device_status", ctx).status is WARN | |
| def test_status_all_blank_warns(): | |
| ctx = _context({"device_status": tuple([""] * 100)}, channel="device_status") | |
| assert _only("glove.device_status", ctx).status is WARN | |
| # ── 2. 阵列完整性 ─────────────────────────────────────────── | |
| def test_shape_full_array_passes(): | |
| ctx = _context({"tactile": tuple([_frame()] * 50)}) | |
| assert _only("glove.array_shape", ctx).status is PASS | |
| def test_shape_catches_truncation(): | |
| """★ 正是那个真实踩过的 bug:256 维被静默截成 3 维。""" | |
| ctx = _context({"tactile": tuple([_frame(size=3)] * 500)}) | |
| finding = _only("glove.array_shape", ctx) | |
| assert finding.status is FAIL | |
| assert finding.metrics["bad_ratio"] == 1.0 | |
| assert finding.metrics["observed_sizes"] == [3] | |
| def test_shape_single_null_frame_only_warns(): | |
| """偶发一帧缺失不该拦住整批。""" | |
| values = [_frame(600.0)] * 999 + [()] | |
| ctx = _context({"tactile": tuple(values)}) | |
| assert _only("glove.array_shape", ctx).status is WARN | |
| # ── 3. 取值下限 ───────────────────────────────────────────── | |
| def test_gate_floor_normal_values_pass(): | |
| ctx = _context({"tactile": (_frame(0.0), _frame(508.09), _frame(1500.0))}) | |
| assert _only("glove.gate_floor", ctx).status is PASS | |
| def test_gate_floor_catches_encoding_change(): | |
| """★ 固件改成直接输出原始 ADC 时,值会掉到门限以下 —— 而别的检查全绿。""" | |
| values = [_frame(v) for v in (5.0, 20.0, 137.0, 400.0)] + [_frame(900.0)] | |
| ctx = _context({"tactile": tuple(values)}) | |
| finding = _only("glove.gate_floor", ctx) | |
| assert finding.status is FAIL | |
| assert finding.metrics["below_ratio"] == 0.8 | |
| def test_gate_floor_all_zero_is_not_its_business(): | |
| """整集全零是 glove.no_contact 的事,不在这里重复报。""" | |
| findings = get_check("glove.gate_floor").run(_context({"tactile": (_frame(),)})) | |
| assert findings == [] | |
| # ── 4. 阵列卡死 ───────────────────────────────────────────── | |
| def test_frozen_normal_device_rate_passes(): | |
| """★ 设备本来就每 4 帧才更新一次 —— 静止 4 帧是**正常**,不是卡死。""" | |
| values = [] | |
| for block in range(100): | |
| values.extend([_frame(600.0 + block)] * 4) | |
| ctx = _context({"tactile": tuple(values)}) | |
| assert _only("glove.frozen_array", ctx).status is PASS | |
| def test_frozen_detects_stall(): | |
| values = [_frame(600.0)] * 500 + [_frame(900.0)] * 10 | |
| ctx = _context({"tactile": tuple(values)}) | |
| finding = _only("glove.frozen_array", ctx) | |
| assert finding.status is FAIL # 500 帧 ≥ fail_frames(300) | |
| assert finding.metrics["longest_run_frames"] == 500 | |
| # 区间要能定位到哪儿卡了 | |
| assert finding.ranges and finding.ranges[0].start_frame == 0 | |
| def test_frozen_ignores_all_zero_stretches(): | |
| """★ 实测踩过的坑:全零段天然"完全相同",算进去会报出大片假区间。 | |
| 真实数据里一集有 88% 的帧全零,最长"静止"575 帧 —— 全部来自全零段。 | |
| """ | |
| values = [_frame(0.0)] * 800 + [_frame(600.0)] * 10 | |
| ctx = _context({"tactile": tuple(values)}) | |
| assert _only("glove.frozen_array", ctx).status is PASS | |
| def test_frozen_warn_threshold_between_normal_and_stall(): | |
| """40~300 帧是警告区(正常 4 帧,卡死 300+)。""" | |
| values = [_frame(600.0)] * 100 + [_frame(700.0)] * 10 | |
| ctx = _context({"tactile": tuple(values)}) | |
| assert _only("glove.frozen_array", ctx).status is WARN | |
| # ── 5. 无接触 ─────────────────────────────────────────────── | |
| def test_no_contact_with_pressure_passes(): | |
| ctx = _context({"tactile": (_frame(0.0), _frame(620.0))}) | |
| assert _only("glove.no_contact", ctx).status is PASS | |
| def test_no_contact_all_zero_warns(): | |
| ctx = _context({"tactile": tuple([_frame(0.0)] * 500)}) | |
| finding = _only("glove.no_contact", ctx) | |
| assert finding.status is WARN | |
| assert finding.metrics["active_frames"] == 0 | |
| if __name__ == "__main__": | |
| import pytest | |
| raise SystemExit(pytest.main([__file__, "-q"])) | |