chunker and ui
This commit is contained in:
144
tests/chunker/test_pipeline.py
Normal file
144
tests/chunker/test_pipeline.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
Tests for Pipeline — end-to-end orchestration, stats, error handling.
|
||||
|
||||
Demonstrates: TDD (Interview Topic 8) — integration testing with mocked FFmpeg probe.
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from core.chunker import Pipeline
|
||||
from core.chunker.exceptions import PipelineError
|
||||
|
||||
|
||||
def mock_probe(duration):
|
||||
"""Create a mock ProbeResult with the given duration."""
|
||||
result = MagicMock()
|
||||
result.duration = duration
|
||||
return result
|
||||
|
||||
|
||||
class TestPipeline:
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_end_to_end(self, mock_pf, temp_file):
|
||||
"""Full pipeline processes a file successfully."""
|
||||
path = temp_file(b"x" * 4096)
|
||||
mock_pf.return_value = mock_probe(40.0)
|
||||
|
||||
result = Pipeline(
|
||||
source=path,
|
||||
chunk_duration=10.0,
|
||||
num_workers=2,
|
||||
processor_type="checksum",
|
||||
).run()
|
||||
|
||||
assert result.total_chunks == 4
|
||||
assert result.processed == 4
|
||||
assert result.failed == 0
|
||||
assert result.elapsed_time > 0
|
||||
assert result.chunks_in_order is True
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_throughput_calculated(self, mock_pf, temp_file):
|
||||
"""Pipeline calculates throughput."""
|
||||
path = temp_file(b"x" * 10000)
|
||||
mock_pf.return_value = mock_probe(30.0)
|
||||
|
||||
result = Pipeline(source=path, chunk_duration=10.0, num_workers=2).run()
|
||||
|
||||
assert result.throughput_mbps > 0
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_worker_stats(self, mock_pf, temp_file):
|
||||
"""Pipeline reports per-worker stats."""
|
||||
path = temp_file(b"x" * 4000)
|
||||
mock_pf.return_value = mock_probe(40.0)
|
||||
|
||||
result = Pipeline(
|
||||
source=path, chunk_duration=10.0, num_workers=2
|
||||
).run()
|
||||
|
||||
assert len(result.worker_stats) == 2
|
||||
for worker_id, stats in result.worker_stats.items():
|
||||
assert "processed" in stats
|
||||
assert "errors" in stats
|
||||
|
||||
def test_nonexistent_file(self):
|
||||
"""Non-existent file raises PipelineError."""
|
||||
with pytest.raises(PipelineError):
|
||||
Pipeline(source="/nonexistent/file.mp4").run()
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_event_callback(self, mock_pf, temp_file):
|
||||
"""Pipeline emits events through callback."""
|
||||
path = temp_file(b"x" * 2048)
|
||||
mock_pf.return_value = mock_probe(20.0)
|
||||
events = []
|
||||
|
||||
def capture(event_type, data):
|
||||
events.append(event_type)
|
||||
|
||||
Pipeline(
|
||||
source=path,
|
||||
chunk_duration=10.0,
|
||||
num_workers=1,
|
||||
event_callback=capture,
|
||||
).run()
|
||||
|
||||
assert "pipeline_start" in events
|
||||
assert "pipeline_complete" in events
|
||||
assert "chunk_queued" in events
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_simulated_decode_processor(self, mock_pf, temp_file):
|
||||
"""Pipeline works with simulated_decode processor."""
|
||||
path = temp_file(b"x" * 2048)
|
||||
mock_pf.return_value = mock_probe(20.0)
|
||||
|
||||
result = Pipeline(
|
||||
source=path,
|
||||
chunk_duration=10.0,
|
||||
num_workers=2,
|
||||
processor_type="simulated_decode",
|
||||
).run()
|
||||
|
||||
assert result.total_chunks == 2
|
||||
assert result.failed == 0
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_single_chunk_file(self, mock_pf, temp_file):
|
||||
"""Duration shorter than chunk_duration produces one chunk."""
|
||||
path = temp_file(b"x" * 100)
|
||||
mock_pf.return_value = mock_probe(5.0)
|
||||
|
||||
result = Pipeline(source=path, chunk_duration=10.0).run()
|
||||
|
||||
assert result.total_chunks == 1
|
||||
assert result.processed == 1
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_retries_tracked(self, mock_pf, temp_file):
|
||||
"""Pipeline result tracks total retries."""
|
||||
path = temp_file(b"x" * 2048)
|
||||
mock_pf.return_value = mock_probe(20.0)
|
||||
|
||||
result = Pipeline(source=path, chunk_duration=10.0).run()
|
||||
|
||||
assert result.retries >= 0 # Might be 0 if no failures
|
||||
|
||||
@patch("core.chunker.chunker.probe_file")
|
||||
def test_output_dir_and_chunk_files(self, mock_pf, temp_file):
|
||||
"""Pipeline tracks output_dir and chunk_files when set."""
|
||||
path = temp_file(b"x" * 1024)
|
||||
mock_pf.return_value = mock_probe(10.0)
|
||||
|
||||
result = Pipeline(
|
||||
source=path,
|
||||
chunk_duration=10.0,
|
||||
processor_type="checksum",
|
||||
).run()
|
||||
|
||||
# No output_dir set, so chunk_files should be empty
|
||||
assert result.output_dir is None
|
||||
assert result.chunk_files == []
|
||||
Reference in New Issue
Block a user