sentinel / tests /test_watcher.py
samarthmishra46's picture
Sentinel V2 — HF deploy snapshot (full stack, DeBERTa on)
1788dab
Raw
History Blame Contribute Delete
1.73 kB
"""Tests for the policy hot-reload watcher."""
from __future__ import annotations
import os
import shutil
from pathlib import Path
from app.policy.store import PolicyStore
from app.policy.watcher import PolicyWatcher
REAL_BUNDLE = Path(__file__).resolve().parents[1] / "policies" / "v1"
def _temp_bundle(tmp_path: Path) -> Path:
dest = tmp_path / "v1"
shutil.copytree(REAL_BUNDLE, dest)
return dest
def test_poll_no_change_returns_false(tmp_path: Path) -> None:
bundle = _temp_bundle(tmp_path)
store = PolicyStore(bundle_path=bundle)
watcher = PolicyWatcher(store, bundle_path=bundle)
assert watcher.poll_once() is False
def test_poll_reloads_on_change(tmp_path: Path) -> None:
bundle = _temp_bundle(tmp_path)
store = PolicyStore(bundle_path=bundle)
assert "R-01" in store.active.catalog
watcher = PolicyWatcher(store, bundle_path=bundle)
# Rewrite the catalog with a distinct rule and force a newer mtime.
catalog = bundle / "catalog.yaml"
catalog.write_text('policies:\n - id: "R-99"\n disposition: STOP\n', encoding="utf-8")
future = catalog.stat().st_mtime + 10
os.utime(catalog, (future, future))
assert watcher.poll_once() is True # change detected -> reloaded
assert "R-99" in store.active.catalog # new policy is live
assert "R-01" not in store.active.catalog # old policy swapped out
def test_start_stop_is_clean(tmp_path: Path) -> None:
bundle = _temp_bundle(tmp_path)
store = PolicyStore(bundle_path=bundle)
watcher = PolicyWatcher(store, bundle_path=bundle, interval=0.01)
watcher.start()
watcher.start() # idempotent — second start is a no-op
watcher.stop() # must not raise