# Copyright (c) 2017 Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import annotations
import pytest
from ansible.module_utils import basic
from ansible_collections.community.general.plugins.modules import maven_artifact
pytestmark = pytest.mark.usefixtures("patch_ansible_module")
maven_metadata_example = b"""
junit
junit
4.13-beta-2
4.13-beta-2
3.7
3.8
3.8.1
3.8.2
4.0
4.1
4.2
4.3
4.3.1
4.4
4.5
4.6
4.7
4.8
4.8.1
4.8.2
4.9
4.10
4.11-beta-1
4.11
4.12-beta-1
4.12-beta-2
4.12-beta-3
4.12
4.13-beta-1
4.13-beta-2
20190202141051
"""
@pytest.mark.parametrize(
"patch_ansible_module, version_by_spec, version_choosed",
[
(None, "(,3.9]", "3.8.2"),
(None, "3.0", "3.8.2"),
(None, "[3.7]", "3.7"),
(None, "[4.10, 4.12]", "4.12"),
(None, "[4.10, 4.12)", "4.11"),
(None, "[2.0,)", "4.13-beta-2"),
],
)
def test_find_version_by_spec(mocker, version_by_spec, version_choosed):
_getContent = mocker.patch(
"ansible_collections.community.general.plugins.modules.maven_artifact.MavenDownloader._getContent"
)
_getContent.return_value = maven_metadata_example
artifact = maven_artifact.Artifact("junit", "junit", None, version_by_spec, "jar")
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo1.maven.org/maven2")
assert mvn_downloader.find_version_by_spec(artifact) == version_choosed
# Metadata with multiple snapshotVersion entries per extension (as produced by GitHub Packages).
# The entries are deliberately NOT in chronological order to verify that
# resolution uses the timestamp rather than relying on list position.
snapshot_metadata_multiple_entries = b"""
com.example
my-lib
1.0.0-SNAPSHOT
20260210.152345
3
20260210153158
jar
1.0.0-20260205.091032-2
20260205091858
jar
1.0.0-20260210.152345-3
20260210153154
pom
1.0.0-20260210.152345-3
20260210153153
jar
1.0.0-20260203.123107-1
20260203123944
pom
1.0.0-20260203.123107-1
20260203123943
pom
1.0.0-20260205.091032-2
20260205091857
"""
# Metadata without a block but with only.
snapshot_metadata_no_snapshot_block = b"""
com.example
my-lib
1.0.0-SNAPSHOT
20260210153158
jar
1.0.0-20260203.123107-1
20260203123944
pom
1.0.0-20260203.123107-1
20260203123943
"""
@pytest.mark.parametrize("patch_ansible_module", [None])
def test_find_uri_for_snapshot_resolves_to_latest(mocker):
"""When metadata has multiple snapshotVersion entries per extension,
the entry with the newest updated timestamp should be resolved."""
_getContent = mocker.patch(
"ansible_collections.community.general.plugins.modules.maven_artifact.MavenDownloader._getContent"
)
_getContent.return_value = snapshot_metadata_multiple_entries
artifact = maven_artifact.Artifact("com.example", "my-lib", "1.0.0-SNAPSHOT", None, "", "jar")
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo.example.com")
uri = mvn_downloader.find_uri_for_artifact(artifact)
assert "1.0.0-20260210.152345-3.jar" in uri
@pytest.mark.parametrize("patch_ansible_module", [None])
def test_find_uri_for_snapshot_without_snapshot_block_uses_snapshot_versions(mocker):
"""When metadata lacks a block, fall back to scanning
entries."""
_getContent = mocker.patch(
"ansible_collections.community.general.plugins.modules.maven_artifact.MavenDownloader._getContent"
)
_getContent.return_value = snapshot_metadata_no_snapshot_block
artifact = maven_artifact.Artifact("com.example", "my-lib", "1.0.0-SNAPSHOT", None, "", "jar")
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo.example.com")
uri = mvn_downloader.find_uri_for_artifact(artifact)
assert "1.0.0-20260203.123107-1.jar" in uri
# Metadata with a block that has but no .
# This is schema-valid but non-standard (e.g. produced by non-Maven tools).
# The module should fall back to scanning.
snapshot_metadata_incomplete_snapshot_block = b"""
com.example
my-lib
1.0.0-SNAPSHOT
20260210.152345
20260210153158
jar
1.0.0-20260210.152345-3
20260210153154
pom
1.0.0-20260210.152345-3
20260210153153
"""
@pytest.mark.parametrize("patch_ansible_module", [None])
def test_find_uri_for_snapshot_incomplete_snapshot_block_uses_snapshot_versions(mocker):
"""When the block is incomplete (e.g. missing ),
fall back to instead of raising an error."""
_getContent = mocker.patch(
"ansible_collections.community.general.plugins.modules.maven_artifact.MavenDownloader._getContent"
)
_getContent.return_value = snapshot_metadata_incomplete_snapshot_block
artifact = maven_artifact.Artifact("com.example", "my-lib", "1.0.0-SNAPSHOT", None, "", "jar")
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo.example.com")
uri = mvn_downloader.find_uri_for_artifact(artifact)
assert "1.0.0-20260210.152345-3.jar" in uri
@pytest.mark.parametrize("patch_ansible_module", [None])
def test_find_uri_for_release_version_unaffected(mocker):
"""Non-SNAPSHOT versions must not be affected by snapshot resolution logic."""
artifact = maven_artifact.Artifact("com.example", "my-lib", "2.1.0", None, "", "jar")
mvn_downloader = maven_artifact.MavenDownloader(basic.AnsibleModule, "https://repo.example.com")
uri = mvn_downloader.find_uri_for_artifact(artifact)
assert uri == "https://repo.example.com/com/example/my-lib/2.1.0/my-lib-2.1.0.jar"