Files
ComfyAssets-ComfyUI_PromptM…/tests/test_output_dir.py
Vito caa9649f32 feat: reuse positive and negative prompt combinations (#195)
* feat(db): add pair schema and stage restore migrations for #193

* feat(database): persist reusable ordered prompt pairs (#193)

* feat(api): expose reusable pairs and atomic metadata enrichment (#193)

* feat(metadata): resolve canonical prompt pairs with bounded provenance (#193)

* feat(scan): enrich image pairs without guessing or duplicate links (#193)

* fix(database): preserve pair tags during global maintenance (#193)

* feat(tracking): enrich live image pairs and cancel scans safely (#193)

* feat(nodes): encode paired prompts and count cached recipe runs (#193)

* fix(database): validate restored pair ownership and provenance (#193)

* feat(admin): report pair scan outcomes and cancellation (#193)

* feat(ui): add paired prompt editor and explicit recipe library for #193

* fix(autocomplete): include reusable pair metadata vocabulary (#193)

* fix(pairs): honor recent sorting and conservative scan outcomes (#193)

* fix(ui): protect paired draft saves and clarify negative variants (#193)

* fix(metadata): preserve bounded paired execution evidence (#193)

* fix(tracking): follow actual pair output roles and prefer execution evidence (#193)

* docs(pairs): document live validation and retain renderer screenshots (#193)

* test(api): inject disposable databases before API startup (#194)

* test(api): canonicalize portable temporary gallery roots (#194)

* docs(ui): prototype branching negative variant history (#193)

* docs(ui): show selected negative beneath positive in timeline concept (#193)

* docs: retain approved timeline for later gallery redesign (#193)

* test(db): close restore fixture connections before cleanup (#194)

* test(db): reuse existing handle guards in all pair fixtures (#194)

* chore: clarify rollback test and intentional exception handling (#193)
2026-10-17 08:00:42 -07:00

143 lines
5.6 KiB
Python

"""
Tests for _find_comfyui_output_dir() — verifies that user-configured
directories take priority over auto-detection, and that the cache is
invalidated when the setting changes.
"""
import os
import sys
import tempfile
import unittest
from pathlib import Path
from unittest.mock import MagicMock, patch
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Mock ComfyUI's server module before importing anything that touches config
_mock_server = MagicMock()
_mock_server.PromptServer.instance.routes = MagicMock()
sys.modules.setdefault("server", _mock_server)
from py.api import PromptManagerAPI
from py.config import GalleryConfig
class TestFindComfyuiOutputDir(unittest.TestCase):
"""Test _find_comfyui_output_dir() respects user-configured directories."""
def setUp(self):
roots = patch.object(
GalleryConfig,
"allowed_gallery_parents",
return_value=[os.path.normcase(os.path.realpath(tempfile.gettempdir()))],
)
roots.start()
self.addCleanup(roots.stop)
database = MagicMock()
database.cleanup_duplicates.return_value = 0
self.api = PromptManagerAPI(db=database)
self.api._cached_output_dir = None
self._orig_dirs = list(GalleryConfig.MONITORING_DIRECTORIES)
def tearDown(self):
GalleryConfig.MONITORING_DIRECTORIES = self._orig_dirs
def test_configured_directory_takes_priority(self):
"""When a valid directory is configured, it should be used instead of
auto-detect."""
with tempfile.TemporaryDirectory() as tmpdir:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir]
self.api._cached_output_dir = None
result = self.api._find_comfyui_output_dir()
self.assertEqual(result, str(Path(tmpdir).resolve()))
def test_nonexistent_configured_directory_falls_through(self):
"""When the configured directory doesn't exist, fall back to auto-detection."""
GalleryConfig.MONITORING_DIRECTORIES = ["/nonexistent/fake/path/output"]
self.api._cached_output_dir = None
# Should not return the nonexistent path — will either find
# ComfyUI output via auto-detect or return None
result = self.api._find_comfyui_output_dir()
self.assertNotEqual(result, "/nonexistent/fake/path/output")
def test_empty_config_uses_auto_detection(self):
"""When MONITORING_DIRECTORIES is empty, auto-detection should be used."""
GalleryConfig.MONITORING_DIRECTORIES = []
self.api._cached_output_dir = None
# Should not raise — auto-detection may or may not find a dir
result = self.api._find_comfyui_output_dir()
# Result is either a valid path or None
if result is not None:
self.assertTrue(Path(result).is_dir())
def test_cache_returns_same_value(self):
"""After first lookup, cached value should be returned."""
with tempfile.TemporaryDirectory() as tmpdir:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir]
self.api._cached_output_dir = None
result1 = self.api._find_comfyui_output_dir()
# Change config — should NOT affect result because of cache
GalleryConfig.MONITORING_DIRECTORIES = ["/some/other/path"]
result2 = self.api._find_comfyui_output_dir()
self.assertEqual(result1, result2)
def test_cache_invalidation_picks_up_new_directory(self):
"""After clearing the cache, _find_comfyui_output_dir should use new config."""
with tempfile.TemporaryDirectory() as tmpdir1:
with tempfile.TemporaryDirectory() as tmpdir2:
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir1]
self.api._cached_output_dir = None
result1 = self.api._find_comfyui_output_dir()
self.assertEqual(result1, str(Path(tmpdir1).resolve()))
# Simulate what save_settings does: update config + invalidate cache
GalleryConfig.MONITORING_DIRECTORIES = [tmpdir2]
self.api._cached_output_dir = None
result2 = self.api._find_comfyui_output_dir()
self.assertEqual(result2, str(Path(tmpdir2).resolve()))
def test_configured_directory_is_resolved(self):
"""Configured paths with symlinks or .. should be resolved to absolute."""
with tempfile.TemporaryDirectory() as tmpdir:
# Use a relative-ish path with ..
parent = str(Path(tmpdir).parent)
basename = Path(tmpdir).name
dotdot_path = os.path.join(parent, ".", basename)
GalleryConfig.MONITORING_DIRECTORIES = [dotdot_path]
self.api._cached_output_dir = None
result = self.api._find_comfyui_output_dir()
self.assertEqual(result, str(Path(tmpdir).resolve()))
class TestOutputDirectoryFixturePortability(unittest.TestCase):
def test_aliased_temporary_parent_uses_the_real_gallery_allowlist(self):
with tempfile.TemporaryDirectory() as directory:
parent = Path(directory)
(parent / "alias").mkdir()
(parent / "actual").mkdir()
aliased = str(parent / "alias" / ".." / "actual")
with patch("tempfile.gettempdir", return_value=aliased):
case = TestFindComfyuiOutputDir(
"test_configured_directory_takes_priority"
)
result = unittest.TestResult()
case.run(result)
self.assertEqual(result.errors, [])
self.assertEqual(result.failures, [])
if __name__ == "__main__":
unittest.main()