62 lines
2.2 KiB
Python
62 lines
2.2 KiB
Python
|
|
"""Tests for per-shard extension activation (SHARD-WP-0014 T3, ADR-0001)."""
|
||
|
|
|
||
|
|
from shard_wiki.engine import (
|
||
|
|
ActivationContext,
|
||
|
|
ActivationResolver,
|
||
|
|
StaticProvider,
|
||
|
|
feature_control_provider,
|
||
|
|
)
|
||
|
|
|
||
|
|
CANDIDATES = ["ext.overlay", "ext.views", "ext.struct", "ext.compute"]
|
||
|
|
|
||
|
|
|
||
|
|
def test_static_provider_default_off():
|
||
|
|
r = ActivationResolver(StaticProvider()) # nothing enabled
|
||
|
|
assert r.active_extensions(CANDIDATES, ActivationContext("s")) == set()
|
||
|
|
|
||
|
|
|
||
|
|
def test_static_provider_global_flags():
|
||
|
|
r = ActivationResolver(StaticProvider(flags={"ext.overlay": True, "ext.views": True}))
|
||
|
|
assert r.active_extensions(CANDIDATES, ActivationContext("s")) == {"ext.overlay", "ext.views"}
|
||
|
|
|
||
|
|
|
||
|
|
def test_per_shard_scoping_overrides_global():
|
||
|
|
provider = StaticProvider(
|
||
|
|
flags={"ext.views": True},
|
||
|
|
per_shard={"engB": {"ext.struct": True, "ext.views": False}},
|
||
|
|
)
|
||
|
|
r = ActivationResolver(provider)
|
||
|
|
assert r.active_extensions(CANDIDATES, ActivationContext("engA")) == {"ext.views"}
|
||
|
|
assert r.active_extensions(CANDIDATES, ActivationContext("engB")) == {"ext.struct"}
|
||
|
|
|
||
|
|
|
||
|
|
def test_context_carries_tenant():
|
||
|
|
captured = {}
|
||
|
|
|
||
|
|
class Spy(StaticProvider):
|
||
|
|
def is_active(self, feature_key, context):
|
||
|
|
captured.update(context)
|
||
|
|
return super().is_active(feature_key, context)
|
||
|
|
|
||
|
|
ActivationResolver(Spy(flags={"ext.views": True})).active_extensions(
|
||
|
|
["ext.views"], ActivationContext("s1", tenant_id="acme")
|
||
|
|
)
|
||
|
|
assert captured["shard_id"] == "s1" and captured["tenant_id"] == "acme"
|
||
|
|
|
||
|
|
|
||
|
|
def test_activation_profile_returns_config_for_active():
|
||
|
|
provider = StaticProvider(
|
||
|
|
flags={"ext.struct": True},
|
||
|
|
configs={"ext.struct": {"max_fields": 50}},
|
||
|
|
)
|
||
|
|
profile = ActivationResolver(provider).activation_profile(CANDIDATES, ActivationContext("s"))
|
||
|
|
assert profile == {"ext.struct": {"max_fields": 50}}
|
||
|
|
|
||
|
|
|
||
|
|
def test_feature_control_provider_degrades_gracefully():
|
||
|
|
# feature_control_sdk is not a dependency of shard-wiki: when absent the factory returns
|
||
|
|
# None (standalone path stays dependency-free, ADR-0001); when present it yields a usable
|
||
|
|
# ActivationProvider. Either way it must not raise.
|
||
|
|
provider = feature_control_provider()
|
||
|
|
assert provider is None or hasattr(provider, "is_active")
|