How the claude-video Test Suite Functions Without Network Access

The claude-video test suite runs entirely offline by using ffmpeg's lavfi filters to synthesize video and audio on the fly, routing download requests through local file:// URLs, and mocking external network calls like yt-dlp.

The claude-video repository provides video processing automation that typically interacts with online sources. However, its comprehensive test suite is engineered to execute in completely isolated CI environments where no external network access is available, ensuring reliable and deterministic test runs regardless of internet connectivity.

Synthetic Media Generation with ffmpeg lavfi

Rather than downloading real-world content, the test suite generates synthetic media assets on demand using ffmpeg's lavfi (Libavfilter) input device. This creates reproducible video frames and audio waveforms without touching the network.

Creating Video Clips for Frame Extraction

The make_video_clip fixture helper in tests/conftest.py constructs temporary MP4 files using the lavfi color source filter. This generates solid-color video streams at specified resolutions and frame rates, eliminating the need to store large binary assets in the repository or fetch them remotely.


# tests/conftest.py

import subprocess
import pytest
from pathlib import Path

def make_video_clip(tmp_path: Path, duration=1, size="640x360", fps=30, color="red"):
    """Generate a synthetic video file using ffmpeg lavfi."""
    out_file = tmp_path / "clip.mp4"
    cmd = [
        "ffmpeg",
        "-y",  # overwrite output if exists

        "-f", "lavfi",
        "-i", f"color=c={color}:s={size}:r={fps}",
        "-t", str(duration),
        "-c:v", "libx264",
        "-pix_fmt", "yuv420p",
        str(out_file),
    ]
    subprocess.check_call(cmd)
    return out_file

@pytest.fixture
def temp_video_path(tmp_path):
    """Provide a synthetic 1-second red video clip."""
    return make_video_clip(tmp_path, color="red", duration=1)

These synthetic clips feed into tests/test_frames.py, which validates frame extraction logic without requiring actual downloaded content.

Generating Audio for Whisper Transcription Tests

For speech recognition testing, tests/test_whisper.py creates deterministic audio using the lavfi sine wave source. This produces a pure 440 Hz tone that can be predictably transcribed or used to test audio pipeline handling.


# tests/test_whisper.py

import subprocess
from pathlib import Path

def test_transcribe_sine_wave(tmp_path: Path):
    """Test Whisper transcription on locally generated sine wave audio."""
    audio_file = tmp_path / "tone.wav"
    
    # Generate 2-second 440Hz sine wave at 16kHz sample rate

    subprocess.check_call([
        "ffmpeg", "-y",
        "-f", "lavfi", 
        "-i", "sine=frequency=440:sample_rate=16000",
        "-t", "2",
        str(audio_file),
    ])
    
    transcript = transcribe(audio_file)  # calls the Whisper wrapper

    assert isinstance(transcript, str)
    assert len(transcript) > 0

Intercepting Network Dependencies

The suite stubs out all network-bound operations to prevent accidental HTTP requests during test execution.

Mocking yt-dlp Interactions

The skills/watch/scripts/download.py module normally interfaces with yt-dlp to fetch video metadata and streams. During testing, tests/test_download.py patches the YoutubeDL class using unittest.mock to return static dictionaries, simulating successful extraction without network I/O.


# tests/test_download.py

from unittest.mock import patch, MagicMock
from skills.watch.scripts.download import download_video

@patch("skills.watch.scripts.download.YoutubeDL")
def test_download_with_mocked_metadata(mock_ydl, tmp_path):
    """Verify download logic works with mocked yt-dlp responses."""
    # Create a local synthetic file to act as the "downloaded" content

    local_file = tmp_path / "mock_video.mp4"
    local_file.write_bytes(b"fake video content")
    
    # Configure mock to return local file path as the download URL

    mock_instance = MagicMock()
    mock_instance.extract_info.return_value = {
        "url": f"file://{local_file}",
        "ext": "mp4"
    }
    mock_ydl.return_value.__enter__.return_value = mock_instance
    
    result = download_video("https://example.com/video")
    assert result.exists()

Routing Downloads Through file:// URLs

The download script accepts standard file:// URLs and treats them as valid sources, allowing tests to bypass HTTP entirely. When tests/test_download.py invokes download_video() with a file:// path pointing to the synthetic fixtures, the code copies the local file rather than attempting an HTTP fetch.


# Example usage within a test

from skills.watch.scripts.download import download_video

def test_download_local_file(temp_video_path):
    """Verify download handles local file:// URLs correctly."""
    file_url = f"file://{temp_video_path}"
    result = download_video(file_url)
    assert result == temp_video_path

Reusable Fixtures in conftest.py

The tests/conftest.py file centralizes all synthetic media creation, providing pytest fixtures that are reused across test_frames.py, test_whisper.py, and test_download.py. This ensures consistent test data and automatic cleanup of temporary files.

Key fixtures include:

  • temp_video_path: Provides a 640x360 H.264 video clip generated via lavfi
  • temp_audio_path: Supplies 16kHz mono audio for transcription tests
  • tmp_path: Standard pytest fixture utilized for sandboxed file system operations

All fixtures rely solely on subprocess calls to ffmpeg and local temporary directories, maintaining strict network isolation.

Summary

  • Synthetic media generation: The test suite uses ffmpeg -f lavfi to create video color bars and sine wave audio on demand, eliminating external file dependencies.
  • Local file URLs: The download logic in skills/watch/scripts/download.py accepts file:// schemes, allowing tests to route requests to locally generated assets.
  • Network mocking: External calls to yt-dlp.YoutubeDL are patched in tests/test_download.py to return static metadata without HTTP requests.
  • Centralized fixtures: tests/conftest.py manages temporary file creation and cleanup, ensuring isolated, reproducible test environments.

Frequently Asked Questions

How does claude-video test video frame extraction without downloading real videos?

The tests/test_frames.py module uses fixtures from tests/conftest.py that generate synthetic MP4 files via ffmpeg's lavfi color filter. These files contain valid H.264 video streams at defined frame rates, allowing frame extraction logic to run against real codec data without network access.

Can the test suite run in an air-gapped CI environment?

Yes. The only external dependency required is a local ffmpeg binary. All media assets are synthesized during test setup, and all network calls to services like YouTube are mocked. The repository contains no hardcoded URLs to external video files.

Why does the download test use file:// URLs instead of mocking HTTP responses?

Using file:// URLs tests the actual download script's file-handling logic in skills/watch/scripts/download.py without requiring network privileges. This approach verifies that the download pipeline correctly handles path resolution, file copying, and extension detection while remaining completely offline.

What ffmpeg filters are used to generate test audio and video?

The test suite uses the lavfi (Libavfilter) input device with the color filter for video generation (creating solid color frames) and the sine audio source for audio generation (producing pure tone waveforms). These are deterministic, parameter-driven sources that require no input files or network streams.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →