From ea106db806918f371b8f392cc896dc7a2d6677a1 Mon Sep 17 00:00:00 2001 From: Prudhvi Vuda <53619858+Prudhvivuda@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:51:34 -0400 Subject: [PATCH] [Bugfix][Bench] Clean up synthetic video files and writers (#59529) Signed-off-by: Prudhvivuda Co-authored-by: OpenAI Codex --- .../test_random_multimodal_dataset_video.py | 40 ++++++++++++++++++- vllm/benchmarks/datasets/datasets.py | 30 ++++++-------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/tests/benchmarks/test_random_multimodal_dataset_video.py b/tests/benchmarks/test_random_multimodal_dataset_video.py index b394ea2c0d..ebe17989c1 100644 --- a/tests/benchmarks/test_random_multimodal_dataset_video.py +++ b/tests/benchmarks/test_random_multimodal_dataset_video.py @@ -2,8 +2,11 @@ # SPDX-FileCopyrightText: Copyright contributors to the vLLM project import os +import tempfile +from pathlib import Path from tempfile import NamedTemporaryFile from typing import Any, cast +from unittest.mock import Mock import cv2 import pybase64 as base64 @@ -61,11 +64,17 @@ def test_map_config_to_modality(video_dataset: RandomMultiModalDataset): @pytest.mark.benchmark -def test_generate_mm_item_video(video_dataset: RandomMultiModalDataset): - """Test generating multimodal items for video configurations.""" +def test_generate_mm_item_video( + video_dataset: RandomMultiModalDataset, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, +): + """Generate a decodable video without leaving temporary files behind.""" + monkeypatch.setattr(tempfile, "tempdir", str(tmp_path)) # Test video item generation video_config = (64, 48, 8) # height, width, num_frames result = video_dataset.generate_mm_item(video_config) + assert not list(tmp_path.iterdir()) # Check the result structure matches OpenAI API format assert isinstance(result, dict) @@ -105,6 +114,33 @@ def test_generate_mm_item_video(video_dataset: RandomMultiModalDataset): os.unlink(temp_path) +@pytest.mark.benchmark +@pytest.mark.parametrize("writer_opened", [False, True], ids=["open", "write"]) +def test_generate_synthetic_video_cleans_up_on_error( + video_dataset: RandomMultiModalDataset, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + writer_opened: bool, +): + """Release the writer and remove temporary storage when encoding fails.""" + monkeypatch.setattr(tempfile, "tempdir", str(tmp_path)) + writer = Mock(spec=cv2.VideoWriter) + writer.isOpened.return_value = writer_opened + writer.write.side_effect = RuntimeError("Failed to write video frame") + monkeypatch.setattr(cv2, "VideoWriter", lambda *args, **kwargs: writer) + + error = ( + "Failed to write video frame" + if writer_opened + else "Failed to create video writer" + ) + with pytest.raises(RuntimeError, match=error): + video_dataset.generate_synthetic_video(48, 64, 8) + + assert not list(tmp_path.iterdir()) + writer.release.assert_called_once_with() + + @pytest.mark.benchmark def test_generate_mm_item_image(video_dataset: RandomMultiModalDataset): """Test generating multimodal items for image configurations.""" diff --git a/vllm/benchmarks/datasets/datasets.py b/vllm/benchmarks/datasets/datasets.py index 76de75a66f..abaf299a19 100644 --- a/vllm/benchmarks/datasets/datasets.py +++ b/vllm/benchmarks/datasets/datasets.py @@ -25,7 +25,7 @@ from dataclasses import dataclass, replace from functools import cache from io import BytesIO from pathlib import Path -from tempfile import NamedTemporaryFile +from tempfile import TemporaryDirectory from typing import Any, cast import numpy as np @@ -975,32 +975,26 @@ class RandomMultiModalDataset(RandomDataset): dtype=np.uint8, ) - # Create a temporary video file in memory fourcc = cv2.VideoWriter_fourcc(*"mp4v") fps = 30 # frames per second - with NamedTemporaryFile(suffix=".mp4", delete=False) as temp_file: - temp_path = temp_file.name + with TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) / "video.mp4" - # Create video writer video_writer = cv2.VideoWriter( - temp_path, fourcc=fourcc, fps=fps, frameSize=(width, height) + str(temp_path), fourcc=fourcc, fps=fps, frameSize=(width, height) ) - if not video_writer.isOpened(): - raise RuntimeError("Failed to create video writer") + try: + if not video_writer.isOpened(): + raise RuntimeError("Failed to create video writer") - for frame in random_pixels: - video_writer.write(frame) + for frame in random_pixels: + video_writer.write(frame) + finally: + video_writer.release() - video_writer.release() - temp_file.close() - - # Read the video file content - with open(temp_path, "rb") as f: - video_content = f.read() - - return {"bytes": video_content} + return {"bytes": temp_path.read_bytes()} def map_config_to_modality(self, config: tuple[int, int, int]) -> str: """Map the configuration to the modality."""