Files
ThothII/harness/tests/test_preprocess_cli.py
T

283 lines
9.2 KiB
Python

import json
from pathlib import Path
from types import SimpleNamespace
from typer.testing import CliRunner
from tht.cli import app
def _runtime_config(tmp_path: Path, name: str = "workspace.yaml") -> Path:
path = tmp_path / name
(tmp_path / "evidence").mkdir(exist_ok=True)
path.write_text(
f"""
runtime_identity:
workspace_id: psd-clinical
workspace_revision: {'a' * 40}
dwh:
type: postgres_direct
connection: {{database: analytics, schema: mart, user: reader, password: secret}}
vectors:
type: qdrant
base_url: http://qdrant:6333
collection: psd-clinical
embeddings:
provider: ollama_internal
base_url: http://embedding:11434
model: qwen3-embedding:0.6b
dim: 1024
evidence:
sources:
- type: filesystem
root: {tmp_path / 'evidence'}
roots:
sessions: {tmp_path / 'sessions'}
artifacts: {tmp_path / 'artifacts'}
indexes: {tmp_path / 'indexes'}
"""
)
return path
def test_preprocess_evidence_json_is_pristine(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
result = SimpleNamespace(
model_dump=lambda mode=None: {
"status": "succeeded",
"generation": "gen:abc",
"published": True,
"counts": {"changed": 0, "unchanged": 0, "removed": 0, "documents": 0, "chunks": 0},
"changed": [],
"unchanged": [],
"removed": [],
"manifest_id": "manifest-1",
"run_id": "a" * 32,
"resumed_from": None,
}
)
monkeypatch.setattr(command, "run_from_config", lambda *args, **kwargs: result)
response = CliRunner().invoke(app, ["preprocess", "evidence", "--json", "-c", str(config)])
assert response.exit_code == 0, response.output
assert response.stderr == ""
assert json.loads(response.stdout) == {
"changed": [],
"code": "ok",
"counts": {"changed": 0, "chunks": 0, "documents": 0, "removed": 0, "unchanged": 0},
"generation": "gen:abc",
"manifest_id": "manifest-1",
"operation": "preprocess_evidence",
"published": True,
"removed": [],
"resumed_from": None,
"run_id": "a" * 32,
"schemaVersion": 1,
"status": "succeeded",
"unchanged": [],
"workspaceId": "psd-clinical",
"workspaceRevision": "a" * 40,
}
def test_preprocess_failure_is_structured_and_nonzero(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
monkeypatch.setattr(
command,
"run_from_config",
lambda *a, **k: (_ for _ in ()).throw(RuntimeError("secret detail")),
)
response = CliRunner().invoke(app, ["preprocess", "evidence", "--json", "-c", str(config)])
assert response.exit_code != 0
payload = json.loads(response.stdout)
assert payload == {
"code": "preprocessing_failed",
"error": "preprocessing failed",
"operation": "preprocess_evidence",
"schemaVersion": 1,
"status": "failed",
"workspaceId": "psd-clinical",
"workspaceRevision": "a" * 40,
}
assert "secret detail" not in response.output
def test_preprocess_failed_job_report_is_sanitized_json_and_nonzero(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
result = SimpleNamespace(
model_dump=lambda mode=None: {
"status": "failed",
"run_id": "a" * 32,
"published": False,
"generation": "gen:" + "b" * 32,
"changed": ["fs:one"],
"unchanged": [],
"removed": [],
"counts": {"changed": 1, "unchanged": 0, "removed": 0, "documents": 1, "chunks": 1},
"manifest_id": "manifest-1",
"resumed_from": None,
}
)
monkeypatch.setattr(command, "run_from_config", lambda *args, **kwargs: result)
response = CliRunner().invoke(app, ["preprocess", "evidence", "--json", "-c", str(config)])
assert response.exit_code == 1
payload = json.loads(response.stdout)
assert payload["status"] == "failed"
assert payload["error"] == "preprocessing job failed"
assert payload["workspaceId"] == "psd-clinical"
assert "traceback" not in response.output.lower()
def test_preprocess_real_failed_stage_result_exits_nonzero(monkeypatch, tmp_path):
from test_corpus_pipeline import Source, item, pipeline
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
result = pipeline(
tmp_path,
Source([(item("one", "a"), RuntimeError("SENSITIVE EVIDENCE secret"))]),
).run_as_job(
workspace_id="demo",
workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
assert result.status == "failed"
monkeypatch.setattr(command, "run_from_config", lambda *args, **kwargs: result)
response = CliRunner().invoke(app, ["preprocess", "evidence", "--json", "-c", str(config)])
assert response.exit_code == 1
assert json.loads(response.stdout)["status"] == "failed"
assert "SENSITIVE EVIDENCE" not in response.output
assert "secret" not in response.output
def test_preprocess_evidence_text_uses_uncapped_result_counts(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
result = SimpleNamespace(
model_dump=lambda mode=None: {
"status": "succeeded",
"run_id": "a" * 32,
"generation": "gen:" + "b" * 64,
"published": True,
"changed": ["fs:item"] * 100,
"unchanged": ["fs:item"] * 100,
"removed": ["fs:item"] * 100,
"counts": {"changed": 1001, "unchanged": 902, "removed": 803},
"manifest_id": "manifest-1",
"resumed_from": None,
}
)
monkeypatch.setattr(command, "run_from_config", lambda *args, **kwargs: result)
response = CliRunner().invoke(app, ["preprocess", "evidence", "-c", str(config)])
assert response.exit_code == 0, response.output
assert "changed=1001 unchanged=902 removed=803" in response.output
def test_preprocess_resume_rejects_generation_id_before_configuration(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
called = False
def forbidden(*args, **kwargs):
nonlocal called
called = True
monkeypatch.setattr(command, "run_from_config", forbidden)
response = CliRunner().invoke(
app,
[
"preprocess",
"evidence",
"--resume",
"gen:" + "a" * 32,
"--json",
"-c",
str(config),
],
)
assert response.exit_code != 0
assert json.loads(response.output) == {
"code": "invalid_resume",
"error": "resume requires a preprocessing run id",
"operation": "preprocess_evidence",
"schemaVersion": 1,
"status": "failed",
}
assert called is False
def test_run_from_config_uses_runtime_identity_workspace_id(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path, name="3")
calls = {}
class FakePipeline:
def __init__(
self,
*,
store,
sources,
embedder,
vector_store,
embedding_model,
embedding_dimensions,
chunk_policy,
pipeline_version,
retain_published_generations,
sparse_language,
):
calls["init"] = {
"embedding_model": embedding_model,
"embedding_dimensions": embedding_dimensions,
"pipeline_version": pipeline_version,
"sparse_language": sparse_language,
}
def run_as_job(self, **kwargs):
calls["run_as_job"] = kwargs
return SimpleNamespace(model_dump=lambda mode=None: {"status": "succeeded"})
monkeypatch.setattr("tht.evidence.build_sources", lambda cfg: [])
monkeypatch.setattr(
"tht.evidence.build_preprocessing_pipeline",
lambda **kwargs: FakePipeline(**kwargs),
)
monkeypatch.setattr("tht.adapters.factory.build_vector_store", lambda cfg, require_write: object())
monkeypatch.setattr("tht.cli.vector_cmd.make_embedder", lambda cfg: object())
command.run_from_config(config)
assert calls["init"]["sparse_language"] == "english"
assert calls["run_as_job"]["workspace_id"] == "psd-clinical"
assert calls["run_as_job"]["input_fingerprint"] != calls["run_as_job"]["config_fingerprint"]
def test_preprocess_evidence_gc_json_is_pristine(monkeypatch, tmp_path):
import tht.cli.preprocess_cmd as command
config = _runtime_config(tmp_path)
monkeypatch.setattr(command, "gc_from_config", lambda *a, **k: {
"status": "succeeded",
"dry_run": True,
"evicted": [],
"failures": [],
})
response = CliRunner().invoke(
app,
["preprocess", "evidence", "gc", "--dry-run", "--json", "-c", str(config)],
)
assert response.exit_code == 0, response.output
assert json.loads(response.output)["dry_run"] is True