Files
Aniworld/tests/unit/test_scheduler_config_model.py
2026-06-05 17:18:00 +02:00

202 lines
7.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Unit tests for SchedulerConfig model fields and validators (Task 3)."""
import pytest
from pydantic import ValidationError
from src.server.models.config import SchedulerConfig
ALL_DAYS = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
class TestSchedulerConfigDefaults:
"""3.1 Default values."""
def test_default_schedule_time(self) -> None:
config = SchedulerConfig()
assert config.schedule_time == "03:00"
def test_default_schedule_days(self) -> None:
config = SchedulerConfig()
assert config.schedule_days == ALL_DAYS
def test_default_auto_download(self) -> None:
config = SchedulerConfig()
assert config.auto_download_after_rescan is False
def test_default_enabled(self) -> None:
config = SchedulerConfig()
assert config.enabled is True
def test_default_interval_minutes(self) -> None:
config = SchedulerConfig()
assert config.interval_minutes == 60
class TestSchedulerConfigValidScheduleTime:
"""3.2 Valid schedule_time values."""
@pytest.mark.parametrize("time_val", ["00:00", "03:00", "12:30", "23:59"])
def test_valid_times(self, time_val: str) -> None:
config = SchedulerConfig(schedule_time=time_val)
assert config.schedule_time == time_val
class TestSchedulerConfigInvalidScheduleTime:
"""3.3 Invalid schedule_time values must raise ValidationError."""
@pytest.mark.parametrize(
"time_val",
["25:00", "3pm", "", "3:00pm", "24:00", "-1:00", "9:00", "1:60"],
)
def test_invalid_times(self, time_val: str) -> None:
with pytest.raises(ValidationError):
SchedulerConfig(schedule_time=time_val)
class TestSchedulerConfigValidScheduleDays:
"""3.4 Valid schedule_days values."""
def test_single_day(self) -> None:
config = SchedulerConfig(schedule_days=["mon"])
assert config.schedule_days == ["mon"]
def test_multiple_days(self) -> None:
config = SchedulerConfig(schedule_days=["mon", "fri"])
assert config.schedule_days == ["mon", "fri"]
def test_all_days(self) -> None:
config = SchedulerConfig(schedule_days=ALL_DAYS)
assert config.schedule_days == ALL_DAYS
def test_empty_list(self) -> None:
config = SchedulerConfig(schedule_days=[])
assert config.schedule_days == []
class TestSchedulerConfigInvalidScheduleDays:
"""3.5 Invalid schedule_days values must raise ValidationError."""
@pytest.mark.parametrize(
"days",
[
["monday"],
["xyz"],
["Mon"], # Case-sensitive — must be lowercase
[""],
],
)
def test_invalid_days(self, days: list) -> None:
with pytest.raises(ValidationError):
SchedulerConfig(schedule_days=days)
class TestSchedulerConfigAutoDownload:
"""3.6 auto_download_after_rescan field."""
def test_set_true(self) -> None:
config = SchedulerConfig(auto_download_after_rescan=True)
assert config.auto_download_after_rescan is True
def test_set_false(self) -> None:
config = SchedulerConfig(auto_download_after_rescan=False)
assert config.auto_download_after_rescan is False
class TestSchedulerConfigBackwardCompat:
"""3.7 Backward compatibility: old fields still work."""
def test_legacy_fields_use_defaults(self) -> None:
config = SchedulerConfig(enabled=True, interval_minutes=30)
assert config.schedule_time == "03:00"
assert config.schedule_days == ALL_DAYS
assert config.auto_download_after_rescan is False
assert config.enabled is True
assert config.interval_minutes == 30
class TestSchedulerConfigLegacyAliases:
"""3.10 Legacy config key aliases (auto_download, folder_scan)."""
def test_legacy_auto_download_true(self) -> None:
"""Legacy auto_download=true maps to auto_download_after_rescan=True."""
config = SchedulerConfig(auto_download=True)
assert config.auto_download_after_rescan is True
def test_explicit_primary_overrides_legacy(self) -> None:
"""Primary field explicitly set to False still wins over legacy True.
When user provides both old and new key, newer key wins by virtue of
being the intended migration target. Legacy alias only applies when
primary key is absent from data entirely.
"""
config = SchedulerConfig(
auto_download=True,
auto_download_after_rescan=True,
)
# Both set to True — no conflict possible when both agree
assert config.auto_download_after_rescan is True
def test_explicit_primary_false_wins_over_legacy_true(self) -> None:
"""Primary=False explicitly set wins over legacy=True.
User has migrated config to new keys but old key still present.
Explicit primary value must be respected.
"""
config = SchedulerConfig(
auto_download=True,
auto_download_after_rescan=False,
)
assert config.auto_download_after_rescan is False
def test_explicit_primary_true_wins_over_legacy_false(self) -> None:
"""Primary=True explicitly set wins over legacy=False."""
config = SchedulerConfig(
auto_download=False,
auto_download_after_rescan=True,
)
assert config.auto_download_after_rescan is True
def test_legacy_in_json_dict(self) -> None:
"""Simulate config.json with legacy auto_download key."""
data = {
"enabled": True,
"schedule_time": "03:00",
"schedule_days": ALL_DAYS,
"auto_download": True,
}
config = SchedulerConfig(**data)
assert config.auto_download_after_rescan is True
class TestSchedulerConfigSerialisation:
"""3.9 Serialisation roundtrip."""
def test_roundtrip(self) -> None:
original = SchedulerConfig(
enabled=True,
interval_minutes=120,
schedule_time="04:30",
schedule_days=["mon", "wed", "fri"],
auto_download_after_rescan=True,
)
dumped = original.model_dump()
restored = SchedulerConfig(**dumped)
assert restored == original
def test_roundtrip_excludes_none_alias_fields(self) -> None:
"""model_dump must not emit null auto_download/folder_scan keys.
Previously these null keys were written to config.json on save.
On reload they were present (even as None), so the alias mapping in
__init__ was skipped and the primary fields retained their default
False values instead of the configured True values.
"""
original = SchedulerConfig(
auto_download_after_rescan=True,
)
dumped = original.model_dump()
# Alias fields must not appear when None
assert "auto_download" not in dumped
# Primary fields roundtrip correctly
restored = SchedulerConfig(**dumped)
assert restored.auto_download_after_rescan is True