fix(preprocess): publish DWH artifacts atomically
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from typer.testing import CliRunner
|
||||
|
||||
@@ -22,8 +23,8 @@ def test_selected_dwh_stages_run_in_declared_order(tmp_path):
|
||||
workspace_root=tmp_path,
|
||||
config_fingerprint=FP,
|
||||
input_fingerprint=FP,
|
||||
introspect=lambda: calls.append("introspect"),
|
||||
build_lsh=lambda: calls.append("lsh"),
|
||||
introspect=lambda output: (calls.append("introspect"), output.write_text("catalog")),
|
||||
build_lsh=lambda physical, output: _write_lsh(calls, physical, output),
|
||||
)
|
||||
|
||||
report = pipeline.run(("introspect", "lsh"))
|
||||
@@ -31,6 +32,19 @@ def test_selected_dwh_stages_run_in_declared_order(tmp_path):
|
||||
assert report.status == "succeeded"
|
||||
assert calls == ["introspect", "lsh"]
|
||||
assert [stage.name for stage in report.stages] == ["introspect", "lsh"]
|
||||
active = (tmp_path / ".tht-dwh" / "ACTIVE").read_text().strip()
|
||||
published = tmp_path / ".tht-dwh" / "generations" / active
|
||||
assert (published / "physical.yaml").read_text() == "catalog"
|
||||
assert sorted(path.name for path in published.iterdir()) == [
|
||||
"demo_lsh.pkl", "demo_meta.json", "demo_minhashes.pkl", "physical.yaml"
|
||||
]
|
||||
|
||||
|
||||
def _write_lsh(calls, physical: Path, output: Path):
|
||||
calls.append("lsh")
|
||||
assert physical.read_text() == "catalog"
|
||||
for name in ("demo_lsh.pkl", "demo_minhashes.pkl", "demo_meta.json"):
|
||||
(output / name).write_text(name)
|
||||
|
||||
|
||||
def test_preprocess_dwh_json_is_pristine(monkeypatch, tmp_path):
|
||||
@@ -81,3 +95,47 @@ def test_preprocess_dwh_rejects_unknown_or_duplicate_steps(monkeypatch, tmp_path
|
||||
assert response.exit_code == 2
|
||||
assert json.loads(response.output)["status"] == "failed"
|
||||
assert called is False
|
||||
|
||||
|
||||
def test_failed_multi_file_build_never_replaces_active_generation(tmp_path):
|
||||
def catalog(output):
|
||||
output.write_text("old-catalog")
|
||||
|
||||
first = DwhPreprocessPipeline(
|
||||
workspace_id="demo", workspace_root=tmp_path,
|
||||
config_fingerprint=FP, input_fingerprint=FP,
|
||||
introspect=catalog,
|
||||
build_lsh=lambda physical, output: [
|
||||
(output / name).write_text(name)
|
||||
for name in ("demo_lsh.pkl", "demo_minhashes.pkl", "demo_meta.json")
|
||||
],
|
||||
).run(("introspect", "lsh"))
|
||||
assert first.status == "succeeded"
|
||||
old_active = (tmp_path / ".tht-dwh" / "ACTIVE").read_text()
|
||||
|
||||
def partial_lsh(physical, output):
|
||||
(output / "demo_lsh.pkl").write_text("new-but-partial")
|
||||
raise RuntimeError("crash between LSH files")
|
||||
|
||||
failed = DwhPreprocessPipeline(
|
||||
workspace_id="demo", workspace_root=tmp_path,
|
||||
config_fingerprint=FP, input_fingerprint=FP,
|
||||
introspect=lambda output: output.write_text("new-catalog"),
|
||||
build_lsh=partial_lsh,
|
||||
).run(("introspect", "lsh"))
|
||||
|
||||
assert failed.status == "failed"
|
||||
assert (tmp_path / ".tht-dwh" / "ACTIVE").read_text() == old_active
|
||||
|
||||
resumed = DwhPreprocessPipeline(
|
||||
workspace_id="demo", workspace_root=tmp_path,
|
||||
config_fingerprint=FP, input_fingerprint=FP,
|
||||
introspect=lambda output: (_ for _ in ()).throw(
|
||||
AssertionError("completed introspection must not repeat")
|
||||
),
|
||||
build_lsh=lambda physical, output: [
|
||||
(output / name).write_text("recovered")
|
||||
for name in ("demo_lsh.pkl", "demo_minhashes.pkl", "demo_meta.json")
|
||||
],
|
||||
).run(("introspect", "lsh"), resume_run_id=failed.run_id)
|
||||
assert resumed.status == "succeeded"
|
||||
|
||||
Reference in New Issue
Block a user