mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-10 00:57:38 -04:00
- Hosts with a legacy alias in /etc/timezone (e.g. US/Central) passed the old pytz validation but failed Django's own check against /usr/share/zoneinfo, raising ValueError at startup in every Django process (server, celery, migrate) - Validate the way Django does: a zoneinfo lookup plus the on-disk file check, falling back to UTC when either fails - Ship tzdata-legacy in the base image so legacy aliases resolve and devices keep their actual local time instead of dropping to UTC - Add regression tests for the validation fallback Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
94 lines
3.2 KiB
Python
94 lines
3.2 KiB
Python
"""Tests for the host-timezone validation in the Django settings.
|
|
|
|
Regression coverage for the `US/Central` crash-loop: the host's
|
|
/etc/timezone can carry a legacy alias that the zoneinfo database
|
|
knows but the image's /usr/share/zoneinfo doesn't ship as a file
|
|
(trixie moved legacy aliases into tzdata-legacy). Django validates
|
|
TIME_ZONE against the on-disk tree, so the settings module must
|
|
apply the same check and fall back to UTC instead of letting Django
|
|
raise ValueError at startup.
|
|
"""
|
|
|
|
from pathlib import Path
|
|
|
|
from anthias_server.django_project.settings import get_host_time_zone
|
|
|
|
|
|
def _write_timezone(tmp_path: Path, value: str) -> str:
|
|
timezone_file = tmp_path / 'etc-timezone'
|
|
timezone_file.write_text(value)
|
|
return str(timezone_file)
|
|
|
|
|
|
def _zoneinfo_root(tmp_path: Path, *zone_files: str) -> Path:
|
|
root = tmp_path / 'zoneinfo'
|
|
for zone in zone_files:
|
|
zone_path = root.joinpath(*zone.split('/'))
|
|
zone_path.parent.mkdir(parents=True, exist_ok=True)
|
|
zone_path.touch()
|
|
root.mkdir(exist_ok=True)
|
|
return root
|
|
|
|
|
|
class TestGetHostTimeZone:
|
|
def test_valid_zone_present_on_disk(self, tmp_path: Path) -> None:
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=_write_timezone(tmp_path, 'America/Chicago\n'),
|
|
zoneinfo_root=_zoneinfo_root(tmp_path, 'America/Chicago'),
|
|
)
|
|
== 'America/Chicago'
|
|
)
|
|
|
|
def test_zone_known_to_zoneinfo_but_missing_on_disk(
|
|
self, tmp_path: Path
|
|
) -> None:
|
|
# The Sentry crash: `US/Central` resolves via the tzdata
|
|
# package, but the on-disk tree (Django's source of truth)
|
|
# lacks the legacy alias.
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=_write_timezone(tmp_path, 'US/Central\n'),
|
|
zoneinfo_root=_zoneinfo_root(tmp_path, 'America/Chicago'),
|
|
)
|
|
== 'UTC'
|
|
)
|
|
|
|
def test_unknown_zone_name(self, tmp_path: Path) -> None:
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=_write_timezone(tmp_path, 'Not/AZone\n'),
|
|
zoneinfo_root=_zoneinfo_root(tmp_path, 'America/Chicago'),
|
|
)
|
|
== 'UTC'
|
|
)
|
|
|
|
def test_empty_timezone_file(self, tmp_path: Path) -> None:
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=_write_timezone(tmp_path, '\n'),
|
|
zoneinfo_root=_zoneinfo_root(tmp_path, 'America/Chicago'),
|
|
)
|
|
== 'UTC'
|
|
)
|
|
|
|
def test_missing_timezone_file(self, tmp_path: Path) -> None:
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=str(tmp_path / 'does-not-exist'),
|
|
zoneinfo_root=_zoneinfo_root(tmp_path, 'America/Chicago'),
|
|
)
|
|
== 'UTC'
|
|
)
|
|
|
|
def test_no_zoneinfo_root_skips_disk_check(self, tmp_path: Path) -> None:
|
|
# Mirrors Django: when /usr/share/zoneinfo is absent the disk
|
|
# check is skipped and the zoneinfo lookup alone decides.
|
|
assert (
|
|
get_host_time_zone(
|
|
timezone_file=_write_timezone(tmp_path, 'America/Chicago\n'),
|
|
zoneinfo_root=tmp_path / 'no-such-zoneinfo',
|
|
)
|
|
== 'America/Chicago'
|
|
)
|