fix: normalise scope and blank strings on the construction path too
The verifier found four more env-only behaviours of the same class the branch
was already fixing. The worst is scope: it goes straight into the Redis keys
(pgw:limit:{scope}, pgw:gate:{scope}), so one process using from_env("LLM")
and another constructing scope="LLM" by hand split the rate limit and breaker
state across two namespaces, each tracking its own quota, with no error.
Blank redis_url and pricing_path now collapse to None as from_env has always
done, so they fall into the required-field checks instead of reaching the redis
client as an unparseable URL. EmbeddingSettings gains the __post_init__ it never
had, moving its batch_size and expected_dim checks off the from_env-only path.
Also adds the cache backend whitelist test that mutation testing showed missing.
This commit is contained in:
@@ -7,7 +7,7 @@ import pytest
|
||||
from loguru import logger
|
||||
|
||||
from polygateway.client import GatewayClient
|
||||
from polygateway.config import GatewaySettings, OcrSettings
|
||||
from polygateway.config import EmbeddingSettings, GatewaySettings, OcrSettings
|
||||
|
||||
_BASE_ENV = {
|
||||
"LLM__QWEN__1__BASE_URL": "https://gw-a.example/v1",
|
||||
@@ -271,6 +271,11 @@ class TestAssemblyGuards:
|
||||
with pytest.raises(ValueError, match="TELEMETRY_BACKEND"):
|
||||
GatewaySettings.from_env("LLM", env=_env(PGW_TELEMETRY_BACKEND="mysql"))
|
||||
|
||||
def test_cache_backend_whitelist(self):
|
||||
"""对称于上一条: env 层的域检查保留是为了报错能点出键名,得有测试守着。"""
|
||||
with pytest.raises(ValueError, match="CACHE_BACKEND"):
|
||||
GatewaySettings.from_env("LLM", env=_env(PGW_CACHE_BACKEND="rediss"))
|
||||
|
||||
def test_pricing_path_optional(self):
|
||||
assert GatewaySettings.from_env("LLM", env=_env()).pricing_path is None
|
||||
s = GatewaySettings.from_env("LLM", env=_env(PGW_PRICING_PATH="conf/prices.json"))
|
||||
@@ -552,6 +557,51 @@ class TestCrossFieldInvariants:
|
||||
assert settings.telemetry_pg_dsn == "postgresql://u@h/db"
|
||||
assert not warnings
|
||||
|
||||
# —— 构造期规范化: env 路一直在做的,构造路也要做(否则两条路产出不同的值)——
|
||||
|
||||
@pytest.mark.parametrize("raw", ["LLM", " llm ", " LLM "])
|
||||
def test_scope_normalized_on_direct_construction(self, raw):
|
||||
"""scope 直接进 Redis key(pgw:limit:{scope}:…)。
|
||||
|
||||
大小写不一致会让同一逻辑 scope 的限流/熔断状态分裂到两套命名空间——
|
||||
两边各记各的配额与熔断状态,分布式治理静默失效且不报错。
|
||||
"""
|
||||
base = self._base()
|
||||
assert dataclasses.replace(base, scope=raw).scope == "llm"
|
||||
|
||||
def test_blank_redis_url_normalized_to_none(self):
|
||||
"""空串此前只有 env 路归 None,构造路留着它骗过 `is None` 判断。"""
|
||||
base = self._base()
|
||||
assert dataclasses.replace(base, redis_url="").redis_url is None
|
||||
|
||||
def test_blank_redis_url_still_blocks_redis_backend(self):
|
||||
"""归 None 后必须落进条件必填,而不是放行到 redis 库去抛连接串天书。"""
|
||||
base = self._base()
|
||||
with pytest.raises(ValueError, match="redis_url"):
|
||||
dataclasses.replace(base, limiter_backend="redis", redis_url="")
|
||||
|
||||
def test_blank_pricing_path_normalized_to_none(self):
|
||||
base = self._base()
|
||||
assert dataclasses.replace(base, pricing_path="").pricing_path is None
|
||||
|
||||
# —— EmbeddingSettings 自身的字段域(此前只有 from_env 校验)——
|
||||
|
||||
@pytest.mark.parametrize("bad", [0, -3])
|
||||
def test_embedding_settings_rejects_non_positive_batch_size(self, bad):
|
||||
base = self._base()
|
||||
with pytest.raises(ValueError, match="batch_size"):
|
||||
EmbeddingSettings(gateway=base, batch_size=bad)
|
||||
|
||||
def test_embedding_settings_rejects_non_positive_expected_dim(self):
|
||||
base = self._base()
|
||||
with pytest.raises(ValueError, match="expected_dim"):
|
||||
EmbeddingSettings(gateway=base, batch_size=8, expected_dim=0)
|
||||
|
||||
def test_embedding_settings_accepts_valid_values(self):
|
||||
base = self._base()
|
||||
settings = EmbeddingSettings(gateway=base, batch_size=8, expected_dim=1024)
|
||||
assert settings.batch_size == 8 and settings.expected_dim == 1024
|
||||
|
||||
# —— 回归护栏: client.py 的 assert 前提确实被保证了 ——
|
||||
|
||||
def test_factory_accepts_valid_redis_stack(self):
|
||||
|
||||
Reference in New Issue
Block a user