mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 12:50:22 -07:00
Refactor common network shared and platform utils code into package (#33452)
* Refactor common network shared and platform specific code into package (part-1) As per proposal #76 refactor common network shared and platform specific code into sub-package. https://github.com/ansible/proposals/issues/76 * ansible.module_utils.network.common - command shared functions * ansible.module_utils.network.{{ platform }} - where platform is platform specific shared functions * Fix review comments * Fix review comments
This commit is contained in:
parent
18aca48075
commit
11c9ad23d5
483 changed files with 871 additions and 887 deletions
0
test/units/module_utils/network/__init__.py
Normal file
0
test/units/module_utils/network/__init__.py
Normal file
0
test/units/module_utils/network/aci/__init__.py
Normal file
0
test/units/module_utils/network/aci/__init__.py
Normal file
289
test/units/module_utils/network/aci/test_aci.py
Normal file
289
test/units/module_utils/network/aci/test_aci.py
Normal file
|
@ -0,0 +1,289 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2017 Dag Wieers <dag@wieers.com>
|
||||
|
||||
# This file is part of Ansible by Red Hat
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
from ansible.compat.tests import unittest
|
||||
from ansible.module_utils.network.aci.aci import aci_response_json, aci_response_xml
|
||||
from ansible.module_utils.six import PY2, PY3
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
try:
|
||||
from lxml import etree
|
||||
if sys.version_info >= (2, 7):
|
||||
from xmljson import cobra
|
||||
except ImportError:
|
||||
raise SkipTest("ACI Ansible modules require the lxml and xmljson Python libraries")
|
||||
|
||||
|
||||
class AciRest(unittest.TestCase):
|
||||
|
||||
def test_invalid_aci_login(self):
|
||||
self.maxDiff = None
|
||||
|
||||
expected_result = {
|
||||
'error_code': '401',
|
||||
'error_text': 'Username or password is incorrect - FAILED local authentication',
|
||||
'imdata': [{
|
||||
'error': {
|
||||
'attributes': {
|
||||
'code': '401',
|
||||
'text': 'Username or password is incorrect - FAILED local authentication',
|
||||
},
|
||||
},
|
||||
}],
|
||||
'totalCount': '1',
|
||||
}
|
||||
|
||||
json_response = '{"totalCount":"1","imdata":[{"error":{"attributes":{"code":"401","text":"Username or password is incorrect - FAILED local authentication"}}}]}' # NOQA
|
||||
json_result = dict()
|
||||
aci_response_json(json_result, json_response)
|
||||
self.assertEqual(expected_result, json_result)
|
||||
|
||||
# Python 2.7+ is needed for xmljson
|
||||
if sys.version_info < (2, 7):
|
||||
return
|
||||
|
||||
xml_response = '''<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1">
|
||||
<error code="401" text="Username or password is incorrect - FAILED local authentication"/>
|
||||
</imdata>
|
||||
'''
|
||||
xml_result = dict()
|
||||
aci_response_xml(xml_result, xml_response)
|
||||
self.assertEqual(json_result, xml_result)
|
||||
|
||||
def test_valid_aci_login(self):
|
||||
self.maxDiff = None
|
||||
|
||||
expected_result = {
|
||||
'error_code': 0,
|
||||
'error_text': 'Success',
|
||||
'imdata': [{
|
||||
'aaaLogin': {
|
||||
'attributes': {
|
||||
'token': 'ZldYAsoO9d0FfAQM8xaEVWvQPSOYwpnqzhwpIC1r4MaToknJjlIuAt9+TvXqrZ8lWYIGPj6VnZkWiS8nJfaiaX/AyrdD35jsSxiP3zydh+849xym7ALCw/fFNsc7b5ik1HaMuSUtdrN8fmCEUy7Pq/QNpGEqkE8m7HaxAuHpmvXgtdW1bA+KKJu2zY1c/tem', # NOQA
|
||||
'siteFingerprint': 'NdxD72K/uXaUK0wn',
|
||||
'refreshTimeoutSeconds': '600',
|
||||
'maximumLifetimeSeconds': '86400',
|
||||
'guiIdleTimeoutSeconds': '1200',
|
||||
'restTimeoutSeconds': '90',
|
||||
'creationTime': '1500134817',
|
||||
'firstLoginTime': '1500134817',
|
||||
'userName': 'admin',
|
||||
'remoteUser': 'false',
|
||||
'unixUserId': '15374',
|
||||
'sessionId': 'o7hObsqNTfCmDGcZI5c4ng==',
|
||||
'lastName': '',
|
||||
'firstName': '',
|
||||
'version': '2.0(2f)',
|
||||
'buildTime': 'Sat Aug 20 23:07:07 PDT 2016',
|
||||
'node': 'topology/pod-1/node-1',
|
||||
},
|
||||
'children': [{
|
||||
'aaaUserDomain': {
|
||||
'attributes': {
|
||||
'name': 'all',
|
||||
'rolesR': 'admin',
|
||||
'rolesW': 'admin',
|
||||
},
|
||||
'children': [{
|
||||
'aaaReadRoles': {
|
||||
'attributes': {},
|
||||
},
|
||||
}, {
|
||||
'aaaWriteRoles': {
|
||||
'attributes': {},
|
||||
'children': [{
|
||||
'role': {
|
||||
'attributes': {
|
||||
'name': 'admin',
|
||||
},
|
||||
},
|
||||
}],
|
||||
},
|
||||
}],
|
||||
},
|
||||
}, {
|
||||
'DnDomainMapEntry': {
|
||||
'attributes': {
|
||||
'dn': 'uni/tn-common',
|
||||
'readPrivileges': 'admin',
|
||||
'writePrivileges': 'admin',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
'DnDomainMapEntry': {
|
||||
'attributes': {
|
||||
'dn': 'uni/tn-infra',
|
||||
'readPrivileges': 'admin',
|
||||
'writePrivileges': 'admin',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
'DnDomainMapEntry': {
|
||||
'attributes': {
|
||||
'dn': 'uni/tn-mgmt',
|
||||
'readPrivileges': 'admin',
|
||||
'writePrivileges': 'admin',
|
||||
},
|
||||
},
|
||||
}],
|
||||
},
|
||||
}],
|
||||
'totalCount': '1',
|
||||
}
|
||||
|
||||
json_response = '{"totalCount":"1","imdata":[{"aaaLogin":{"attributes":{"token":"ZldYAsoO9d0FfAQM8xaEVWvQPSOYwpnqzhwpIC1r4MaToknJjlIuAt9+TvXqrZ8lWYIGPj6VnZkWiS8nJfaiaX/AyrdD35jsSxiP3zydh+849xym7ALCw/fFNsc7b5ik1HaMuSUtdrN8fmCEUy7Pq/QNpGEqkE8m7HaxAuHpmvXgtdW1bA+KKJu2zY1c/tem","siteFingerprint":"NdxD72K/uXaUK0wn","refreshTimeoutSeconds":"600","maximumLifetimeSeconds":"86400","guiIdleTimeoutSeconds":"1200","restTimeoutSeconds":"90","creationTime":"1500134817","firstLoginTime":"1500134817","userName":"admin","remoteUser":"false","unixUserId":"15374","sessionId":"o7hObsqNTfCmDGcZI5c4ng==","lastName":"","firstName":"","version":"2.0(2f)","buildTime":"Sat Aug 20 23:07:07 PDT 2016","node":"topology/pod-1/node-1"},"children":[{"aaaUserDomain":{"attributes":{"name":"all","rolesR":"admin","rolesW":"admin"},"children":[{"aaaReadRoles":{"attributes":{}}},{"aaaWriteRoles":{"attributes":{},"children":[{"role":{"attributes":{"name":"admin"}}}]}}]}},{"DnDomainMapEntry":{"attributes":{"dn":"uni/tn-common","readPrivileges":"admin","writePrivileges":"admin"}}},{"DnDomainMapEntry":{"attributes":{"dn":"uni/tn-infra","readPrivileges":"admin","writePrivileges":"admin"}}},{"DnDomainMapEntry":{"attributes":{"dn":"uni/tn-mgmt","readPrivileges":"admin","writePrivileges":"admin"}}}]}}]}' # NOQA
|
||||
json_result = dict()
|
||||
aci_response_json(json_result, json_response)
|
||||
self.assertEqual(expected_result, json_result)
|
||||
|
||||
# Python 2.7+ is needed for xmljson
|
||||
if sys.version_info < (2, 7):
|
||||
return
|
||||
|
||||
xml_response = '<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1">\n<aaaLogin token="ZldYAsoO9d0FfAQM8xaEVWvQPSOYwpnqzhwpIC1r4MaToknJjlIuAt9+TvXqrZ8lWYIGPj6VnZkWiS8nJfaiaX/AyrdD35jsSxiP3zydh+849xym7ALCw/fFNsc7b5ik1HaMuSUtdrN8fmCEUy7Pq/QNpGEqkE8m7HaxAuHpmvXgtdW1bA+KKJu2zY1c/tem" siteFingerprint="NdxD72K/uXaUK0wn" refreshTimeoutSeconds="600" maximumLifetimeSeconds="86400" guiIdleTimeoutSeconds="1200" restTimeoutSeconds="90" creationTime="1500134817" firstLoginTime="1500134817" userName="admin" remoteUser="false" unixUserId="15374" sessionId="o7hObsqNTfCmDGcZI5c4ng==" lastName="" firstName="" version="2.0(2f)" buildTime="Sat Aug 20 23:07:07 PDT 2016" node="topology/pod-1/node-1">\n<aaaUserDomain name="all" rolesR="admin" rolesW="admin">\n<aaaReadRoles/>\n<aaaWriteRoles>\n<role name="admin"/>\n</aaaWriteRoles>\n</aaaUserDomain>\n<DnDomainMapEntry dn="uni/tn-common" readPrivileges="admin" writePrivileges="admin"/>\n<DnDomainMapEntry dn="uni/tn-infra" readPrivileges="admin" writePrivileges="admin"/>\n<DnDomainMapEntry dn="uni/tn-mgmt" readPrivileges="admin" writePrivileges="admin"/>\n</aaaLogin></imdata>\n''' # NOQA
|
||||
xml_result = dict()
|
||||
aci_response_xml(xml_result, xml_response)
|
||||
self.assertEqual(json_result, xml_result)
|
||||
|
||||
def test_invalid_input(self):
|
||||
self.maxDiff = None
|
||||
|
||||
expected_result = {
|
||||
'error_code': '401',
|
||||
'error_text': 'Username or password is incorrect - FAILED local authentication',
|
||||
'imdata': [{
|
||||
'error': {
|
||||
'attributes': {
|
||||
'code': '401',
|
||||
'text': 'Username or password is incorrect - FAILED local authentication',
|
||||
},
|
||||
},
|
||||
}],
|
||||
'totalCount': '1',
|
||||
}
|
||||
|
||||
json_response = '{"totalCount":"1","imdata":[{"error":{"attributes":{"code":"401","text":"Username or password is incorrect - FAILED local authentication"}}}]}' # NOQA
|
||||
json_result = dict()
|
||||
aci_response_json(json_result, json_response)
|
||||
self.assertEqual(expected_result, json_result)
|
||||
|
||||
# Python 2.7+ is needed for xmljson
|
||||
if sys.version_info < (2, 7):
|
||||
return
|
||||
|
||||
xml_response = '''<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1">
|
||||
<error code="401" text="Username or password is incorrect - FAILED local authentication"/>
|
||||
</imdata>
|
||||
'''
|
||||
xml_result = dict()
|
||||
aci_response_xml(xml_result, xml_response)
|
||||
self.assertEqual(json_result, xml_result)
|
||||
|
||||
def test_empty_response(self):
|
||||
self.maxDiffi = None
|
||||
|
||||
if PY2:
|
||||
error_text = "Unable to parse output as JSON, see 'raw' output. No JSON object could be decoded"
|
||||
else:
|
||||
error_text = "Unable to parse output as JSON, see 'raw' output. Expecting value: line 1 column 1 (char 0)"
|
||||
|
||||
expected_json_result = {
|
||||
'error_code': -1,
|
||||
'error_text': error_text,
|
||||
'raw': '',
|
||||
}
|
||||
|
||||
json_response = ''
|
||||
json_result = dict()
|
||||
aci_response_json(json_result, json_response)
|
||||
self.assertEqual(expected_json_result, json_result)
|
||||
|
||||
# Python 2.7+ is needed for xmljson
|
||||
if sys.version_info < (2, 7):
|
||||
return
|
||||
|
||||
elif etree.LXML_VERSION < (3, 3, 0, 0):
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. None",
|
||||
elif etree.LXML_VERSION < (4, 0, 0, 0):
|
||||
error_text = to_native(u"Unable to parse output as XML, see 'raw' output. None (line 0)", errors='surrogate_or_strict')
|
||||
elif PY2:
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. Document is empty, line 1, column 1 (line 1)"
|
||||
else:
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. Document is empty, line 1, column 1 (<string>, line 1)"
|
||||
|
||||
expected_xml_result = {
|
||||
'error_code': -1,
|
||||
'error_text': error_text,
|
||||
'raw': '',
|
||||
}
|
||||
|
||||
xml_response = ''
|
||||
xml_result = dict()
|
||||
aci_response_xml(xml_result, xml_response)
|
||||
self.assertEqual(expected_xml_result, xml_result)
|
||||
|
||||
def test_invalid_response(self):
|
||||
self.maxDiff = None
|
||||
|
||||
if sys.version_info < (2, 7):
|
||||
error_text = "Unable to parse output as JSON, see 'raw' output. Expecting object: line 1 column 8 (char 8)"
|
||||
elif PY2:
|
||||
error_text = "Unable to parse output as JSON, see 'raw' output. No JSON object could be decoded"
|
||||
else:
|
||||
error_text = "Unable to parse output as JSON, see 'raw' output. Expecting value: line 1 column 9 (char 8)"
|
||||
|
||||
expected_json_result = {
|
||||
'error_code': -1,
|
||||
'error_text': error_text,
|
||||
'raw': '{ "aaa":',
|
||||
}
|
||||
|
||||
json_response = '{ "aaa":'
|
||||
json_result = dict()
|
||||
aci_response_json(json_result, json_response)
|
||||
self.assertEqual(expected_json_result, json_result)
|
||||
|
||||
# Python 2.7+ is needed for xmljson
|
||||
if sys.version_info < (2, 7):
|
||||
return
|
||||
|
||||
elif etree.LXML_VERSION < (3, 3, 0, 0):
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. Couldn't find end of Start Tag aaa line 1, line 1, column 5" # NOQA
|
||||
|
||||
elif PY2:
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. Couldn't find end of Start Tag aaa line 1, line 1, column 6 (line 1)" # NOQA
|
||||
|
||||
else:
|
||||
error_text = "Unable to parse output as XML, see 'raw' output. Couldn't find end of Start Tag aaa line 1, line 1, column 6 (<string>, line 1)" # NOQA
|
||||
|
||||
expected_xml_result = {
|
||||
'error_code': -1,
|
||||
'error_text': error_text,
|
||||
'raw': '<aaa ',
|
||||
}
|
||||
|
||||
xml_response = '<aaa '
|
||||
xml_result = dict()
|
||||
aci_response_xml(xml_result, xml_response)
|
||||
self.assertEqual(expected_xml_result, xml_result)
|
0
test/units/module_utils/network/common/__init__.py
Normal file
0
test/units/module_utils/network/common/__init__.py
Normal file
151
test/units/module_utils/network/common/test_utils.py
Normal file
151
test/units/module_utils/network/common/test_utils.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# (c) 2017 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Make coding more python3-ish
|
||||
from __future__ import (absolute_import, division)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.compat.tests import unittest
|
||||
|
||||
from ansible.module_utils.network.common.utils import to_list, sort_list
|
||||
from ansible.module_utils.network.common.utils import dict_diff, dict_merge
|
||||
from ansible.module_utils.network.common.utils import conditional, Template
|
||||
|
||||
|
||||
class TestModuleUtilsNetworkCommon(unittest.TestCase):
|
||||
|
||||
def test_to_list(self):
|
||||
for scalar in ('string', 1, True, False, None):
|
||||
self.assertTrue(isinstance(to_list(scalar), list))
|
||||
|
||||
for container in ([1, 2, 3], {'one': 1}):
|
||||
self.assertTrue(isinstance(to_list(container), list))
|
||||
|
||||
test_list = [1, 2, 3]
|
||||
self.assertNotEqual(id(test_list), id(to_list(test_list)))
|
||||
|
||||
def test_sort(self):
|
||||
data = [3, 1, 2]
|
||||
self.assertEqual([1, 2, 3], sort_list(data))
|
||||
|
||||
string_data = '123'
|
||||
self.assertEqual(string_data, sort_list(string_data))
|
||||
|
||||
def test_dict_diff(self):
|
||||
base = dict(obj2=dict(), b1=True, b2=False, b3=False,
|
||||
one=1, two=2, three=3, obj1=dict(key1=1, key2=2),
|
||||
l1=[1, 3], l2=[1, 2, 3], l4=[4],
|
||||
nested=dict(n1=dict(n2=2)))
|
||||
|
||||
other = dict(b1=True, b2=False, b3=True, b4=True,
|
||||
one=1, three=4, four=4, obj1=dict(key1=2),
|
||||
l1=[2, 1], l2=[3, 2, 1], l3=[1],
|
||||
nested=dict(n1=dict(n2=2, n3=3)))
|
||||
|
||||
result = dict_diff(base, other)
|
||||
|
||||
# string assertions
|
||||
self.assertNotIn('one', result)
|
||||
self.assertNotIn('two', result)
|
||||
self.assertEqual(result['three'], 4)
|
||||
self.assertEqual(result['four'], 4)
|
||||
|
||||
# dict assertions
|
||||
self.assertIn('obj1', result)
|
||||
self.assertIn('key1', result['obj1'])
|
||||
self.assertNotIn('key2', result['obj1'])
|
||||
|
||||
# list assertions
|
||||
self.assertEqual(result['l1'], [2, 1])
|
||||
self.assertNotIn('l2', result)
|
||||
self.assertEqual(result['l3'], [1])
|
||||
self.assertNotIn('l4', result)
|
||||
|
||||
# nested assertions
|
||||
self.assertIn('obj1', result)
|
||||
self.assertEqual(result['obj1']['key1'], 2)
|
||||
self.assertNotIn('key2', result['obj1'])
|
||||
|
||||
# bool assertions
|
||||
self.assertNotIn('b1', result)
|
||||
self.assertNotIn('b2', result)
|
||||
self.assertTrue(result['b3'])
|
||||
self.assertTrue(result['b4'])
|
||||
|
||||
def test_dict_merge(self):
|
||||
base = dict(obj2=dict(), b1=True, b2=False, b3=False,
|
||||
one=1, two=2, three=3, obj1=dict(key1=1, key2=2),
|
||||
l1=[1, 3], l2=[1, 2, 3], l4=[4],
|
||||
nested=dict(n1=dict(n2=2)))
|
||||
|
||||
other = dict(b1=True, b2=False, b3=True, b4=True,
|
||||
one=1, three=4, four=4, obj1=dict(key1=2),
|
||||
l1=[2, 1], l2=[3, 2, 1], l3=[1],
|
||||
nested=dict(n1=dict(n2=2, n3=3)))
|
||||
|
||||
result = dict_merge(base, other)
|
||||
|
||||
# string assertions
|
||||
self.assertIn('one', result)
|
||||
self.assertIn('two', result)
|
||||
self.assertEqual(result['three'], 4)
|
||||
self.assertEqual(result['four'], 4)
|
||||
|
||||
# dict assertions
|
||||
self.assertIn('obj1', result)
|
||||
self.assertIn('key1', result['obj1'])
|
||||
self.assertIn('key2', result['obj1'])
|
||||
|
||||
# list assertions
|
||||
self.assertEqual(result['l1'], [1, 2, 3])
|
||||
self.assertIn('l2', result)
|
||||
self.assertEqual(result['l3'], [1])
|
||||
self.assertIn('l4', result)
|
||||
|
||||
# nested assertions
|
||||
self.assertIn('obj1', result)
|
||||
self.assertEqual(result['obj1']['key1'], 2)
|
||||
self.assertIn('key2', result['obj1'])
|
||||
|
||||
# bool assertions
|
||||
self.assertIn('b1', result)
|
||||
self.assertIn('b2', result)
|
||||
self.assertTrue(result['b3'])
|
||||
self.assertTrue(result['b4'])
|
||||
|
||||
def test_conditional(self):
|
||||
self.assertTrue(conditional(10, 10))
|
||||
self.assertTrue(conditional('10', '10'))
|
||||
self.assertTrue(conditional('foo', 'foo'))
|
||||
self.assertTrue(conditional(True, True))
|
||||
self.assertTrue(conditional(False, False))
|
||||
self.assertTrue(conditional(None, None))
|
||||
self.assertTrue(conditional("ge(1)", 1))
|
||||
self.assertTrue(conditional("gt(1)", 2))
|
||||
self.assertTrue(conditional("le(2)", 2))
|
||||
self.assertTrue(conditional("lt(3)", 2))
|
||||
self.assertTrue(conditional("eq(1)", 1))
|
||||
self.assertTrue(conditional("neq(0)", 1))
|
||||
self.assertTrue(conditional("min(1)", 1))
|
||||
self.assertTrue(conditional("max(1)", 1))
|
||||
self.assertTrue(conditional("exactly(1)", 1))
|
||||
|
||||
def test_template(self):
|
||||
tmpl = Template()
|
||||
self.assertEqual('foo', tmpl('{{ test }}', {'test': 'foo'}))
|
0
test/units/module_utils/network/nso/__init__.py
Normal file
0
test/units/module_utils/network/nso/__init__.py
Normal file
245
test/units/module_utils/network/nso/test_nso.py
Normal file
245
test/units/module_utils/network/nso/test_nso.py
Normal file
|
@ -0,0 +1,245 @@
|
|||
# Copyright (c) 2017 Cisco and/or its affiliates.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
|
||||
import json
|
||||
|
||||
from ansible.compat.tests.mock import patch
|
||||
from ansible.compat.tests import unittest
|
||||
from ansible.module_utils.network.nso import nso
|
||||
|
||||
|
||||
MODULE_PREFIX_MAP = '''
|
||||
{
|
||||
"ansible-nso": "an",
|
||||
"tailf-ncs": "ncs"
|
||||
}
|
||||
'''
|
||||
|
||||
|
||||
SCHEMA_DATA = {
|
||||
'/an:id-name-leaf': '''
|
||||
{
|
||||
"meta": {
|
||||
"prefix": "an",
|
||||
"namespace": "http://github.com/ansible/nso",
|
||||
"types": {
|
||||
"http://github.com/ansible/nso:id-name-t": [
|
||||
{
|
||||
"name": "http://github.com/ansible/nso:id-name-t",
|
||||
"enumeration": [
|
||||
{
|
||||
"label": "id-one"
|
||||
},
|
||||
{
|
||||
"label": "id-two"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "identityref"
|
||||
}
|
||||
]
|
||||
},
|
||||
"keypath": "/an:id-name-leaf"
|
||||
},
|
||||
"data": {
|
||||
"kind": "leaf",
|
||||
"type": {
|
||||
"namespace": "http://github.com/ansible/nso",
|
||||
"name": "id-name-t"
|
||||
},
|
||||
"name": "id-name-leaf",
|
||||
"qname": "an:id-name-leaf"
|
||||
}
|
||||
}''',
|
||||
'/an:id-name-values': '''
|
||||
{
|
||||
"meta": {
|
||||
"prefix": "an",
|
||||
"namespace": "http://github.com/ansible/nso",
|
||||
"types": {},
|
||||
"keypath": "/an:id-name-values"
|
||||
},
|
||||
"data": {
|
||||
"kind": "container",
|
||||
"name": "id-name-values",
|
||||
"qname": "an:id-name-values",
|
||||
"children": [
|
||||
{
|
||||
"kind": "list",
|
||||
"name": "id-name-value",
|
||||
"qname": "an:id-name-value",
|
||||
"key": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
''',
|
||||
'/an:id-name-values/id-name-value': '''
|
||||
{
|
||||
"meta": {
|
||||
"prefix": "an",
|
||||
"namespace": "http://github.com/ansible/nso",
|
||||
"types": {
|
||||
"http://github.com/ansible/nso:id-name-t": [
|
||||
{
|
||||
"name": "http://github.com/ansible/nso:id-name-t",
|
||||
"enumeration": [
|
||||
{
|
||||
"label": "id-one"
|
||||
},
|
||||
{
|
||||
"label": "id-two"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "identityref"
|
||||
}
|
||||
]
|
||||
},
|
||||
"keypath": "/an:id-name-values/id-name-value"
|
||||
},
|
||||
"data": {
|
||||
"kind": "list",
|
||||
"name": "id-name-value",
|
||||
"qname": "an:id-name-value",
|
||||
"key": [
|
||||
"name"
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"kind": "key",
|
||||
"name": "name",
|
||||
"qname": "an:name",
|
||||
"type": {
|
||||
"namespace": "http://github.com/ansible/nso",
|
||||
"name": "id-name-t"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "leaf",
|
||||
"type": {
|
||||
"primitive": true,
|
||||
"name": "string"
|
||||
},
|
||||
"name": "value",
|
||||
"qname": "an:value"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
'''
|
||||
}
|
||||
|
||||
|
||||
class MockResponse(object):
|
||||
def __init__(self, method, params, code, body, headers=None):
|
||||
if headers is None:
|
||||
headers = {}
|
||||
|
||||
self.method = method
|
||||
self.params = params
|
||||
|
||||
self.code = code
|
||||
self.body = body
|
||||
self.headers = dict(headers)
|
||||
|
||||
def read(self):
|
||||
return self.body
|
||||
|
||||
|
||||
def mock_call(calls, url, data=None, headers=None, method=None):
|
||||
result = calls[0]
|
||||
del calls[0]
|
||||
|
||||
request = json.loads(data)
|
||||
if result.method != request['method']:
|
||||
raise ValueError('expected method {0}({1}), got {2}({3})'.format(
|
||||
result.method, result.params,
|
||||
request['method'], request['params']))
|
||||
|
||||
for key, value in result.params.items():
|
||||
if key not in request['params']:
|
||||
raise ValueError('{0} not in parameters'.format(key))
|
||||
if value != request['params'][key]:
|
||||
raise ValueError('expected {0} to be {1}, got {2}'.format(
|
||||
key, value, request['params'][key]))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_schema_response(path):
|
||||
return MockResponse(
|
||||
'get_schema', {'path': path}, 200, '{{"result": {0}}}'.format(
|
||||
SCHEMA_DATA[path]))
|
||||
|
||||
|
||||
class TestValueBuilder(unittest.TestCase):
|
||||
@patch('ansible.module_utils.network.nso.nso.open_url')
|
||||
def test_identityref_leaf(self, open_url_mock):
|
||||
calls = [
|
||||
MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
|
||||
get_schema_response('/an:id-name-leaf'),
|
||||
MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP))
|
||||
]
|
||||
open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
|
||||
|
||||
parent = "/an:id-name-leaf"
|
||||
schema_data = json.loads(
|
||||
SCHEMA_DATA['/an:id-name-leaf'])
|
||||
schema = schema_data['data']
|
||||
|
||||
vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc'))
|
||||
vb.build(parent, None, 'ansible-nso:id-two', schema)
|
||||
self.assertEquals(1, len(vb.values))
|
||||
value = vb.values[0]
|
||||
self.assertEquals(parent, value.path)
|
||||
self.assertEquals('set', value.state)
|
||||
self.assertEquals('an:id-two', value.value)
|
||||
|
||||
self.assertEqual(0, len(calls))
|
||||
|
||||
@patch('ansible.module_utils.network.nso.nso.open_url')
|
||||
def test_identityref_key(self, open_url_mock):
|
||||
calls = [
|
||||
MockResponse('new_trans', {}, 200, '{"result": {"th": 1}}'),
|
||||
get_schema_response('/an:id-name-values/id-name-value'),
|
||||
MockResponse('get_module_prefix_map', {}, 200, '{{"result": {0}}}'.format(MODULE_PREFIX_MAP)),
|
||||
MockResponse('exists', {'path': '/an:id-name-values/id-name-value{an:id-one}'}, 200, '{"result": {"exists": true}}'),
|
||||
]
|
||||
open_url_mock.side_effect = lambda *args, **kwargs: mock_call(calls, *args, **kwargs)
|
||||
|
||||
parent = "/an:id-name-values"
|
||||
schema_data = json.loads(
|
||||
SCHEMA_DATA['/an:id-name-values/id-name-value'])
|
||||
schema = schema_data['data']
|
||||
|
||||
vb = nso.ValueBuilder(nso.JsonRpc('http://localhost:8080/jsonrpc'))
|
||||
vb.build(parent, 'id-name-value', [{'name': 'ansible-nso:id-one', 'value': '1'}], schema)
|
||||
self.assertEquals(1, len(vb.values))
|
||||
value = vb.values[0]
|
||||
self.assertEquals('{0}/id-name-value{{an:id-one}}/value'.format(parent), value.path)
|
||||
self.assertEquals('set', value.state)
|
||||
self.assertEquals('1', value.value)
|
||||
|
||||
self.assertEqual(0, len(calls))
|
Loading…
Add table
Add a link
Reference in a new issue