Add node runtime contract smoke

This commit is contained in:
2026-06-27 14:47:35 +02:00
parent ac4c50bf34
commit 29e5e65e5f
+64
View File
@@ -5998,6 +5998,69 @@ def smoke_formatter_metadata_fixtures() -> None:
_expect("coworking lounge" in caption_text, "Generated training caption lost scene metadata") _expect("coworking lounge" in caption_text, "Generated training caption lost scene metadata")
def _expect_comfy_input_spec(node_name: str, group: str, input_name: str, spec: Any) -> None:
_expect(isinstance(input_name, str) and input_name, f"{node_name}.{group} has invalid input name {input_name!r}")
if group == "hidden":
_expect(
isinstance(spec, (str, tuple)),
f"{node_name}.{input_name} hidden input should be a ComfyUI hidden token or tuple",
)
return
_expect(isinstance(spec, tuple) and spec, f"{node_name}.{input_name} visible input has invalid spec")
type_spec = spec[0]
_expect(
isinstance(type_spec, str) or isinstance(type_spec, list),
f"{node_name}.{input_name} input type should be a socket type or choices list",
)
if isinstance(type_spec, list):
_expect(type_spec, f"{node_name}.{input_name} choice list should not be empty")
_expect(len(spec) >= 2 and isinstance(spec[1], dict), f"{node_name}.{input_name} visible input options should be a dict")
_expect("tooltip" in spec[1], f"{node_name}.{input_name} visible input is missing tooltip")
def smoke_node_runtime_contracts() -> None:
node_names = sorted(sxcp_nodes.NODE_CLASS_MAPPINGS)
_expect(node_names, "Node registry is empty")
_expect(
set(sxcp_nodes.NODE_CLASS_MAPPINGS) == set(sxcp_nodes.NODE_DISPLAY_NAME_MAPPINGS),
"Node class and display registries are out of sync",
)
_expect(len(node_names) >= 50, "Node registry unexpectedly small")
for node_name in node_names:
node_class = sxcp_nodes.NODE_CLASS_MAPPINGS[node_name]
display_name = sxcp_nodes.NODE_DISPLAY_NAME_MAPPINGS.get(node_name)
_expect(isinstance(display_name, str) and display_name, f"{node_name} has no display name")
input_types = node_class.INPUT_TYPES()
_expect(isinstance(input_types, dict), f"{node_name}.INPUT_TYPES should return a dict")
_expect("required" in input_types, f"{node_name}.INPUT_TYPES lost required group")
for group, inputs in input_types.items():
_expect(group in {"required", "optional", "hidden"}, f"{node_name}.INPUT_TYPES has unknown group {group!r}")
_expect(isinstance(inputs, dict), f"{node_name}.{group} inputs should be a dict")
for input_name, spec in inputs.items():
_expect_comfy_input_spec(node_name, group, input_name, spec)
return_types = getattr(node_class, "RETURN_TYPES", None)
_expect(isinstance(return_types, tuple) and return_types, f"{node_name}.RETURN_TYPES should be a non-empty tuple")
for output_type in return_types:
_expect(isinstance(output_type, str) and output_type, f"{node_name}.RETURN_TYPES contains an invalid output type")
return_names = getattr(node_class, "RETURN_NAMES", None)
if return_names is not None:
_expect(isinstance(return_names, tuple), f"{node_name}.RETURN_NAMES should be a tuple when present")
_expect(len(return_names) == len(return_types), f"{node_name}.RETURN_NAMES length does not match RETURN_TYPES")
for output_name in return_names:
_expect(isinstance(output_name, str) and output_name, f"{node_name}.RETURN_NAMES contains an invalid name")
function_name = getattr(node_class, "FUNCTION", None)
_expect(isinstance(function_name, str) and function_name, f"{node_name}.FUNCTION should name the executor method")
_expect(callable(getattr(node_class(), function_name, None)), f"{node_name}.FUNCTION target is not callable")
category = getattr(node_class, "CATEGORY", None)
_expect(isinstance(category, str) and category, f"{node_name}.CATEGORY should be a non-empty string")
def smoke_node_utility_registration() -> None: def smoke_node_utility_registration() -> None:
required_nodes = [ required_nodes = [
"SxCPGlobalSeed", "SxCPGlobalSeed",
@@ -7100,6 +7163,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
("fallback_role_graph_routes", smoke_fallback_role_graph_routes), ("fallback_role_graph_routes", smoke_fallback_role_graph_routes),
("expression_disabled", smoke_no_expression_fallback), ("expression_disabled", smoke_no_expression_fallback),
("formatter_metadata_fixtures", smoke_formatter_metadata_fixtures), ("formatter_metadata_fixtures", smoke_formatter_metadata_fixtures),
("node_runtime_contracts", smoke_node_runtime_contracts),
("node_utility_registration", smoke_node_utility_registration), ("node_utility_registration", smoke_node_utility_registration),
("server_route_payload_policy", smoke_server_route_payload_policy), ("server_route_payload_policy", smoke_server_route_payload_policy),
("seed_config_policy", smoke_seed_config_policy), ("seed_config_policy", smoke_seed_config_policy),