Files
soxoj--maigret/tests/test_idempotent_writes.py
wehub-resource-sync e52ddb7dd4
CodeQL / Analyze (python) (push) Failing after 1s
Linting and testing / build (3.11) (push) Failing after 0s
Package exe with PyInstaller - Windows / build (push) Failing after 2s
Linting and testing / build (3.10) (push) Failing after 1s
Linting and testing / minimal-install (push) Failing after 1s
Update sites rating and statistics / build (push) Failing after 1s
Build docker image and push to DockerHub / docker (push) Failing after 1s
Linting and testing / build (3.12) (push) Failing after 1s
Linting and testing / build (3.14) (push) Failing after 1s
Linting and testing / build (3.13) (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:10:17 +08:00

248 lines
8.2 KiB
Python

"""Tests for the 'don't rewrite files unless content actually changed' logic
in utils.generate_db_meta and utils.update_site_data. The point is to keep
sites.md and db_meta.json untouched when only the embedded timestamp/date
would change — so a precommit hook doesn't end up staging a no-op diff
every time someone runs the updater.
"""
import json
from datetime import datetime, timezone
from utils.generate_db_meta import (
DEFAULT_MIN_VERSION,
build_meta,
meta_payload_equals,
resolve_min_version,
write_meta_if_changed,
)
from utils.update_site_data import (
sites_md_payload_equals,
write_sites_md_if_changed,
)
# ---------------------------------------------------------------------------
# generate_db_meta
# ---------------------------------------------------------------------------
def _write_data_json(path, sites):
with open(path, "w", encoding="utf-8") as f:
json.dump({"sites": sites}, f)
def test_meta_payload_equals_ignores_timestamp():
a = {"sites_count": 10, "data_sha256": "abc", "updated_at": "2026-01-01T00:00:00Z"}
b = {"sites_count": 10, "data_sha256": "abc", "updated_at": "2027-12-31T23:59:59Z"}
assert meta_payload_equals(a, b)
def test_meta_payload_equals_detects_real_change():
a = {"sites_count": 10, "data_sha256": "abc", "updated_at": "2026-01-01T00:00:00Z"}
b = {"sites_count": 11, "data_sha256": "abc", "updated_at": "2026-01-01T00:00:00Z"}
assert not meta_payload_equals(a, b)
def test_write_meta_creates_file_when_missing(tmp_path):
data_path = tmp_path / "data.json"
meta_path = tmp_path / "db_meta.json"
_write_data_json(data_path, {"GitHub": {}})
meta, written = write_meta_if_changed(
str(data_path), str(meta_path), "0.6.0", "https://example/data.json"
)
assert written is True
assert meta_path.exists()
on_disk = json.loads(meta_path.read_text())
assert on_disk["sites_count"] == 1
assert on_disk["updated_at"] == meta["updated_at"]
def test_write_meta_skips_when_only_timestamp_would_change(tmp_path):
data_path = tmp_path / "data.json"
meta_path = tmp_path / "db_meta.json"
_write_data_json(data_path, {"GitHub": {}})
# First write seeds the file with an old timestamp.
old = datetime(2026, 1, 1, tzinfo=timezone.utc)
_, written_first = write_meta_if_changed(
str(data_path), str(meta_path), "0.6.0", "https://example/data.json", now=old
)
assert written_first is True
seeded_bytes = meta_path.read_bytes()
# Second call with a NEW `now` but identical data.json — must be a no-op.
new = datetime(2027, 6, 15, tzinfo=timezone.utc)
_, written_second = write_meta_if_changed(
str(data_path), str(meta_path), "0.6.0", "https://example/data.json", now=new
)
assert written_second is False
# File on disk is byte-for-byte the same — including the OLD timestamp.
assert meta_path.read_bytes() == seeded_bytes
on_disk = json.loads(meta_path.read_text())
assert on_disk["updated_at"] == "2026-01-01T00:00:00Z"
def test_write_meta_writes_when_data_sha256_changes(tmp_path):
data_path = tmp_path / "data.json"
meta_path = tmp_path / "db_meta.json"
_write_data_json(data_path, {"GitHub": {}})
write_meta_if_changed(
str(data_path),
str(meta_path),
"0.6.0",
"https://example/data.json",
now=datetime(2026, 1, 1, tzinfo=timezone.utc),
)
# Real change to data.json — sha256 + sites_count both move.
_write_data_json(data_path, {"GitHub": {}, "GitLab": {}})
new_now = datetime(2027, 6, 15, tzinfo=timezone.utc)
meta, written = write_meta_if_changed(
str(data_path), str(meta_path), "0.6.0", "https://example/data.json", now=new_now
)
assert written is True
on_disk = json.loads(meta_path.read_text())
assert on_disk["sites_count"] == 2
assert on_disk["updated_at"] == "2027-06-15T00:00:00Z"
def test_write_meta_writes_when_min_version_changes(tmp_path):
data_path = tmp_path / "data.json"
meta_path = tmp_path / "db_meta.json"
_write_data_json(data_path, {"GitHub": {}})
write_meta_if_changed(
str(data_path),
str(meta_path),
"0.5.0",
"https://example/data.json",
now=datetime(2026, 1, 1, tzinfo=timezone.utc),
)
_, written = write_meta_if_changed(
str(data_path),
str(meta_path),
"0.6.0", # bumped
"https://example/data.json",
now=datetime(2026, 1, 2, tzinfo=timezone.utc),
)
assert written is True
on_disk = json.loads(meta_path.read_text())
assert on_disk["min_maigret_version"] == "0.6.0"
def test_write_meta_writes_when_existing_file_is_corrupt(tmp_path):
data_path = tmp_path / "data.json"
meta_path = tmp_path / "db_meta.json"
_write_data_json(data_path, {"GitHub": {}})
meta_path.write_text("this is not valid json")
_, written = write_meta_if_changed(
str(data_path), str(meta_path), "0.6.0", "https://example/data.json"
)
assert written is True
json.loads(meta_path.read_text()) # now parseable
def test_resolve_min_version_prefers_cli_value(tmp_path):
meta_path = tmp_path / "db_meta.json"
meta_path.write_text(json.dumps({"min_maigret_version": "0.6.1"}))
assert resolve_min_version("0.9.0", str(meta_path)) == "0.9.0"
def test_resolve_min_version_preserves_existing_when_no_cli_value(tmp_path):
# Routine regeneration (e.g. after a version bump) must keep the existing
# floor, not raise it to the current release.
meta_path = tmp_path / "db_meta.json"
meta_path.write_text(json.dumps({"min_maigret_version": "0.5.0"}))
assert resolve_min_version(None, str(meta_path)) == "0.5.0"
def test_resolve_min_version_falls_back_to_default_when_no_meta(tmp_path):
meta_path = tmp_path / "db_meta.json" # does not exist
assert resolve_min_version(None, str(meta_path)) == DEFAULT_MIN_VERSION
def test_build_meta_uses_provided_now(tmp_path):
data_path = tmp_path / "data.json"
_write_data_json(data_path, {"GitHub": {}})
fixed = datetime(2030, 7, 4, 12, 0, 0, tzinfo=timezone.utc)
meta = build_meta(str(data_path), "0.6.0", "https://example/data.json", now=fixed)
assert meta["updated_at"] == "2030-07-04T12:00:00Z"
# ---------------------------------------------------------------------------
# update_site_data
# ---------------------------------------------------------------------------
_SITES_MD_TEMPLATE = (
"## List of supported sites (search methods): total 1\n\n"
"Rank data fetched from Majestic Million by domains.\n\n"
"1. [GitHub](https://github.com/)*: top 100*\n"
"\nThe list was updated at ({date})\n"
"## Statistics\n\n"
"Some stats.\n"
)
def test_sites_md_payload_equals_ignores_date():
a = _SITES_MD_TEMPLATE.format(date="2026-01-01")
b = _SITES_MD_TEMPLATE.format(date="2027-12-31")
assert sites_md_payload_equals(a, b)
def test_sites_md_payload_equals_detects_body_change():
a = _SITES_MD_TEMPLATE.format(date="2026-01-01")
b = a.replace("GitHub", "GitLab")
assert not sites_md_payload_equals(a, b)
def test_write_sites_md_creates_file_when_missing(tmp_path):
target = tmp_path / "sites.md"
content = _SITES_MD_TEMPLATE.format(date="2026-05-15")
written = write_sites_md_if_changed(content, str(target))
assert written is True
assert target.read_text() == content
def test_write_sites_md_skips_when_only_date_would_change(tmp_path):
target = tmp_path / "sites.md"
seeded = _SITES_MD_TEMPLATE.format(date="2026-01-01")
target.write_text(seeded)
# New content has a different date but identical body.
new_content = _SITES_MD_TEMPLATE.format(date="2027-12-31")
written = write_sites_md_if_changed(new_content, str(target))
assert written is False
# File untouched, including the OLD date.
assert target.read_text() == seeded
def test_write_sites_md_writes_when_body_changes(tmp_path):
target = tmp_path / "sites.md"
target.write_text(_SITES_MD_TEMPLATE.format(date="2026-01-01"))
new_content = _SITES_MD_TEMPLATE.format(date="2026-01-01").replace(
"GitHub", "GitLab"
)
written = write_sites_md_if_changed(new_content, str(target))
assert written is True
assert "GitLab" in target.read_text()
assert "GitHub" not in target.read_text()