Files
feature-control/tests/test_registry_resolver.py
2026-06-15 00:42:14 +02:00

117 lines
2.9 KiB
Python

"""
Tests for T02 registry + T03 resolver (WP-0003).
Run: PYTHONPATH=src python -m pytest tests/test_registry_resolver.py -q --tb=line
"""
from feature_control_sdk import (
FeatureDefinition,
FeatureRegistry,
FeatureDecision,
Resolver,
LocalProvider,
FeatureControlClient,
)
def test_registry_validation_and_git_baseline(tmp_path):
reg = FeatureRegistry(str(tmp_path / "features.json"))
# Valid
fd = FeatureDefinition(
feature_key="test.compute",
name="Test Compute",
description="...",
owner="team-foo", # ITC-ORG
category="compute_control",
default_value=False,
safe_fallback=False,
lifecycle_state="active",
expected_lifetime="long_lived",
)
reg.register(fd)
reg.save()
assert "test.compute" in reg.keys()
loaded = FeatureRegistry(str(tmp_path / "features.json"))
assert loaded.get("test.compute").owner == "team-foo"
# Invalid: no owner
try:
reg.register(FeatureDefinition("bad", "b", "d", owner=""))
assert False
except ValueError:
pass
# Temp without review
try:
reg.register(
FeatureDefinition(
"temp.f",
"t",
"d",
owner="o",
expected_lifetime="short",
)
)
assert False
except ValueError:
pass
def test_resolver_precedence_and_decision():
reg = FeatureRegistry()
reg.register(
FeatureDefinition(
"kill.test",
"Kill Test",
"...",
owner="o",
default_value=True,
safe_fallback=False,
)
)
reg.register(
FeatureDefinition(
"tenant.test",
"Tenant Test",
"...",
owner="o",
default_value=False,
)
)
provider = LocalProvider(
{
"kill:kill.test": True, # kill signal
"tenant:acme:tenant.test": True,
}
)
resolver = Resolver(reg, provider.values)
# Kill wins
d = resolver.evaluate("kill.test", True, {"tenant_id": "acme"})
assert d.value is False
assert d.reason == "kill_switch"
assert d.source == "kill_switch"
# Tenant policy
d2 = resolver.evaluate("tenant.test", False, {"tenant_id": "acme"})
assert d2.value is True
assert d2.reason == "tenant_policy"
assert d2.scope == "tenant:acme"
# Default
d3 = resolver.evaluate("tenant.test", False, {"tenant_id": "other"})
assert d3.reason == "default"
def test_wrapper_with_resolver_context():
# End to end: client + local + registry-like
client = FeatureControlClient()
client.set_provider(LocalProvider({"feat.agent": True}))
ctx = {"actor_type": "agent", "agent_id": "foo", "tenant_id": "acme"}
val = client.get_boolean_value("feat.agent", False, ctx)
assert val is True