2026-04-27 21:40:31 +08:00
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
2026-06-15 22:50:50 +08:00
|
|
|
"""Source-level regression tests for diffusion output/engine helpers.
|
2026-04-27 21:40:31 +08:00
|
|
|
|
|
|
|
|
These tests verify naming conventions and patterns by inspecting source code
|
|
|
|
|
at the function level using AST. They are intentionally coupled to the source
|
2026-06-15 22:50:50 +08:00
|
|
|
layout and should be updated whenever the inspected helper code is refactored.
|
2026-04-27 21:40:31 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import ast
|
|
|
|
|
import os
|
|
|
|
|
|
2026-07-29 23:53:03 +08:00
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
|
|
|
|
|
|
|
|
|
|
2026-04-27 21:40:31 +08:00
|
|
|
_ENGINE_PATH = os.path.normpath(
|
|
|
|
|
os.path.join(
|
|
|
|
|
os.path.dirname(__file__),
|
|
|
|
|
os.pardir,
|
|
|
|
|
os.pardir,
|
|
|
|
|
"vllm_omni",
|
|
|
|
|
"diffusion",
|
|
|
|
|
"diffusion_engine.py",
|
|
|
|
|
)
|
|
|
|
|
)
|
2026-06-15 22:50:50 +08:00
|
|
|
_FORMATTER_PATH = os.path.normpath(
|
|
|
|
|
os.path.join(
|
|
|
|
|
os.path.dirname(__file__),
|
|
|
|
|
os.pardir,
|
|
|
|
|
os.pardir,
|
|
|
|
|
"vllm_omni",
|
|
|
|
|
"diffusion",
|
|
|
|
|
"output_formatter.py",
|
|
|
|
|
)
|
|
|
|
|
)
|
2026-04-27 21:40:31 +08:00
|
|
|
|
|
|
|
|
|
2026-06-15 22:50:50 +08:00
|
|
|
def _read_source(path: str) -> str:
|
|
|
|
|
with open(path) as f:
|
2026-04-27 21:40:31 +08:00
|
|
|
return f.read()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _get_function_source(source: str, class_name: str | None, func_name: str) -> str:
|
|
|
|
|
"""Extract the source of a specific function/method using AST.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
source: Full file source code.
|
|
|
|
|
class_name: Enclosing class name, or None for module-level functions.
|
|
|
|
|
func_name: Function/method name.
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
Source code of the function body.
|
|
|
|
|
"""
|
|
|
|
|
tree = ast.parse(source)
|
|
|
|
|
if class_name is not None:
|
|
|
|
|
for node in ast.walk(tree):
|
|
|
|
|
if isinstance(node, ast.ClassDef) and node.name == class_name:
|
|
|
|
|
for item in node.body:
|
|
|
|
|
if isinstance(item, (ast.FunctionDef, ast.AsyncFunctionDef)) and item.name == func_name:
|
|
|
|
|
result = ast.get_source_segment(source, item)
|
|
|
|
|
assert result is not None, f"{class_name}.{func_name} source not found"
|
|
|
|
|
return result
|
|
|
|
|
else:
|
|
|
|
|
for node in ast.walk(tree):
|
|
|
|
|
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == func_name:
|
|
|
|
|
result = ast.get_source_segment(source, node)
|
|
|
|
|
assert result is not None, f"{func_name} source not found"
|
|
|
|
|
return result
|
|
|
|
|
raise AssertionError(f"Function {class_name + '.' if class_name else ''}{func_name} not found in source")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestMetricKeys:
|
2026-06-15 22:50:50 +08:00
|
|
|
"""Verify metric naming conventions in diffusion output formatting."""
|
2026-04-27 21:40:31 +08:00
|
|
|
|
|
|
|
|
def test_no_duplicate_preprocess_key(self) -> None:
|
2026-06-15 22:50:50 +08:00
|
|
|
"""format_diffusion_outputs() should not duplicate 'preprocess_time_ms'."""
|
|
|
|
|
source = _read_source(_FORMATTER_PATH)
|
|
|
|
|
formatter_source = _get_function_source(source, None, "format_diffusion_outputs")
|
|
|
|
|
assert "preprocessing_time_ms" not in formatter_source, (
|
|
|
|
|
"Found duplicate key 'preprocessing_time_ms' in "
|
|
|
|
|
"format_diffusion_outputs() — should only use 'preprocess_time_ms'"
|
2026-04-27 21:40:31 +08:00
|
|
|
)
|
|
|
|
|
|
2026-07-23 10:06:08 +08:00
|
|
|
def test_timing_metric_key_naming_consistency(self) -> None:
|
|
|
|
|
"""Timing metrics should be attached by the engine orchestration path."""
|
2026-06-15 22:50:50 +08:00
|
|
|
source = _read_source(_FORMATTER_PATH)
|
|
|
|
|
formatter_source = _get_function_source(source, None, "format_diffusion_outputs")
|
2026-07-23 10:06:08 +08:00
|
|
|
engine_source = _read_source(_ENGINE_PATH)
|
|
|
|
|
step_streaming_source = _get_function_source(engine_source, "DiffusionEngine", "step_streaming")
|
2026-06-15 22:50:50 +08:00
|
|
|
lines = formatter_source.split("\n")
|
2026-04-27 21:40:31 +08:00
|
|
|
|
|
|
|
|
for line in lines:
|
|
|
|
|
if '"diffusion_engine_exec_time_ms"' in line:
|
2026-07-23 10:06:08 +08:00
|
|
|
raise AssertionError("diffusion_engine_exec_time_ms should be attached in step_streaming()")
|
2026-04-27 21:40:31 +08:00
|
|
|
if '"diffusion_engine_total_time_ms"' in line:
|
2026-07-23 10:06:08 +08:00
|
|
|
raise AssertionError("diffusion_engine_total_time_ms should be attached in step_streaming()")
|
|
|
|
|
|
|
|
|
|
assert '"diffusion_engine_exec_time_ms": exec_total_time * 1000' in step_streaming_source
|
|
|
|
|
assert '"diffusion_engine_total_time_ms": step_total_ms' in step_streaming_source
|
|
|
|
|
assert '"postprocess_time_ms": postprocess_time * 1000' in step_streaming_source
|
2026-04-27 21:40:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestDummyRunAllocation:
|
|
|
|
|
"""Verify _dummy_run generates exact-sized audio arrays."""
|
|
|
|
|
|
|
|
|
|
def test_no_oversized_allocation(self) -> None:
|
|
|
|
|
"""_dummy_run should not allocate more audio than needed."""
|
2026-06-15 22:50:50 +08:00
|
|
|
source = _read_source(_ENGINE_PATH)
|
2026-04-27 21:40:31 +08:00
|
|
|
dummy_source = _get_function_source(source, "DiffusionEngine", "_dummy_run")
|
|
|
|
|
assert "audio_sr * audio_duration_sec" not in dummy_source, (
|
|
|
|
|
"_dummy_run should generate exact-sized audio, not allocate and slice"
|
|
|
|
|
)
|