Files
manage/backend/tests/test_jobs.py
T
alex 47baee854b Add comprehensive test suite for backend (133 tests)
Test coverage:
- test_utils.py: formatting helpers (human_size, ticks_to_minutes,
  format_duration, format_bitrate, ffprobe summaries, stream parsing)
- test_path_utils.py: path resolution (prefix, media root mapping,
  edge cases with spaces/special chars)
- test_domain_media.py: Jellyfin item normalization (HDR detection,
  media sources, stream extraction, display formatting)
- test_jobs.py: job template rendering and shell quoting safety
- test_media_index.py: SQLite index CRUD, querying, filtering,
  sorting, pagination
- test_config.py: pydantic-settings env loading
- test_api.py: full FastAPI integration tests with mocked SSH/Jellyfin
  (all endpoints: dashboard, monitoring, media, files, jobs)

All tests run without network/SSH dependencies using mocks.
2026-05-03 12:45:14 +02:00

56 lines
2.0 KiB
Python

"""Unit tests for jobs.py template rendering and safety."""
import pytest
from media_library_viewer_api.jobs import JOB_TEMPLATES, JobTemplate, run_job
class TestJobTemplate:
def test_render_basic(self):
template = JobTemplate(
name="Test",
description="A test job",
command_template="echo {path}",
)
result = template.render({"path": "/media/file.mkv"})
assert result == "echo /media/file.mkv"
def test_render_quotes_spaces(self):
template = JobTemplate(
name="Test",
description="A test job",
command_template="du -sh {path}",
)
result = template.render({"path": "/media/My Movie (2024)/file.mkv"})
# shlex.quote wraps in single quotes
assert "'" in result or "\\" in result
assert "My Movie (2024)" in result
def test_render_quotes_special_chars(self):
template = JobTemplate(
name="Test",
description="A test job",
command_template="stat {path}",
)
result = template.render({"path": "/media/file;rm -rf /"})
# Injection attempt should be safely quoted
assert "rm -rf" in result # it's there but quoted
assert result.startswith("stat ")
# Should not be executable as separate command
assert ";" not in result or "'" in result
class TestBuiltinTemplates:
def test_all_templates_exist(self):
assert "disk_usage" in JOB_TEMPLATES
assert "ffprobe" in JOB_TEMPLATES
assert "dry_run_find_empty_dirs" in JOB_TEMPLATES
def test_all_templates_renderable(self):
for key, template in JOB_TEMPLATES.items():
result = template.render({"path": "/test/path"})
assert "/test/path" in result or "'/test/path'" in result
def test_no_destructive_in_phase1(self):
for key, template in JOB_TEMPLATES.items():
assert template.destructive is False, f"Template {key} is marked destructive"