mirror of
https://github.com/rookiestar28/ComfyUI-OpenClaw.git
synced 2026-08-14 00:48:07 +00:00
119 lines
4.5 KiB
Python
119 lines
4.5 KiB
Python
"""
|
|
Tests for Template Service (R8/F5).
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
sys.path.append(os.getcwd())
|
|
|
|
from services.templates import TemplateService
|
|
from services.tenant_context import tenant_scope
|
|
|
|
|
|
class TestTemplateService(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
# Create a temp directory for templates
|
|
self.test_dir = tempfile.mkdtemp()
|
|
|
|
# Create manifest
|
|
self.manifest = {
|
|
"version": 1,
|
|
"templates": {"t1": {"path": "t1.json", "allowed_inputs": ["input1"]}},
|
|
}
|
|
with open(os.path.join(self.test_dir, "manifest.json"), "w") as f:
|
|
json.dump(self.manifest, f)
|
|
|
|
# Create template file
|
|
self.template_data = {"node1": {"inputs": {"text": "{{input1}}"}}}
|
|
with open(os.path.join(self.test_dir, "t1.json"), "w") as f:
|
|
json.dump(self.template_data, f)
|
|
|
|
# Create an additional template file that is NOT in the manifest.
|
|
# Policy: `<template_id>.json` on disk should be runnable even without a manifest entry.
|
|
with open(os.path.join(self.test_dir, "t2.json"), "w") as f:
|
|
json.dump({"node1": {"inputs": {"text": "{{input_any}}"}}}, f)
|
|
|
|
self.service = TemplateService(templates_root=self.test_dir)
|
|
|
|
def tearDown(self):
|
|
shutil.rmtree(self.test_dir)
|
|
|
|
def test_load_manifest(self):
|
|
"""Test manifest loading."""
|
|
config = self.service.get_template_config("t1")
|
|
self.assertIsNotNone(config)
|
|
self.assertEqual(config.path, "t1.json")
|
|
self.assertEqual(config.allowed_inputs, ["input1"])
|
|
|
|
def test_unknown_template(self):
|
|
"""Test unknown template raises ValueError."""
|
|
with self.assertRaises(ValueError):
|
|
self.service.render_template("unknown", {})
|
|
|
|
def test_extra_input_is_ignored(self):
|
|
"""Extra inputs should not raise (policy: no per-template input allowlist)."""
|
|
rendered = self.service.render_template("t1", {"forbidden": "val"})
|
|
# Placeholder remains because `forbidden` does not match any placeholder in the template.
|
|
self.assertEqual(rendered["node1"]["inputs"]["text"], "{{input1}}")
|
|
|
|
def test_render_substitution(self):
|
|
"""Test variable substitution."""
|
|
rendered = self.service.render_template("t1", {"input1": "hello"})
|
|
self.assertEqual(rendered["node1"]["inputs"]["text"], "hello")
|
|
|
|
def test_strict_substitution_only(self):
|
|
"""Test that partial substitution is NOT performed."""
|
|
# Update template to have partial placeholder
|
|
with open(os.path.join(self.test_dir, "t1.json"), "w") as f:
|
|
json.dump({"node1": {"inputs": {"text": "prefix {{input1}} suffix"}}}, f)
|
|
|
|
# Should NOT replace because "prefix {{input1}} suffix" != "{{input1}}"
|
|
rendered = self.service.render_template("t1", {"input1": "hello"})
|
|
self.assertEqual(
|
|
rendered["node1"]["inputs"]["text"], "prefix {{input1}} suffix"
|
|
)
|
|
|
|
def test_file_based_template_without_manifest_entry(self):
|
|
"""Templates present as `<id>.json` should be runnable even if not in manifest.json."""
|
|
rendered = self.service.render_template("t2", {"input_any": "hello"})
|
|
self.assertEqual(rendered["node1"]["inputs"]["text"], "hello")
|
|
|
|
def test_multi_tenant_manifest_visibility(self):
|
|
"""S49: manifest tenant bindings should gate visibility in multi-tenant mode."""
|
|
manifest = {
|
|
"version": 1,
|
|
"templates": {
|
|
"t1": {
|
|
"path": "t1.json",
|
|
"allowed_inputs": ["input1"],
|
|
"tenants": ["tenant-a"],
|
|
}
|
|
},
|
|
}
|
|
with open(os.path.join(self.test_dir, "manifest.json"), "w") as f:
|
|
json.dump(manifest, f)
|
|
self.service._load_manifest()
|
|
|
|
with patch.dict("os.environ", {"OPENCLAW_MULTI_TENANT_ENABLED": "1"}):
|
|
with tenant_scope("tenant-a"):
|
|
self.assertIsNotNone(self.service.get_template_config("t1"))
|
|
with tenant_scope("tenant-b"):
|
|
self.assertIsNone(self.service.get_template_config("t1"))
|
|
|
|
def test_multi_tenant_hides_discovery_only_templates(self):
|
|
"""S49: discovery-only templates are hidden in multi-tenant mode."""
|
|
with patch.dict("os.environ", {"OPENCLAW_MULTI_TENANT_ENABLED": "1"}):
|
|
with tenant_scope("tenant-a"):
|
|
self.assertIsNone(self.service.get_template_config("t2"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|