98 lines
3.7 KiB
Python
98 lines
3.7 KiB
Python
import json
|
|
import os
|
|
import sys
|
|
import unittest
|
|
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
|
|
from _helpers import TempDirMixin
|
|
|
|
from app import client_policy
|
|
|
|
|
|
class ClientPolicyTests(TempDirMixin, unittest.TestCase):
|
|
def _payload(self, *, check=True, enforce=False):
|
|
return {
|
|
"policy_version": 1,
|
|
"subscription_check_enabled": check,
|
|
"subscription_enforcement_enabled": enforce,
|
|
"updated_at": "2026-07-28T15:19:19+08:00",
|
|
}
|
|
|
|
def test_parse_supports_off_observe_and_enforce(self):
|
|
off = client_policy.parse_client_policy(
|
|
self._payload(check=False, enforce=False)
|
|
)
|
|
observe = client_policy.parse_client_policy(
|
|
self._payload(check=True, enforce=False)
|
|
)
|
|
enforce = client_policy.parse_client_policy(
|
|
self._payload(check=True, enforce=True)
|
|
)
|
|
|
|
self.assertEqual("off", off.mode)
|
|
self.assertEqual("observe", observe.mode)
|
|
self.assertEqual("enforce", enforce.mode)
|
|
|
|
def test_illegal_combination_is_normalized_to_off(self):
|
|
policy = client_policy.parse_client_policy(
|
|
self._payload(check=False, enforce=True)
|
|
)
|
|
|
|
self.assertEqual("off", policy.mode)
|
|
self.assertFalse(policy.subscription_enforcement_enabled)
|
|
self.assertIn("组合非法", policy.warning)
|
|
|
|
def test_parser_rejects_loose_types_or_timestamp_without_timezone(self):
|
|
invalid_bool = self._payload()
|
|
invalid_bool["subscription_check_enabled"] = 1
|
|
invalid_time = self._payload()
|
|
invalid_time["updated_at"] = "2026-07-28T15:19:19"
|
|
|
|
with self.assertRaises(client_policy.ClientPolicyError):
|
|
client_policy.parse_client_policy(invalid_bool)
|
|
with self.assertRaises(client_policy.ClientPolicyError):
|
|
client_policy.parse_client_policy(invalid_time)
|
|
|
|
def test_valid_remote_policy_is_cached_without_sensitive_fields(self):
|
|
with self.make_temp_dir() as temp_dir:
|
|
path = os.path.join(temp_dir, "config", "client_policy.json")
|
|
remote = client_policy.parse_client_policy(
|
|
self._payload(check=True, enforce=True)
|
|
)
|
|
|
|
resolved = client_policy.resolve_client_policy(remote, path=path)
|
|
loaded = client_policy.load_cached_policy(path=path)
|
|
|
|
self.assertEqual("remote", resolved.source)
|
|
self.assertEqual("cache", loaded.source)
|
|
self.assertEqual("enforce", loaded.mode)
|
|
with open(path, "r", encoding="utf-8") as handle:
|
|
raw = json.load(handle)
|
|
self.assertIn("cached_at", raw)
|
|
self.assertNotIn("api_key", json.dumps(raw).lower())
|
|
self.assertNotIn("account", json.dumps(raw).lower())
|
|
|
|
def test_missing_remote_uses_cache_then_observation_fallback(self):
|
|
with self.make_temp_dir() as temp_dir:
|
|
path = os.path.join(temp_dir, "client_policy.json")
|
|
cached = client_policy.parse_client_policy(
|
|
self._payload(check=False, enforce=False)
|
|
)
|
|
client_policy.save_cached_policy(cached, path=path)
|
|
|
|
from_cache = client_policy.resolve_client_policy(None, path=path)
|
|
self.assertEqual("cache", from_cache.source)
|
|
self.assertEqual("off", from_cache.mode)
|
|
|
|
with open(path, "w", encoding="utf-8") as handle:
|
|
handle.write("{broken")
|
|
fallback = client_policy.resolve_client_policy(None, path=path)
|
|
self.assertEqual("fallback", fallback.source)
|
|
self.assertEqual("observe", fallback.mode)
|
|
self.assertIn("观察模式", fallback.warning)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|