Skip to content

Commit d3b877b

Browse files
author
Jussi Kukkonen
authored
Merge pull request #1705 from kairoaraujo/issue#1682/repositorysimulator-fetch-tracker
Implemented fetch_tracker to RepositorySimulator
2 parents b2d8572 + 35cbc3e commit d3b877b

File tree

2 files changed

+57
-46
lines changed

2 files changed

+57
-46
lines changed

tests/repository_simulator.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
import os
4949
import tempfile
5050
from collections import OrderedDict
51-
from dataclasses import dataclass
51+
from dataclasses import dataclass, field
5252
from datetime import datetime, timedelta
5353
from typing import Dict, Iterator, List, Optional, Tuple
5454
from urllib import parse
@@ -81,6 +81,14 @@
8181
SPEC_VER = ".".join(SPECIFICATION_VERSION)
8282

8383

84+
@dataclass
85+
class FetchTracker:
86+
"""Fetcher counter for metadata and targets."""
87+
88+
metadata: List[Tuple[str, Optional[int]]] = field(default_factory=list)
89+
targets: List[Tuple[str, Optional[str]]] = field(default_factory=list)
90+
91+
8492
@dataclass
8593
class RepositoryTarget:
8694
"""Contains actual target data and the related target metadata."""
@@ -116,6 +124,8 @@ def __init__(self) -> None:
116124
self.dump_dir: Optional[str] = None
117125
self.dump_version = 0
118126

127+
self.fetch_tracker = FetchTracker()
128+
119129
now = datetime.utcnow()
120130
self.safe_expiry = now.replace(microsecond=0) + timedelta(days=30)
121131

@@ -229,6 +239,8 @@ def _fetch_target(
229239
230240
If hash is None, then consistent_snapshot is not used.
231241
"""
242+
self.fetch_tracker.targets.append((target_path, target_hash))
243+
232244
repo_target = self.target_files.get(target_path)
233245
if repo_target is None:
234246
raise FetcherHTTPError(f"No target {target_path}", 404)
@@ -248,6 +260,8 @@ def _fetch_metadata(
248260
249261
If version is None, non-versioned metadata is being requested.
250262
"""
263+
self.fetch_tracker.metadata.append((role, version))
264+
251265
if role == Root.type:
252266
# return a version previously serialized in publish_root()
253267
if version is None or version > len(self.signed_roots):

tests/test_updater_consistent_snapshot.py

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import tempfile
1111
import unittest
1212
from typing import Any, Dict, Iterable, List, Optional
13-
from unittest.mock import call, patch
1413

1514
from tests import utils
1615
from tests.repository_simulator import RepositorySimulator
@@ -90,19 +89,19 @@ def _assert_targets_files_exist(self, filenames: Iterable[str]) -> None:
9089
"consistent_snaphot disabled": {
9190
"consistent_snapshot": False,
9291
"calls": [
93-
call("root", 3),
94-
call("timestamp", None),
95-
call("snapshot", None),
96-
call("targets", None),
92+
("root", 3),
93+
("timestamp", None),
94+
("snapshot", None),
95+
("targets", None),
9796
],
9897
},
9998
"consistent_snaphot enabled": {
10099
"consistent_snapshot": True,
101100
"calls": [
102-
call("root", 3),
103-
call("timestamp", None),
104-
call("snapshot", 1),
105-
call("targets", 1),
101+
("root", 3),
102+
("timestamp", None),
103+
("snapshot", 1),
104+
("targets", 1),
106105
],
107106
},
108107
}
@@ -117,15 +116,14 @@ def test_top_level_roles_update(self, test_case_data: Dict[str, Any]):
117116
sim = self._init_repo(consistent_snapshot)
118117
updater = self._init_updater(sim)
119118

120-
with patch.object(
121-
sim, "_fetch_metadata", wraps=sim._fetch_metadata
122-
) as wrapped_fetch:
123-
updater.refresh()
119+
# cleanup fetch tracker metadata
120+
sim.fetch_tracker.metadata.clear()
121+
updater.refresh()
124122

125-
# metadata files are fetched with the expected version (or None)
126-
self.assertListEqual(wrapped_fetch.call_args_list, expected_calls)
127-
# metadata files are always persisted without a version prefix
128-
self._assert_metadata_files_exist(TOP_LEVEL_ROLE_NAMES)
123+
# metadata files are fetched with the expected version (or None)
124+
self.assertListEqual(sim.fetch_tracker.metadata, expected_calls)
125+
# metadata files are always persisted without a version prefix
126+
self._assert_metadata_files_exist(TOP_LEVEL_ROLE_NAMES)
129127

130128
self._cleanup_dir(self.metadata_dir)
131129

