* fix(images): read a loading collection as loading, never as 0 of 0 images (#391) A reset published {loading, loaded:0, total:0} and the caption painted it as "0 of 0 images" until the first page answered, so a fast reader (the inspector concept spec on WebKit) read an empty result the server never returned. The count line now says "Loading images…" while a first page is in flight; the spec waits for the answered count, and a held-listing spec pins the ordering. * test(thumbnails): make the no-JPEG-XL-encoder fixture authoritative (#371) {available:false} stood in only the cached detection, and every settings read probes a cached None again, finding the host's real encoder. The fixture now stands in for the detector itself and reset restores it; a unit test proves the route against a detector that finds an encoder. * test(system): wait for the restore job's own end before its toast (#361) The reviewed-restore specs waited for the "Database restore finished" toast with the 5 s expect, in effect a deadline on the disk-bound publish. They now wait for the job's progress stream to close, assert the job finished, and only then check the toast with the default timeout. * test(images): wait for the search's answered count in the concept comparison (#391) searchOf took the first changed caption as the search's count, the same read-before-the-response race as the inspector's tag chip.
95 lines
3.7 KiB
Python
95 lines
3.7 KiB
Python
"""The System browser hooks only ever reset their own server's config.json (#249 S3)
|
|
and decide JPEG XL availability whatever the host has installed (#371)."""
|
|
|
|
import asyncio
|
|
import os
|
|
import sys
|
|
import tempfile
|
|
import types
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
from aiohttp import web
|
|
from aiohttp.test_utils import TestClient, TestServer
|
|
|
|
_mock_server = mock.MagicMock()
|
|
_mock_server.PromptServer.instance.routes = mock.MagicMock()
|
|
sys.modules.setdefault("server", _mock_server)
|
|
|
|
from py.api import thumbnail_encode # noqa: E402
|
|
from tests.browser.workspace_system_fixture import ( # noqa: E402
|
|
register_system_commands,
|
|
)
|
|
|
|
|
|
class TestWorkspaceSystemFixture(unittest.TestCase):
|
|
def setUp(self):
|
|
self.tmp = tempfile.TemporaryDirectory()
|
|
self.addCleanup(self.tmp.cleanup)
|
|
self.root = Path(self.tmp.name) / "server"
|
|
self.root.mkdir()
|
|
|
|
def test_refuses_a_config_path_outside_its_root(self):
|
|
elsewhere = Path(self.tmp.name) / "config.json"
|
|
elsewhere.write_bytes(b'{"real": true}')
|
|
for value in (str(elsewhere), None):
|
|
env = {
|
|
k: v for k, v in os.environ.items() if k != "PROMPT_MANAGER_CONFIG_PATH"
|
|
}
|
|
if value is not None:
|
|
env["PROMPT_MANAGER_CONFIG_PATH"] = value
|
|
with (
|
|
self.subTest(value=value),
|
|
mock.patch.dict(os.environ, env, clear=True),
|
|
):
|
|
with self.assertRaisesRegex(RuntimeError, "PROMPT_MANAGER_CONFIG_PATH"):
|
|
register_system_commands(None, None, None, self.root)
|
|
self.assertEqual(elsewhere.read_bytes(), b'{"real": true}')
|
|
|
|
def test_no_encoder_holds_even_when_the_host_has_one(self):
|
|
"""``{available: false}`` survives the settings read's re-probe (#371)."""
|
|
config = self.root / "config.json"
|
|
env = {**os.environ, "PROMPT_MANAGER_CONFIG_PATH": str(config)}
|
|
api = types.SimpleNamespace()
|
|
app, routes = web.Application(), web.RouteTableDef()
|
|
real_detect = thumbnail_encode._detect
|
|
with mock.patch.dict(os.environ, env, clear=True):
|
|
reset = register_system_commands(app, routes, api, self.root)
|
|
app.add_routes(routes)
|
|
self.addCleanup(thumbnail_encode.reset_encoders)
|
|
self.addCleanup(setattr, thumbnail_encode, "_detect", real_detect)
|
|
|
|
async def scenario():
|
|
async with TestClient(TestServer(app)) as client:
|
|
|
|
async def post(available):
|
|
response = await client.post(
|
|
"/__test__/system/jxl-encoder", json={"available": available}
|
|
)
|
|
self.assertEqual(response.status, 200)
|
|
|
|
await post(False)
|
|
status = thumbnail_encode.encoder_status()["jxl"]
|
|
self.assertFalse(status["available"])
|
|
self.assertIsNone(
|
|
thumbnail_encode.detect_jxl_encoder(recheck_missing=True)
|
|
)
|
|
await post(True)
|
|
status = thumbnail_encode.encoder_status()["jxl"]
|
|
self.assertEqual(status["encoder"], "cjxl")
|
|
await post(False)
|
|
|
|
# The host's real detector finds an encoder (Pillow can save JPEG XL).
|
|
with mock.patch.object(thumbnail_encode, "_pillow_can_save_jxl", lambda: True):
|
|
asyncio.run(scenario())
|
|
# Reset gives detection back to the host.
|
|
reset()
|
|
self.assertIs(thumbnail_encode._detect, real_detect)
|
|
status = thumbnail_encode.encoder_status()["jxl"]
|
|
self.assertEqual(status["encoder"], "pillow")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|