FTD modules: upsert functionality and bug fixes (#47747)

* FTD modules: bug fixes and upsert functionality

* Fix sanity checks

* Fix unit tests for Python 2.6

* Log status code for login/logout

* Use string formatting in logging
This commit is contained in:
Anton Nikulin 2018-11-16 00:25:36 -06:00 committed by Deepak Agrawal
parent ce3a9cfae5
commit 9770ac70f9
15 changed files with 2232 additions and 547 deletions

View file

@ -17,20 +17,18 @@
#
import json
import os
from io import BytesIO
from ansible.module_utils.six.moves.urllib.error import HTTPError
from units.compat import mock
from units.compat import unittest
from units.compat.builtins import BUILTINS
from units.compat.mock import mock_open, patch
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.ftd.common import HTTPMethod, ResponseParams
from ansible.module_utils.network.ftd.fdm_swagger_client import SpecProp, FdmSwaggerParser
from ansible.module_utils.six import PY3, StringIO
from ansible.module_utils.six import BytesIO, StringIO
from ansible.plugins.httpapi.ftd import HttpApi
EXPECTED_BASE_HEADERS = {
@ -114,6 +112,15 @@ class TestFtdHttpApi(unittest.TestCase):
assert 'Server returned response without token info during connection authentication' in str(res.exception)
def test_login_raises_exception_when_http_error(self):
self.connection_mock.send.side_effect = HTTPError('http://testhost.com', 400, '', {},
StringIO('{"message": "Failed to authenticate user"}'))
with self.assertRaises(ConnectionError) as res:
self.ftd_plugin.login('foo', 'bar')
assert 'Failed to authenticate user' in str(res.exception)
def test_logout_should_revoke_tokens(self):
self.ftd_plugin.access_token = 'ACCESS_TOKEN_TO_REVOKE'
self.ftd_plugin.refresh_token = 'REFRESH_TOKEN_TO_REVOKE'
@ -182,6 +189,10 @@ class TestFtdHttpApi(unittest.TestCase):
def test_handle_httperror_should_not_retry_on_non_auth_errors(self):
assert not self.ftd_plugin.handle_httperror(HTTPError('http://testhost.com', 500, '', {}, None))
def test_handle_httperror_should_not_retry_when_ignoring_http_errors(self):
self.ftd_plugin._ignore_http_errors = True
assert not self.ftd_plugin.handle_httperror(HTTPError('http://testhost.com', 401, '', {}, None))
@patch('os.path.isdir', mock.Mock(return_value=False))
def test_download_file(self):
self.connection_mock.send.return_value = self._connection_response('File content')
@ -259,6 +270,44 @@ class TestFtdHttpApi(unittest.TestCase):
assert 'Specification for TestModel' == self.ftd_plugin.get_model_spec('TestModel')
assert self.ftd_plugin.get_model_spec('NonExistingTestModel') is None
@patch.object(FdmSwaggerParser, 'parse_spec')
def test_get_model_spec(self, parse_spec_mock):
self.connection_mock.send.return_value = self._connection_response(None)
operation1 = {'modelName': 'TestModel'}
op_model_name_is_none = {'modelName': None}
op_without_model_name = {'url': 'testUrl'}
parse_spec_mock.return_value = {
SpecProp.MODEL_OPERATIONS: {
'TestModel': {
'testOp1': operation1,
'testOp2': 'spec2'
},
'TestModel2': {
'testOp10': 'spec10',
'testOp20': 'spec20'
}
},
SpecProp.OPERATIONS: {
'testOp1': operation1,
'testOp10': {
'modelName': 'TestModel2'
},
'testOpWithoutModelName': op_without_model_name,
'testOpModelNameIsNone': op_model_name_is_none
}
}
assert {'testOp1': operation1, 'testOp2': 'spec2'} == self.ftd_plugin.get_operation_specs_by_model_name(
'TestModel')
assert None is self.ftd_plugin.get_operation_specs_by_model_name(
'testOpModelNameIsNone')
assert None is self.ftd_plugin.get_operation_specs_by_model_name(
'testOpWithoutModelName')
assert self.ftd_plugin.get_operation_specs_by_model_name('nonExistingOperation') is None
@staticmethod
def _connection_response(response, status=200):
response_mock = mock.Mock()