修复 Studio 失败测试并新增合并门禁
把丢失的 box 录像放回 apps/studio/tests/data/,修掉第 3 节 3–10 号与两处过时测试桩, 注册 timing 标记并让根目录收集零错误;新增 tools/gate.ps1 与可选的 pre-push 钩子。 验证:studio 524 通过 19 跳过、shared 467 通过 18 跳过、ui_check 632 项 0 失败、gate.ps1 退出码 0。 细节见 docs/test-repair-plan.zh.md。
This commit is contained in:
@@ -18,7 +18,7 @@ chain — and assert on the picture the panel actually shows, not on a state a h
|
||||
built.
|
||||
|
||||
The recording is copied before use: a pass writes its result into the recording's own
|
||||
directory, and nothing may write into ``dist/``.
|
||||
directory, and the tracked copy the tests read must never be written to.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -34,11 +34,11 @@ from orisys_app_shared.acquisition.image_backend import (
|
||||
ARROW_PURE,
|
||||
ARROW_STITCHED,
|
||||
DEPTH,
|
||||
DEPTH_ARROWS,
|
||||
DERIVED_MODES,
|
||||
RECORDED,
|
||||
plan_image,
|
||||
)
|
||||
from orisys_app_shared.i18n import t
|
||||
from orisys_app_shared.scene3d.contracts import DisplaySettings
|
||||
from orisys_app_shared.scene3d.visual_policy import (
|
||||
select_flow_samples,
|
||||
@@ -46,14 +46,8 @@ from orisys_app_shared.scene3d.visual_policy import (
|
||||
from orisys_studio.replay import MODE_RECORDING
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
REPO = Path(__file__).resolve().parents[3]
|
||||
STUDIO = REPO / "dist" / "OrisysStudio"
|
||||
SOURCE_RECORDING = (
|
||||
STUDIO
|
||||
/ "outputs"
|
||||
/ "recordings"
|
||||
/ "20260930T015028Z_session0002_40cb8e7441434feab48bb646afdba011"
|
||||
)
|
||||
#: The tracking-visible test input (``data/README.md`` explains where it came from).
|
||||
DATA = Path(__file__).resolve().parent / "data" / "box_short_20260930"
|
||||
#: What makes a directory a recording for the application, and all a replay reads.
|
||||
RECORDING_FILES = (
|
||||
"frames.csv",
|
||||
@@ -61,29 +55,41 @@ RECORDING_FILES = (
|
||||
"events.csv",
|
||||
"session.json",
|
||||
"raw_0001.mp4",
|
||||
"preroll_0001.mp4",
|
||||
)
|
||||
#: Written by a recording and read by nothing a replay needs: ``preroll_segment()``
|
||||
#: answers ``None`` when the file is absent, so it is copied when it is there and never
|
||||
#: required. It stays out of the repository because it is a third of the data's size.
|
||||
OPTIONAL_FILES = ("preroll_0001.mp4",)
|
||||
|
||||
|
||||
def _require_recording() -> None:
|
||||
"""The recording must be here, and its absence is a failure, not a skip.
|
||||
|
||||
The old version skipped: the tests went green on a machine where the footage had
|
||||
been repackaged away, which is exactly how eleven failing tests went unnoticed.
|
||||
"""
|
||||
missing = [
|
||||
str(DATA / name) for name in RECORDING_FILES if not (DATA / name).is_file()
|
||||
]
|
||||
assert not missing, (
|
||||
"the replay wiring tests need the tracked box test recording at "
|
||||
f"{DATA}; missing: {', '.join(missing)}. It is committed "
|
||||
"(apps/studio/tests/data/README.md); restore it rather than skipping."
|
||||
)
|
||||
|
||||
|
||||
def _require_inputs() -> None:
|
||||
missing = [
|
||||
str(SOURCE_RECORDING / name)
|
||||
for name in ("frames.csv", "raw_0001.mp4", "session.json")
|
||||
if not (SOURCE_RECORDING / name).exists()
|
||||
]
|
||||
if missing:
|
||||
pytest.skip(
|
||||
"the replay wiring tests need the evidence recording: " + ", ".join(missing)
|
||||
)
|
||||
_require_recording()
|
||||
pytest.importorskip("orisys", reason="the analysis pass drives the SDK chain")
|
||||
|
||||
|
||||
def _copy_recording(destination: Path) -> Path:
|
||||
"""The evidence recording, copied: nothing may write into ``dist/``."""
|
||||
"""The test recording, copied: nothing may write into the tracked data."""
|
||||
_require_recording()
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
for name in RECORDING_FILES:
|
||||
source = SOURCE_RECORDING / name
|
||||
if source.exists():
|
||||
for name in RECORDING_FILES + OPTIONAL_FILES:
|
||||
source = DATA / name
|
||||
if source.is_file():
|
||||
shutil.copy2(source, destination / name)
|
||||
return destination
|
||||
|
||||
@@ -303,11 +309,16 @@ def test_the_operator_sees_the_cached_views_over_the_recording(
|
||||
"a pass ran over a recording that already had a result"
|
||||
)
|
||||
|
||||
# ``depth_arrows`` joined the derived views in ``091d0fd`` ("二维增加深度叠箭头"), which
|
||||
# updated ``ui_check`` and the live-view tests but not this one: it was skipping on the
|
||||
# missing footage at the time, so nothing caught it. The claim is unchanged — the
|
||||
# recording's own picture stays one step away from *every* derived view.
|
||||
assert window.arrow_panel.view_modes() == (
|
||||
RECORDED,
|
||||
ARROW_PURE,
|
||||
ARROW_STITCHED,
|
||||
DEPTH,
|
||||
DEPTH_ARROWS,
|
||||
), "the recording's own picture must stay one step away from the derived views"
|
||||
assert window.arrow_panel.view_mode() in DERIVED_MODES, (
|
||||
"the operator was left on the camera picture although a result is served"
|
||||
@@ -343,14 +354,22 @@ def test_the_operator_sees_the_cached_views_over_the_recording(
|
||||
"the arrow view is the recording's raw picture"
|
||||
)
|
||||
|
||||
# The depth view is the stored map, drawn through the window's own backend. This
|
||||
# result's map is exactly zero on every frame it holds — the box chain's depth is
|
||||
# flat on this footage — and it is still a stored array of the result's own shape,
|
||||
# so the pixels are checked against it rather than against a flat placeholder.
|
||||
# The depth view is the stored map, drawn through the window's own backend. The
|
||||
# map is this result's own array of the result's own shape, so the pixels are checked
|
||||
# against it rather than against a placeholder.
|
||||
#
|
||||
# It is **not** all-zero, which is what this asserted when the recording was first
|
||||
# played (a "flat depth" note): measured on the restored footage with the shipped box
|
||||
# config, the stored map has 8926 non-zero cells of 365², i.e. the chain does return
|
||||
# a depth field here. Flatness was a property of an earlier run's result, not a
|
||||
# product promise; the claim this block exists for — the depth view's pixels are
|
||||
# ``depth_map_to_bgr`` of the stored frame — is asserted below and is unchanged.
|
||||
# The colour-scale caption names the range only.
|
||||
_set_mode(window, DEPTH)
|
||||
target = active_frame
|
||||
assert target.depth is not None and target.depth_nonzero == 0
|
||||
assert target.depth is not None and target.depth_nonzero > 0, (
|
||||
f"the stored depth map holds no value at all: {target.depth_nonzero} non-zero cells"
|
||||
)
|
||||
QApplication.processEvents()
|
||||
drawn = captured[-1]
|
||||
assert drawn.frame_id == target.frame_id
|
||||
|
||||
Reference in New Issue
Block a user