from app.domains.rendering.workflow_config_utils import ( build_preset_workflow_config, build_workflow_blueprint_config, build_starter_workflow_config, canonicalize_workflow_config, extract_runtime_workflow, get_workflow_execution_mode, workflow_config_requires_canonicalization, ) def test_build_preset_workflow_config_creates_canonical_dag(): config = build_preset_workflow_config( "still", {"render_engine": "cycles", "samples": 256, "resolution": [1920, 1080]}, ) assert config["version"] == 1 assert config["ui"]["preset"] == "still" assert config["ui"]["execution_mode"] == "legacy" assert [node["step"] for node in config["nodes"]] == [ "order_line_setup", "resolve_template", "blender_still", "output_save", ] render_node = next(node for node in config["nodes"] if node["step"] == "blender_still") assert render_node["params"]["width"] == 1920 assert render_node["params"]["height"] == 1080 def test_build_preset_workflow_config_creates_graph_still_variant(): config = build_preset_workflow_config( "still_graph", {"render_engine": "cycles", "samples": 128, "resolution": [1600, 900]}, ) assert config["version"] == 1 assert config["ui"]["preset"] == "still_graph" assert config["ui"]["execution_mode"] == "graph" assert [node["step"] for node in config["nodes"]] == [ "order_line_setup", "auto_populate_materials", "resolve_template", "material_map_resolve", "blender_still", "output_save", "notify", ] render_node = next(node for node in config["nodes"] if node["step"] == "blender_still") assert render_node["params"]["width"] == 1600 assert render_node["params"]["height"] == 900 assert render_node["params"]["samples"] == 128 def test_canonicalize_workflow_config_migrates_legacy_preset(): legacy = { "type": "turntable", "params": {"render_engine": "cycles", "samples": 64, "fps": 24}, "ui": {"execution_mode": "shadow", "label": "Legacy Turntable"}, } canonical = canonicalize_workflow_config(legacy) assert canonical["version"] == 1 assert canonical["ui"]["preset"] == "turntable" assert canonical["ui"]["execution_mode"] == "shadow" assert canonical["ui"]["label"] == "Legacy Turntable" assert any(node["step"] == "blender_turntable" for node in canonical["nodes"]) def test_get_workflow_execution_mode_uses_legacy_preset_ui_override(): legacy = { "type": "still", "params": {"width": 1024, "height": 768}, "ui": {"execution_mode": "graph"}, } assert get_workflow_execution_mode(legacy) == "graph" def test_extract_runtime_workflow_uses_canonical_render_node_params(): config = build_preset_workflow_config( "multi_angle", {"render_engine": "cycles", "samples": 128, "angles": [0, 45, 90]}, ) preset, params = extract_runtime_workflow(config) assert preset == "multi_angle" assert params["render_engine"] == "cycles" assert params["samples"] == 128 assert params["angles"] == [0.0, 45.0, 90.0] def test_canonicalize_legacy_custom_config_preserves_edges(): legacy = { "type": "custom", "nodes": [ { "id": "input", "type": "inputNode", "position": {"x": 0, "y": 0}, "data": {"label": "Input", "pipeline_step": "resolve_step_path", "params": {}}, }, { "id": "render", "type": "renderNode", "position": {"x": 200, "y": 0}, "data": {"label": "Render", "pipeline_step": "blender_still", "params": {"resolution": [1024, 1024]}}, }, ], "edges": [ {"id": "e1", "source": "input", "target": "render"}, ], } canonical = canonicalize_workflow_config(legacy) assert canonical["ui"]["preset"] == "custom" assert canonical["ui"]["execution_mode"] == "legacy" assert canonical["edges"] == [{"id": "e1", "from": "input", "to": "render"}] def test_canonicalize_legacy_custom_config_without_nodes_builds_render_fallback_graph(): legacy = { "type": "custom", "params": { "samples": 256, "resolution": [2048, 2048], "render_engine": "cycles", }, } canonical = canonicalize_workflow_config(legacy) assert canonical["version"] == 1 assert canonical["ui"]["preset"] == "custom" assert canonical["ui"]["execution_mode"] == "legacy" assert [node["step"] for node in canonical["nodes"]] == [ "order_line_setup", "blender_still", ] assert canonical["edges"] == [{"from": "setup", "to": "render"}] render_node = next(node for node in canonical["nodes"] if node["step"] == "blender_still") assert render_node["params"]["render_engine"] == "cycles" assert render_node["params"]["samples"] == 256 assert render_node["params"]["width"] == 2048 assert render_node["params"]["height"] == 2048 assert render_node["params"]["use_custom_render_settings"] is True def test_extract_runtime_workflow_converts_resolution_to_dimensions(): config = build_preset_workflow_config( "turntable", {"resolution": [1920, 1080], "fps": 24}, ) preset, params = extract_runtime_workflow(config) assert preset == "turntable" assert params["width"] == 1920 assert params["height"] == 1080 assert "resolution" not in params def test_build_preset_workflow_config_keeps_render_overrides_opt_in_disabled_by_default(): config = build_preset_workflow_config( "still_with_exports", {"width": 640, "height": 640, "samples": 32}, ) render_node = next(node for node in config["nodes"] if node["step"] == "blender_still") assert "use_custom_render_settings" not in render_node["params"] assert render_node["params"]["width"] == 640 assert render_node["params"]["height"] == 640 assert render_node["params"]["samples"] == 32 def test_canonicalize_workflow_config_preserves_unset_override_intent_for_saved_preset_configs(): canonical = canonicalize_workflow_config( { "version": 1, "nodes": [ {"id": "setup", "step": "order_line_setup", "params": {}}, { "id": "render", "step": "blender_still", "params": {"width": 1024, "height": 768}, }, ], "edges": [{"from": "setup", "to": "render"}], "ui": {"preset": "still_with_exports", "execution_mode": "graph"}, } ) render_node = next(node for node in canonical["nodes"] if node["step"] == "blender_still") assert "use_custom_render_settings" not in render_node["params"] def test_canonicalize_workflow_config_defaults_execution_mode_for_canonical_configs(): canonical = canonicalize_workflow_config( { "version": 1, "nodes": [ {"id": "setup", "step": "order_line_setup", "params": {}}, ], "edges": [], "ui": {"preset": "custom"}, } ) assert canonical["ui"]["preset"] == "custom" assert canonical["ui"]["execution_mode"] == "legacy" def test_workflow_config_requires_canonicalization_for_legacy_payloads(): assert workflow_config_requires_canonicalization( { "type": "still", "params": {"width": 1024, "height": 768}, } ) def test_workflow_config_requires_canonicalization_skips_already_canonical_configs(): config = build_preset_workflow_config("still", {"width": 1024, "height": 768}) assert workflow_config_requires_canonicalization(config) is False def test_build_workflow_blueprint_config_creates_cad_intake_family_graph(): config = build_workflow_blueprint_config("cad_intake") assert config["version"] == 1 assert config["ui"]["preset"] == "custom" assert config["ui"]["blueprint"] == "cad_intake" assert [node["step"] for node in config["nodes"]] == [ "resolve_step_path", "occ_object_extract", "occ_glb_export", "stl_cache_generate", "blender_render", "threejs_render", "thumbnail_save", "thumbnail_save", ] def test_build_workflow_blueprint_config_creates_order_rendering_family_graph(): config = build_workflow_blueprint_config("order_rendering") assert config["version"] == 1 assert config["ui"]["preset"] == "custom" assert config["ui"]["blueprint"] == "order_rendering" assert any(node["step"] == "blender_still" for node in config["nodes"]) assert any(node["step"] == "blender_turntable" for node in config["nodes"]) assert any(node["step"] == "export_blend" for node in config["nodes"]) assert sum(1 for node in config["nodes"] if node["step"] == "notify") == 3 def test_build_starter_workflow_config_creates_minimal_valid_custom_graph(): config = build_starter_workflow_config() assert config["version"] == 1 assert config["ui"]["preset"] == "custom" assert config["ui"]["blueprint"] == "starter_order_rendering" assert config["nodes"] == [ { "id": "setup", "step": "order_line_setup", "params": {}, "ui": { "type": "processNode", "position": {"x": 120, "y": 140}, "label": "Order Line Setup", }, } ]