@@ -147,7 +145,7 @@ def test_delegated_roles_update(self, test_case_data: Dict[str, Any]):
147145
consistent_snapshot: bool = test_case_data["consistent_snapshot"]
148146
expected_version: Optional[int] = test_case_data["expected_version"]
149147
rolenames = ["role1", "..", "."]
150-
expected_calls = [call(role, expected_version) for role in rolenames]
148+
expected_calls = [(role, expected_version) for role in rolenames]
151149

152150
sim = self._init_repo(consistent_snapshot)
153151
# Add new delegated targets
@@ -159,15 +157,14 @@ def test_delegated_roles_update(self, test_case_data: Dict[str, Any]):
159157
updater = self._init_updater(sim)
160158
updater.refresh()
161159

162-
with patch.object(
163-
sim, "_fetch_metadata", wraps=sim._fetch_metadata
164-
) as wrapped_fetch:
165-
# trigger updater to fetch the delegated metadata
166-
updater.get_targetinfo("anything")
167-
# metadata files are fetched with the expected version (or None)
168-
self.assertListEqual(wrapped_fetch.call_args_list, expected_calls)
169-
# metadata files are always persisted without a version prefix
170-
self._assert_metadata_files_exist(rolenames)
160+
# cleanup fetch tracker metadata
161+
sim.fetch_tracker.metadata.clear()
162+
# trigger updater to fetch the delegated metadata
163+
updater.get_targetinfo("anything")
164+
# metadata files are fetched with the expected version (or None)
165+
self.assertListEqual(sim.fetch_tracker.metadata, expected_calls)
166+
# metadata files are always persisted without a version prefix
167+
self._assert_metadata_files_exist(rolenames)
171168

172169
self._cleanup_dir(self.metadata_dir)
173170

@@ -176,16 +173,19 @@ def test_delegated_roles_update(self, test_case_data: Dict[str, Any]):
176173
"consistent_snapshot": False,
177174
"prefix_targets": True,
178175
"hash_algo": None,
176+
"targetpaths": ["file", "file.txt", "..file.ext", "f.le"],
179177
},
180178
"consistent_snaphot enabled without prefixed targets": {
181179
"consistent_snapshot": True,
182180
"prefix_targets": False,
183181
"hash_algo": None,
182+
"targetpaths": ["file", "file.txt", "..file.ext", "f.le"],
184183
},
185184
"consistent_snaphot enabled with prefixed targets": {
186185
"consistent_snapshot": True,
187186
"prefix_targets": True,
188187
"hash_algo": "sha256",
188+
"targetpaths": ["file", "file.txt", "..file.ext", "f.le"],
189189
},
190190
}
191191

@@ -197,7 +197,7 @@ def test_download_targets(self, test_case_data: Dict[str, Any]):
197197
consistent_snapshot: bool = test_case_data["consistent_snapshot"]
198198
prefix_targets_with_hash: bool = test_case_data["prefix_targets"]
199199
hash_algo: Optional[str] = test_case_data["hash_algo"]
200-
targetpaths = ["file", "file.txt", "..file.ext", "f.le"]
200+
targetpaths: List[str] = test_case_data["targetpaths"]
201201

202202
sim = self._init_repo(consistent_snapshot, prefix_targets_with_hash)
203203
# Add targets to repository
@@ -210,23 +210,20 @@ def test_download_targets(self, test_case_data: Dict[str, Any]):
210210
updater.config.prefix_targets_with_hash = prefix_targets_with_hash
211211
updater.refresh()
212212

213-
with patch.object(
214-
sim, "_fetch_target", wraps=sim._fetch_target
215-
) as wrapped_fetch_target:
216-
217-
for targetpath in targetpaths:
218-
info = updater.get_targetinfo(targetpath)
219-
updater.download_target(info)
220-
expected_prefix = (
221-
None if not hash_algo else info.hashes[hash_algo]
222-
)
223-
# files are fetched with the expected hash prefix (or None)
224-
wrapped_fetch_target.assert_called_once_with(
225-
info.path, expected_prefix
226-
)
227-
# target files are always persisted without hash prefix
228-
self._assert_targets_files_exist([info.path])
229-
wrapped_fetch_target.reset_mock()
213+
for targetpath in targetpaths:
214+
info = updater.get_targetinfo(targetpath)
215+
updater.download_target(info)
216+
217+
# target files are always persisted without hash prefix
218+
self._assert_targets_files_exist([info.path])
219+
220+
# files are fetched with the expected hash prefix (or None)
221+
expected_fetches = [
222+
(targetpath, None if not hash_algo else info.hashes[hash_algo])
223+
]
224+
225+
self.assertListEqual(sim.fetch_tracker.targets, expected_fetches)
226+
sim.fetch_tracker.targets.clear()
230227

231228
self._cleanup_dir(self.targets_dir)
232229

0 commit comments

Comments
 (0)