22# All rights reserved
33# Licensed under a 3-clause BSD style license (see LICENSE)
44
5- """Unit tests for TUFPointerDownloader (v2 repository format).
6-
7- All tests are offline: the TUF Updater and HTTP calls are mocked so that no
8- network traffic is needed.
9- """
5+ """Unit tests for TUFPointerDownloader (v2 repository format)."""
106
117import hashlib
128import json
1814from datadog_checks .downloader .download_v2 import TUFPointerDownloader
1915from datadog_checks .downloader .exceptions import DigestMismatch , TargetNotFoundError
2016
21- # ---------------------------------------------------------------------------
22- # Shared fixtures
23- # ---------------------------------------------------------------------------
24-
2517_PROJECT = 'datadog-postgres'
2618_VERSION = '14.0.0'
2719_WHEEL_CONTENT = b'fake wheel bytes for testing'
2820_WHEEL_DIGEST = hashlib .sha256 (_WHEEL_CONTENT ).hexdigest ()
2921_WHEEL_LENGTH = len (_WHEEL_CONTENT )
22+ _REPO_URL = 'https://agent-integration-wheels-staging.s3.amazonaws.com'
3023
3124_POINTER = {
3225 'digest' : _WHEEL_DIGEST ,
3326 'length' : _WHEEL_LENGTH ,
3427 'version' : _VERSION ,
35- 'repository' : 'https://agent-integration-wheels-staging.s3.amazonaws.com' ,
28+ 'repository' : _REPO_URL ,
3629 'wheel_path' : f'/wheels/{ _PROJECT } /datadog_postgres-{ _VERSION } -py3-none-any.whl' ,
3730 'attestation_path' : f'/attestations/{ _PROJECT } /{ _VERSION } .sigstore.json' ,
3831}
3932
40- _REPO_URL = 'https://agent-integration-wheels-staging.s3.amazonaws.com'
41-
4233
4334def _mock_tuf_updater (pointer : dict ) -> MagicMock :
44- """Return a mock Updater that yields *pointer* as the target content."""
35+ """Return an Updater mock that writes *pointer* as target content."""
4536 pointer_bytes = json .dumps (pointer ).encode ()
4637 mock_updater = MagicMock ()
4738 mock_updater .get_targetinfo .return_value = MagicMock ()
@@ -54,9 +45,26 @@ def fake_download_target(_target_info, dest_path):
5445 return mock_updater
5546
5647
57- # ---------------------------------------------------------------------------
58- # target-path unit tests
59- # ---------------------------------------------------------------------------
48+ def _mock_response (content : bytes ) -> MagicMock :
49+ response = MagicMock ()
50+ response .__enter__ = lambda s : s
51+ response .__exit__ = MagicMock (return_value = False )
52+ response .read .return_value = content
53+ return response
54+
55+
56+ @pytest .fixture
57+ def mock_urlopen ():
58+ with patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' ) as mock :
59+ mock .return_value = _mock_response (_WHEEL_CONTENT )
60+ yield mock
61+
62+
63+ @pytest .fixture
64+ def mock_updater_cls ():
65+ with patch ('datadog_checks.downloader.download_v2.Updater' ) as mock :
66+ mock .return_value = _mock_tuf_updater (_POINTER )
67+ yield mock
6068
6169
6270class TestTargetPath :
@@ -67,85 +75,38 @@ def test_missing_version_uses_latest_pointer(self):
6775 assert TUFPointerDownloader ._target_path (_PROJECT , None ) == f'{ _PROJECT } /latest.json'
6876
6977
70- # ---------------------------------------------------------------------------
71- # Happy-path integration tests
72- # ---------------------------------------------------------------------------
73-
74-
7578@pytest .mark .offline
7679class TestHappyPath :
77- @patch ('datadog_checks.downloader.download_v2.Updater' )
78- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
7980 def test_download_returns_wheel_path (self , mock_urlopen , mock_updater_cls , tmp_path ):
80- mock_updater_cls .return_value = _mock_tuf_updater (_POINTER )
81-
82- mock_urlopen .return_value .__enter__ = lambda s : s
83- mock_urlopen .return_value .__exit__ = MagicMock (return_value = False )
84- mock_urlopen .return_value .read .return_value = _WHEEL_CONTENT
85-
8681 downloader = TUFPointerDownloader (repository_url = _REPO_URL )
8782 wheel_path = downloader .download (_PROJECT , version = _VERSION , dest_dir = tmp_path )
8883
8984 assert wheel_path .exists ()
9085 assert wheel_path .read_bytes () == _WHEEL_CONTENT
9186 assert wheel_path .name == f'datadog_postgres-{ _VERSION } -py3-none-any.whl'
9287
93- @patch ('datadog_checks.downloader.download_v2.Updater' )
94- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
9588 def test_repository_flag_overrides_pointer_repository (self , mock_urlopen , mock_updater_cls , tmp_path ):
96- """--repository supersedes the repository field baked into the pointer."""
97- staging_url = 'https://agent-integration-wheels-staging.s3.amazonaws.com'
9889 prod_pointer = {** _POINTER , 'repository' : 'https://agent-integration-wheels-prod.s3.amazonaws.com' }
9990 mock_updater_cls .return_value = _mock_tuf_updater (prod_pointer )
10091
101- captured_urls : list [str ] = []
102-
103- def fake_urlopen (url ):
104- captured_urls .append (url )
105- mock_resp = MagicMock ()
106- mock_resp .__enter__ = lambda s : s
107- mock_resp .__exit__ = MagicMock (return_value = False )
108- mock_resp .read .return_value = _WHEEL_CONTENT
109- return mock_resp
110-
111- mock_urlopen .side_effect = fake_urlopen
112-
113- downloader = TUFPointerDownloader (repository_url = staging_url )
92+ downloader = TUFPointerDownloader (repository_url = _REPO_URL )
11493 downloader .download (_PROJECT , version = _VERSION , dest_dir = tmp_path )
11594
116- wheel_fetch_url = captured_urls [- 1 ]
117- assert wheel_fetch_url .startswith (staging_url ), (
118- f'Expected wheel fetch from { staging_url !r} , got { wheel_fetch_url !r} '
95+ mock_urlopen .assert_called_once_with (
96+ f'{ _REPO_URL } /wheels/{ _PROJECT } /datadog_postgres-{ _VERSION } -py3-none-any.whl'
11997 )
12098
121- @patch ('datadog_checks.downloader.download_v2.Updater' )
122- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
12399 def test_version_none_fetches_latest_pointer (self , mock_urlopen , mock_updater_cls , tmp_path ):
124- """version=None fetches <project>/latest.json."""
125- mock_updater = _mock_tuf_updater (_POINTER )
126- mock_updater_cls .return_value = mock_updater
127-
128- mock_urlopen .return_value .__enter__ = lambda s : s
129- mock_urlopen .return_value .__exit__ = MagicMock (return_value = False )
130- mock_urlopen .return_value .read .return_value = _WHEEL_CONTENT
131-
132100 downloader = TUFPointerDownloader (repository_url = _REPO_URL )
133101 downloader .download (_PROJECT , dest_dir = tmp_path )
134102
135- call_args = mock_updater .get_targetinfo .call_args [0 ][0 ]
136- assert call_args == f'{ _PROJECT } /latest.json'
137-
138-
139- # ---------------------------------------------------------------------------
140- # Error-path tests
141- # ---------------------------------------------------------------------------
103+ mock_updater = mock_updater_cls .return_value
104+ assert mock_updater .get_targetinfo .call_args [0 ][0 ] == f'{ _PROJECT } /latest.json'
142105
143106
144107@pytest .mark .offline
145108class TestTargetNotFound :
146- @patch ('datadog_checks.downloader.download_v2.Updater' )
147- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
148- def test_raises_when_tuf_target_absent (self , mock_urlopen , mock_updater_cls , tmp_path ):
109+ def test_raises_when_tuf_target_absent (self , mock_urlopen , mock_updater_cls ):
149110 mock_updater = MagicMock ()
150111 mock_updater .get_targetinfo .return_value = None
151112 mock_updater_cls .return_value = mock_updater
@@ -157,66 +118,37 @@ def test_raises_when_tuf_target_absent(self, mock_urlopen, mock_updater_cls, tmp
157118
158119@pytest .mark .offline
159120class TestDigestMismatch :
160- @patch ('datadog_checks.downloader.download_v2.Updater' )
161- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
162121 def test_raises_on_corrupted_wheel (self , mock_urlopen , mock_updater_cls , tmp_path ):
163- mock_updater_cls .return_value = _mock_tuf_updater (_POINTER )
164-
165- mock_urlopen .return_value .__enter__ = lambda s : s
166- mock_urlopen .return_value .__exit__ = MagicMock (return_value = False )
167- mock_urlopen .return_value .read .return_value = b'tampered bytes'
122+ mock_urlopen .return_value = _mock_response (b'tampered bytes' )
168123
169124 downloader = TUFPointerDownloader (repository_url = _REPO_URL )
170125 with pytest .raises (DigestMismatch , match = _PROJECT ):
171126 downloader .download (_PROJECT , version = _VERSION , dest_dir = tmp_path )
172127
173- @patch ('datadog_checks.downloader.download_v2.Updater' )
174- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
175128 def test_raises_on_length_mismatch (self , mock_urlopen , mock_updater_cls , tmp_path ):
176129 bad_pointer = {** _POINTER , 'length' : _WHEEL_LENGTH + 1 }
177130 mock_updater_cls .return_value = _mock_tuf_updater (bad_pointer )
178131
179- mock_urlopen .return_value .__enter__ = lambda s : s
180- mock_urlopen .return_value .__exit__ = MagicMock (return_value = False )
181- mock_urlopen .return_value .read .return_value = _WHEEL_CONTENT
182-
183132 downloader = TUFPointerDownloader (repository_url = _REPO_URL )
184133 with pytest .raises (DigestMismatch , match = 'length' ):
185134 downloader .download (_PROJECT , version = _VERSION , dest_dir = tmp_path )
186135
187136
188- # ---------------------------------------------------------------------------
189- # Disable-verification mode
190- # ---------------------------------------------------------------------------
191-
192-
193137@pytest .mark .offline
194138class TestDisableVerification :
195- @patch ('datadog_checks.downloader.download_v2.urllib.request.urlopen' )
196139 def test_directly_downloads_wheel_without_tuf_or_digest_checks (self , mock_urlopen , tmp_path ):
197- """disable_verification bypasses TUF/pointers and downloads the wheel by
198- convention from /wheels/<project>/<wheel>.whl."""
199- captured_urls : list [str ] = []
200-
201- def fake_urlopen (url ):
202- captured_urls .append (url )
203- mock_resp = MagicMock ()
204- mock_resp .__enter__ = lambda s : s
205- mock_resp .__exit__ = MagicMock (return_value = False )
206- mock_resp .read .return_value = b'bytes not matching any signed pointer'
207- return mock_resp
208-
209- mock_urlopen .side_effect = fake_urlopen
140+ content = b'bytes not matching any signed pointer'
141+ mock_urlopen .return_value = _mock_response (content )
210142
211143 with patch ('datadog_checks.downloader.download_v2.Updater' ) as mock_updater_cls :
212144 downloader = TUFPointerDownloader (repository_url = _REPO_URL , disable_verification = True )
213145 wheel_path = downloader .download (_PROJECT , version = _VERSION , dest_dir = tmp_path )
214146
215- assert captured_urls == [
216- f'{ _REPO_URL } /wheels/{ _PROJECT } /datadog_postgres-{ _VERSION } -py3-none-any.whl' ,
217- ]
147+ mock_urlopen . assert_called_once_with (
148+ f'{ _REPO_URL } /wheels/{ _PROJECT } /datadog_postgres-{ _VERSION } -py3-none-any.whl'
149+ )
218150 assert wheel_path .name == f'datadog_postgres-{ _VERSION } -py3-none-any.whl'
219- assert wheel_path .read_bytes () == b'bytes not matching any signed pointer'
151+ assert wheel_path .read_bytes () == content
220152 mock_updater_cls .assert_not_called ()
221153
222154 def test_direct_download_requires_explicit_version (self , tmp_path ):
0 commit comments