"""Sparse End overrides through the standalone serverless bridge, CPU only.""" import asyncio import copy import math import os from pathlib import Path import struct import subprocess import sys import pytest import torch from unittest.mock import patch from test_image_list_serverless import adapter, codec, contract, handler, item, prepare, source @pytest.mark.skipif(not os.environ.get('COMFYUI_SOURCE_ROOT'), reason='set COMFYUI_SOURCE_ROOT for real CPU executor') def test_real_cpu_standalone_bridge_calculated_overrides(tmp_path): env = dict(os.environ, CUDA_VISIBLE_DEVICES='', HIP_VISIBLE_DEVICES='', ROCR_VISIBLE_DEVICES='', PYTHONDONTWRITEBYTECODE='1') env.pop('PYTHONPATH', None) helper = Path(__file__).parent / 'helpers' / 'image_list_serverless_values_check.py' result = subprocess.run([sys.executable, str(helper), os.environ['COMFYUI_SOURCE_ROOT'], str(tmp_path)], env=env, text=True, capture_output=True, timeout=90) assert result.returncode == 0, result.stdout + result.stderr assert 'IMAGE_LIST_SERVERLESS_VALUES_CPU_OK' in result.stdout def assert_exact(actual, expected): assert type(actual) is type(expected) if isinstance(expected, torch.Tensor): assert actual.dtype == expected.dtype and actual.shape == expected.shape assert torch.equal(actual.contiguous().view(torch.uint8), expected.contiguous().view(torch.uint8)) elif isinstance(expected, float): assert struct.pack('!d', actual) == struct.pack('!d', expected) else: assert actual == expected @pytest.mark.parametrize('value', [False, True, 2**63 + 123, -(2**100), -0.0, 1.0000000000000002, '', ' \r\n雪 ', torch.ones(2, 2, 3, 4, dtype=torch.float64), torch.ones(2, 2, 3, dtype=torch.bfloat16)]) def test_value_codec_exact_types(value): descriptor, payload = codec.encode_payload('VALUE', value) assert_exact(codec.decode_payload('VALUE', descriptor, payload), value) @pytest.mark.parametrize('value', [None, {}, [], (1,), object(), float('inf'), float('nan'), torch.ones(2), torch.ones(1, 2, 3, dtype=torch.int64), torch.full((1, 2, 3), float('nan'))]) def test_value_codec_rejects_unsupported_or_nonfinite(value): with pytest.raises((ValueError, TypeError)): codec.encode_payload('VALUE', value) def test_sparse_exports_never_create_collector_or_forward_unchanged_values(): async def check(): prompt, value = source(), item() prompt['ns/end']['inputs'].update(value_2=['ns/start', 5], value_10=['process', 2]) original = copy.deepcopy(prompt) job = await prepare(prompt, value) assert prompt == original bindings = {binding['socket']: binding for binding in job['manifest']} assert set(bindings) == {'images', 'masks', 'texts', 'value_2', 'value_10'} assert bindings['value_2']['kind'] == bindings['value_10']['kind'] == 'VALUE' assert all('Collector' not in node['class_type'] for node in job['workflow'].values()) assert all(node['class_type'] not in (adapter.runtime.START_CLASS, adapter.runtime.END_CLASS) for node in job['workflow'].values()) handler._validate_request({key: job[key] for key in ('workflow', 'images', 'media')}) asyncio.run(check()) @pytest.mark.parametrize('slot', ['value_0', 'value_11', 'value_01', 'values.value_1']) def test_unknown_end_override_slot_rejected(slot): prompt = source() prompt['ns/end']['inputs'][slot] = ['ns/start', 4] with pytest.raises(ValueError, match='slot'): asyncio.run(prepare(prompt)) def test_value_codec_budgets_and_malformed_payload(): with pytest.raises(ValueError, match='byte limit'): codec.encode_payload('VALUE', '雪', max_bytes=2) descriptor, payload = codec.encode_payload('VALUE', True) with pytest.raises(ValueError): codec.decode_payload('VALUE', dict(descriptor, type='INT'), payload) descriptor, payload = codec.encode_payload('VALUE', -0.0) with pytest.raises(ValueError): codec.decode_payload('VALUE', descriptor, struct.pack('