diff --git a/.github/workflows/update_ci.yml b/.github/workflows/update_ci.yml index 18400a440..008acbaf9 100644 --- a/.github/workflows/update_ci.yml +++ b/.github/workflows/update_ci.yml @@ -74,37 +74,6 @@ jobs: env: GH_TOKEN: "${{ secrets.RELEASE_TOKEN }}" continue-on-error: true - - uses: "actions/checkout@v4" - with: - fetch-depth: 0 - path: "pulp_ansible" - ref: "0.15" - - - name: "Run update" - working-directory: "pulp_ansible" - run: | - ../plugin_template/scripts/update_ci.sh --release - - - name: "Create Pull Request for CI files" - uses: "peter-evans/create-pull-request@v6" - id: "create_pr_0_15" - with: - token: "${{ secrets.RELEASE_TOKEN }}" - path: "pulp_ansible" - committer: "pulpbot " - author: "pulpbot " - title: "Update CI files for branch 0.15" - branch: "update-ci/0.15" - base: "0.15" - delete-branch: true - - name: "Mark PR automerge" - working-directory: "pulp_ansible" - run: | - gh pr merge --rebase --auto "${{ steps.create_pr_0_15.outputs.pull-request-number }}" - if: "steps.create_pr_0_15.outputs.pull-request-number" - env: - GH_TOKEN: "${{ secrets.RELEASE_TOKEN }}" - continue-on-error: true - uses: "actions/checkout@v4" with: fetch-depth: 0 diff --git a/pulp_ansible/tests/functional/api/collection/v3/test_collection.py b/pulp_ansible/tests/functional/api/collection/v3/test_collection.py index 83e46108f..a4e4d90fc 100644 --- a/pulp_ansible/tests/functional/api/collection/v3/test_collection.py +++ b/pulp_ansible/tests/functional/api/collection/v3/test_collection.py @@ -1,42 +1,35 @@ """Tests related to upload of collections.""" import hashlib -import logging import pathlib import re +import time from datetime import datetime from urllib.parse import urljoin import pytest +import requests -from pulp_smash import api, config -from pulp_smash.pulp3.utils import gen_distribution, gen_repo -from pulp_smash.utils import http_get -from pulp_ansible.tests.functional.constants import ( - ANSIBLE_COLLECTION_FILE_NAME, - ANSIBLE_COLLECTION_UPLOAD_FIXTURE_URL, - ANSIBLE_DISTRIBUTION_PATH, - ANSIBLE_REPO_PATH, -) +class NullAuth(requests.auth.AuthBase): + def __call__(self, r): + return r -logger = logging.getLogger(__name__) +class BaseURLSession(requests.Session): + def __init__(self, base_url, *args, **kwargs): + self.base_url = base_url + super().__init__(*args, **kwargs) + def request(self, method, url, **kwargs): + return super().request(method, urljoin(self.base_url, url), **kwargs) -def upload_handler(client, response): - """Handle responses to collection upload by fetching and returning the task data.""" - response.raise_for_status() - logger.debug("response status: %s", response.status_code) - if response.status_code == 204: - return response - api._handle_202(client._cfg, response, client.pulp_host) - if response.request.method == "POST": - task_url = response.json()["task"] - task = client.get(task_url) - return task - else: - return response.json() + +@pytest.fixture(scope="module") +def http_session(bindings_cfg): + with BaseURLSession(bindings_cfg.host) as session: + session.auth = (bindings_cfg.username, bindings_cfg.password) + yield session def get_galaxy_url(base, path): @@ -44,12 +37,8 @@ def get_galaxy_url(base, path): Takes the expected GALAXY_API_ROOT setting of the target into consideration. """ - cfg = config.get_config() - path = path.lstrip("/") - GALAXY_API_ROOT = cfg.custom.get( - "galaxy_api_root", "/pulp_ansible/galaxy/%(base_path)s/api/" - ) % {"base_path": base} - return urljoin(GALAXY_API_ROOT, path) + GALAXY_API_ROOT = f"/pulp_ansible/galaxy/{base}/api/" + return urljoin(GALAXY_API_ROOT, path.lstrip("/")) @pytest.fixture(scope="module") @@ -68,294 +57,279 @@ def collection_artifact2(ansible_collection_factory): return ansible_collection_factory() -def get_metadata_published(pulp_client, pulp_dist): +def get_metadata_published(http_session, pulp_dist): """Return published datetime.""" - metadata = pulp_client.using_handler(api.json_handler).get( - get_galaxy_url(pulp_dist["base_path"], "/v3/") - ) + response = http_session.get(get_galaxy_url(pulp_dist.base_path, "/v3/")) + response.raise_for_status() + metadata = response.json() return datetime.strptime(metadata["published"], "%Y-%m-%dT%H:%M:%S.%fZ") -def upload_collection(client, filename, base_path): +def upload_collection(http_session, filename, base_path): """Helper to upload collections to pulp_ansible/galaxy.""" UPLOAD_PATH = get_galaxy_url(base_path, "/v3/artifacts/collections/") - collection = {"file": (open(filename, "rb"))} - - return client.using_handler(upload_handler).post(UPLOAD_PATH, files=collection) - - -@pytest.fixture(scope="module") -def collection_upload(pulp_client, collection_artifact, pulp_dist): + with open(filename, "rb") as fp: + collection = {"file": fp} + response = http_session.post(UPLOAD_PATH, files=collection) + response.raise_for_status() + task = response.json()["task"] + while True: + response = http_session.get(task) + response.raise_for_status() + result = response.json() + if result["state"] == "running": + time.sleep(1) + continue + if result["state"] == "completed": + break + raise Exception(str(result)) + return result + + +@pytest.fixture(scope="class") +def collection_upload(http_session, collection_artifact, pulp_dist): """Publish a new collection and return the processed response data.""" - published_before_upload = get_metadata_published(pulp_client, pulp_dist) - response = upload_collection(pulp_client, collection_artifact.filename, pulp_dist["base_path"]) - published_after_upload = get_metadata_published(pulp_client, pulp_dist) + published_before_upload = get_metadata_published(http_session, pulp_dist) + response = upload_collection(http_session, collection_artifact.filename, pulp_dist.base_path) + published_after_upload = get_metadata_published(http_session, pulp_dist) assert published_after_upload > published_before_upload return response -@pytest.fixture(scope="module") -def collection_upload2(pulp_client, collection_artifact2, pulp_dist): +@pytest.fixture(scope="class") +def collection_upload2(http_session, collection_artifact2, pulp_dist): """Publish the second new collection and return the processed response data.""" - published_before_upload = get_metadata_published(pulp_client, pulp_dist) - response = upload_collection(pulp_client, collection_artifact2.filename, pulp_dist["base_path"]) - published_after_upload = get_metadata_published(pulp_client, pulp_dist) + published_before_upload = get_metadata_published(http_session, pulp_dist) + response = upload_collection(http_session, collection_artifact2.filename, pulp_dist.base_path) + published_after_upload = get_metadata_published(http_session, pulp_dist) assert published_after_upload > published_before_upload return response -@pytest.fixture(scope="module") -def collection_detail(collection_upload, pulp_client, pulp_dist, collection_artifact): +@pytest.fixture(scope="class") +def collection_detail(http_session, collection_upload, pulp_dist, collection_artifact): """Fetch and parse a collection details response from an uploaded collection.""" url = get_galaxy_url( - pulp_dist["base_path"], + pulp_dist.base_path, f"/v3/collections/{collection_artifact.namespace}/{collection_artifact.name}/", ) - response = pulp_client.using_handler(api.json_handler).get(url) - return response - - -@pytest.fixture(scope="module") -def pulp_client(): - """Create and configure a Pulp API client, including custom authentication headers.""" - cfg = config.get_config() - client = api.Client(cfg) - headers = cfg.custom.get("headers", None) - if headers: - client.request_kwargs.setdefault("headers", {}).update(headers) - return client - - -@pytest.fixture(scope="module") -def pulp_repo(pulp_client): - """Find or create a Repository to attach to the Ansible Distribution we create.""" - repos = pulp_client.get(ANSIBLE_REPO_PATH) - if repos: - yield repos[0] - else: - repo_data = gen_repo(name="automation-hub") - repo = pulp_client.post(ANSIBLE_REPO_PATH, repo_data) - yield repo - pulp_client.delete(repo["pulp_href"]) + response = http_session.get(url) + response.raise_for_status() + return response.json() -@pytest.fixture(scope="module") -def pulp_dist(pulp_client, pulp_repo): +@pytest.fixture(scope="class") +def pulp_dist(ansible_repository_factory, ansible_distribution_factory): """Create an Ansible Distribution to simulate the automation hub environment for testing.""" - dists = pulp_client.get(ANSIBLE_DISTRIBUTION_PATH + "?base_path=automation-hub") - - if len(dists) == 0: - dist_data = gen_distribution( - name="automation-hub", base_path="automation-hub", repository=pulp_repo["pulp_href"] - ) - dist = pulp_client.post(ANSIBLE_DISTRIBUTION_PATH, dist_data) - created = True - elif len(dists) == 1: - dist = dists[0] - created = False - else: - raise ValueError("Found too many Ansible Distributions at 'automation-hub'.") - yield dist - if created: - pulp_client.delete(dist["pulp_href"]) - - -@pytest.fixture(scope="module") -def known_collection(): - """Fetch and prepare a known collection from Galaxy to use in an upload test.""" - collection_content = http_get(ANSIBLE_COLLECTION_UPLOAD_FIXTURE_URL) - collection = {"file": (ANSIBLE_COLLECTION_FILE_NAME, collection_content)} - return collection + return ansible_distribution_factory(repository=ansible_repository_factory()) -def test_collection_upload(collection_upload): - """Upload a new collection. +class TestCollection: - Uploads a newly generated collection and validates the resulting collection version details. - """ - # Validate the upload response - assert collection_upload["error"] is None - assert re.match( - r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", collection_upload["id"] - ) - assert collection_upload["state"] == "completed" - - assert "updated_at" in collection_upload - assert "started_at" in collection_upload - assert "created_at" in collection_upload - assert "finished_at" in collection_upload - assert "messages" in collection_upload - - # TODO: Add this back when namespace, name, and version are apart of the CollectionImport - # for key, value in collection_upload.items(): - # if key in COLLECTION_METADATA.keys(): - # assert COLLECTION_METADATA[key] == value, collection_upload - - -def test_collection_list( - collection_artifact, - collection_artifact2, - collection_upload, - collection_upload2, - pulp_client, - pulp_dist, -): - """Tests the collection list endpoint after uploading both collections.""" - url = get_galaxy_url(pulp_dist["base_path"], "v3/collections/") - response = pulp_client.using_handler(api.json_handler).get(url) - - assert response["meta"]["count"] >= 2 - present_collections = {c["href"].split("collections/")[1] for c in response["data"]} - uploaded_collections = { - f"index/{collection_artifact.namespace}/{collection_artifact.name}/", - f"index/{collection_artifact2.namespace}/{collection_artifact2.name}/", - } - assert uploaded_collections.issubset(present_collections) - - -def test_collection_detail(collection_artifact, collection_detail, pulp_dist): - """Test collection detail resulting from a successful upload of one version. - - Includes information of the most current version. - """ - url = ( - f"plugin/ansible/content/{pulp_dist['base_path']}" - f"/collections/index/{collection_artifact.namespace}/{collection_artifact.name}/" - ) + def test_collection_upload(self, collection_upload): + """Upload a new collection. - assert not collection_detail["deprecated"] - - # Check that the URL ends with the correct path so that this test doesn't fail - # when galaxy_ng is installed - assert collection_detail["href"].endswith(url) - assert collection_detail["namespace"] == collection_artifact.namespace - assert collection_detail["name"] == collection_artifact.name - assert collection_detail["highest_version"]["version"] == "1.0.0" - assert collection_detail["download_count"] == 0 - - -def test_collection_version_list( - collection_artifact, pulp_client, collection_detail, collection_upload2 -): - """Test the versions endpoint, listing the available versions of a given collection.""" - # Version List Endpoint - versions = pulp_client.using_handler(api.json_handler).get(collection_detail["versions_url"]) - assert versions["meta"]["count"] == 1 - version = versions["data"][0] - - assert version["version"] == "1.0.0" - assert version["href"] == collection_detail["highest_version"]["href"] - - -def test_collection_version_filter_by_q( - ansible_bindings, - ansible_collection_factory, - pulp_client, - pulp_dist, - monitor_task, - delete_orphans_pre, -): - """Verify successive imports do not aggregate tags into search vectors.""" - - def publish(new_artifact): - body = { - "file": new_artifact.filename, - "expected_namespace": new_artifact.namespace, - "expected_name": new_artifact.name, - "expected_version": new_artifact.version, - } - resp = ansible_bindings.ContentCollectionVersionsApi.create(**body) - monitor_task(resp.task) - - # make&publish 2 collections with each having unique tags - specs = [("tag1", "ns1", "col1"), ("tag2", "ns1", "col2")] - for spec in specs: - cfg = { - "namespace": spec[1], - "name": spec[2], - "description": "", - "repository": f"https://github.com/{spec[1]}/{spec[2]}", - "authors": ["jimbob"], - "version": "1.0.0", - "tags": [spec[0]], + Uploads a newly generated collection and validates the resulting collection version details. + """ + # Validate the upload response + assert collection_upload["error"] is None + assert re.match( + r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", collection_upload["id"] + ) + assert collection_upload["state"] == "completed" + + assert "updated_at" in collection_upload + assert "started_at" in collection_upload + assert "created_at" in collection_upload + assert "finished_at" in collection_upload + assert "messages" in collection_upload + + # TODO: Add this back when namespace, name, and version are apart of the CollectionImport + # for key, value in collection_upload.items(): + # if key in COLLECTION_METADATA.keys(): + # assert COLLECTION_METADATA[key] == value, collection_upload + + def test_collection_list( + self, + http_session, + collection_artifact, + collection_artifact2, + collection_upload, + collection_upload2, + pulp_dist, + ): + """Tests the collection list endpoint after uploading both collections.""" + url = get_galaxy_url(pulp_dist.base_path, "v3/collections/") + response = http_session.get(url) + response.raise_for_status() + result = response.json() + + assert result["meta"]["count"] >= 2 + present_collections = {c["href"].split("collections/")[1] for c in result["data"]} + uploaded_collections = { + f"index/{collection_artifact.namespace}/{collection_artifact.name}/", + f"index/{collection_artifact2.namespace}/{collection_artifact2.name}/", } - this_artifact = ansible_collection_factory(config=cfg) - publish(this_artifact) - - for spec in specs: - resp = ansible_bindings.ContentCollectionVersionsApi.list(q=spec[0]) - - # should only get the 1 cv as a result ... - assert resp.count == 1 - assert resp.results[0].namespace == spec[1] - assert resp.results[0].name == spec[2] - - -def test_collection_version(collection_artifact, pulp_client, collection_detail): - """Test collection version endpoint. - - Each collection version details a specific uploaded artifact for the collection. - """ - # Version Endpoint - version = pulp_client.using_handler(api.json_handler).get( - collection_detail["highest_version"]["href"] - ) - - assert version["name"] == collection_artifact.name - assert version["namespace"] == {"metadata_sha256": None, "name": collection_artifact.namespace} - assert version["version"] == "1.0.0" - - tarball = open(collection_artifact.filename, "rb").read() - assert version["artifact"]["sha256"] == hashlib.sha256(tarball).hexdigest() - assert version["artifact"]["size"] == len(tarball) - - assert version["artifact"]["filename"] == pathlib.Path(collection_artifact.filename).name - - assert "updated_at" in version - assert "created_at" in version - - assert "files" in version - assert "manifest" in version - assert "requires_ansible" in version + assert uploaded_collections.issubset(present_collections) - # # TODO: Test meta data - # # 'metadata': {'authors': ['Orion User 1'], - # # 'contents': [], - # # 'dependencies': {}, - # # 'description': 'a collection with some deps on other collections', - # # 'documentation': '', - # # 'homepage': '', - # # 'issues': '', - # # 'license': ['GPL-3.0-or-later'], - # # 'repository': 'http://github.example.com/orionuser1/skeleton', - # # 'tags': ['collectiontest']}, - - -def test_collection_download(collection_artifact, pulp_client, collection_detail): - """Test collection download URL. - - Should require authentication and redirect to a download location. - """ - version = pulp_client.using_handler(api.json_handler).get( - collection_detail["highest_version"]["href"] - ) - - # Artifact Download Endoint - url = version["download_url"] - - tarball = open(collection_artifact.filename, "rb").read() - - c = pulp_client.using_handler(api.echo_handler) - f = c.get(url) - assert f.status_code == 200, (url, f.request.headers) - assert f.content == tarball + def test_collection_detail(self, collection_artifact, collection_detail, pulp_dist): + """Test collection detail resulting from a successful upload of one version. + Includes information of the most current version. + """ + url = ( + f"plugin/ansible/content/{pulp_dist.base_path}" + f"/collections/index/{collection_artifact.namespace}/{collection_artifact.name}/" + ) -def test_collection_upload_repeat(pulp_client, collection_artifact, pulp_dist, collection_upload): - """ - Upload a duplicate collection. - """ - response = upload_collection(pulp_client, collection_artifact.filename, pulp_dist["base_path"]) - assert response["error"] is None - assert response["state"] == "completed" - assert re.match(r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", response["id"]) + assert not collection_detail["deprecated"] + + # Check that the URL ends with the correct path so that this test doesn't fail + # when galaxy_ng is installed + assert collection_detail["href"].endswith(url) + assert collection_detail["namespace"] == collection_artifact.namespace + assert collection_detail["name"] == collection_artifact.name + assert collection_detail["highest_version"]["version"] == "1.0.0" + assert collection_detail["download_count"] == 0 + + def test_collection_version_list( + self, http_session, collection_artifact, collection_detail, collection_upload2 + ): + """Test the versions endpoint, listing the available versions of a given collection.""" + # Version List Endpoint + response = http_session.get(collection_detail["versions_url"]) + response.raise_for_status() + versions = response.json() + assert versions["meta"]["count"] == 1 + version = versions["data"][0] + + assert version["version"] == "1.0.0" + assert version["href"] == collection_detail["highest_version"]["href"] + + def test_collection_version_filter_by_q( + self, + ansible_bindings, + ansible_collection_factory, + pulp_dist, + monitor_task, + delete_orphans_pre, + ): + """Verify successive imports do not aggregate tags into search vectors.""" + + def publish(new_artifact): + body = { + "file": new_artifact.filename, + "expected_namespace": new_artifact.namespace, + "expected_name": new_artifact.name, + "expected_version": new_artifact.version, + } + resp = ansible_bindings.ContentCollectionVersionsApi.create(**body) + monitor_task(resp.task) + + # make&publish 2 collections with each having unique tags + specs = [("tag1", "ns1", "col1"), ("tag2", "ns1", "col2")] + for spec in specs: + cfg = { + "namespace": spec[1], + "name": spec[2], + "description": "", + "repository": f"https://github.com/{spec[1]}/{spec[2]}", + "authors": ["jimbob"], + "version": "1.0.0", + "tags": [spec[0]], + } + this_artifact = ansible_collection_factory(config=cfg) + publish(this_artifact) + + for spec in specs: + resp = ansible_bindings.ContentCollectionVersionsApi.list(q=spec[0]) + + # should only get the 1 cv as a result ... + assert resp.count == 1 + assert resp.results[0].namespace == spec[1] + assert resp.results[0].name == spec[2] + + def test_collection_version(self, http_session, collection_artifact, collection_detail): + """Test collection version endpoint. + + Each collection version details a specific uploaded artifact for the collection. + """ + # Version Endpoint + response = http_session.get(collection_detail["highest_version"]["href"]) + response.raise_for_status() + version = response.json() + + assert version["name"] == collection_artifact.name + assert version["namespace"] == { + "metadata_sha256": None, + "name": collection_artifact.namespace, + } + assert version["version"] == "1.0.0" + with open(collection_artifact.filename, "rb") as fp: + tarball = fp.read() + assert version["artifact"]["sha256"] == hashlib.sha256(tarball).hexdigest() + assert version["artifact"]["size"] == len(tarball) + + assert version["artifact"]["filename"] == pathlib.Path(collection_artifact.filename).name + + assert "updated_at" in version + assert "created_at" in version + + assert "files" in version + assert "manifest" in version + assert "requires_ansible" in version + + # # TODO: Test meta data + # # 'metadata': {'authors': ['Orion User 1'], + # # 'contents': [], + # # 'dependencies': {}, + # # 'description': 'a collection with some deps on other collections', + # # 'documentation': '', + # # 'homepage': '', + # # 'issues': '', + # # 'license': ['GPL-3.0-or-later'], + # # 'repository': 'http://github.example.com/orionuser1/skeleton', + # # 'tags': ['collectiontest']}, + + def test_collection_download( + self, + http_session, + collection_detail, + collection_artifact, + ): + """Test collection download URL. + + Should require authentication and redirect to a download location. + """ + response = http_session.get(collection_detail["highest_version"]["href"], auth=NullAuth()) + assert response.status_code == 401 + response = http_session.get(collection_detail["highest_version"]["href"]) + response.raise_for_status() + version = response.json() + + # Artifact Download Endoint + url = version["download_url"] + + with open(collection_artifact.filename, "rb") as fp: + tarball = fp.read() + + response = http_session.get(url, auth=NullAuth()) + assert response.status_code == 401 + response = http_session.get(url) + assert response.status_code == 200, (url, response.request.headers) + assert response.content == tarball + + def test_collection_upload_repeat( + self, http_session, ansible_collection_factory, pulp_dist, collection_upload + ): + """ + Upload a duplicate collection. + """ + response = upload_collection( + http_session, ansible_collection_factory().filename, pulp_dist.base_path + ) + assert response["error"] is None + assert response["state"] == "completed" + assert re.match( + r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", response["id"] + ) diff --git a/pulp_ansible/tests/functional/api/collection/v3/test_serializers.py b/pulp_ansible/tests/functional/api/collection/v3/test_serializers.py index cf09229dc..944fe72b3 100644 --- a/pulp_ansible/tests/functional/api/collection/v3/test_serializers.py +++ b/pulp_ansible/tests/functional/api/collection/v3/test_serializers.py @@ -11,12 +11,12 @@ ) from pulp_smash.pulp3.bindings import monitor_task -from pulp_ansible.tests.functional.utils import SyncHelpersMixin, TestCaseUsingBindings +from pulp_ansible.tests.functional.utils import TestCaseUsingBindings from pulp_ansible.tests.functional.utils import gen_ansible_client, gen_ansible_remote from pulp_ansible.tests.functional.utils import tasks -class CollectionsV3TestCase(TestCaseUsingBindings, SyncHelpersMixin): +class CollectionsV3TestCase(TestCaseUsingBindings): """Test Collections V3 endpoint.""" @classmethod @@ -77,7 +77,7 @@ def test_v3_updated_at(self): sync_response = self.repo_api.sync(repo.pulp_href, repository_sync_data) monitor_task(sync_response.task) task = tasks.read(sync_response.task) - self.assertEqual(task.state, "completed") + assert task.state == "completed" # enumerate new data after 2nd sync ... collections = self.collections_api.list(distribution.base_path) @@ -87,11 +87,11 @@ def test_v3_updated_at(self): "squeezer", "pulp", distribution.base_path ).meta.count - self.assertEqual(original_highest_version, "0.0.7") - self.assertEqual(highest_version, "0.0.17") - self.assertEqual(original_total_versions, 1) - self.assertEqual(total_versions, 2) - self.assertGreater(updated_at, original_updated_at) + assert original_highest_version == "0.0.7" + assert highest_version == "0.0.17" + assert original_total_versions == 1 + assert total_versions == 2 + assert updated_at > original_updated_at def test_v3_collection_version_from_synced_data(self): """Test Collection Versions V3 endpoint fields.""" @@ -111,6 +111,6 @@ def test_v3_collection_version_from_synced_data(self): "nxos", "cisco", distribution.base_path, "1.4.0" ) - self.assertEqual(version.requires_ansible, ">=2.9.10,<2.11") - self.assertTrue("'name': 'README.md'" in str(version.files)) - self.assertEqual(version.manifest["collection_info"]["name"], "nxos") + assert version.requires_ansible == ">=2.9.10,<2.11" + assert "'name': 'README.md'" in str(version.files) + assert version.manifest["collection_info"]["name"] == "nxos" diff --git a/pulp_ansible/tests/functional/api/collection/v3/test_sync.py b/pulp_ansible/tests/functional/api/collection/v3/test_sync.py index 465265d78..1a33e54a1 100644 --- a/pulp_ansible/tests/functional/api/collection/v3/test_sync.py +++ b/pulp_ansible/tests/functional/api/collection/v3/test_sync.py @@ -1,28 +1,19 @@ """Tests related to sync ansible plugin collection content type.""" -import os -import unittest - -from pulpcore.client.pulp_ansible import ( - AnsibleRepositorySyncURL, - ContentCollectionVersionsApi, - DistributionsAnsibleApi, - PulpAnsibleApiV3CollectionsApi, - RepositoriesAnsibleApi, - RemotesCollectionApi, -) -from pulp_smash.pulp3.bindings import PulpTaskError, PulpTestCase +from pulpcore.client.pulp_ansible import AnsibleRepositorySyncURL + +from pulpcore.tests.functional.utils import PulpTaskError from pulp_ansible.tests.functional.utils import ( - gen_ansible_client, gen_ansible_remote, monitor_task, - tasks, ) -from pulp_ansible.tests.functional.utils import SyncHelpersMixin, TestCaseUsingBindings +from pulp_ansible.tests.functional.utils import TestCaseUsingBindings +REQUIREMENTS_FILE = "collections:\n - testing.k8s_demo_collection" -class SyncCollectionsFromPulpServerTestCase(TestCaseUsingBindings, SyncHelpersMixin): + +class SyncCollectionsFromPulpServerTestCase(TestCaseUsingBindings): """ Test whether one can sync collections from a Pulp server. @@ -36,7 +27,7 @@ def setUp(self): self.requirements_file = "collections:\n - testing.k8s_demo_collection" body = gen_ansible_remote( url="https://galaxy.ansible.com", - requirements_file=self.requirements_file, + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, ) self.remote = self.remote_collection_api.create(body) @@ -49,7 +40,7 @@ def test_sync_collections_from_pulp(self): """Test sync collections from pulp server.""" second_body = gen_ansible_remote( url=self.distribution.client_url, - requirements_file=self.requirements_file, + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, include_pulp_auth=True, ) @@ -61,15 +52,15 @@ def test_sync_collections_from_pulp(self): first_content = self.cv_api.list( repository_version=f"{self.first_repo.pulp_href}versions/1/" ) - self.assertGreaterEqual(len(first_content.results), 1) + assert len(first_content.results) >= 1 second_content = self.cv_api.list(repository_version=f"{second_repo.pulp_href}versions/1/") - self.assertGreaterEqual(len(second_content.results), 1) + assert len(second_content.results) >= 1 def test_sync_collections_from_pulp_using_mirror_second_time(self): """Test sync collections from pulp server using a mirror option the second time.""" body = gen_ansible_remote( url="https://galaxy.ansible.com", - requirements_file="collections:\n - testing.k8s_demo_collection", + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, ) remote = self.remote_collection_api.create(body) @@ -85,9 +76,9 @@ def test_sync_collections_from_pulp_using_mirror_second_time(self): second_repo = self._create_repo_and_sync_with_remote(second_remote) first_content = self.cv_api.list(repository_version=f"{first_repo.pulp_href}versions/1/") - self.assertGreaterEqual(len(first_content.results), 1) + assert len(first_content.results) >= 1 second_content = self.cv_api.list(repository_version=f"{second_repo.pulp_href}versions/1/") - self.assertGreaterEqual(len(second_content.results), 1) + assert len(second_content.results) >= 1 def test_sync_collection_named_api(self): """Test sync collections from pulp server.""" @@ -104,14 +95,14 @@ def test_sync_collection_named_api(self): collection = self.collections_v3api.read("api", "rswaf", distribution.base_path) - self.assertEqual("api", collection.name) - self.assertEqual("rswaf", collection.namespace) + assert "api" == collection.name + assert "rswaf" == collection.namespace def test_noop_resync_collections_from_pulp(self): """Test whether sync yields no-op when repo hasn't changed since last sync.""" second_body = gen_ansible_remote( url=self.distribution.client_url, - requirements_file=self.requirements_file, + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, include_pulp_auth=True, ) @@ -121,26 +112,25 @@ def test_noop_resync_collections_from_pulp(self): second_repo = self._create_repo_with_attached_remote_and_sync(second_remote) second_content = self.cv_api.list(repository_version=f"{second_repo.pulp_href}versions/1/") - self.assertGreaterEqual(len(second_content.results), 1) + assert len(second_content.results) >= 1 # Resync repository_sync_data = AnsibleRepositorySyncURL( remote=second_remote.pulp_href, optimize=True ) sync_response = self.repo_api.sync(second_repo.pulp_href, repository_sync_data) - monitor_task(sync_response.task) + task = monitor_task(sync_response.task) second_repo = self.repo_api.read(second_repo.pulp_href) - task = tasks.read(sync_response.task) msg = "no-op: {url} did not change since last sync".format(url=second_remote.url) messages = [r.message for r in task.progress_reports] - self.assertIn(msg, str(messages)) + assert msg in str(messages) def test_noop_resync_with_mirror_from_pulp(self): """Test whether no-op sync with mirror=True doesn't remove repository content.""" second_body = gen_ansible_remote( url=self.distribution.client_url, - requirements_file=self.requirements_file, + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, include_pulp_auth=True, ) @@ -150,27 +140,26 @@ def test_noop_resync_with_mirror_from_pulp(self): second_repo = self._create_repo_with_attached_remote_and_sync(second_remote) second_content = self.cv_api.list(repository_version=f"{second_repo.pulp_href}versions/1/") - self.assertGreaterEqual(len(second_content.results), 1) + assert len(second_content.results) >= 1 # Resync repository_sync_data = AnsibleRepositorySyncURL( remote=second_remote.pulp_href, optimize=True, mirror=True ) sync_response = self.repo_api.sync(second_repo.pulp_href, repository_sync_data) - monitor_task(sync_response.task) + task = monitor_task(sync_response.task) second_repo = self.repo_api.read(second_repo.pulp_href) - self.assertEqual(int(second_repo.latest_version_href[-2]), 1) - task = tasks.read(sync_response.task) + assert int(second_repo.latest_version_href[-2]) == 1 msg = "no-op: {url} did not change since last sync".format(url=second_remote.url) messages = [r.message for r in task.progress_reports] - self.assertIn(msg, str(messages)) + assert msg in str(messages) def test_update_requirements_file(self): """Test requirements_file update.""" body = gen_ansible_remote( url=self.distribution.client_url, - requirements_file=self.requirements_file, + requirements_file=REQUIREMENTS_FILE, sync_dependencies=False, include_pulp_auth=True, ) @@ -178,7 +167,7 @@ def test_update_requirements_file(self): self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) repo = self._create_repo_with_attached_remote_and_sync(remote) - self.assertIsNotNone(repo.last_synced_metadata_time) + assert repo.last_synced_metadata_time is not None response = self.remote_collection_api.partial_update( remote.pulp_href, {"requirements_file": "collections:\n - ansible.posix"} @@ -186,7 +175,7 @@ def test_update_requirements_file(self): monitor_task(response.task) repo = self.repo_api.read(repo.pulp_href) - self.assertIsNone(repo.last_synced_metadata_time) + assert repo.last_synced_metadata_time is None def test_sync_with_missing_collection(self): """Test that syncing with a non-present collection gives a useful error.""" @@ -204,172 +193,4 @@ def test_sync_with_missing_collection(self): task_result = cm.exception.task.to_dict() msg = "absent.not_present does not exist" - self.assertIn(msg, task_result["error"]["description"], task_result["error"]["description"]) - - -@unittest.skipUnless( - "AUTOMATION_HUB_TOKEN_AUTH" in os.environ, - "'AUTOMATION_HUB_TOKEN_AUTH' env var is not defined", -) -class AutomationHubV3SyncCase(PulpTestCase, SyncHelpersMixin): - """Test syncing from Pulp to Pulp.""" - - @classmethod - def setUpClass(cls): - """Create class-wide variables.""" - cls.client = gen_ansible_client() - cls.repo_api = RepositoriesAnsibleApi(cls.client) - cls.remote_collection_api = RemotesCollectionApi(cls.client) - cls.distributions_api = DistributionsAnsibleApi(cls.client) - cls.collections_api = PulpAnsibleApiV3CollectionsApi(cls.client) - cls.cv_api = ContentCollectionVersionsApi(cls.client) - cls.url = "https://cloud.redhat.com/api/automation-hub/" - cls.aurl = ( - "https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token" - ) - - def test_sync_with_token_from_automation_hub(self): - """Test whether we can sync with an auth token from Automation Hub.""" - body = gen_ansible_remote( - url=self.url, - requirements_file="collections:\n - ansible.posix", - auth_url=self.aurl, - token=os.environ["AUTOMATION_HUB_TOKEN_AUTH"], - rate_limit=10, - tls_validation=False, - sync_dependencies=False, - ) - remote = self.remote_collection_api.create(body) - self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) - - repo = self._create_repo_and_sync_with_remote(remote) - - # Check content of both repos. - original_content = self.cv_api.list(repository_version=f"{repo.pulp_href}versions/1/") - self.assertTrue(len(original_content.results) >= 3) # check that we have at least 3 results - - @unittest.skip("Skipping until synclist no longer creates new repository") - def test_syncing_with_excludes_list_from_automation_hub(self): - """Test if syncing collections know to be on the synclist will be mirrored.""" - namespace = "autohubtest2" - # Collections are randomly generated, in case of failure, please change the names below: - name = "collection_dep_a_zzduuntr" - excluded = "collection_dep_a_tworzgsx" - excluded_version = "awcrosby.collection_test==2.1.0" - requirements = f""" - collections: - - {namespace}.{name} - - {namespace}.{excluded} - - {excluded_version} - """ - body = gen_ansible_remote( - url=self.url, - requirements_file=requirements, - auth_url=self.aurl, - token=os.environ["AUTOMATION_HUB_TOKEN_AUTH"], - rate_limit=10, - tls_validation=False, - sync_dependencies=False, - ) - remote = self.remote_collection_api.create(body) - self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) - - repo = self._create_repo_and_sync_with_remote(remote) - - # Assert that at least one CollectionVersion was downloaded - repo_ver = f"{repo.pulp_href}versions/1/" - content = self.cv_api.list(repository_version=repo_ver) - self.assertTrue(content.count >= 1) - - # Assert that excluded collection was not synced - exclude_content = self.cv_api.list(repository_version=repo_ver, name=excluded) - self.assertTrue(exclude_content.count == 0) - - -# TODO QA-AH has been deprecated, remove/replace tests -@unittest.skipUnless( - "QA_AUTOMATION_HUB_TOKEN_AUTH" in os.environ, - "'QA_AUTOMATION_HUB_TOKEN_AUTH' env var is not defined", -) -class AutomationHubCIV3SyncCase(PulpTestCase, SyncHelpersMixin): - """Test syncing from Pulp to Pulp.""" - - @classmethod - def setUpClass(cls): - """Create class-wide variables.""" - cls.client = gen_ansible_client() - cls.repo_api = RepositoriesAnsibleApi(cls.client) - cls.remote_collection_api = RemotesCollectionApi(cls.client) - cls.distributions_api = DistributionsAnsibleApi(cls.client) - cls.collections_api = PulpAnsibleApiV3CollectionsApi(cls.client) - cls.cv_api = ContentCollectionVersionsApi(cls.client) - cls.url = "https://qa.cloud.redhat.com/api/automation-hub/" - cls.aurl = ( - "https://sso.qa.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token" - ) - - def test_mirror_from_automation_hub_ci_with_auth_token(self): - """Test whether we can mirror from Automation Hub CI with an auth token.""" - body = gen_ansible_remote( - url=self.url, - auth_url=self.aurl, - token=os.environ["QA_AUTOMATION_HUB_TOKEN_AUTH"], - rate_limit=10, - tls_validation=False, - sync_dependencies=False, - ) - remote = self.remote_collection_api.create(body) - self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) - - repo = self._create_repo_and_sync_with_remote(remote) - - # Assert at least one hundred CollectionVersions are returned - content = self.cv_api.list(repository_version=f"{repo.pulp_href}versions/1/") - self.assertTrue(len(content.results) >= 100) - - def test_sync_from_automation_hub_ci_with_auth_token_and_requirements_file(self): - """Test sync from Automation Hub CI with an auth token and requirements file.""" - namespace = "autohubtest2" - # Collections are randomly generated, in case of failure, please change the name below: - name = "collection_dep_a_zzduuntr" - body = gen_ansible_remote( - url=self.url, - requirements_file=f"collections:\n - {namespace}.{name}", - auth_url=self.aurl, - token=os.environ["QA_AUTOMATION_HUB_TOKEN_AUTH"], - rate_limit=10, - tls_validation=False, - sync_dependencies=False, - ) - remote = self.remote_collection_api.create(body) - self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) - - repo = self._create_repo_and_sync_with_remote(remote) - - # Assert that at least one CollectionVersion was downloaded - content = self.cv_api.list(repository_version=f"{repo.pulp_href}versions/1/") - self.assertTrue(len(content.results) >= 1) - - def test_install_collection_with_invalid_token_from_automation_hub_ci(self): - """Test whether we can mirror from Automation Hub CI with an invalid auth token.""" - body = gen_ansible_remote( - url=self.url, - auth_url=self.aurl, - token="invalid token string", - tls_validation=False, - sync_dependencies=False, - ) - remote = self.remote_collection_api.create(body) - self.addCleanup(self.remote_collection_api.delete, remote.pulp_href) - - with self.assertRaises(PulpTaskError) as cm: - self._create_repo_and_sync_with_remote(remote) - - task_result = cm.exception.task.to_dict() - msg = ( - "400, message='Bad Request', url=URL(" - "'https://sso.qa.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token')" - ) - self.assertEqual( - msg, task_result["error"]["description"], task_result["error"]["description"] - ) + assert msg in task_result["error"]["description"], task_result["error"]["description"] diff --git a/pulp_ansible/tests/functional/constants.py b/pulp_ansible/tests/functional/constants.py index 70a9d2be5..be2817641 100644 --- a/pulp_ansible/tests/functional/constants.py +++ b/pulp_ansible/tests/functional/constants.py @@ -1,19 +1,10 @@ from urllib.parse import urljoin -from pulp_smash.pulp3.constants import ( - BASE_DISTRIBUTION_PATH, - BASE_REPO_PATH, -) - GALAXY_ANSIBLE_BASE_URL = "https://galaxy.ansible.com" ANSIBLE_ROLE_NAME = "ansible.role" -ANSIBLE_DISTRIBUTION_PATH = urljoin(BASE_DISTRIBUTION_PATH, "ansible/ansible/") - -ANSIBLE_REPO_PATH = urljoin(BASE_REPO_PATH, "ansible/ansible/") - ANSIBLE_GALAXY_URL = urljoin(GALAXY_ANSIBLE_BASE_URL, "api/v1/roles/") NAMESPACE_ANSIBLE = "?owner__username=ansible" diff --git a/pulp_ansible/tests/functional/utils.py b/pulp_ansible/tests/functional/utils.py index 63003617c..753c33d2e 100644 --- a/pulp_ansible/tests/functional/utils.py +++ b/pulp_ansible/tests/functional/utils.py @@ -19,7 +19,6 @@ from pulpcore.client.pulpcore import ( ApiClient as CoreApiClient, TasksApi, - StatusApi, ) from pulpcore.client.pulp_ansible import ( ApiClient as AnsibleApiClient, @@ -44,20 +43,6 @@ def randstr(): return "".join(random.choices(string.ascii_lowercase, k=8)) -def is_galaxy_ng_installed(): - """Returns whether or not the galaxy_ng plugin is installed.""" - configuration = cfg.get_bindings_config() - core_client = CoreApiClient(configuration) - status_client = StatusApi(core_client) - - status = status_client.status_read() - - for plugin in status.versions: - if plugin.component == "galaxy": - return True - return False - - def content_counts(repository_version, summary_type="present"): content_summary = getattr(repository_version.content_summary, summary_type) return {key: value["count"] for key, value in content_summary.items()} @@ -109,10 +94,6 @@ def tearDownClass(cls): """Clean class-wide variable.""" delete_orphans() - -class SyncHelpersMixin: - """A common place for sync helper functions.""" - def _create_repo_and_sync_with_remote(self, remote, distribution=False, **repo_kwargs): """ Create a repository and then sync with the provided `remote`. diff --git a/template_config.yml b/template_config.yml index d5af3b89f..970b2f068 100644 --- a/template_config.yml +++ b/template_config.yml @@ -64,7 +64,6 @@ stalebot_days_until_close: 30 stalebot_days_until_stale: 90 stalebot_limit_to_pulls: true supported_release_branches: -- '0.15' - '0.16' - '0.18' - '0.20' diff --git a/unittest_requirements.txt b/unittest_requirements.txt index 5d9fd2ea9..82e72f7e7 100644 --- a/unittest_requirements.txt +++ b/unittest_requirements.txt @@ -1,4 +1,3 @@ mock -pulp-smash @ git+https://github.com/pulp/pulp-smash.git pytest-django pytest<9