Files
Open_Ultra_SAST/tests/test_hunt_artifact.py
T

166 lines
5.8 KiB
Python

"""Checks for stable run records and budget accounting."""
import errno
import json
import os
import stat
from concurrent.futures import ThreadPoolExecutor
import pytest
from openultrasast.hunt import artifact as artifact_module
from openultrasast.hunt.artifact import MAX_ATTEMPT_ORDINAL, RunArtifact, UsageLedger
def artifact():
return RunArtifact(
program_id="program",
schema_version=1,
mask=("source",),
data_digests={"train": "abc"},
configurations=[{"seed": 0}],
usage={"usd": 0.1, "calls": 1, "replay_hits": 0, "wall_seconds": 2},
versions={"dspy": "3.4.0", "litellm": "1", "openultrasast": "2.0.1"},
created="2026-10-13T00:00:00Z",
)
def test_artifact_round_trip_and_tamper(tmp_path):
run = artifact()
assert run.artifact_id == artifact().artifact_id
path = run.write(tmp_path)
assert RunArtifact.read(path) == run
payload = json.loads(path.read_text())
payload["program_id"] = "tampered"
path.write_text(json.dumps(payload))
with pytest.raises(ValueError, match="id"):
RunArtifact.read(path)
def test_artifact_persistence_is_create_only_and_idempotent(tmp_path):
run = artifact()
path = run.write(tmp_path)
before = (path.read_bytes(), path.stat().st_mtime_ns)
assert run.write(tmp_path) == path
assert (path.read_bytes(), path.stat().st_mtime_ns) == before
path.write_text("conflicting bytes\n")
with pytest.raises(ValueError, match="conflict"):
run.write(tmp_path)
def test_missing_attempt_sequence_fails_closed_when_artifacts_exist(tmp_path):
first = artifact()
first_path = first.write(tmp_path, reserve_attempt=True)
before = (first_path.read_bytes(), first_path.stat().st_mtime_ns)
(tmp_path / ".attempt-sequence").unlink()
resumed = artifact()
resumed.created = "2026-11-02T00:00:01+00:00"
with pytest.raises(ValueError, match="attempt sequence is missing"):
resumed.write(tmp_path, reserve_attempt=True)
assert (first_path.read_bytes(), first_path.stat().st_mtime_ns) == before
assert not (tmp_path / ".attempt-sequence").exists()
def test_attempt_ordinals_are_unique_under_concurrency_and_resume(tmp_path):
def persist(index):
run = artifact()
run.created = f"2026-11-02T00:00:{index:02d}+00:00"
run.write(tmp_path, reserve_attempt=True)
return run.attempt_ordinal
with ThreadPoolExecutor(max_workers=4) as pool:
ordinals = list(pool.map(persist, range(4)))
resumed = artifact()
resumed.created = "2026-11-02T00:01:00+00:00"
resumed.write(tmp_path, reserve_attempt=True)
assert sorted(ordinals) == [1, 2, 3, 4]
assert resumed.attempt_ordinal == 5
assert (tmp_path / ".attempt-sequence").read_text() == "5\n"
@pytest.mark.parametrize(("state", "message"), (("corrupt\n", "unreadable"), ("-1\n", "invalid")))
def test_corrupt_attempt_sequence_fails_closed(tmp_path, state, message):
(tmp_path / ".attempt-sequence").write_text(state)
with pytest.raises(ValueError, match=message):
artifact().write(tmp_path, reserve_attempt=True)
def test_attempt_sequence_allocates_the_signed_64_bit_maximum(tmp_path):
(tmp_path / ".attempt-sequence").write_text(f"{MAX_ATTEMPT_ORDINAL - 1}\n")
run = artifact()
run.write(tmp_path, reserve_attempt=True)
assert run.attempt_ordinal == MAX_ATTEMPT_ORDINAL
assert (tmp_path / ".attempt-sequence").read_text() == f"{MAX_ATTEMPT_ORDINAL}\n"
def test_attempt_sequence_refuses_overflow_without_mutation(tmp_path):
sequence = tmp_path / ".attempt-sequence"
sequence.write_text(f"{MAX_ATTEMPT_ORDINAL}\n")
before = (sequence.read_bytes(), sequence.stat().st_mtime_ns)
with pytest.raises(ValueError, match="exhausted"):
artifact().write(tmp_path, reserve_attempt=True)
assert (sequence.read_bytes(), sequence.stat().st_mtime_ns) == before
assert not list(tmp_path.glob("*.json"))
def test_attempt_sequence_and_artifact_creation_fsync_the_directory(tmp_path, monkeypatch):
real_fsync = os.fsync
directory_syncs = []
def recording_fsync(descriptor):
if stat.S_ISDIR(os.fstat(descriptor).st_mode):
directory_syncs.append(descriptor)
real_fsync(descriptor)
monkeypatch.setattr(artifact_module.os, "fsync", recording_fsync)
artifact().write(tmp_path, reserve_attempt=True)
assert len(directory_syncs) == 2
def test_directory_fsync_ignores_only_unsupported_platform_errors(tmp_path, monkeypatch):
def unsupported(_descriptor):
raise OSError(errno.EOPNOTSUPP, "unsupported")
monkeypatch.setattr(artifact_module.os, "fsync", unsupported)
artifact_module._sync_directory(tmp_path)
def io_failure(_descriptor):
raise OSError(errno.EIO, "I/O failure")
monkeypatch.setattr(artifact_module.os, "fsync", io_failure)
with pytest.raises(OSError, match="I/O failure"):
artifact_module._sync_directory(tmp_path)
def test_ledger_and_budget_prevent_artifact(tmp_path):
run = artifact()
ledger = UsageLedger(artifact=run)
ledger.add({"usd": 0.25, "calls": 1, "wall_seconds": 2})
ledger.add({"usd": 0, "replay_hits": 1, "wall_seconds": 1})
assert ledger.usage == {"usd": 0.25, "calls": 1, "replay_hits": 1, "wall_seconds": 3}
assert ledger.exhausted({"usd": 0.25, "calls": 10})
assert ledger.exhausted({"usd": 10, "calls": 1})
assert ledger.finish({"usd": 0.25}) is None
assert not list(tmp_path.iterdir())
result = ledger.finish({"usd": 1, "calls": 2})
assert result is run
assert result.usage == ledger.usage
assert run.finish({"usd": 0.25}) is None
assert run.write(tmp_path, budget={"usd": 0.25}) is None
assert not list(tmp_path.iterdir())
@pytest.mark.parametrize("value", [-1, float("nan"), float("inf")])
def test_invalid_usage_rejected(value):
with pytest.raises(ValueError):
UsageLedger().add({"usd": value})