Optional tower cli (#3)

* Allow running tests without tower_cli

* patch up test mutability

* Fix test import error, warning mock

* flake8 error

Update documentation for non-converted modules
This commit is contained in:
Alan Rominger 2020-02-17 09:20:54 -05:00 committed by beeankha
parent d8513a4e86
commit 2e4e687d69
17 changed files with 67 additions and 45 deletions

View File

@ -36,9 +36,6 @@ options:
- Path to the Tower or AWX config file.
type: path
requirements:
- ansible-tower-cli >= 3.0.2
notes:
- If no I(config_file) is provided we will attempt to use the tower-cli library
defaults to find your Tower host information.

View File

@ -33,7 +33,7 @@ class ItemNotDefined(Exception):
class TowerModule(AnsibleModule):
url = None
honorred_settings = ['host', 'username', 'password', 'verify_ssl', 'oauth_token']
honorred_settings = ('host', 'username', 'password', 'verify_ssl', 'oauth_token')
host = '127.0.0.1'
username = None
password = None
@ -43,7 +43,6 @@ class TowerModule(AnsibleModule):
session = None
cookie_jar = CookieJar()
authenticated = False
json_output = {'changed': False}
config_name = 'tower_cli.cfg'
def __init__(self, argument_spec, **kwargs):
@ -58,6 +57,8 @@ class TowerModule(AnsibleModule):
args.update(argument_spec)
kwargs['supports_check_mode'] = True
self.json_output = {'changed': False}
# We have to take off mutually_exclusive_if in order to init with Ansible
mutually_exclusive_if = kwargs.pop('mutually_exclusive_if', None)
@ -136,7 +137,7 @@ class TowerModule(AnsibleModule):
raise ConfigFileException('The specified config file does not exist')
if not access(config_path, R_OK):
raise ConfigFileException("The specified config file can not be read")
raise ConfigFileException("The specified config file cannot be read")
# Read in the file contents:
with open(config_path, 'r') as f:

View File

@ -160,6 +160,10 @@ options:
choices: ["present", "absent"]
default: "present"
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -219,7 +219,12 @@ options:
default: "present"
choices: ["present", "absent"]
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
notes:
- JSON for survey_spec can be found in Tower API Documentation. See
U(https://docs.ansible.com/ansible-tower/latest/html/towerapi/api_ref.html#/Job_Templates/Job_Templates_job_templates_survey_spec_create)

View File

@ -42,6 +42,10 @@ options:
description:
- Maximum time in seconds to wait for a job to finish.
type: int
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -39,6 +39,10 @@ options:
default: "present"
choices: ["present", "absent"]
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -191,6 +191,10 @@ options:
default: "present"
choices: ["present", "absent"]
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -68,6 +68,10 @@ options:
default: "present"
choices: ["present", "absent"]
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -44,6 +44,8 @@ options:
requirements:
- "python >= 2.6"
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -81,6 +81,10 @@ options:
default: "present"
choices: ["present", "absent"]
type: str
requirements:
- ansible-tower-cli >= 3.0.2
extends_documentation_fragment: awx.awx.auth
'''

View File

@ -5,7 +5,7 @@ import io
import json
import datetime
import importlib
from contextlib import redirect_stdout
from contextlib import redirect_stdout, suppress
from unittest import mock
import logging
@ -16,6 +16,12 @@ import pytest
from awx.main.tests.functional.conftest import _request
from awx.main.models import Organization, Project, Inventory, Credential, CredentialType
try:
import tower_cli # noqa
HAS_TOWER_CLI = True
except ImportError:
HAS_TOWER_CLI = False
logger = logging.getLogger('awx.main.tests')
@ -104,7 +110,11 @@ def run_module(request):
with mock.patch.object(resource_module.TowerModule, '_load_params', new=mock_load_params):
# Call the test utility (like a mock server) instead of issuing HTTP requests
with mock.patch('ansible.module_utils.urls.Request.open', new=new_open):
with mock.patch('tower_cli.api.Session.request', new=new_request):
if HAS_TOWER_CLI:
tower_cli_mgr = mock.patch('tower_cli.api.Session.request', new=new_request)
else:
tower_cli_mgr = suppress()
with tower_cli_mgr:
# Ansible modules return data to the mothership over stdout
with redirect_stdout(stdout_buffer):
try:
@ -114,6 +124,9 @@ def run_module(request):
module_stdout = stdout_buffer.getvalue().strip()
result = json.loads(module_stdout)
# A module exception should never be a test expectation
if 'exception' in result:
raise Exception('Module encountered error:\n{0}'.format(result['exception']))
return result
return rf

View File

@ -25,11 +25,9 @@ def test_create_group(run_module, admin_user):
result.pop('invocation')
assert result == {
'credential_type': 'Nexus',
'id': group.id,
'name': 'Test Group',
'changed': True,
'state': 'present'
}
@ -54,8 +52,5 @@ def test_tower_group_idempotent(run_module, admin_user):
result.pop('invocation')
assert result == {
'id': group.id,
'credential_type': 'Nexus',
'name': 'Test Group',
'changed': False, # idempotency assertion
'state': 'present'
}

View File

@ -38,8 +38,6 @@ def test_inventory_source_create(run_module, admin_user, base_inventory):
assert result == {
'id': inv_src.id,
'name': 'foo',
'state': 'present',
'credential_type': 'Nexus'
}
@ -61,9 +59,7 @@ def test_create_inventory_source_implied_org(run_module, admin_user):
result.pop('invocation')
assert result == {
"credential_type": "Nexus",
"name": "Test Inventory Source",
"state": "present",
"id": inv_src.id,
}
@ -90,9 +86,7 @@ def test_create_inventory_source_multiple_orgs(run_module, admin_user):
result.pop('invocation')
assert result == {
"credential_type": "Nexus",
"name": "Test Inventory Source",
"state": "present",
"id": inv_src.id,
}

View File

@ -30,8 +30,6 @@ def test_create_organization(run_module, admin_user):
assert result == {
"name": "foo",
"changed": True,
"state": "present",
"credential_type": "Nexus",
"id": org.id,
"invocation": {
"module_args": module_args
@ -55,8 +53,6 @@ def test_create_organization_with_venv(run_module, admin_user, mocker):
org = Organization.objects.get(name='foo')
result.pop('invocation')
assert result == {
"credential_type": "Nexus",
"state": "present",
"name": "foo",
"id": org.id
}

View File

@ -3,20 +3,23 @@ __metaclass__ = type
import pytest
from unittest import mock
from awx.main.models import Project
@pytest.mark.django_db
def test_create_project(run_module, admin_user, organization):
result = run_module('tower_project', dict(
name='foo',
organization=organization.name,
scm_type='git',
scm_url='https://foo.invalid',
wait=False,
scm_update_cache_timeout=5
), admin_user)
warning = ['scm_update_cache_timeout will be ignored since scm_update_on_launch was not set to true']
with mock.patch('ansible.module_utils.basic.AnsibleModule.warn') as mock_warn:
result = run_module('tower_project', dict(
name='foo',
organization=organization.name,
scm_type='git',
scm_url='https://foo.invalid',
wait=False,
scm_update_cache_timeout=5
), admin_user)
mock_warn.assert_called_once_with('scm_update_cache_timeout will be ignored since scm_update_on_launch was not set to true')
assert result.pop('changed', None), result
proj = Project.objects.get(name='foo')
@ -25,9 +28,6 @@ def test_create_project(run_module, admin_user, organization):
result.pop('invocation')
assert result == {
'credential_type': 'Nexus',
'state': 'present',
'name': 'foo',
'id': proj.id,
'warnings': warning
'id': proj.id
}

View File

@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import pytest
from unittest import mock
import json
from awx.main.models import (
@ -65,7 +66,9 @@ def test_receive_send_jt(run_module, admin_user, mocker):
# recreate everything
with mocker.patch('sys.stdin.isatty', return_value=True):
with mocker.patch('tower_cli.models.base.MonitorableResource.wait'):
result = run_module('tower_send', dict(assets=json.dumps(assets)), admin_user)
# warns based on password_management param, but not security issue
with mock.patch('ansible.module_utils.basic.AnsibleModule.warn'):
result = run_module('tower_send', dict(assets=json.dumps(assets)), admin_user)
assert not result.get('failed'), result

View File

@ -23,8 +23,6 @@ def test_create_team(run_module, admin_user):
assert result == {
"changed": True,
"name": "foo_team",
"credential_type": "Nexus",
"state": "present",
"id": team.id if team else None,
}
team = Team.objects.get(name='foo_team')
@ -50,10 +48,7 @@ def test_modify_team(run_module, admin_user):
team.refresh_from_db()
result.pop('invocation')
assert result == {
"state": "present",
"changed": True,
"name": "foo_team",
"credential_type": "Nexus",
"id": team.id,
}
assert team.description == 'fooin around'
@ -66,9 +61,6 @@ def test_modify_team(run_module, admin_user):
}, admin_user)
result.pop('invocation')
assert result == {
"credential_type": "Nexus",
"name": "foo_team",
"id": team.id,
"state": "present",
"changed": False
}