feat(tests): add comprehensive unit test suite for variables, strategy modulation, and loop health
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
test_modulate_strategy.py — Unit and integration tests for:
|
||||
1. Hierarchical override scoping:
|
||||
(input_type, subtype, agent) -> (input_type, None, agent) ->
|
||||
(input_type, subtype, None) -> (input_type, None, None) -> Builtin table
|
||||
2. Dynamic strategy evaluation (`modulate.py eval` / `box-ctl.py strat-get`)
|
||||
3. Atomic persistence to strategy.json
|
||||
4. Override resets and isolation across input types
|
||||
"""
|
||||
import unittest
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path("/home/super/Projects/NetVM")
|
||||
BIN_DIR = REPO_ROOT / "bin"
|
||||
BOX_CTL = BIN_DIR / "box-ctl.py"
|
||||
|
||||
sys.path.insert(0, str(BIN_DIR))
|
||||
import modulate
|
||||
|
||||
|
||||
class TestModulationHierarchy(unittest.TestCase):
|
||||
"""Test strategy lookup cascade and overrides."""
|
||||
|
||||
def setUp(self):
|
||||
self.tmp_dir = tempfile.mkdtemp()
|
||||
self.strat_file = str(Path(self.tmp_dir) / "strategy.json")
|
||||
self.orig_default = modulate.DEFAULT_STRATEGY_FILE
|
||||
self.orig_fallback = modulate.FALLBACK_STRATEGY_FILE
|
||||
modulate.DEFAULT_STRATEGY_FILE = self.strat_file
|
||||
modulate.FALLBACK_STRATEGY_FILE = self.strat_file
|
||||
|
||||
def tearDown(self):
|
||||
modulate.DEFAULT_STRATEGY_FILE = self.orig_default
|
||||
modulate.FALLBACK_STRATEGY_FILE = self.orig_fallback
|
||||
shutil.rmtree(self.tmp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def test_builtin_fallback(self):
|
||||
# Default builtin policy for manual DMs
|
||||
pol = modulate.modulate(modulate.InputType.MANUAL, agent="646")
|
||||
self.assertIsNotNone(pol)
|
||||
self.assertTrue(pol.track)
|
||||
self.assertEqual(pol.timeout_s, 3600)
|
||||
|
||||
def test_agent_specific_override(self):
|
||||
# Set override for agent 'pip' on 'manual'
|
||||
modulate.set_strategy_override(
|
||||
"manual",
|
||||
None,
|
||||
"pip",
|
||||
track=False,
|
||||
timeout_s=1800,
|
||||
nudges=0,
|
||||
escalate="none",
|
||||
)
|
||||
|
||||
# Pip gets the custom override (track=False -> modulate returns None)
|
||||
pip_pol = modulate.modulate(modulate.InputType.MANUAL, agent="pip")
|
||||
self.assertIsNone(pip_pol)
|
||||
|
||||
# 646 gets the default builtin policy
|
||||
other_pol = modulate.modulate(modulate.InputType.MANUAL, agent="646")
|
||||
self.assertTrue(other_pol.track)
|
||||
self.assertEqual(other_pol.timeout_s, 3600)
|
||||
|
||||
|
||||
def test_subtype_hierarchical_resolution(self):
|
||||
# Set type-level default
|
||||
modulate.set_strategy_override("health", None, None, timeout_s=900)
|
||||
# Set subtype override
|
||||
modulate.set_strategy_override("health", "DEGRADED", None, timeout_s=3600)
|
||||
|
||||
# Health without subtype gets type-level
|
||||
pol1 = modulate.modulate(modulate.InputType.HEALTH, subtype="OK")
|
||||
self.assertEqual(pol1.timeout_s, 900)
|
||||
|
||||
# Health with 'DEGRADED' subtype gets subtype-specific
|
||||
pol2 = modulate.modulate(modulate.InputType.HEALTH, subtype="DEGRADED")
|
||||
self.assertEqual(pol2.timeout_s, 3600)
|
||||
|
||||
def test_override_reset(self):
|
||||
modulate.set_strategy_override("wake", None, "opm", timeout_s=600)
|
||||
self.assertEqual(modulate.modulate(modulate.InputType.WAKE, agent="opm", actionable=True).timeout_s, 600)
|
||||
|
||||
modulate.reset_strategy_override("wake", None, "opm")
|
||||
# Reverts to builtin default (7200s for wake)
|
||||
self.assertEqual(modulate.modulate(modulate.InputType.WAKE, agent="opm", actionable=True).timeout_s, 7200)
|
||||
|
||||
|
||||
|
||||
class TestStrategyRpc(unittest.TestCase):
|
||||
"""Test box-ctl.py allowlisted RPC actions for strategy."""
|
||||
|
||||
def test_box_ctl_strat_list(self):
|
||||
cmd = [sys.executable, str(BOX_CTL), "strat-list"]
|
||||
res = subprocess.run(cmd, capture_output=True, text=True)
|
||||
self.assertEqual(res.returncode, 0)
|
||||
data = json.loads(res.stdout)
|
||||
self.assertTrue(data.get("ok"))
|
||||
self.assertIn("strategies", data)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user