summaryrefslogtreecommitdiff
path: root/test/units/galaxy
diff options
context:
space:
mode:
authorJordan Borean <jborean93@gmail.com>2019-08-30 11:55:19 +1000
committerGitHub <noreply@github.com>2019-08-30 11:55:19 +1000
commita7fd6e99d90d2c991aa1cc97b9fb0ba7d153bd8b (patch)
tree08829f84bc2c96dca1ff96d1195699977900280c /test/units/galaxy
parent82c1becd24afe7d32f0510a1f61fad676770a9dd (diff)
downloadansible-a7fd6e99d90d2c991aa1cc97b9fb0ba7d153bd8b.tar.gz
Refactor galaxy collection API for v3 support (#61510)
* Refactor galaxy collection API for v3 support * Added unit tests for GalaxyAPI and starting to fix other failures * finalise tests * more unit test fixes
Diffstat (limited to 'test/units/galaxy')
-rw-r--r--test/units/galaxy/test_api.py749
-rw-r--r--test/units/galaxy/test_collection.py537
-rw-r--r--test/units/galaxy/test_collection_install.py305
3 files changed, 841 insertions, 750 deletions
diff --git a/test/units/galaxy/test_api.py b/test/units/galaxy/test_api.py
index 7def7cb0bb..c2439b9b3f 100644
--- a/test/units/galaxy/test_api.py
+++ b/test/units/galaxy/test_api.py
@@ -6,13 +6,26 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import json
+import os
+import re
import pytest
+import tarfile
+import tempfile
+import time
+
+from io import BytesIO, StringIO
+from units.compat.mock import MagicMock
from ansible import context
from ansible.errors import AnsibleError
-from ansible.galaxy.api import GalaxyAPI
+from ansible.galaxy import api as galaxy_api
+from ansible.galaxy.api import CollectionVersionMetadata, GalaxyAPI, GalaxyError
from ansible.galaxy.token import GalaxyToken
+from ansible.module_utils._text import to_native, to_text
+from ansible.module_utils.six.moves.urllib import error as urllib_error
from ansible.utils import context_objects as co
+from ansible.utils.display import Display
@pytest.fixture(autouse='function')
@@ -24,9 +37,34 @@ def reset_cli_args():
co.GlobalCLIArgs._Singleton__instance = None
+@pytest.fixture()
+def collection_artifact(tmp_path_factory):
+ ''' Creates a collection artifact tarball that is ready to be published '''
+ output_dir = to_text(tmp_path_factory.mktemp('test-ÅÑŚÌβŁÈ Output'))
+
+ tar_path = os.path.join(output_dir, 'namespace-collection-v1.0.0.tar.gz')
+ with tarfile.open(tar_path, 'w:gz') as tfile:
+ b_io = BytesIO(b"\x00\x01\x02\x03")
+ tar_info = tarfile.TarInfo('test')
+ tar_info.size = 4
+ tar_info.mode = 0o0644
+ tfile.addfile(tarinfo=tar_info, fileobj=b_io)
+
+ yield tar_path
+
+
+def get_test_galaxy_api(url, version):
+ api = GalaxyAPI(None, "test", url)
+ api._available_api_versions = {version: '/api/%s' % version}
+ api.token = GalaxyToken(token="my token")
+
+ return api
+
+
def test_api_no_auth():
api = GalaxyAPI(None, "test", "https://galaxy.ansible.com")
- actual = api._auth_header(required=False)
+ actual = {}
+ api._add_auth_token(actual, "")
assert actual == {}
@@ -34,23 +72,722 @@ def test_api_no_auth_but_required():
expected = "No access token or username set. A token can be set with --api-key, with 'ansible-galaxy login', " \
"or set in ansible.cfg."
with pytest.raises(AnsibleError, match=expected):
- GalaxyAPI(None, "test", "https://galaxy.ansible.com")._auth_header()
+ GalaxyAPI(None, "test", "https://galaxy.ansible.com")._add_auth_token({}, "", required=True)
def test_api_token_auth():
token = GalaxyToken(token=u"my_token")
api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=token)
- actual = api._auth_header()
+ actual = {}
+ api._add_auth_token(actual, "")
+ assert actual == {'Authorization': 'Token my_token'}
+
+
+def test_api_token_auth_with_token_type():
+ token = GalaxyToken(token=u"my_token")
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=token)
+ actual = {}
+ api._add_auth_token(actual, "", token_type="Bearer")
+ assert actual == {'Authorization': 'Bearer my_token'}
+
+
+def test_api_token_auth_with_v3_url():
+ token = GalaxyToken(token=u"my_token")
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=token)
+ actual = {}
+ api._add_auth_token(actual, "https://galaxy.ansible.com/api/v3/resource/name")
+ assert actual == {'Authorization': 'Bearer my_token'}
+
+
+def test_api_token_auth_with_v2_url():
+ token = GalaxyToken(token=u"my_token")
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=token)
+ actual = {}
+ # Add v3 to random part of URL but response should only see the v2 as the full URI path segment.
+ api._add_auth_token(actual, "https://galaxy.ansible.com/api/v2/resourcev3/name")
assert actual == {'Authorization': 'Token my_token'}
def test_api_basic_auth_password():
api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", username=u"user", password=u"pass")
- actual = api._auth_header()
+ actual = {}
+ api._add_auth_token(actual, "")
assert actual == {'Authorization': 'Basic dXNlcjpwYXNz'}
def test_api_basic_auth_no_password():
api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", username=u"user",)
- actual = api._auth_header()
+ actual = {}
+ api._add_auth_token(actual, "")
assert actual == {'Authorization': 'Basic dXNlcjo='}
+
+
+def test_api_dont_override_auth_header():
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com")
+ actual = {'Authorization': 'Custom token'}
+ api._add_auth_token(actual, "")
+ assert actual == {'Authorization': 'Custom token'}
+
+
+def test_initialise_galaxy(monkeypatch):
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(u'{"available_versions":{"v1":"/api/v1"}}'),
+ StringIO(u'{"token":"my token"}'),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com")
+ actual = api.authenticate("github_token")
+
+ assert len(api.available_api_versions) == 2
+ assert api.available_api_versions['v1'] == u'/api/v1'
+ assert api.available_api_versions['v2'] == u'/api/v2'
+ assert actual == {u'token': u'my token'}
+ assert mock_open.call_count == 2
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.ansible.com/api'
+ assert mock_open.mock_calls[1][1][0] == 'https://galaxy.ansible.com/api/v1/tokens/'
+ assert mock_open.mock_calls[1][2]['data'] == 'github_token=github_token'
+
+
+def test_initialise_galaxy_with_auth(monkeypatch):
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(u'{"available_versions":{"v1":"/api/v1"}}'),
+ StringIO(u'{"token":"my token"}'),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=GalaxyToken(token='my_token'))
+ actual = api.authenticate("github_token")
+
+ assert len(api.available_api_versions) == 2
+ assert api.available_api_versions['v1'] == u'/api/v1'
+ assert api.available_api_versions['v2'] == u'/api/v2'
+ assert actual == {u'token': u'my token'}
+ assert mock_open.call_count == 2
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.ansible.com/api'
+ assert mock_open.mock_calls[0][2]['headers'] == {'Authorization': 'Token my_token'}
+ assert mock_open.mock_calls[1][1][0] == 'https://galaxy.ansible.com/api/v1/tokens/'
+ assert mock_open.mock_calls[1][2]['data'] == 'github_token=github_token'
+
+
+def test_initialise_automation_hub(monkeypatch):
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ urllib_error.HTTPError('https://galaxy.ansible.com/api', 401, 'msg', {}, StringIO()),
+ # AH won't return v1 but we do for authenticate() to work.
+ StringIO(u'{"available_versions":{"v1":"/api/v1","v3":"/api/v3"}}'),
+ StringIO(u'{"token":"my token"}'),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=GalaxyToken(token='my_token'))
+ actual = api.authenticate("github_token")
+
+ assert len(api.available_api_versions) == 2
+ assert api.available_api_versions['v1'] == u'/api/v1'
+ assert api.available_api_versions['v3'] == u'/api/v3'
+ assert actual == {u'token': u'my token'}
+ assert mock_open.call_count == 3
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.ansible.com/api'
+ assert mock_open.mock_calls[0][2]['headers'] == {'Authorization': 'Token my_token'}
+ assert mock_open.mock_calls[1][1][0] == 'https://galaxy.ansible.com/api'
+ assert mock_open.mock_calls[1][2]['headers'] == {'Authorization': 'Bearer my_token'}
+ assert mock_open.mock_calls[2][1][0] == 'https://galaxy.ansible.com/api/v1/tokens/'
+ assert mock_open.mock_calls[2][2]['data'] == 'github_token=github_token'
+
+
+def test_initialise_unknown(monkeypatch):
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ urllib_error.HTTPError('https://galaxy.ansible.com/api', 500, 'msg', {}, StringIO(u'{"msg":"raw error"}')),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com", token=GalaxyToken(token='my_token'))
+
+ expected = "Error when finding available api versions from test (%s/api) (HTTP Code: 500, Message: Unknown " \
+ "error returned by Galaxy server.)" % api.api_server
+ with pytest.raises(GalaxyError, match=re.escape(expected)):
+ api.authenticate("github_token")
+
+
+def test_get_available_api_versions(monkeypatch):
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(u'{"available_versions":{"v1":"/api/v1","v2":"/api/v2"}}'),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ api = GalaxyAPI(None, "test", "https://galaxy.ansible.com")
+ actual = api.available_api_versions
+ assert len(actual) == 2
+ assert actual['v1'] == u'/api/v1'
+ assert actual['v2'] == u'/api/v2'
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.ansible.com/api'
+
+
+def test_publish_collection_missing_file():
+ fake_path = u'/fake/ÅÑŚÌβŁÈ/path'
+ expected = to_native("The collection path specified '%s' does not exist." % fake_path)
+
+ api = get_test_galaxy_api("https://galaxy.ansible.com", "v2")
+ with pytest.raises(AnsibleError, match=expected):
+ api.publish_collection(fake_path)
+
+
+def test_publish_collection_not_a_tarball():
+ expected = "The collection path specified '{0}' is not a tarball, use 'ansible-galaxy collection build' to " \
+ "create a proper release artifact."
+
+ api = get_test_galaxy_api("https://galaxy.ansible.com", "v2")
+ with tempfile.NamedTemporaryFile(prefix=u'ÅÑŚÌβŁÈ') as temp_file:
+ temp_file.write(b"\x00")
+ temp_file.flush()
+ with pytest.raises(AnsibleError, match=expected.format(to_native(temp_file.name))):
+ api.publish_collection(temp_file.name)
+
+
+def test_publish_collection_unsupported_version():
+ expected = "Galaxy action publish_collection requires API versions 'v2, v3' but only 'v1' are available on test " \
+ "https://galaxy.ansible.com"
+
+ api = get_test_galaxy_api("https://galaxy.ansible.com", "v1")
+ with pytest.raises(AnsibleError, match=expected):
+ api.publish_collection("path")
+
+
+@pytest.mark.parametrize('api_version, collection_url', [
+ ('v2', 'collections'),
+ ('v3', 'artifacts/collections'),
+])
+def test_publish_collection(api_version, collection_url, collection_artifact, monkeypatch):
+ api = get_test_galaxy_api("https://galaxy.ansible.com", api_version)
+
+ mock_call = MagicMock()
+ mock_call.return_value = {'task': 'http://task.url/'}
+ monkeypatch.setattr(api, '_call_galaxy', mock_call)
+
+ actual = api.publish_collection(collection_artifact)
+ assert actual == 'http://task.url/'
+ assert mock_call.call_count == 1
+ assert mock_call.mock_calls[0][1][0] == 'https://galaxy.ansible.com/api/%s/%s/' % (api_version, collection_url)
+ assert mock_call.mock_calls[0][2]['headers']['Content-length'] == len(mock_call.mock_calls[0][2]['args'])
+ assert mock_call.mock_calls[0][2]['headers']['Content-type'].startswith(
+ 'multipart/form-data; boundary=--------------------------')
+ assert mock_call.mock_calls[0][2]['args'].startswith(b'--------------------------')
+ assert mock_call.mock_calls[0][2]['method'] == 'POST'
+ assert mock_call.mock_calls[0][2]['auth_required'] is True
+
+
+@pytest.mark.parametrize('api_version, collection_url, response, expected', [
+ ('v2', 'collections', {},
+ 'Error when publishing collection to test (%s) (HTTP Code: 500, Message: Unknown error returned by Galaxy '
+ 'server. Code: Unknown)'),
+ ('v2', 'collections', {
+ 'message': u'Galaxy error messäge',
+ 'code': 'GWE002',
+ }, u'Error when publishing collection to test (%s) (HTTP Code: 500, Message: Galaxy error messäge Code: GWE002)'),
+ ('v3', 'artifact/collections', {},
+ 'Error when publishing collection to test (%s) (HTTP Code: 500, Message: Unknown error returned by Galaxy '
+ 'server. Code: Unknown)'),
+ ('v3', 'artifact/collections', {
+ 'errors': [
+ {
+ 'code': 'conflict.collection_exists',
+ 'detail': 'Collection "mynamespace-mycollection-4.1.1" already exists.',
+ 'title': 'Conflict.',
+ 'status': '400',
+ },
+ {
+ 'code': 'quantum_improbability',
+ 'title': u'Rändom(?) quantum improbability.',
+ 'source': {'parameter': 'the_arrow_of_time'},
+ 'meta': {'remediation': 'Try again before'},
+ },
+ ],
+ }, u'Error when publishing collection to test (%s) (HTTP Code: 500, Message: Collection '
+ u'"mynamespace-mycollection-4.1.1" already exists. Code: conflict.collection_exists), (HTTP Code: 500, '
+ u'Message: Rändom(?) quantum improbability. Code: quantum_improbability)')
+])
+def test_publish_failure(api_version, collection_url, response, expected, collection_artifact, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+
+ expected_url = '%s/api/%s/%s' % (api.api_server, api_version, collection_url)
+
+ mock_open = MagicMock()
+ mock_open.side_effect = urllib_error.HTTPError(expected_url, 500, 'msg', {},
+ StringIO(to_text(json.dumps(response))))
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ with pytest.raises(GalaxyError, match=re.escape(to_native(expected % api.api_server))):
+ api.publish_collection(collection_artifact)
+
+
+@pytest.mark.parametrize('api_version, token_type', [
+ ('v2', 'Token'),
+ ('v3', 'Bearer'),
+])
+def test_wait_import_task(api_version, token_type, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+ import_uri = 'https://galaxy.server.com/api/%s/task/1234' % api_version
+
+ mock_open = MagicMock()
+ mock_open.return_value = StringIO(u'{"state":"success","finished_at":"time"}')
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ mock_display = MagicMock()
+ monkeypatch.setattr(Display, 'display', mock_display)
+
+ api.wait_import_task(import_uri)
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == import_uri
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % import_uri
+
+
+@pytest.mark.parametrize('api_version, token_type', [
+ ('v2', 'Token'),
+ ('v3', 'Bearer'),
+])
+def test_wait_import_task_multiple_requests(api_version, token_type, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+ import_uri = 'https://galaxy.server.com/api/%s/task/1234' % api_version
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(u'{"state":"test"}'),
+ StringIO(u'{"state":"success","finished_at":"time"}'),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ mock_display = MagicMock()
+ monkeypatch.setattr(Display, 'display', mock_display)
+
+ mock_vvv = MagicMock()
+ monkeypatch.setattr(Display, 'vvv', mock_vvv)
+
+ monkeypatch.setattr(time, 'sleep', MagicMock())
+
+ api.wait_import_task(import_uri)
+
+ assert mock_open.call_count == 2
+ assert mock_open.mock_calls[0][1][0] == import_uri
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+ assert mock_open.mock_calls[1][1][0] == import_uri
+ assert mock_open.mock_calls[1][2]['headers']['Authorization'] == '%s my token' % token_type
+
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % import_uri
+
+ assert mock_vvv.call_count == 2 # 1st is opening Galaxy token file.
+ assert mock_vvv.mock_calls[1][1][0] == \
+ 'Galaxy import process has a status of test, wait 2 seconds before trying again'
+
+
+@pytest.mark.parametrize('api_version, token_type', [
+ ('v2', 'Token'),
+ ('v3', 'Bearer'),
+])
+def test_wait_import_task_with_failure(api_version, token_type, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+ import_uri = 'https://galaxy.server.com/api/%s/task/1234' % api_version
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(to_text(json.dumps({
+ 'finished_at': 'some_time',
+ 'state': 'failed',
+ 'error': {
+ 'code': 'GW001',
+ 'description': u'Becäuse I said so!',
+
+ },
+ 'messages': [
+ {
+ 'level': 'error',
+ 'message': u'Somé error',
+ },
+ {
+ 'level': 'warning',
+ 'message': u'Some wärning',
+ },
+ {
+ 'level': 'info',
+ 'message': u'Somé info',
+ },
+ ],
+ }))),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ mock_display = MagicMock()
+ monkeypatch.setattr(Display, 'display', mock_display)
+
+ mock_vvv = MagicMock()
+ monkeypatch.setattr(Display, 'vvv', mock_vvv)
+
+ mock_warn = MagicMock()
+ monkeypatch.setattr(Display, 'warning', mock_warn)
+
+ mock_err = MagicMock()
+ monkeypatch.setattr(Display, 'error', mock_err)
+
+ expected = to_native(u'Galaxy import process failed: Becäuse I said so! (Code: GW001)')
+ with pytest.raises(AnsibleError, match=re.escape(expected)):
+ api.wait_import_task(import_uri)
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == import_uri
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % import_uri
+
+ assert mock_vvv.call_count == 2 # 1st is opening Galaxy token file.
+ assert mock_vvv.mock_calls[1][1][0] == u'Galaxy import message: info - Somé info'
+
+ assert mock_warn.call_count == 1
+ assert mock_warn.mock_calls[0][1][0] == u'Galaxy import warning message: Some wärning'
+
+ assert mock_err.call_count == 1
+ assert mock_err.mock_calls[0][1][0] == u'Galaxy import error message: Somé error'
+
+
+@pytest.mark.parametrize('api_version, token_type', [
+ ('v2', 'Token'),
+ ('v3', 'Bearer'),
+])
+def test_wait_import_task_with_failure_no_error(api_version, token_type, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+ import_uri = 'https://galaxy.server.com/api/%s/task/1234' % api_version
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(to_text(json.dumps({
+ 'finished_at': 'some_time',
+ 'state': 'failed',
+ 'error': {},
+ 'messages': [
+ {
+ 'level': 'error',
+ 'message': u'Somé error',
+ },
+ {
+ 'level': 'warning',
+ 'message': u'Some wärning',
+ },
+ {
+ 'level': 'info',
+ 'message': u'Somé info',
+ },
+ ],
+ }))),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ mock_display = MagicMock()
+ monkeypatch.setattr(Display, 'display', mock_display)
+
+ mock_vvv = MagicMock()
+ monkeypatch.setattr(Display, 'vvv', mock_vvv)
+
+ mock_warn = MagicMock()
+ monkeypatch.setattr(Display, 'warning', mock_warn)
+
+ mock_err = MagicMock()
+ monkeypatch.setattr(Display, 'error', mock_err)
+
+ expected = 'Galaxy import process failed: Unknown error, see %s for more details (Code: UNKNOWN)' % import_uri
+ with pytest.raises(AnsibleError, match=re.escape(expected)):
+ api.wait_import_task(import_uri)
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == import_uri
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % import_uri
+
+ assert mock_vvv.call_count == 2 # 1st is opening Galaxy token file.
+ assert mock_vvv.mock_calls[1][1][0] == u'Galaxy import message: info - Somé info'
+
+ assert mock_warn.call_count == 1
+ assert mock_warn.mock_calls[0][1][0] == u'Galaxy import warning message: Some wärning'
+
+ assert mock_err.call_count == 1
+ assert mock_err.mock_calls[0][1][0] == u'Galaxy import error message: Somé error'
+
+
+@pytest.mark.parametrize('api_version, token_type', [
+ ('v2', 'Token'),
+ ('v3', 'Bearer'),
+])
+def test_wait_import_task_timeout(api_version, token_type, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+ import_uri = 'https://galaxy.server.com/api/%s/task/1234' % api_version
+
+ def return_response(*args, **kwargs):
+ return StringIO(u'{"state":"waiting"}')
+
+ mock_open = MagicMock()
+ mock_open.side_effect = return_response
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ mock_display = MagicMock()
+ monkeypatch.setattr(Display, 'display', mock_display)
+
+ mock_vvv = MagicMock()
+ monkeypatch.setattr(Display, 'vvv', mock_vvv)
+
+ monkeypatch.setattr(time, 'sleep', MagicMock())
+
+ expected = "Timeout while waiting for the Galaxy import process to finish, check progress at '%s'" % import_uri
+ with pytest.raises(AnsibleError, match=expected):
+ api.wait_import_task(import_uri, 1)
+
+ assert mock_open.call_count > 1
+ assert mock_open.mock_calls[0][1][0] == import_uri
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+ assert mock_open.mock_calls[1][1][0] == import_uri
+ assert mock_open.mock_calls[1][2]['headers']['Authorization'] == '%s my token' % token_type
+
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == 'Waiting until Galaxy import task %s has completed' % import_uri
+
+ expected_wait_msg = 'Galaxy import process has a status of waiting, wait {0} seconds before trying again'
+ assert mock_vvv.call_count > 9 # 1st is opening Galaxy token file.
+ assert mock_vvv.mock_calls[1][1][0] == expected_wait_msg.format(2)
+ assert mock_vvv.mock_calls[2][1][0] == expected_wait_msg.format(3)
+ assert mock_vvv.mock_calls[3][1][0] == expected_wait_msg.format(4)
+ assert mock_vvv.mock_calls[4][1][0] == expected_wait_msg.format(6)
+ assert mock_vvv.mock_calls[5][1][0] == expected_wait_msg.format(10)
+ assert mock_vvv.mock_calls[6][1][0] == expected_wait_msg.format(15)
+ assert mock_vvv.mock_calls[7][1][0] == expected_wait_msg.format(22)
+ assert mock_vvv.mock_calls[8][1][0] == expected_wait_msg.format(30)
+
+
+@pytest.mark.parametrize('api_version, token_type, version', [
+ ('v2', 'Token', 'v2.1.13'),
+ ('v3', 'Bearer', 'v1.0.0'),
+])
+def test_get_collection_version_metadata_no_version(api_version, token_type, version, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(to_text(json.dumps({
+ 'download_url': 'https://downloadme.com',
+ 'artifact': {
+ 'sha256': 'ac47b6fac117d7c171812750dacda655b04533cf56b31080b82d1c0db3c9d80f',
+ },
+ 'namespace': {
+ 'name': 'namespace',
+ },
+ 'collection': {
+ 'name': 'collection',
+ },
+ 'version': version,
+ 'metadata': {
+ 'dependencies': {},
+ }
+ }))),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ actual = api.get_collection_version_metadata('namespace', 'collection', version)
+
+ assert isinstance(actual, CollectionVersionMetadata)
+ assert actual.namespace == u'namespace'
+ assert actual.name == u'collection'
+ assert actual.download_url == u'https://downloadme.com'
+ assert actual.artifact_sha256 == u'ac47b6fac117d7c171812750dacda655b04533cf56b31080b82d1c0db3c9d80f'
+ assert actual.version == version
+ assert actual.dependencies == {}
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == '%s/api/%s/collections/namespace/collection/versions/%s' \
+ % (api.api_server, api_version, version)
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+
+
+@pytest.mark.parametrize('api_version, token_type, response', [
+ ('v2', 'Token', {
+ 'count': 2,
+ 'next': None,
+ 'previous': None,
+ 'results': [
+ {
+ 'version': '1.0.0',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.0',
+ },
+ {
+ 'version': '1.0.1',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.1',
+ },
+ ],
+ }),
+ # TODO: Verify this once Automation Hub is actually out
+ ('v3', 'Bearer', {
+ 'count': 2,
+ 'next': None,
+ 'previous': None,
+ 'data': [
+ {
+ 'version': '1.0.0',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.0',
+ },
+ {
+ 'version': '1.0.1',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.1',
+ },
+ ],
+ }),
+])
+def test_get_collection_versions(api_version, token_type, response, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [
+ StringIO(to_text(json.dumps(response))),
+ ]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ actual = api.get_collection_versions('namespace', 'collection')
+ assert actual == [u'1.0.0', u'1.0.1']
+
+ assert mock_open.call_count == 1
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.server.com/api/%s/collections/namespace/collection/' \
+ 'versions' % api_version
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+
+
+@pytest.mark.parametrize('api_version, token_type, responses', [
+ ('v2', 'Token', [
+ {
+ 'count': 6,
+ 'next': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/?page=2',
+ 'previous': None,
+ 'results': [
+ {
+ 'version': '1.0.0',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.0',
+ },
+ {
+ 'version': '1.0.1',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.1',
+ },
+ ],
+ },
+ {
+ 'count': 6,
+ 'next': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/?page=3',
+ 'previous': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions',
+ 'results': [
+ {
+ 'version': '1.0.2',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.2',
+ },
+ {
+ 'version': '1.0.3',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.3',
+ },
+ ],
+ },
+ {
+ 'count': 6,
+ 'next': None,
+ 'previous': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/?page=2',
+ 'results': [
+ {
+ 'version': '1.0.4',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.4',
+ },
+ {
+ 'version': '1.0.5',
+ 'href': 'https://galaxy.server.com/api/v2/collections/namespace/collection/versions/1.0.5',
+ },
+ ],
+ },
+ ]),
+ ('v3', 'Bearer', [
+ {
+ 'count': 6,
+ 'links': {
+ 'next': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/?page=2',
+ 'previous': None,
+ },
+ 'data': [
+ {
+ 'version': '1.0.0',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.0',
+ },
+ {
+ 'version': '1.0.1',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.1',
+ },
+ ],
+ },
+ {
+ 'count': 6,
+ 'links': {
+ 'next': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/?page=3',
+ 'previous': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions',
+ },
+ 'data': [
+ {
+ 'version': '1.0.2',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.2',
+ },
+ {
+ 'version': '1.0.3',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.3',
+ },
+ ],
+ },
+ {
+ 'count': 6,
+ 'links': {
+ 'next': None,
+ 'previous': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/?page=2',
+ },
+ 'data': [
+ {
+ 'version': '1.0.4',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.4',
+ },
+ {
+ 'version': '1.0.5',
+ 'href': 'https://galaxy.server.com/api/v3/collections/namespace/collection/versions/1.0.5',
+ },
+ ],
+ },
+ ]),
+])
+def test_get_collection_versions_pagination(api_version, token_type, responses, monkeypatch):
+ api = get_test_galaxy_api('https://galaxy.server.com', api_version)
+
+ mock_open = MagicMock()
+ mock_open.side_effect = [StringIO(to_text(json.dumps(r))) for r in responses]
+ monkeypatch.setattr(galaxy_api, 'open_url', mock_open)
+
+ actual = api.get_collection_versions('namespace', 'collection')
+ a = ''
+ assert actual == [u'1.0.0', u'1.0.1', u'1.0.2', u'1.0.3', u'1.0.4', u'1.0.5']
+
+ assert mock_open.call_count == 3
+ assert mock_open.mock_calls[0][1][0] == 'https://galaxy.server.com/api/%s/collections/namespace/collection/' \
+ 'versions' % api_version
+ assert mock_open.mock_calls[0][2]['headers']['Authorization'] == '%s my token' % token_type
+ assert mock_open.mock_calls[1][1][0] == 'https://galaxy.server.com/api/%s/collections/namespace/collection/' \
+ 'versions/?page=2' % api_version
+ assert mock_open.mock_calls[1][2]['headers']['Authorization'] == '%s my token' % token_type
+ assert mock_open.mock_calls[2][1][0] == 'https://galaxy.server.com/api/%s/collections/namespace/collection/' \
+ 'versions/?page=3' % api_version
+ assert mock_open.mock_calls[2][2]['headers']['Authorization'] == '%s my token' % token_type
diff --git a/test/units/galaxy/test_collection.py b/test/units/galaxy/test_collection.py
index 6276fb346c..c86a524a09 100644
--- a/test/units/galaxy/test_collection.py
+++ b/test/units/galaxy/test_collection.py
@@ -9,18 +9,13 @@ __metaclass__ = type
import json
import os
import pytest
-import re
import tarfile
-import tempfile
-import time
import uuid
from hashlib import sha256
-from io import BytesIO, StringIO
+from io import BytesIO
from units.compat.mock import MagicMock
-import ansible.module_utils.six.moves.urllib.error as urllib_error
-
from ansible import context
from ansible.cli.galaxy import GalaxyCLI
from ansible.errors import AnsibleError
@@ -56,13 +51,6 @@ def collection_input(tmp_path_factory):
@pytest.fixture()
-def galaxy_api_version(monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
-
-@pytest.fixture()
def collection_artifact(monkeypatch, tmp_path_factory):
''' Creates a temp collection artifact and mocked open_url instance for publishing tests '''
mock_open = MagicMock()
@@ -408,440 +396,53 @@ def test_build_with_symlink_inside_collection(collection_input):
assert actual_file == '63444bfc766154e1bc7557ef6280de20d03fcd81'
-def test_publish_missing_file():
- fake_path = u'/fake/ÅÑŚÌβŁÈ/path'
- expected = to_native("The collection path specified '%s' does not exist." % fake_path)
-
- with pytest.raises(AnsibleError, match=expected):
- collection.publish_collection(fake_path, None, True, 0)
-
-
-def test_publish_not_a_tarball():
- expected = "The collection path specified '{0}' is not a tarball, use 'ansible-galaxy collection build' to " \
- "create a proper release artifact."
-
- with tempfile.NamedTemporaryFile(prefix=u'ÅÑŚÌβŁÈ') as temp_file:
- temp_file.write(b"\x00")
- temp_file.flush()
- with pytest.raises(AnsibleError, match=expected.format(to_native(temp_file.name))):
- collection.publish_collection(temp_file.name, None, True, 0)
-
-
def test_publish_no_wait(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
mock_display = MagicMock()
monkeypatch.setattr(Display, 'display', mock_display)
artifact_path, mock_open = collection_artifact
fake_import_uri = 'https://galaxy.server.com/api/v2/import/1234'
- mock_open.return_value = StringIO(u'{"task":"%s"}' % fake_import_uri)
- expected_form, expected_content_type = collection._get_mime_data(to_bytes(artifact_path))
+ mock_publish = MagicMock()
+ mock_publish.return_value = fake_import_uri
+ monkeypatch.setattr(galaxy_server, 'publish_collection', mock_publish)
collection.publish_collection(artifact_path, galaxy_server, False, 0)
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][1][0] == '%s/api/v2/collections/' % galaxy_server.api_server
- assert mock_open.mock_calls[0][2]['data'] == expected_form
- assert mock_open.mock_calls[0][2]['method'] == 'POST'
- assert mock_open.mock_calls[0][2]['validate_certs'] is True
- assert mock_open.mock_calls[0][2]['headers']['Authorization'] == 'Token key'
- assert mock_open.mock_calls[0][2]['headers']['Content-length'] == len(expected_form)
- assert mock_open.mock_calls[0][2]['headers']['Content-type'] == expected_content_type
-
- assert mock_display.call_count == 2
- assert mock_display.mock_calls[0][1][0] == "Publishing collection artifact '%s' to %s %s" \
- % (artifact_path, galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[1][1][0] == \
- "Collection has been pushed to the Galaxy server %s %s, not waiting until import has completed due to --no-wait " \
- "being set. Import task results can be found at %s" % (galaxy_server.name, galaxy_server.api_server, fake_import_uri)
-
-
-def test_publish_dont_validate_cert(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- galaxy_server.validate_certs = False
- artifact_path, mock_open = collection_artifact
-
- mock_open.return_value = StringIO(u'{"task":"https://galaxy.server.com/api/v2/import/1234"}')
-
- collection.publish_collection(artifact_path, galaxy_server, False, 0)
-
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][2]['validate_certs'] is False
-
-
-def test_publish_failure(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- artifact_path, mock_open = collection_artifact
-
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 500, 'msg', {}, StringIO())
-
- expected = 'Error when publishing collection to test_server (https://galaxy.ansible.com) ' \
- '(HTTP Code: 500, Message: Unknown error returned by Galaxy ' \
- 'server. Code: Unknown)'
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
-
-
-def test_publish_failure_with_json_info(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- artifact_path, mock_open = collection_artifact
-
- return_content = StringIO(u'{"message":"Galaxy error message","code":"GWE002"}')
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 503, 'msg', {}, return_content)
-
- expected = 'Error when publishing collection to test_server (https://galaxy.ansible.com) ' \
- '(HTTP Code: 503, Message: Galaxy error message Code: GWE002)'
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
-
-
-@pytest.mark.parametrize("api_version,token_type", [
- ('v2', 'Token'),
- ('v3', 'Bearer')
-])
-def test_publish_with_wait(api_version, token_type, galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {api_version: '/api/%s' % api_version}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- mock_display = MagicMock()
- monkeypatch.setattr(Display, 'display', mock_display)
-
- fake_import_uri = 'https://galaxy-server/api/v2/import/1234'
-
- artifact_path, mock_open = collection_artifact
-
- mock_open.side_effect = (
- StringIO(u'{"task":"%s"}' % fake_import_uri),
- StringIO(u'{"finished_at":"some_time","state":"success"}')
- )
-
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
-
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[1][1][0] == fake_import_uri
- assert mock_open.mock_calls[1][2]['headers']['Authorization'] == '%s key' % token_type
- assert mock_open.mock_calls[1][2]['validate_certs'] is True
- assert mock_open.mock_calls[1][2]['method'] == 'GET'
-
- assert mock_display.call_count == 5
- assert mock_display.mock_calls[0][1][0] == "Publishing collection artifact '%s' to %s %s" \
- % (artifact_path, galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[1][1][0] == 'Collection has been published to the Galaxy server %s %s'\
- % (galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[2][1][0] == 'Waiting until Galaxy import task %s has completed' % fake_import_uri
- assert mock_display.mock_calls[4][1][0] == 'Collection has been successfully published and imported to the ' \
- 'Galaxy server %s %s' % (galaxy_server.name, galaxy_server.api_server)
-
-
-@pytest.mark.parametrize("api_version,exp_api_url,token_type", [
- ('v2', '/api/v2/collections/', 'Token'),
- ('v3', '/api/v3/artifacts/collections/', 'Bearer')
-])
-def test_publish_with_wait_timeout(api_version, exp_api_url, token_type, galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {api_version: '/api/%s' % api_version}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- monkeypatch.setattr(time, 'sleep', MagicMock())
-
- mock_vvv = MagicMock()
- monkeypatch.setattr(Display, 'vvv', mock_vvv)
-
- fake_import_uri = 'https://galaxy-server/api/v2/import/1234'
-
- artifact_path, mock_open = collection_artifact
-
- mock_open.side_effect = (
- StringIO(u'{"task":"%s"}' % fake_import_uri),
- StringIO(u'{"finished_at":null}'),
- StringIO(u'{"finished_at":"some_time","state":"success"}')
- )
-
- collection.publish_collection(artifact_path, galaxy_server, True, 60)
-
- assert mock_open.call_count == 3
- assert mock_open.mock_calls[1][1][0] == fake_import_uri
- assert mock_open.mock_calls[1][2]['headers']['Authorization'] == '%s key' % token_type
- assert mock_open.mock_calls[1][2]['validate_certs'] is True
- assert mock_open.mock_calls[1][2]['method'] == 'GET'
- assert mock_open.mock_calls[2][1][0] == fake_import_uri
- assert mock_open.mock_calls[2][2]['headers']['Authorization'] == '%s key' % token_type
- assert mock_open.mock_calls[2][2]['validate_certs'] is True
- assert mock_open.mock_calls[2][2]['method'] == 'GET'
-
- assert mock_vvv.call_count == 2
- assert mock_vvv.mock_calls[1][1][0] == \
- 'Galaxy import process has a status of waiting, wait 2 seconds before trying again'
-
-
-def test_publish_with_wait_timeout_failure(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- monkeypatch.setattr(time, 'sleep', MagicMock())
-
- mock_vvv = MagicMock()
- monkeypatch.setattr(Display, 'vvv', mock_vvv)
+ assert mock_publish.call_count == 1
+ assert mock_publish.mock_calls[0][1][0] == artifact_path
- fake_import_uri = 'https://galaxy-server/api/v2/import/1234'
-
- artifact_path, mock_open = collection_artifact
-
- first_call = True
-
- def open_value(*args, **kwargs):
- if first_call:
- return StringIO(u'{"task":"%s"}' % fake_import_uri)
- else:
- return StringIO(u'{"finished_at":null}')
+ assert mock_display.call_count == 1
+ assert mock_display.mock_calls[0][1][0] == \
+ "Collection has been pushed to the Galaxy server %s %s, not waiting until import has completed due to " \
+ "--no-wait being set. Import task results can be found at %s" % (galaxy_server.name, galaxy_server.api_server,
+ fake_import_uri)
- mock_open.side_effect = open_value
-
- expected = "Timeout while waiting for the Galaxy import process to finish, check progress at '%s'" \
- % fake_import_uri
- with pytest.raises(AnsibleError, match=expected):
- collection.publish_collection(artifact_path, galaxy_server, True, 2)
-
- # While the seconds exceed the time we are testing that the exponential backoff gets to 30 and then sits there
- # Because we mock time.sleep() there should be thousands of calls here
- expected_wait_msg = 'Galaxy import process has a status of waiting, wait {0} seconds before trying again'
- assert mock_vvv.call_count > 9
- assert mock_vvv.mock_calls[1][1][0] == expected_wait_msg.format(2)
- assert mock_vvv.mock_calls[2][1][0] == expected_wait_msg.format(3)
- assert mock_vvv.mock_calls[3][1][0] == expected_wait_msg.format(4)
- assert mock_vvv.mock_calls[4][1][0] == expected_wait_msg.format(6)
- assert mock_vvv.mock_calls[5][1][0] == expected_wait_msg.format(10)
- assert mock_vvv.mock_calls[6][1][0] == expected_wait_msg.format(15)
- assert mock_vvv.mock_calls[7][1][0] == expected_wait_msg.format(22)
- assert mock_vvv.mock_calls[8][1][0] == expected_wait_msg.format(30)
-
-
-def test_publish_with_wait_and_failure(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+def test_publish_with_wait(galaxy_server, collection_artifact, monkeypatch):
mock_display = MagicMock()
monkeypatch.setattr(Display, 'display', mock_display)
- mock_vvv = MagicMock()
- monkeypatch.setattr(Display, 'vvv', mock_vvv)
-
- mock_warn = MagicMock()
- monkeypatch.setattr(Display, 'warning', mock_warn)
-
- mock_err = MagicMock()
- monkeypatch.setattr(Display, 'error', mock_err)
-
- fake_import_uri = 'https://galaxy-server/api/v2/import/1234'
-
artifact_path, mock_open = collection_artifact
+ fake_import_uri = 'https://galaxy.server.com/api/v2/import/1234'
- import_stat = {
- 'finished_at': 'some_time',
- 'state': 'failed',
- 'error': {
- 'code': 'GW001',
- 'description': 'Because I said so!',
-
- },
- 'messages': [
- {
- 'level': 'error',
- 'message': 'Some error',
- },
- {
- 'level': 'warning',
- 'message': 'Some warning',
- },
- {
- 'level': 'info',
- 'message': 'Some info',
- },
- ],
- }
-
- mock_open.side_effect = (
- StringIO(u'{"task":"%s"}' % fake_import_uri),
- StringIO(to_text(json.dumps(import_stat)))
- )
-
- expected = 'Galaxy import process failed: Because I said so! (Code: GW001)'
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
-
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[1][1][0] == fake_import_uri
- assert mock_open.mock_calls[1][2]['headers']['Authorization'] == 'Token key'
- assert mock_open.mock_calls[1][2]['validate_certs'] is True
- assert mock_open.mock_calls[1][2]['method'] == 'GET'
-
- assert mock_display.call_count == 4
- assert mock_display.mock_calls[0][1][0] == "Publishing collection artifact '%s' to %s %s"\
- % (artifact_path, galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[1][1][0] == 'Collection has been published to the Galaxy server %s %s'\
- % (galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[2][1][0] == 'Waiting until Galaxy import task %s has completed' % fake_import_uri
-
- assert mock_vvv.call_count == 2
- assert mock_vvv.mock_calls[1][1][0] == 'Galaxy import message: info - Some info'
-
- assert mock_warn.call_count == 1
- assert mock_warn.mock_calls[0][1][0] == 'Galaxy import warning message: Some warning'
-
- assert mock_err.call_count == 1
- assert mock_err.mock_calls[0][1][0] == 'Galaxy import error message: Some error'
-
-
-def test_publish_with_wait_and_failure_and_no_error(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- mock_display = MagicMock()
- monkeypatch.setattr(Display, 'display', mock_display)
-
- mock_vvv = MagicMock()
- monkeypatch.setattr(Display, 'vvv', mock_vvv)
-
- mock_warn = MagicMock()
- monkeypatch.setattr(Display, 'warning', mock_warn)
-
- mock_err = MagicMock()
- monkeypatch.setattr(Display, 'error', mock_err)
-
- fake_import_uri = 'https://galaxy-server/api/v2/import/1234'
-
- artifact_path, mock_open = collection_artifact
-
- import_stat = {
- 'finished_at': 'some_time',
- 'state': 'failed',
- 'error': {},
- 'messages': [
- {
- 'level': 'error',
- 'message': 'Some error',
- },
- {
- 'level': 'warning',
- 'message': 'Some warning',
- },
- {
- 'level': 'info',
- 'message': 'Some info',
- },
- ],
- }
-
- mock_open.side_effect = (
- StringIO(u'{"task":"%s"}' % fake_import_uri),
- StringIO(to_text(json.dumps(import_stat)))
- )
-
- expected = 'Galaxy import process failed: Unknown error, see %s for more details (Code: UNKNOWN)' % fake_import_uri
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
-
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[1][1][0] == fake_import_uri
- assert mock_open.mock_calls[1][2]['headers']['Authorization'] == 'Token key'
- assert mock_open.mock_calls[1][2]['validate_certs'] is True
- assert mock_open.mock_calls[1][2]['method'] == 'GET'
-
- assert mock_display.call_count == 4
- assert mock_display.mock_calls[0][1][0] == "Publishing collection artifact '%s' to %s %s"\
- % (artifact_path, galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[1][1][0] == 'Collection has been published to the Galaxy server %s %s'\
- % (galaxy_server.name, galaxy_server.api_server)
- assert mock_display.mock_calls[2][1][0] == 'Waiting until Galaxy import task %s has completed' % fake_import_uri
-
- assert mock_vvv.call_count == 2
- assert mock_vvv.mock_calls[1][1][0] == 'Galaxy import message: info - Some info'
-
- assert mock_warn.call_count == 1
- assert mock_warn.mock_calls[0][1][0] == 'Galaxy import warning message: Some warning'
-
- assert mock_err.call_count == 1
- assert mock_err.mock_calls[0][1][0] == 'Galaxy import error message: Some error'
-
-
-def test_publish_failure_v3_with_json_info_409_conflict(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v3': '/api/v3'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- artifact_path, mock_open = collection_artifact
-
- error_response = {
- "errors": [
- {
- "code": "conflict.collection_exists",
- "detail": 'Collection "testing-ansible_testing_content-4.0.4" already exists.',
- "title": "Conflict.",
- "status": "409",
- },
- ]
- }
-
- return_content = StringIO(to_text(json.dumps(error_response)))
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 409, 'msg', {}, return_content)
+ mock_publish = MagicMock()
+ mock_publish.return_value = fake_import_uri
+ monkeypatch.setattr(galaxy_server, 'publish_collection', mock_publish)
- expected = 'Error when publishing collection to test_server (https://galaxy.ansible.com) ' \
- '(HTTP Code: 409, Message: Collection "testing-ansible_testing_content-4.0.4"' \
- ' already exists. Code: conflict.collection_exists)'
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
+ mock_wait = MagicMock()
+ monkeypatch.setattr(galaxy_server, 'wait_import_task', mock_wait)
+ collection.publish_collection(artifact_path, galaxy_server, True, 0)
-def test_publish_failure_v3_with_json_info_multiple_errors(galaxy_server, collection_artifact, monkeypatch):
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v3': '/api/v3'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ assert mock_publish.call_count == 1
+ assert mock_publish.mock_calls[0][1][0] == artifact_path
- artifact_path, mock_open = collection_artifact
+ assert mock_wait.call_count == 1
+ assert mock_wait.mock_calls[0][1][0] == fake_import_uri
- error_response = {
- "errors": [
- {
- "code": "conflict.collection_exists",
- "detail": 'Collection "mynamespace-mycollection-4.1.1" already exists.',
- "title": "Conflict.",
- "status": "400",
- },
- {
- "code": "quantum_improbability",
- "title": "Random(?) quantum improbability.",
- "source": {"parameter": "the_arrow_of_time"},
- "meta": {"remediation": "Try again before"}
- },
- ]
- }
-
- return_content = StringIO(to_text(json.dumps(error_response)))
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 400, 'msg', {}, return_content)
-
- expected = 'Error when publishing collection to test_server (https://galaxy.ansible.com) ' \
- '(HTTP Code: 400, Message: Collection "mynamespace-mycollection-4.1.1"' \
- ' already exists. Code: conflict.collection_exists),' \
- ' (HTTP Code: 400, Message: Random(?) quantum improbability. Code: quantum_improbability)'
- with pytest.raises(AnsibleError, match=re.escape(expected)):
- collection.publish_collection(artifact_path, galaxy_server, True, 0)
+ assert mock_display.mock_calls[0][1][0] == "Collection has been published to the Galaxy server test_server %s" \
+ % galaxy_server.api_server
def test_find_existing_collections(tmp_path_factory, monkeypatch):
@@ -962,91 +563,3 @@ def test_extract_tar_file_missing_parent_dir(tmp_tarfile):
collection._extract_tar_file(tfile, filename, output_dir, temp_dir, checksum)
os.path.isfile(output_file)
-
-
-def test_get_available_api_versions_v2_auth_not_required_without_auth(galaxy_server, collection_artifact, monkeypatch):
- # mock_avail_ver = MagicMock()
- # mock_avail_ver.side_effect = {api_version: '/api/%s' % api_version}
- # monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
- response_obj = {
- "description": "GALAXY REST API",
- "current_version": "v1",
- "available_versions": {
- "v1": "/api/v1/",
- "v2": "/api/v2/"
- },
- "server_version": "3.2.4",
- "version_name": "Doin' it Right",
- "team_members": [
- "chouseknecht",
- "cutwater",
- "alikins",
- "newswangerd",
- "awcrosby",
- "tima",
- "gregdek"
- ]
- }
-
- artifact_path, mock_open = collection_artifact
-
- return_content = StringIO(to_text(json.dumps(response_obj)))
- mock_open.return_value = return_content
- res = collection.get_available_api_versions(galaxy_server)
-
- assert res == {'v1': '/api/v1/', 'v2': '/api/v2/'}
-
-
-def test_get_available_api_versions_v3_auth_required_without_auth(galaxy_server, collection_artifact, monkeypatch):
- # mock_avail_ver = MagicMock()
- # mock_avail_ver.side_effect = {api_version: '/api/%s' % api_version}
- # monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
- error_response = {'code': 'unauthorized', 'detail': 'The request was not authorized'}
- artifact_path, mock_open = collection_artifact
-
- return_content = StringIO(to_text(json.dumps(error_response)))
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 401, 'msg', {'WWW-Authenticate': 'Bearer'}, return_content)
- with pytest.raises(AnsibleError):
- collection.get_available_api_versions(galaxy_server)
-
-
-def test_get_available_api_versions_v3_auth_required_with_auth_on_retry(galaxy_server, collection_artifact, monkeypatch):
- # mock_avail_ver = MagicMock()
- # mock_avail_ver.side_effect = {api_version: '/api/%s' % api_version}
- # monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
- error_obj = {'code': 'unauthorized', 'detail': 'The request was not authorized'}
- success_obj = {
- "description": "GALAXY REST API",
- "current_version": "v1",
- "available_versions": {
- "v3": "/api/v3/"
- },
- "server_version": "3.2.4",
- "version_name": "Doin' it Right",
- "team_members": [
- "chouseknecht",
- "cutwater",
- "alikins",
- "newswangerd",
- "awcrosby",
- "tima",
- "gregdek"
- ]
- }
-
- artifact_path, mock_open = collection_artifact
-
- error_response = StringIO(to_text(json.dumps(error_obj)))
- success_response = StringIO(to_text(json.dumps(success_obj)))
- mock_open.side_effect = [
- urllib_error.HTTPError('https://galaxy.server.com', 401, 'msg', {'WWW-Authenticate': 'Bearer'}, error_response),
- success_response,
- ]
-
- try:
- res = collection.get_available_api_versions(galaxy_server)
- except AnsibleError as err:
- print(err)
- raise
-
- assert res == {'v3': '/api/v3/'}
diff --git a/test/units/galaxy/test_collection_install.py b/test/units/galaxy/test_collection_install.py
index 1f5b385807..658c54a69c 100644
--- a/test/units/galaxy/test_collection_install.py
+++ b/test/units/galaxy/test_collection_install.py
@@ -290,21 +290,10 @@ def test_build_requirement_from_tar_invalid_manifest(tmp_path_factory):
collection.CollectionRequirement.from_tar(tar_path, True, True)
-@pytest.mark.parametrize("api_version,exp_api_url", [
- ('v2', '/api/v2/collections/namespace/collection/versions/'),
- ('v3', '/api/v3/collections/namespace/collection/versions/')
-])
-def test_build_requirement_from_name(api_version, exp_api_url, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- avail_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = avail_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- json_str = artifact_versions_json('namespace', 'collection', ['2.1.9', '2.1.10'], galaxy_server, avail_api_versions)
- mock_open = MagicMock()
- mock_open.return_value = StringIO(json_str)
-
- monkeypatch.setattr(collection, 'open_url', mock_open)
+def test_build_requirement_from_name(galaxy_server, monkeypatch):
+ mock_get_versions = MagicMock()
+ mock_get_versions.return_value = ['2.1.9', '2.1.10']
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions)
actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '*', True, True)
@@ -317,27 +306,14 @@ def test_build_requirement_from_name(api_version, exp_api_url, galaxy_server, mo
assert actual.latest_version == u'2.1.10'
assert actual.dependencies is None
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][1][0] == '%s%s' % (galaxy_server.api_server, exp_api_url)
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
-
+ assert mock_get_versions.call_count == 1
+ assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
-@pytest.mark.parametrize("api_version,exp_api_url", [
- ('v2', '/api/v2/collections/namespace/collection/versions/'),
- ('v3', '/api/v3/collections/namespace/collection/versions/')
-])
-def test_build_requirement_from_name_with_prerelease(api_version, exp_api_url, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- avail_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = avail_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- json_str = artifact_versions_json('namespace', 'collection', ['1.0.1', '2.0.1-beta.1', '2.0.1'],
- galaxy_server, avail_api_versions)
- mock_open = MagicMock()
- mock_open.return_value = StringIO(json_str)
- monkeypatch.setattr(collection, 'open_url', mock_open)
+def test_build_requirement_from_name_with_prerelease(galaxy_server, monkeypatch):
+ mock_get_versions = MagicMock()
+ mock_get_versions.return_value = ['1.0.1', '2.0.1-beta.1', '2.0.1']
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions)
actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '*', True, True)
@@ -350,28 +326,15 @@ def test_build_requirement_from_name_with_prerelease(api_version, exp_api_url, g
assert actual.latest_version == u'2.0.1'
assert actual.dependencies is None
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][1][0] == '%s%s' % (galaxy_server.api_server, exp_api_url)
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
-
-
-@pytest.mark.parametrize("api_version,exp_api_url", [
- ('v2', '/api/v2/collections/namespace/collection/versions/2.0.1-beta.1/'),
- ('v3', '/api/v3/collections/namespace/collection/versions/2.0.1-beta.1/')
-])
-def test_build_requirment_from_name_with_prerelease_explicit(api_version, exp_api_url, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- avail_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = avail_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ assert mock_get_versions.call_count == 1
+ assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
- json_str = artifact_json('namespace', 'collection', '2.0.1-beta.1', {}, galaxy_server.api_server)
- mock_open = MagicMock()
- mock_open.side_effect = (
- StringIO(json_str),
- )
- monkeypatch.setattr(collection, 'open_url', mock_open)
+def test_build_requirment_from_name_with_prerelease_explicit(galaxy_server, monkeypatch):
+ mock_get_info = MagicMock()
+ mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1-beta.1', None, None,
+ {})
+ monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info)
actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '2.0.1-beta.1', True,
True)
@@ -385,32 +348,22 @@ def test_build_requirment_from_name_with_prerelease_explicit(api_version, exp_ap
assert actual.latest_version == u'2.0.1-beta.1'
assert actual.dependencies == {}
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][1][0] == '%s%s' % (galaxy_server.api_server, exp_api_url)
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
-
+ assert mock_get_info.call_count == 1
+ assert mock_get_info.mock_calls[0][1] == ('namespace', 'collection', '2.0.1-beta.1')
-@pytest.mark.parametrize("api_version,exp_api_url", [
- ('v2', '/api/v2/collections/namespace/collection/versions/'),
- ('v3', '/api/v3/collections/namespace/collection/versions/')
-])
-def test_build_requirement_from_name_second_server(api_version, exp_api_url, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- avail_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = avail_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- json_str = artifact_versions_json('namespace', 'collection', ['1.0.1', '1.0.2', '1.0.3'], galaxy_server, avail_api_versions)
- mock_open = MagicMock()
- mock_open.side_effect = (
- urllib_error.HTTPError('https://galaxy.server.com', 404, 'msg', {}, None),
- StringIO(json_str)
- )
- monkeypatch.setattr(collection, 'open_url', mock_open)
+def test_build_requirement_from_name_second_server(galaxy_server, monkeypatch):
+ mock_get_versions = MagicMock()
+ mock_get_versions.return_value = ['1.0.1', '1.0.2', '1.0.3']
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions)
broken_server = copy.copy(galaxy_server)
broken_server.api_server = 'https://broken.com/'
+ mock_404 = MagicMock()
+ mock_404.side_effect = api.GalaxyError(urllib_error.HTTPError('https://galaxy.server.com', 404, 'msg', {},
+ StringIO()), "custom msg")
+ monkeypatch.setattr(broken_server, 'get_collection_versions', mock_404)
+
actual = collection.CollectionRequirement.from_name('namespace.collection', [broken_server, galaxy_server],
'>1.0.1', False, True)
@@ -423,99 +376,46 @@ def test_build_requirement_from_name_second_server(api_version, exp_api_url, gal
assert actual.latest_version == u'1.0.3'
assert actual.dependencies is None
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[0][1][0] == u"https://broken.com%s" % exp_api_url
- assert mock_open.mock_calls[1][1][0] == u"%s%s" % (galaxy_server.api_server, exp_api_url)
- assert mock_open.mock_calls[1][2] == {'validate_certs': True, "headers": {}}
+ assert mock_404.call_count == 1
+ assert mock_404.mock_calls[0][1] == ('namespace', 'collection')
+
+ assert mock_get_versions.call_count == 1
+ assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
def test_build_requirement_from_name_missing(galaxy_server, monkeypatch):
mock_open = MagicMock()
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 404, 'msg', {}, None)
-
- monkeypatch.setattr(collection, 'open_url', mock_open)
+ mock_open.side_effect = api.GalaxyError(urllib_error.HTTPError('https://galaxy.server.com', 404, 'msg', {},
+ StringIO()), "")
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_open)
expected = "Failed to find collection namespace.collection:*"
with pytest.raises(AnsibleError, match=expected):
- collection.CollectionRequirement.from_name('namespace.collection',
- [galaxy_server, galaxy_server], '*', False, True)
-
-
-@pytest.mark.parametrize("api_version,errors_to_return,expected", [
- ('v2',
- [],
- 'Error fetching info for .*\\..* \\(HTTP Code: 400, Message: Unknown error returned by Galaxy server. Code: Unknown\\)'),
- ('v2',
- [{'message': 'Polarization error. Try flipping it over.', 'code': 'polarization_error'}],
- 'Error fetching info for .*\\..* \\(HTTP Code: 400, Message: Polarization error. Try flipping it over. Code: polarization_error\\)'),
- ('v3',
- [],
- 'Error fetching info for .*\\..* \\(HTTP Code: 400, Message: Unknown error returned by Galaxy server. Code: Unknown\\)'),
- ('v3',
- [{'code': 'invalid_param', 'detail': '"easy" is not a valid query param'}],
- 'Error fetching info for .*\\..* \\(HTTP Code: 400, Message: "easy" is not a valid query param Code: invalid_param\\)'),
-])
-def test_build_requirement_from_name_400_bad_request(api_version, errors_to_return, expected, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- available_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = available_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server, galaxy_server], '*', False,
+ True)
- json_str = error_json(galaxy_server, errors_to_return=errors_to_return, available_api_versions=available_api_versions)
+def test_build_requirement_from_name_401_unauthorized(galaxy_server, monkeypatch):
mock_open = MagicMock()
- monkeypatch.setattr(collection, 'open_url', mock_open)
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 400, 'msg', {}, StringIO(json_str))
+ mock_open.side_effect = api.GalaxyError(urllib_error.HTTPError('https://galaxy.server.com', 401, 'msg', {},
+ StringIO()), "error")
- with pytest.raises(AnsibleError, match=expected):
- collection.CollectionRequirement.from_name('namespace.collection',
- [galaxy_server, galaxy_server], '*', False)
-
-
-@pytest.mark.parametrize("api_version,errors_to_return,expected", [
- ('v2',
- [],
- 'Error fetching info for .*\\..* \\(HTTP Code: 401, Message: Unknown error returned by Galaxy server. Code: Unknown\\)'),
- ('v3',
- [],
- 'Error fetching info for .*\\..* \\(HTTP Code: 401, Message: Unknown error returned by Galaxy server. Code: Unknown\\)'),
- ('v3',
- [{'code': 'unauthorized', 'detail': 'The request was not authorized'}],
- 'Error fetching info for .*\\..* \\(HTTP Code: 401, Message: The request was not authorized Code: unauthorized\\)'),
-])
-def test_build_requirement_from_name_401_unauthorized(api_version, errors_to_return, expected, galaxy_server, monkeypatch):
- mock_avail_ver = MagicMock()
- available_api_versions = {api_version: '/api/%s' % api_version}
- mock_avail_ver.return_value = available_api_versions
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
-
- json_str = error_json(galaxy_server, errors_to_return=errors_to_return, available_api_versions=available_api_versions)
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_open)
- mock_open = MagicMock()
- monkeypatch.setattr(collection, 'open_url', mock_open)
- mock_open.side_effect = urllib_error.HTTPError('https://galaxy.server.com', 401, 'msg', {}, StringIO(json_str))
-
- with pytest.raises(AnsibleError, match=expected):
- collection.CollectionRequirement.from_name('namespace.collection',
- [galaxy_server, galaxy_server], '*', False)
+ expected = "error (HTTP Code: 401, Message: Unknown error returned by Galaxy server.)"
+ with pytest.raises(api.GalaxyError, match=re.escape(expected)):
+ collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server, galaxy_server], '*', False)
def test_build_requirement_from_name_single_version(galaxy_server, monkeypatch):
- json_str = artifact_json('namespace', 'collection', '2.0.0', {}, galaxy_server.api_server)
- mock_open = MagicMock()
- mock_open.return_value = StringIO(json_str)
-
- monkeypatch.setattr(collection, 'open_url', mock_open)
-
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ mock_get_info = MagicMock()
+ mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.0', None, None,
+ {})
+ monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info)
- actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '2.0.0', True, True)
+ actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '2.0.0', True,
+ True)
assert actual.namespace == u'namespace'
assert actual.name == u'collection'
@@ -526,24 +426,19 @@ def test_build_requirement_from_name_single_version(galaxy_server, monkeypatch):
assert actual.latest_version == u'2.0.0'
assert actual.dependencies == {}
- assert mock_open.call_count == 1
- assert mock_open.mock_calls[0][1][0] == u"%s/api/v2/collections/namespace/collection/versions/2.0.0/" \
- % galaxy_server.api_server
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
+ assert mock_get_info.call_count == 1
+ assert mock_get_info.mock_calls[0][1] == ('namespace', 'collection', '2.0.0')
def test_build_requirement_from_name_multiple_versions_one_match(galaxy_server, monkeypatch):
- json_str1 = artifact_versions_json('namespace', 'collection', ['2.0.0', '2.0.1', '2.0.2'],
- galaxy_server)
- json_str2 = artifact_json('namespace', 'collection', '2.0.1', {}, galaxy_server.api_server)
- mock_open = MagicMock()
- mock_open.side_effect = (StringIO(json_str1), StringIO(json_str2))
+ mock_get_versions = MagicMock()
+ mock_get_versions.return_value = ['2.0.0', '2.0.1', '2.0.2']
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions)
- monkeypatch.setattr(collection, 'open_url', mock_open)
-
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+ mock_get_info = MagicMock()
+ mock_get_info.return_value = api.CollectionVersionMetadata('namespace', 'collection', '2.0.1', None, None,
+ {})
+ monkeypatch.setattr(galaxy_server, 'get_collection_version_metadata', mock_get_info)
actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '>=2.0.1,<2.0.2',
True, True)
@@ -557,62 +452,17 @@ def test_build_requirement_from_name_multiple_versions_one_match(galaxy_server,
assert actual.latest_version == u'2.0.1'
assert actual.dependencies == {}
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[0][1][0] == u"%s/api/v2/collections/namespace/collection/versions/" \
- % galaxy_server.api_server
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
- assert mock_open.mock_calls[1][1][0] == u"%s/api/v2/collections/namespace/collection/versions/2.0.1/" \
- % galaxy_server.api_server
- assert mock_open.mock_calls[1][2] == {'validate_certs': True, "headers": {}}
+ assert mock_get_versions.call_count == 1
+ assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
+ assert mock_get_info.call_count == 1
+ assert mock_get_info.mock_calls[0][1] == ('namespace', 'collection', '2.0.1')
-def test_build_requirement_from_name_multiple_version_results(galaxy_server, monkeypatch):
- json_str1 = json.dumps({
- 'count': 6,
- 'next': '%s/api/v2/collections/namespace/collection/versions/?page=2' % galaxy_server.api_server,
- 'previous': None,
- 'results': [
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.0/' % galaxy_server.api_server,
- 'version': '2.0.0',
- },
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.1/' % galaxy_server.api_server,
- 'version': '2.0.1',
- },
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.2/' % galaxy_server.api_server,
- 'version': '2.0.2',
- },
- ]
- })
- json_str2 = json.dumps({
- 'count': 6,
- 'next': None,
- 'previous': '%s/api/v2/collections/namespace/collection/versions/?page=1' % galaxy_server.api_server,
- 'results': [
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.3/' % galaxy_server.api_server,
- 'version': '2.0.3',
- },
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.4/' % galaxy_server.api_server,
- 'version': '2.0.4',
- },
- {
- 'href': '%s/api/v2/collections/namespace/collection/versions/2.0.5/' % galaxy_server.api_server,
- 'version': '2.0.5',
- },
- ]
- })
- mock_open = MagicMock()
- mock_open.side_effect = (StringIO(to_text(json_str1)), StringIO(to_text(json_str2)))
- monkeypatch.setattr(collection, 'open_url', mock_open)
-
- mock_avail_ver = MagicMock()
- mock_avail_ver.return_value = {'v2': '/api/v2'}
- monkeypatch.setattr(collection, 'get_available_api_versions', mock_avail_ver)
+def test_build_requirement_from_name_multiple_version_results(galaxy_server, monkeypatch):
+ mock_get_versions = MagicMock()
+ mock_get_versions.return_value = ['2.0.0', '2.0.1', '2.0.2', '2.0.3', '2.0.4', '2.0.5']
+ monkeypatch.setattr(galaxy_server, 'get_collection_versions', mock_get_versions)
actual = collection.CollectionRequirement.from_name('namespace.collection', [galaxy_server], '!=2.0.2',
True, True)
@@ -626,13 +476,8 @@ def test_build_requirement_from_name_multiple_version_results(galaxy_server, mon
assert actual.latest_version == u'2.0.5'
assert actual.dependencies is None
- assert mock_open.call_count == 2
- assert mock_open.mock_calls[0][1][0] == u"%s/api/v2/collections/namespace/collection/versions/" \
- % galaxy_server.api_server
- assert mock_open.mock_calls[0][2] == {'validate_certs': True, "headers": {}}
- assert mock_open.mock_calls[1][1][0] == u"%s/api/v2/collections/namespace/collection/versions/?page=2" \
- % galaxy_server.api_server
- assert mock_open.mock_calls[1][2] == {'validate_certs': True, "headers": {}}
+ assert mock_get_versions.call_count == 1
+ assert mock_get_versions.mock_calls[0][1] == ('namespace', 'collection')
@pytest.mark.parametrize('versions, requirement, expected_filter, expected_latest', [
@@ -767,14 +612,10 @@ def test_install_collection_with_download(galaxy_server, collection_artifact, mo
temp_path = os.path.join(os.path.split(collection_tar)[0], b'temp')
os.makedirs(temp_path)
+ meta = api.CollectionVersionMetadata('ansible_namespace', 'collection', '0.1.0', 'https://downloadme.com',
+ 'myhash', {})
req = collection.CollectionRequirement('ansible_namespace', 'collection', None, galaxy_server,
- ['0.1.0'], '*', False)
- req._galaxy_info = {
- 'download_url': 'https://downloadme.com',
- 'artifact': {
- 'sha256': 'myhash',
- },
- }
+ ['0.1.0'], '*', False, metadata=meta)
req.install(to_text(output_path), temp_path)
# Ensure the temp directory is empty, nothing is left behind