Merge branch 'release_3.1.3' into devel

* release_3.1.3: (52 commits)
  ack fact scan messages
  making ldap user/group search fields into codemirror instances
  removing UI parsing for LDAP User and Group Search fields
  Allow exception view to accept all valid HTTP methods.
  Restore ability of parsing extra_vars string for provisioning callback.
  Fix up backup/restore role broken in f7a8e45809758322d9ee41c5305850dd70ed5faf
  Stop / start ansible-tower-service during restores
  value_to_python should encode lookup fields as ascii
  fix brace interpolation on standard out pane
  Adjust some hardcoded usages of 'awx' to use 'aw_user' and 'aw_group'.
  Pull Spanish updates from Zanata
  Temporarily grant awx user createdb role
  Stop giving ownership of backups to postgres
  don't display chunked lines'
  Add dropdown li truncation with ellipsis
  CTiT -> adhoc modules should allow the user to add new modules
  Remove task that was replacing the supervisor systemd tmp file
  Fix failing supervisorctl commands on RH-based distros
  Give ownership of the supervisor socket to awx
  Setting for external log emissions cert verification
  ...
This commit is contained in:
Matthew Jones
2017-04-28 13:57:04 -04:00
50 changed files with 3787 additions and 2938 deletions
@@ -91,6 +91,40 @@ def test_update_kwargs_survey_invalid_default(survey_spec_factory):
assert json.loads(defaulted_extra_vars['extra_vars'])['var2'] == 2
@pytest.mark.parametrize("question_type,default,expect_use,expect_value", [
("multiplechoice", "", False, 'N/A'), # historical bug
("multiplechoice", "zeb", False, 'N/A'), # zeb not in choices
("multiplechoice", "coffee", True, 'coffee'),
("multiselect", None, False, 'N/A'), # NOTE: Behavior is arguable, value of [] may be prefered
("multiselect", "", False, 'N/A'),
("multiselect", ["zeb"], False, 'N/A'),
("multiselect", ["milk"], True, ["milk"]),
("multiselect", ["orange\nmilk"], False, 'N/A'), # historical bug
])
def test_optional_survey_question_defaults(
survey_spec_factory, question_type, default, expect_use, expect_value):
spec = survey_spec_factory([
{
"required": False,
"default": default,
"choices": "orange\nmilk\nchocolate\ncoffee",
"variable": "c",
"type": question_type
},
])
jt = JobTemplate(name="test-jt", survey_spec=spec, survey_enabled=True)
defaulted_extra_vars = jt._update_unified_job_kwargs()
element = spec['spec'][0]
if expect_use:
assert jt._survey_element_validation(element, {element['variable']: element['default']}) == []
else:
assert jt._survey_element_validation(element, {element['variable']: element['default']})
if expect_use:
assert json.loads(defaulted_extra_vars['extra_vars'])['c'] == expect_value
else:
assert 'c' not in defaulted_extra_vars['extra_vars']
class TestWorkflowSurveys:
def test_update_kwargs_survey_defaults(self, survey_spec_factory):
"Assure that the survey default over-rides a JT variable"
+62 -1
View File
@@ -5,9 +5,11 @@ import ConfigParser
import json
import tempfile
import os
import fcntl
import pytest
import yaml
import mock
import yaml
from awx.main.models import (
Credential,
@@ -1067,3 +1069,62 @@ class TestInventoryUpdateCredentials(TestJobExecution):
self.task.run_pexpect = mock.Mock(side_effect=run_pexpect_side_effect)
self.task.run(self.pk)
def test_os_open_oserror():
with pytest.raises(OSError):
os.open('this_file_does_not_exist', os.O_RDONLY)
def test_fcntl_ioerror():
with pytest.raises(IOError):
fcntl.flock(99999, fcntl.LOCK_EX)
@mock.patch('os.open')
@mock.patch('logging.getLogger')
def test_aquire_lock_open_fail_logged(logging_getLogger, os_open):
err = OSError()
err.errno = 3
err.strerror = 'dummy message'
instance = mock.Mock()
instance.get_lock_file.return_value = 'this_file_does_not_exist'
os_open.side_effect = err
logger = mock.Mock()
logging_getLogger.return_value = logger
ProjectUpdate = tasks.RunProjectUpdate()
with pytest.raises(OSError, errno=3, strerror='dummy message'):
ProjectUpdate.acquire_lock(instance)
assert logger.err.called_with("I/O error({0}) while trying to open lock file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message'))
@mock.patch('os.open')
@mock.patch('os.close')
@mock.patch('logging.getLogger')
@mock.patch('fcntl.flock')
def test_aquire_lock_acquisition_fail_logged(fcntl_flock, logging_getLogger, os_close, os_open):
err = IOError()
err.errno = 3
err.strerror = 'dummy message'
instance = mock.Mock()
instance.get_lock_file.return_value = 'this_file_does_not_exist'
os_open.return_value = 3
logger = mock.Mock()
logging_getLogger.return_value = logger
fcntl_flock.side_effect = err
ProjectUpdate = tasks.RunProjectUpdate()
with pytest.raises(IOError, errno=3, strerror='dummy message'):
ProjectUpdate.acquire_lock(instance)
os_close.assert_called_with(3)
assert logger.err.called_with("I/O error({0}) while trying to aquire lock on file [{1}]: {2}".format(3, 'this_file_does_not_exist', 'dummy message'))
+37
View File
@@ -0,0 +1,37 @@
import pytest
import mock
# Django REST Framework
from rest_framework import exceptions
# AWX
from awx.main.views import ApiErrorView
HTTP_METHOD_NAMES = [
'get',
'post',
'put',
'patch',
'delete',
'head',
'options',
'trace',
]
@pytest.fixture
def api_view_obj_fixture():
return ApiErrorView()
@pytest.mark.parametrize('method_name', HTTP_METHOD_NAMES)
def test_exception_view_allow_http_methods(method_name):
assert hasattr(ApiErrorView, method_name)
@pytest.mark.parametrize('method_name', HTTP_METHOD_NAMES)
def test_exception_view_raises_exception(api_view_obj_fixture, method_name):
request_mock = mock.MagicMock()
with pytest.raises(exceptions.APIException):
getattr(api_view_obj_fixture, method_name)(request_mock)
@@ -2,6 +2,7 @@
# Copyright (c) 2017 Ansible, Inc.
# All Rights Reserved.
import pytest
from awx.conf.models import Setting
from awx.main.utils import common
@@ -52,3 +53,13 @@ def test_encrypt_field_with_ask():
def test_encrypt_field_with_empty_value():
encrypted = common.encrypt_field(Setting(value=None), 'value')
assert encrypted is None
@pytest.mark.parametrize('input_, output', [
({"foo": "bar"}, {"foo": "bar"}),
('{"foo": "bar"}', {"foo": "bar"}),
('---\nfoo: bar', {"foo": "bar"}),
(4399, {}),
])
def test_parse_yaml_or_json(input_, output):
assert common.parse_yaml_or_json(input_) == output
+16 -11
View File
@@ -3,10 +3,15 @@ from awx.main.utils import reload
def test_produce_supervisor_command(mocker):
with mocker.patch.object(reload.subprocess, 'Popen'):
reload._supervisor_service_restart(['beat', 'callback', 'fact'])
communicate_mock = mocker.MagicMock(return_value=('Everything is fine', ''))
mock_process = mocker.MagicMock()
mock_process.communicate = communicate_mock
Popen_mock = mocker.MagicMock(return_value=mock_process)
with mocker.patch.object(reload.subprocess, 'Popen', Popen_mock):
reload._supervisor_service_command(['beat', 'callback', 'fact'], "restart")
reload.subprocess.Popen.assert_called_once_with(
['supervisorctl', 'restart', 'tower-processes:receiver', 'tower-processes:factcacher'])
['supervisorctl', 'restart', 'tower-processes:receiver', 'tower-processes:factcacher'],
stderr=-1, stdin=-1, stdout=-1)
def test_routing_of_service_restarts_works(mocker):
@@ -14,13 +19,13 @@ def test_routing_of_service_restarts_works(mocker):
This tests that the parent restart method will call the appropriate
service restart methods, depending on which services are given in args
'''
with mocker.patch.object(reload, '_uwsgi_reload'),\
with mocker.patch.object(reload, '_uwsgi_fifo_command'),\
mocker.patch.object(reload, '_reset_celery_thread_pool'),\
mocker.patch.object(reload, '_supervisor_service_restart'):
mocker.patch.object(reload, '_supervisor_service_command'):
reload.restart_local_services(['uwsgi', 'celery', 'flower', 'daphne'])
reload._uwsgi_reload.assert_called_once_with()
reload._uwsgi_fifo_command.assert_called_once_with(uwsgi_command="c")
reload._reset_celery_thread_pool.assert_called_once_with()
reload._supervisor_service_restart.assert_called_once_with(['flower', 'daphne'])
reload._supervisor_service_command.assert_called_once_with(['flower', 'daphne'], command="restart")
@@ -28,11 +33,11 @@ def test_routing_of_service_restarts_diables(mocker):
'''
Test that methods are not called if not in the args
'''
with mocker.patch.object(reload, '_uwsgi_reload'),\
with mocker.patch.object(reload, '_uwsgi_fifo_command'),\
mocker.patch.object(reload, '_reset_celery_thread_pool'),\
mocker.patch.object(reload, '_supervisor_service_restart'):
mocker.patch.object(reload, '_supervisor_service_command'):
reload.restart_local_services(['flower'])
reload._uwsgi_reload.assert_not_called()
reload._uwsgi_fifo_command.assert_not_called()
reload._reset_celery_thread_pool.assert_not_called()
reload._supervisor_service_restart.assert_called_once_with(['flower'])
reload._supervisor_service_command.assert_called_once_with(['flower'], command="restart")