Pins every registered route and the key paths of GET /prompt_manager/settings while System S13 (#330) moves the legacy pages' tools to native System. Recorded on the unchanged main; cutover (#334) removes it.
137 lines
4.5 KiB
Python
137 lines
4.5 KiB
Python
"""The legacy pages' backend contract does not move under System S13 (#330).
|
|
|
|
S13 points the legacy admin and gallery buttons at native System and removes
|
|
their duplicate dialogs, changing no backend file. This snapshot pins what the
|
|
legacy pages talk to: every registered route (method and path) and the key
|
|
paths of ``GET /prompt_manager/settings``, the one route whose legacy request
|
|
body S13 shrinks. Record again only with a reason in the PR body:
|
|
|
|
PM_RECORD_LEGACY_SNAPSHOT=1 python3 -m unittest tests.test_legacy_contract_snapshot
|
|
|
|
Cutover (#334) removes this test and its fixture.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
try:
|
|
from tests.test_api_admin import AdminAPITestCase
|
|
except ImportError: # discovered with tests/ as the top-level directory
|
|
from test_api_admin import AdminAPITestCase
|
|
|
|
from py.config import GalleryConfig # noqa: E402
|
|
|
|
SNAPSHOT = (
|
|
Path(__file__).resolve().parent / "fixtures" / "legacy_contract_snapshot.json"
|
|
)
|
|
RECORD_ENV = "PM_RECORD_LEGACY_SNAPSHOT"
|
|
SETTINGS = "/prompt_manager/settings"
|
|
DEPTH = 2
|
|
CHANGED = (
|
|
"the legacy contract changed; if the change is intended (a new route, a new"
|
|
" settings key), record it with PM_RECORD_LEGACY_SNAPSHOT=1 and say why in"
|
|
" the PR body"
|
|
)
|
|
|
|
|
|
def key_paths(value, prefix="", depth=1):
|
|
"""The key paths of a JSON object to ``DEPTH`` levels.
|
|
|
|
``{"a": {"b": 1}}`` gives ``a`` and ``a.b``; the items of a list of
|
|
objects give the union of their keys as ``a[].b``.
|
|
"""
|
|
paths = set()
|
|
for key, child in value.items():
|
|
path = f"{prefix}{key}"
|
|
paths.add(path)
|
|
if depth >= DEPTH:
|
|
continue
|
|
if isinstance(child, dict):
|
|
paths |= key_paths(child, f"{path}.", depth + 1)
|
|
elif isinstance(child, list):
|
|
for item in child:
|
|
if isinstance(item, dict):
|
|
paths |= key_paths(item, f"{path}[].", depth + 1)
|
|
return paths
|
|
|
|
|
|
class TestLegacyContractSnapshot(AdminAPITestCase):
|
|
"""Routes and settings keys against tests/fixtures/legacy_contract_snapshot.json.
|
|
|
|
The base case isolates config.json (``PROMPT_MANAGER_CONFIG_PATH`` in the
|
|
temp tree), stubs ComfyUI's ``folder_paths`` and resets the gallery roots;
|
|
nothing here reads the maintainer's install.
|
|
"""
|
|
|
|
async def asyncSetUp(self):
|
|
await super().asyncSetUp()
|
|
self.api._get_all_output_dirs = lambda: [str(self.output_dir)]
|
|
GalleryConfig.MONITORING_DIRECTORIES = [str(self.output_dir)]
|
|
|
|
def _routes(self):
|
|
return sorted(
|
|
{
|
|
f"{route.method} {route.resource.canonical}"
|
|
for route in self.app.router.routes()
|
|
if route.method != "HEAD"
|
|
}
|
|
)
|
|
|
|
async def _settings_keys(self):
|
|
resp = await self.client.request("GET", SETTINGS)
|
|
body = await resp.json()
|
|
self.assertEqual(resp.status, 200, body)
|
|
return sorted(key_paths(body))
|
|
|
|
def _snapshot(self):
|
|
with open(SNAPSHOT, encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
def _record(self, key, value):
|
|
recorded = self._snapshot() if SNAPSHOT.exists() else {}
|
|
recorded[key] = value
|
|
with open(SNAPSHOT, "w", encoding="utf-8", newline="\n") as f:
|
|
json.dump(recorded, f, indent=2)
|
|
f.write("\n")
|
|
|
|
async def test_routes_match_the_snapshot(self):
|
|
routes = self._routes()
|
|
if os.environ.get(RECORD_ENV) == "1":
|
|
self._record("routes", routes)
|
|
self.assertGreater(len(routes), 50)
|
|
self.assertEqual(routes, self._snapshot()["routes"], CHANGED)
|
|
|
|
async def test_settings_response_keeps_its_keys(self):
|
|
keys = await self._settings_keys()
|
|
if os.environ.get(RECORD_ENV) == "1":
|
|
self._record("settings_keys", keys)
|
|
self.assertIn("settings.infinite_scroll", keys)
|
|
self.assertEqual(keys, self._snapshot()["settings_keys"], CHANGED)
|
|
|
|
|
|
class TestKeyPaths(unittest.TestCase):
|
|
def test_depth_and_list_items(self):
|
|
value = {
|
|
"success": True,
|
|
"settings": {"a": 1, "deep": {"hidden": 1}},
|
|
"rows": [{"path": "x"}, {"label": "y"}],
|
|
}
|
|
self.assertEqual(
|
|
sorted(key_paths(value)),
|
|
[
|
|
"rows",
|
|
"rows[].label",
|
|
"rows[].path",
|
|
"settings",
|
|
"settings.a",
|
|
"settings.deep",
|
|
"success",
|
|
],
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|