Skip to content

Commit f2ce93a

Browse files
authored
Merge pull request pulp#676 from gerrod3/test-modernize
Modernize tests to use new fixtures
2 parents 2db2339 + 7188049 commit f2ce93a

24 files changed

+1319
-3057
lines changed

CHANGES/pulpcore.removal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Raised the minimum `pulpcore` bound to `>=3.49` and dropped support for `python 3.8`.

functest_requirements.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
git+https://github.com/pulp/pulp-smash.git#egg=pulp-smash
21
pytest<8
32
lxml
43
twine
54
pypi-simple
65
pulpcore-client
76
pulp-python-client
7+
pytest-custom_exit_code
8+
pytest-xdist
9+
proxy.py~=2.4.4
10+
trustme~=1.1.0

pulp_python/pytest_plugin.py

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import pytest
2+
import uuid
3+
import subprocess
4+
5+
from pulpcore.tests.functional.utils import BindingsNamespace
6+
from pulp_python.tests.functional.constants import (
7+
PYTHON_FIXTURE_URL,
8+
PYTHON_XS_PROJECT_SPECIFIER,
9+
PYTHON_EGG_FILENAME,
10+
PYTHON_URL,
11+
)
12+
13+
14+
# Bindings API Fixtures
15+
16+
17+
@pytest.fixture(scope="session")
18+
def python_bindings(_api_client_set, bindings_cfg):
19+
"""
20+
A namespace providing preconfigured pulp_python api clients.
21+
22+
e.g. `python_bindings.RepositoriesPythonApi.list()`.
23+
"""
24+
from pulpcore.client import pulp_python as python_bindings_module
25+
26+
api_client = python_bindings_module.ApiClient(bindings_cfg)
27+
_api_client_set.add(api_client)
28+
yield BindingsNamespace(python_bindings_module, api_client)
29+
_api_client_set.remove(api_client)
30+
31+
32+
# Object Generation Fixtures
33+
34+
35+
@pytest.fixture
36+
def python_repo_factory(python_bindings, gen_object_with_cleanup):
37+
"""A factory to generate a Python Repository with auto-cleanup."""
38+
def _gen_python_repo(remote=None, **body):
39+
body.setdefault("name", str(uuid.uuid4()))
40+
if remote:
41+
body["remote"] = remote if isinstance(remote, str) else remote.pulp_href
42+
return gen_object_with_cleanup(python_bindings.RepositoriesPythonApi, body)
43+
44+
return _gen_python_repo
45+
46+
47+
@pytest.fixture
48+
def python_repo(python_repo_factory):
49+
"""Creates a Python Repository and deletes it at test cleanup time."""
50+
return python_repo_factory()
51+
52+
53+
@pytest.fixture
54+
def python_distribution_factory(python_bindings, gen_object_with_cleanup):
55+
"""A factory to generate a Python Distribution with auto-cleanup."""
56+
def _gen_python_distribution(publication=None, repository=None, version=None, **body):
57+
name = str(uuid.uuid4())
58+
body.setdefault("name", name)
59+
body.setdefault("base_path", name)
60+
if publication:
61+
body["publication"] = get_href(publication)
62+
elif repository:
63+
repo_href = get_href(repository)
64+
if version:
65+
if version.isnumeric():
66+
ver_href = f"{repo_href}versions/{version}/"
67+
else:
68+
ver_href = get_href(version)
69+
body = {"repository_version": ver_href}
70+
else:
71+
body["repository"] = repo_href
72+
return gen_object_with_cleanup(python_bindings.DistributionsPypiApi, body)
73+
74+
yield _gen_python_distribution
75+
76+
77+
@pytest.fixture
78+
def python_publication_factory(python_bindings, gen_object_with_cleanup):
79+
"""A factory to generate a Python Publication with auto-cleanup."""
80+
def _gen_python_publication(repository, version=None):
81+
repo_href = get_href(repository)
82+
if version:
83+
if version.isnumeric():
84+
ver_href = f"{repo_href}versions/{version}/"
85+
else:
86+
ver_href = get_href(version)
87+
body = {"repository_version": ver_href}
88+
else:
89+
body = {"repository": repo_href}
90+
return gen_object_with_cleanup(python_bindings.PublicationsPypiApi, body)
91+
92+
yield _gen_python_publication
93+
94+
95+
@pytest.fixture
96+
def python_remote_factory(python_bindings, gen_object_with_cleanup):
97+
"""A factory to generate a Python Remote with auto-cleanup."""
98+
def _gen_python_remote(url=PYTHON_FIXTURE_URL, includes=None, **body):
99+
body.setdefault("name", str(uuid.uuid4()))
100+
body.setdefault("url", url)
101+
if includes is None:
102+
includes = PYTHON_XS_PROJECT_SPECIFIER
103+
body["includes"] = includes
104+
return gen_object_with_cleanup(python_bindings.RemotesPythonApi, body)
105+
106+
yield _gen_python_remote
107+
108+
109+
@pytest.fixture
110+
def python_repo_with_sync(
111+
python_bindings, python_repo_factory, python_remote_factory, monitor_task
112+
):
113+
"""A factory to generate a Python Repository synced with the passed in Remote."""
114+
def _gen_python_repo_sync(remote=None, mirror=False, repository=None, **body):
115+
remote = remote or python_remote_factory()
116+
repo = repository or python_repo_factory(**body)
117+
sync_body = {"mirror": mirror, "remote": remote.pulp_href}
118+
monitor_task(python_bindings.RepositoriesPythonApi.sync(repo.pulp_href, sync_body).task)
119+
return python_bindings.RepositoriesPythonApi.read(repo.pulp_href)
120+
121+
yield _gen_python_repo_sync
122+
123+
124+
@pytest.fixture
125+
def download_python_file(tmp_path, http_get):
126+
"""Download a Python file and return its path."""
127+
def _download_python_file(relative_path, url):
128+
file_path = tmp_path / relative_path
129+
with open(file_path, mode="wb") as f:
130+
f.write(http_get(url))
131+
return file_path
132+
133+
yield _download_python_file
134+
135+
136+
@pytest.fixture
137+
def python_file(download_python_file):
138+
"""Get a default (shelf-reader.tar.gz) Python file."""
139+
return download_python_file(PYTHON_EGG_FILENAME, PYTHON_URL)
140+
141+
142+
@pytest.fixture
143+
def python_content_factory(python_bindings, download_python_file, monitor_task):
144+
"""A factory to create a Python Package Content."""
145+
def _gen_python_content(relative_path=PYTHON_EGG_FILENAME, url=None, **body):
146+
body["relative_path"] = relative_path
147+
if url:
148+
body["file"] = download_python_file(relative_path, url)
149+
elif not any(x in body for x in ("artifact", "file", "upload")):
150+
body["file"] = download_python_file(PYTHON_EGG_FILENAME, PYTHON_URL)
151+
if repo := body.get("repository"):
152+
repo_href = repo if isinstance(repo, str) else repo.pulp_href
153+
body["repository"] = repo_href
154+
155+
task = python_bindings.ContentPackagesApi.create(**body).task
156+
response = monitor_task(task)
157+
return python_bindings.ContentPackagesApi.read(response.created_resources[0])
158+
159+
yield _gen_python_content
160+
161+
162+
# Utility fixtures
163+
164+
165+
@pytest.fixture
166+
def shelf_reader_cleanup():
167+
"""Take care of uninstalling shelf-reader before/after the test."""
168+
cmd = ("pip", "uninstall", "shelf-reader", "-y")
169+
subprocess.run(cmd)
170+
yield
171+
subprocess.run(cmd)
172+
173+
174+
@pytest.fixture
175+
def python_content_summary(python_bindings):
176+
"""Get a summary of the repository version's content."""
177+
def _gen_summary(repository_version=None, repository=None, version=None):
178+
if repository_version is None:
179+
repo_href = get_href(repository)
180+
if version:
181+
repo_ver_href = f"{repo_href}versions/{version}/"
182+
else:
183+
repo_api = python_bindings.RepositoriesPythonApi
184+
repo_ver_href = repo_api.read(repo_href).latest_version_href
185+
else:
186+
repo_ver_href = get_href(repository_version)
187+
return python_bindings.RepositoriesPythonVersionsApi.read(repo_ver_href).content_summary
188+
189+
yield _gen_summary
190+
191+
192+
def get_href(item):
193+
"""Tries to get the href from the given item, wether it is a string or object."""
194+
return item if isinstance(item, str) else item.pulp_href
Lines changed: 41 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,41 @@
1-
# coding=utf-8
2-
"""Tests automatic updating of publications and distributions."""
3-
from pulp_smash.pulp3.bindings import monitor_task
4-
from pulp_smash.pulp3.utils import download_content_unit
5-
6-
from pulp_python.tests.functional.utils import (
7-
cfg,
8-
gen_python_remote,
9-
TestCaseUsingBindings,
10-
TestHelpersMixin
11-
)
12-
from pulp_python.tests.functional.utils import set_up_module as setUpModule # noqa:F401
13-
from pulpcore.client.pulp_python import RepositorySyncURL
14-
15-
16-
class AutoPublishDistributeTestCase(TestCaseUsingBindings, TestHelpersMixin):
17-
"""Test auto-publish and auto-distribution"""
18-
19-
def setUp(self):
20-
"""Create remote, repo, publish settings, and distribution."""
21-
self.remote = self.remote_api.create(gen_python_remote(policy="immediate"))
22-
self.addCleanup(self.remote_api.delete, self.remote.pulp_href)
23-
self.repo, self.distribution = self._create_empty_repo_and_distribution(autopublish=True)
24-
25-
def test_01_sync(self):
26-
"""Assert that syncing the repository triggers auto-publish and auto-distribution."""
27-
self.assertEqual(self.publications_api.list().count, 0)
28-
self.assertTrue(self.distribution.publication is None)
29-
30-
# Sync the repository.
31-
repository_sync_data = RepositorySyncURL(remote=self.remote.pulp_href)
32-
sync_response = self.repo_api.sync(self.repo.pulp_href, repository_sync_data)
33-
task = monitor_task(sync_response.task)
34-
35-
# Check that all the appropriate resources were created
36-
self.assertGreater(len(task.created_resources), 1)
37-
self.assertEqual(self.publications_api.list().count, 1)
38-
download_content_unit(cfg, self.distribution.to_dict(), "simple/")
39-
40-
# Sync the repository again. Since there should be no new repository version, there
41-
# should be no new publications or distributions either.
42-
sync_response = self.repo_api.sync(self.repo.pulp_href, repository_sync_data)
43-
task = monitor_task(sync_response.task)
44-
45-
self.assertEqual(len(task.created_resources), 0)
46-
self.assertEqual(self.publications_api.list().count, 1)
47-
48-
def test_02_modify(self):
49-
"""Assert that modifying the repository triggers auto-publish and auto-distribution."""
50-
self.assertEqual(self.publications_api.list().count, 0)
51-
self.assertTrue(self.distribution.publication is None)
52-
53-
# Modify the repository by adding a content unit
54-
content = self.content_api.list().results[0].pulp_href
55-
modify_response = self.repo_api.modify(
56-
self.repo.pulp_href, {"add_content_units": [content]}
57-
)
58-
task = monitor_task(modify_response.task)
59-
60-
# Check that all the appropriate resources were created
61-
self.assertGreater(len(task.created_resources), 1)
62-
self.assertEqual(self.publications_api.list().count, 1)
63-
download_content_unit(cfg, self.distribution.to_dict(), "simple/")
1+
import pytest
2+
3+
4+
@pytest.mark.parallel
5+
def test_autopublish_sync(
6+
python_bindings, python_repo_factory, python_remote_factory, monitor_task
7+
):
8+
"""Assert that syncing the repository triggers auto-publish."""
9+
remote = python_remote_factory()
10+
repo = python_repo_factory(remote=remote, autopublish=True)
11+
12+
# Sync repository
13+
task = monitor_task(python_bindings.RepositoriesPythonApi.sync(repo.pulp_href, {}).task)
14+
assert len(task.created_resources) == 2
15+
results = python_bindings.PublicationsPypiApi.list(repository=repo.pulp_href)
16+
assert results.count == 1
17+
assert results.results[0].pulp_href in task.created_resources
18+
19+
# Sync the repository again. Since there should be no new repository version, there
20+
# should be no new publications
21+
task = monitor_task(python_bindings.RepositoriesPythonApi.sync(repo.pulp_href, {}).task)
22+
assert len(task.created_resources) == 0
23+
results = python_bindings.PublicationsPypiApi.list(repository=repo.pulp_href)
24+
assert results.count == 1
25+
26+
27+
@pytest.mark.parallel
28+
def test_autopublish_modify(
29+
python_bindings, python_repo_factory, python_content_factory, monitor_task
30+
):
31+
"""Assert that modifying the repository triggers auto-publish."""
32+
repo = python_repo_factory(autopublish=True)
33+
content = python_content_factory()
34+
35+
# Modify the repository by adding a content unit
36+
body = {"add_content_units": [content.pulp_href]}
37+
task = monitor_task(python_bindings.RepositoriesPythonApi.modify(repo.pulp_href, body).task)
38+
assert len(task.created_resources) == 2
39+
results = python_bindings.PublicationsPypiApi.list(repository=repo.pulp_href)
40+
assert results.count == 1
41+
assert results.results[0].pulp_href in task.created_resources

0 commit comments

Comments
 (0)