|
11 | 11 | import sys
|
12 | 12 | import tempfile
|
13 | 13 | import unittest
|
14 |
| -from datetime import datetime, timedelta |
15 | 14 | from typing import Optional
|
16 |
| -from unittest.mock import MagicMock, call, patch |
| 15 | +from unittest.mock import MagicMock, Mock, patch |
17 | 16 |
|
18 | 17 | from tests import utils
|
19 | 18 | from tests.repository_simulator import RepositorySimulator
|
20 | 19 | from tuf.api.metadata import (
|
21 | 20 | SPECIFICATION_VERSION,
|
| 21 | + DelegatedRole, |
22 | 22 | Metadata,
|
23 | 23 | Targets,
|
24 | 24 | )
|
25 |
| -from tuf.api.serialization.json import JSONSerializer |
26 | 25 | from tuf.exceptions import BadVersionNumberError, UnsignedMetadataError
|
27 | 26 | from tuf.ngclient import Updater
|
28 | 27 |
|
@@ -213,74 +212,31 @@ def test_not_loading_targets_twice(self, wrapped_open: MagicMock) -> None:
|
213 | 212 | updater.get_targetinfo("somepath")
|
214 | 213 | wrapped_open.assert_not_called()
|
215 | 214 |
|
216 |
| - @patch.object(builtins, "open", wraps=builtins.open) |
217 |
| - def test_expired_metadata(self, wrapped_open: MagicMock) -> None: |
218 |
| - # Test that expired timestamp/snapshot can be used to verify the next |
219 |
| - # version of timestamp/snapshot respectively. |
220 |
| - # If there is an expired local targets it won't be verified and the |
221 |
| - # updater will try to fetch and verify the next version without using |
222 |
| - # any information from the old expired targets file. |
| 215 | + def test_expired_metadata(self) -> None: |
| 216 | + # Test that expired local timestamp/snapshot can be used for updating |
| 217 | + # from remote |
223 | 218 |
|
224 | 219 | # Make a successful update of valid metadata which stores it in cache
|
225 | 220 | self._run_refresh()
|
226 | 221 |
|
227 |
| - past_datetime = datetime.utcnow().replace(microsecond=0) - timedelta( |
228 |
| - days=5 |
229 |
| - ) |
230 |
| - |
231 |
| - # Store the future_datetime for future reference |
232 |
| - future_datetime = self.sim.timestamp.expires |
233 |
| - |
234 |
| - # Make version 1 stored metadata in the simulator expired. |
235 |
| - past_datetime = datetime.utcnow().replace(microsecond=0) - timedelta( |
236 |
| - weeks=52 |
237 |
| - ) |
238 |
| - self.sim.timestamp.expires = past_datetime |
239 |
| - self.sim.snapshot.expires = past_datetime |
240 |
| - self.sim.targets.expires = past_datetime |
241 |
| - |
242 |
| - # Serializer is used to serialize JSON in a human readable format. |
243 |
| - seriazer = JSONSerializer() |
244 |
| - |
245 |
| - # Replace current version 1 roles with expired ones. |
246 |
| - for role in ["timestamp", "snapshot"]: |
247 |
| - md = Metadata.from_bytes(self.sim.fetch_metadata(role)) |
248 |
| - md.to_file(f"{self.metadata_dir}/{role}.json", seriazer) |
249 |
| - |
250 |
| - # Make version 2 of the roles valid by using a future expiry date |
251 |
| - self.sim.timestamp.expires = future_datetime |
252 |
| - self.sim.snapshot.expires = future_datetime |
253 |
| - self.sim.targets.expires = future_datetime |
254 |
| - |
255 |
| - self.sim.targets.version += 1 |
256 |
| - self.sim.update_snapshot() |
257 |
| - |
258 |
| - # Clean up calls to open during refresh() |
259 |
| - wrapped_open.reset_mock() |
260 |
| - |
261 |
| - # Create a new updater and perform a second update while |
262 |
| - # the metadata is already stored in cache (metadata dir) |
263 |
| - self._run_refresh() |
264 |
| - |
265 |
| - # Test that an expired timestamp/snapshot when loaded from cache is not |
266 |
| - # stored as final but is used to verify the new timestamp |
267 |
| - wrapped_open.assert_has_calls( |
268 |
| - [ |
269 |
| - call(os.path.join(self.metadata_dir, "root.json"), "rb"), |
270 |
| - call(os.path.join(self.metadata_dir, "timestamp.json"), "rb"), |
271 |
| - call(os.path.join(self.metadata_dir, "snapshot.json"), "rb"), |
272 |
| - call(os.path.join(self.metadata_dir, "targets.json"), "rb"), |
273 |
| - ] |
| 222 | + # Simulate expired local metadata by mocking system time one second ahead |
| 223 | + mock_time = Mock() |
| 224 | + mock_time.return_value = ( |
| 225 | + int(self.sim.timestamp.expires.strftime("%Y%m%d%H%M%S")) + 1 |
274 | 226 | )
|
| 227 | + with patch("time.time", mock_time): |
| 228 | + self.sim.targets.version += 1 |
| 229 | + self.sim.update_snapshot() |
| 230 | + # Create a new updater and perform a second update while |
| 231 | + # the metadata is already stored in cache (metadata dir) |
| 232 | + self._run_refresh() |
275 | 233 |
|
276 |
| - # Assert that the final version of timestamp/snapshot is version 2 with |
277 |
| - # a future expiry date. |
| 234 | + # Assert that the final version of timestamp/snapshot is version 2 |
| 235 | + # which means a successful refresh is performed |
| 236 | + # with expired local metadata |
278 | 237 | for role in ["timestamp", "snapshot", "targets"]:
|
279 | 238 | md = Metadata.from_file(f"{self.metadata_dir}/{role}.json")
|
280 | 239 | self.assertEqual(md.signed.version, 2)
|
281 |
| - self.assertEqual(md.signed.expires, future_datetime) |
282 |
| - |
283 |
| - wrapped_open.reset_mock() |
284 | 240 |
|
285 | 241 |
|
286 | 242 | if __name__ == "__main__":
|
|
0 commit comments