129 lines
4.8 KiB
Python
Executable File
129 lines
4.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import tempfile
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
|
|
MODULE_PATH = Path(__file__).with_name("ui_gallery.py")
|
|
SPEC = importlib.util.spec_from_file_location("ui_gallery", MODULE_PATH)
|
|
assert SPEC is not None and SPEC.loader is not None
|
|
UI_GALLERY = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(UI_GALLERY)
|
|
|
|
|
|
class UiGalleryWorkflowTests(unittest.TestCase):
|
|
def test_compiler_artifact_reports_identity_target_and_freshness(self) -> None:
|
|
message = {
|
|
"reason": "compiler-artifact",
|
|
"package_id": "path+file:///workspace#editor_ui@0.1.0",
|
|
"target": {"name": "editor_ui"},
|
|
"fresh": True,
|
|
}
|
|
self.assertEqual(
|
|
UI_GALLERY.compiler_artifact(message),
|
|
(
|
|
"path+file:///workspace#editor_ui@0.1.0",
|
|
"editor_ui",
|
|
True,
|
|
),
|
|
)
|
|
|
|
def test_compiler_artifact_rejects_non_artifact_messages(self) -> None:
|
|
self.assertIsNone(UI_GALLERY.compiler_artifact({"reason": "build-finished"}))
|
|
|
|
def test_bounded_output_rejects_oversized_machine_documents(self) -> None:
|
|
with self.assertRaises(RuntimeError):
|
|
UI_GALLERY.bounded_command_output(
|
|
[
|
|
"python3",
|
|
"-c",
|
|
"import sys; sys.stdout.write('x' * 4097)",
|
|
],
|
|
4096,
|
|
)
|
|
|
|
def test_bounded_output_returns_small_json(self) -> None:
|
|
document = {"packages": [], "resolve": {"nodes": []}}
|
|
output = UI_GALLERY.bounded_command_output(
|
|
["python3", "-c", f"print({json.dumps(json.dumps(document))})"],
|
|
4096,
|
|
)
|
|
self.assertEqual(json.loads(output), document)
|
|
|
|
def test_source_snapshot_tracks_only_rust_and_manifests(self) -> None:
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
root = Path(temporary)
|
|
source = root / "src"
|
|
source.mkdir()
|
|
(source / "panel.rs").write_text("fn panel() {}\n", encoding="utf-8")
|
|
(source / "theme.json").write_text("{}\n", encoding="utf-8")
|
|
original_roots = UI_GALLERY.WATCH_ROOTS
|
|
original_files = UI_GALLERY.WATCH_FILES
|
|
try:
|
|
UI_GALLERY.WATCH_ROOTS = (source,)
|
|
UI_GALLERY.WATCH_FILES = ()
|
|
snapshot = UI_GALLERY.source_snapshot()
|
|
finally:
|
|
UI_GALLERY.WATCH_ROOTS = original_roots
|
|
UI_GALLERY.WATCH_FILES = original_files
|
|
self.assertEqual(list(snapshot), [source / "panel.rs"])
|
|
|
|
def test_build_graph_cache_requires_matching_manifest_key(self) -> None:
|
|
with tempfile.TemporaryDirectory() as temporary:
|
|
cache = Path(temporary) / "graph.json"
|
|
original = UI_GALLERY.BUILD_GRAPH_CACHE
|
|
UI_GALLERY.BUILD_GRAPH_CACHE = cache
|
|
try:
|
|
UI_GALLERY.save_build_graph("current", {"package-a", "package-b"})
|
|
self.assertEqual(
|
|
UI_GALLERY.cached_build_graph("current"),
|
|
{"package-a", "package-b"},
|
|
)
|
|
self.assertIsNone(UI_GALLERY.cached_build_graph("stale"))
|
|
finally:
|
|
UI_GALLERY.BUILD_GRAPH_CACHE = original
|
|
|
|
def test_failed_rebuild_preserves_the_last_good_gallery(self) -> None:
|
|
current = mock.Mock()
|
|
with (
|
|
mock.patch.object(UI_GALLERY, "build_gallery", return_value=1),
|
|
mock.patch.object(UI_GALLERY, "launch_gallery") as launch,
|
|
mock.patch.object(UI_GALLERY, "stop_gallery") as stop,
|
|
):
|
|
replacement = UI_GALLERY.rebuild_and_replace_gallery(current)
|
|
self.assertIs(replacement, current)
|
|
launch.assert_not_called()
|
|
stop.assert_not_called()
|
|
|
|
def test_successful_rebuild_launches_before_retiring_the_last_good_gallery(self) -> None:
|
|
current = mock.Mock()
|
|
next_gallery = mock.Mock()
|
|
order: list[str] = []
|
|
with (
|
|
mock.patch.object(UI_GALLERY, "build_gallery", return_value=0),
|
|
mock.patch.object(
|
|
UI_GALLERY,
|
|
"launch_gallery",
|
|
side_effect=lambda: order.append("launch") or next_gallery,
|
|
),
|
|
mock.patch.object(
|
|
UI_GALLERY,
|
|
"stop_gallery",
|
|
side_effect=lambda process: order.append("stop"),
|
|
) as stop,
|
|
):
|
|
replacement = UI_GALLERY.rebuild_and_replace_gallery(current)
|
|
self.assertIs(replacement, next_gallery)
|
|
self.assertEqual(order, ["launch", "stop"])
|
|
stop.assert_called_once_with(current)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|