11
11
import sys
12
12
import tempfile
13
13
import unittest
14
+ from datetime import datetime , timedelta
14
15
from typing import Optional , Tuple
15
- from unittest .mock import MagicMock , patch
16
+ from unittest .mock import call , MagicMock , patch
16
17
17
18
from tests import utils
18
19
from tests .repository_simulator import RepositorySimulator
19
20
from tuf .api .metadata import SPECIFICATION_VERSION , Targets
20
- from tuf .exceptions import BadVersionNumberError , UnsignedMetadataError
21
+ from tuf .exceptions import BadVersionNumberError , ExpiredMetadataError , UnsignedMetadataError
21
22
from tuf .ngclient import Updater
22
23
23
24
@@ -241,6 +242,7 @@ def test_not_loading_targets_twice(self, wrapped_open: MagicMock) -> None:
241
242
242
243
# Run refresh, top-level roles are loaded
243
244
updater = self ._run_refresh ()
245
+
244
246
# Clean up calls to open during refresh()
245
247
wrapped_open .reset_mock ()
246
248
@@ -254,6 +256,50 @@ def test_not_loading_targets_twice(self, wrapped_open: MagicMock) -> None:
254
256
updater .get_targetinfo ("somepath" )
255
257
wrapped_open .assert_not_called ()
256
258
259
+ @patch .object (builtins , "open" , wraps = builtins .open )
260
+ def test_expired_metadata (self , wrapped_open : MagicMock ) -> None :
261
+ updater = self ._run_refresh ()
262
+
263
+ past_datetime = datetime .utcnow ().replace (microsecond = 0 ) - timedelta (days = 5 )
264
+
265
+ self .sim .timestamp .expires = past_datetime
266
+ self .sim .snapshot .expires = past_datetime
267
+ self .sim .targets .expires = past_datetime
268
+
269
+ # Add targets to repository
270
+ self .sim .targets .version += 1
271
+ self .sim .add_target ("targets" , b'some content' , self .targets_dir )
272
+ self .sim .update_snapshot ()
273
+
274
+ # Clean up calls to open during refresh()
275
+ wrapped_open .reset_mock ()
276
+
277
+ # Make a successful update of valid metadata which stores it in cache
278
+ updater .get_targetinfo (self .targets_dir )
279
+
280
+ # Create a new updater and perform a second update while
281
+ # the metadata is already stored in cache (metadata dir)
282
+ updater = Updater (
283
+ self .metadata_dir ,
284
+ "https://example.com/metadata/" ,
285
+ self .targets_dir ,
286
+ "https://example.com/targets/" ,
287
+ self .sim ,
288
+ )
289
+
290
+ with self .assertRaises (ExpiredMetadataError ):
291
+ updater .get_targetinfo (self .targets_dir )
292
+
293
+ # Test that an expired timestamp/snapshot/targets
294
+ # when loaded from cache is not stored as final
295
+ # but is used to verify the new timestamp
296
+ wrapped_open .assert_has_calls ([
297
+ call (os .path .join (self .metadata_dir , "root.json" ), "rb" ),
298
+ call (os .path .join (self .metadata_dir , "timestamp.json" ), "rb" ),
299
+ ])
300
+
301
+ wrapped_open .reset_mock ()
302
+
257
303
258
304
if __name__ == "__main__" :
259
305
if "--dump" in sys .argv :
0 commit comments