gpu-perf-prophet / tests /test_train_final.py
vxa8502's picture
Code cleanup
0623ff0
Raw
History Blame Contribute Delete
2.11 kB
"""Tests for src/models/train_final.py's `_load_validation_metrics`, using a synthetic tmp_path file rather than the real data/models/logo_cv_metrics.json so tests don't depend on notebooks/03 having been re-run recently."""
from __future__ import annotations
import json
import pytest
from src.models import train_final
from src.models.train_final import _load_validation_metrics
class TestLoadValidationMetrics:
def test_returns_none_when_file_absent(self, tmp_path):
missing = tmp_path / "logo_cv_metrics.json"
assert _load_validation_metrics(missing) is None
def test_returns_parsed_dict_when_present(self, tmp_path):
path = tmp_path / "logo_cv_metrics.json"
payload = {"primary": {"mape": 0.234, "smape": 0.212, "n_folds": 5}}
path.write_text(json.dumps(payload))
assert _load_validation_metrics(path) == payload
def test_default_path_does_not_raise(self):
# Whether or not the real file exists on this machine, calling with no argument must never raise — it's a best-effort informational read, not a hard requirement of train_and_save().
result = _load_validation_metrics()
assert result is None or isinstance(result, dict)
def test_refuses_symlinked_file(self, tmp_path):
"""Same guard predictor.py applies to feature_metadata.json/prophet_v1.json — a symlinked metrics file could point at attacker-controlled content committed into validation_metrics with no warning."""
real = tmp_path / "real.json"
real.write_text(json.dumps({"primary": {"mape": 0.0}}))
link = tmp_path / "link.json"
link.symlink_to(real)
with pytest.raises(ValueError, match="symlink"):
_load_validation_metrics(link)
def test_refuses_oversized_file(self, tmp_path, monkeypatch):
monkeypatch.setattr(train_final, "_MAX_VALIDATION_METRICS_BYTES", 10)
p = tmp_path / "logo_cv_metrics.json"
p.write_text(json.dumps({"primary": {"mape": 0.234}}))
with pytest.raises(ValueError, match="too large"):
_load_validation_metrics(p)