sync fb5cdef..HEAD
Browse files- tests_contract/test_v46.py +70 -0
tests_contract/test_v46.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""V4.6 契约测试:扩展卡槽(只声明不接线)。"""
|
| 3 |
+
import json
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
import unittest
|
| 7 |
+
|
| 8 |
+
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 9 |
+
sys.path.insert(0, ROOT)
|
| 10 |
+
sys.path.insert(0, os.path.join(ROOT, "scripts"))
|
| 11 |
+
|
| 12 |
+
from holoaeon.fusion_upgrade import slot_registry as sr
|
| 13 |
+
from holoaeon.fusion_upgrade.model_gateway import build_gateway
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class SlotTest(unittest.TestCase):
|
| 17 |
+
@classmethod
|
| 18 |
+
def setUpClass(cls):
|
| 19 |
+
cls.payload = sr.load(ROOT)
|
| 20 |
+
|
| 21 |
+
def test_01_validates_clean(self):
|
| 22 |
+
self.assertEqual(sr.validate(self.payload), [])
|
| 23 |
+
|
| 24 |
+
def test_02_lock_unchanged(self):
|
| 25 |
+
s = sr.summary(self.payload)
|
| 26 |
+
self.assertEqual(s["lock"], {"agents": 25, "skills": 47, "packs": 9})
|
| 27 |
+
|
| 28 |
+
def test_03_ids_unique_and_prefixed(self):
|
| 29 |
+
ids = [x["slot_id"] for x in self.payload["slots"]]
|
| 30 |
+
self.assertEqual(len(ids), len(set(ids)))
|
| 31 |
+
self.assertTrue(all(i.startswith("EXT-") for i in ids))
|
| 32 |
+
|
| 33 |
+
def test_04_kinds_and_status_whitelisted(self):
|
| 34 |
+
for s in self.payload["slots"]:
|
| 35 |
+
self.assertIn(s["kind"], sr.KINDS)
|
| 36 |
+
self.assertIn(s["status"], sr.STATUSES)
|
| 37 |
+
|
| 38 |
+
def test_05_open_slots_are_claimable(self):
|
| 39 |
+
opens = sr.open_slots(self.payload)
|
| 40 |
+
self.assertGreaterEqual(len(opens), 1)
|
| 41 |
+
for s in opens:
|
| 42 |
+
self.assertTrue(s["next_action"])
|
| 43 |
+
|
| 44 |
+
def test_06_no_public_url_in_slots(self):
|
| 45 |
+
for s in self.payload["slots"]:
|
| 46 |
+
blob = " ".join(str(s.get(k) or "") for k in ("contract", "next_action", "notes"))
|
| 47 |
+
self.assertFalse(sr._has_public_url(blob), s["slot_id"])
|
| 48 |
+
|
| 49 |
+
def test_07_slots_do_not_switch_anything_on(self):
|
| 50 |
+
clean = {k: v for k, v in os.environ.items() if not k.startswith("HOLOAEON_")}
|
| 51 |
+
gw = build_gateway(ROOT, environ=clean)
|
| 52 |
+
self.assertEqual(gw.state()["enabled"], [])
|
| 53 |
+
|
| 54 |
+
def test_08_bad_payload_reports_errors(self):
|
| 55 |
+
bad = json.loads(json.dumps(self.payload))
|
| 56 |
+
bad["slots"][0]["slot_id"] = "X-1"
|
| 57 |
+
bad["lock"]["agents"] = 26
|
| 58 |
+
errs = sr.validate(bad)
|
| 59 |
+
self.assertTrue(any("前缀" in e for e in errs))
|
| 60 |
+
self.assertTrue(any("维度锁" in e for e in errs))
|
| 61 |
+
|
| 62 |
+
def test_09_guide_covers_every_slot(self):
|
| 63 |
+
with open(os.path.join(ROOT, "docs", "扩展卡槽与协作开发指南.md"), encoding="utf-8") as f:
|
| 64 |
+
text = f.read()
|
| 65 |
+
for s in self.payload["slots"]:
|
| 66 |
+
self.assertIn(s["slot_id"], text)
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
if __name__ == "__main__":
|
| 70 |
+
unittest.main()
|