|
5 | 5 | import json |
6 | 6 | import xml.etree.ElementTree as E |
7 | 7 |
|
| 8 | +from datetime import datetime, timezone |
8 | 9 | from pathlib import Path |
| 10 | +from unittest.mock import MagicMock, patch |
9 | 11 |
|
10 | 12 | import pytest |
11 | 13 | import requests_mock as req_mock # noqa: F401 — activates the requests_mock fixture |
@@ -87,6 +89,59 @@ def test_fetch_file_not_found( |
87 | 89 | client.fetch_file(url, output_dir=str(tmp_path)) |
88 | 90 |
|
89 | 91 |
|
| 92 | +def test_fetch_file_skips_download_when_local_file_is_newer( |
| 93 | + tmp_path: Path, |
| 94 | + client: TINDClient, |
| 95 | +) -> None: |
| 96 | + """fetch_file returns the cached path without downloading when local mtime >= meta_mtime.""" |
| 97 | + |
| 98 | + url = f"{BASE_URL}/api/v1/record/12345/files/some-image.jpg/download/?version=1" |
| 99 | + cached = tmp_path / "some-image.jpg" |
| 100 | + cached.write_bytes(b"cached content") |
| 101 | + |
| 102 | + meta_mtime = datetime(2026, 1, 1, 0, 0, 0, tzinfo=timezone.utc) |
| 103 | + local_mtime = datetime(2026, 1, 3, 0, 0, 0, tzinfo=timezone.utc) # newer |
| 104 | + |
| 105 | + mock_stat = MagicMock() |
| 106 | + mock_stat.st_mtime = local_mtime.timestamp() |
| 107 | + |
| 108 | + with patch.object(Path, "stat", return_value=mock_stat): |
| 109 | + result = client.fetch_file(url, output_dir=str(tmp_path), meta_mtime=meta_mtime) |
| 110 | + |
| 111 | + assert result == str(cached) |
| 112 | + |
| 113 | + |
| 114 | +def test_fetch_file_redownloads_when_local_file_is_older( |
| 115 | + requests_mock: req_mock.Mocker, |
| 116 | + tmp_path: Path, |
| 117 | + client: TINDClient, |
| 118 | +) -> None: |
| 119 | + """fetch_file re-downloads when local mtime < meta_mtime.""" |
| 120 | + |
| 121 | + url = f"{BASE_URL}/api/v1/record/12345/files/some-other-image.jpg/download/?version=1" |
| 122 | + cached = tmp_path / "some-other-image.jpg" |
| 123 | + cached.write_bytes(b"stale content") |
| 124 | + |
| 125 | + meta_mtime = datetime(2026, 1, 3, 0, 0, 0, tzinfo=timezone.utc) |
| 126 | + local_mtime = datetime(2026, 1, 1, 0, 0, 0, tzinfo=timezone.utc) # older |
| 127 | + |
| 128 | + mock_stat = MagicMock() |
| 129 | + mock_stat.st_mtime = local_mtime.timestamp() |
| 130 | + |
| 131 | + requests_mock.get( |
| 132 | + url, |
| 133 | + content=b"fresh content", |
| 134 | + status_code=200, |
| 135 | + headers={"Content-Disposition": 'attachment; filename="some-other-image.jpg"'}, |
| 136 | + ) |
| 137 | + |
| 138 | + with patch.object(Path, "stat", return_value=mock_stat): |
| 139 | + result = client.fetch_file(url, output_dir=str(tmp_path), meta_mtime=meta_mtime) |
| 140 | + |
| 141 | + assert result.endswith("some-other-image.jpg") |
| 142 | + assert Path(result).read_bytes() == b"fresh content" |
| 143 | + |
| 144 | + |
90 | 145 | # --------------------------------------------------------------------------- |
91 | 146 | # fetch_file_metadata |
92 | 147 | # --------------------------------------------------------------------------- |
|
0 commit comments