mirror of
https://opendev.org/openstack/ansible-collections-openstack.git
synced 2026-05-07 22:03:09 +00:00
Migrate openstack modules as a collection
Migrate accordin to Ansible guidelines [1[]] and tool migrate.py [2] Also fixed ALL ansible-test sanity issues Add pep8 and linter job with runs ansible-test sanity test. [1] https://etherpad.openstack.org/p/openstack-ansible-modules [2] https://github.com/ansible-community/collection_migration Change-Id: Ib2b1c8f23aacfca95304132bfe5c4cdedbea0520
This commit is contained in:
1
tests/.gitignore
vendored
Normal file
1
tests/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
output/
|
||||
135
tests/sanity/ignore-2.10.txt
Normal file
135
tests/sanity/ignore-2.10.txt
Normal file
@@ -0,0 +1,135 @@
|
||||
plugins/module_utils/openstack.py future-import-boilerplate
|
||||
plugins/module_utils/openstack.py metaclass-boilerplate
|
||||
plugins/modules/os_auth.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_client_config.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_coe_cluster.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_coe_cluster.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_coe_cluster_template.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_coe_cluster_template.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_coe_cluster_template.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_flavor_info.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_flavor_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_flavor_info.py validate-modules:implied-parameter-type-mismatch
|
||||
plugins/modules/os_flavor_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_floating_ip.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_group_info.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_image.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_image.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_image.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_image.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_image_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_ironic.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_ironic.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/os_ironic.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_ironic.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_ironic_inspect.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic_node.py validate-modules:implied-parameter-type-mismatch
|
||||
plugins/modules/os_ironic_node.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_ironic_node.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_keypair.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_keystone_role.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_service.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_listener.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_listener.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_loadbalancer.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_loadbalancer.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_member.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_member.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_network.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_network.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_networks_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_networks_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_nova_flavor.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_nova_flavor.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_nova_flavor.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_nova_host_aggregate.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_nova_host_aggregate.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_object.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_pool.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_port.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_port_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_project.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_access.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_access.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_project_access.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_project_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_info.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_project_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_quota.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_quota.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_quota.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/os_quota.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_quota.py validate-modules:return-syntax-error
|
||||
plugins/modules/os_quota.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_recordset.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_recordset.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_recordset.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_router.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_router.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_security_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_security_group_rule.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_security_group_rule.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_server.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_server.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_server_action.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_server_action.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_action.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_server_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_group.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_metadata.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_metadata.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_volume.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_stack.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_stack.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_stack.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_subnet.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_subnet.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_subnet.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_subnets_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_subnets_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user_info.py validate-modules:doc-required-mismatch
|
||||
plugins/modules/os_user_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user_role.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_volume.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_volume.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_volume.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_volume_snapshot.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_zone.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_zone.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_zone.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/doc_fragments/openstack.py future-import-boilerplate
|
||||
plugins/doc_fragments/openstack.py metaclass-boilerplate
|
||||
tests/unit/mock/path.py future-import-boilerplate
|
||||
tests/unit/mock/path.py metaclass-boilerplate
|
||||
tests/unit/mock/yaml_helper.py future-import-boilerplate
|
||||
tests/unit/mock/yaml_helper.py metaclass-boilerplate
|
||||
tests/unit/modules/cloud/openstack/test_os_server.py future-import-boilerplate
|
||||
tests/unit/modules/cloud/openstack/test_os_server.py metaclass-boilerplate
|
||||
tests/unit/modules/conftest.py future-import-boilerplate
|
||||
tests/unit/modules/conftest.py metaclass-boilerplate
|
||||
tests/unit/modules/utils.py future-import-boilerplate
|
||||
tests/unit/modules/utils.py metaclass-boilerplate
|
||||
124
tests/sanity/ignore-2.9.txt
Normal file
124
tests/sanity/ignore-2.9.txt
Normal file
@@ -0,0 +1,124 @@
|
||||
plugins/module_utils/openstack.py future-import-boilerplate
|
||||
plugins/module_utils/openstack.py metaclass-boilerplate
|
||||
plugins/modules/os_auth.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_client_config.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_coe_cluster.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_coe_cluster.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_coe_cluster_template.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_coe_cluster_template.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_flavor_info.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_flavor_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_flavor_info.py validate-modules:implied-parameter-type-mismatch
|
||||
plugins/modules/os_flavor_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_floating_ip.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_image.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_image.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_image.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_image.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_image_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_ironic.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/os_ironic.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_ironic.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_ironic_inspect.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_ironic_node.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_ironic_node.py validate-modules:implied-parameter-type-mismatch
|
||||
plugins/modules/os_ironic_node.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_ironic_node.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_keypair.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_domain_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_keystone_endpoint.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_keystone_role.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_keystone_service.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_listener.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_listener.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_loadbalancer.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_loadbalancer.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_member.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_member.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_network.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_network.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_networks_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_networks_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_nova_flavor.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_nova_flavor.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_nova_host_aggregate.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_nova_host_aggregate.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_object.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_pool.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_port_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_port_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_project.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_access.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_access.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_project_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_project_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_quota.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_quota.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_quota.py validate-modules:nonexistent-parameter-documented
|
||||
plugins/modules/os_quota.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_quota.py validate-modules:return-syntax-error
|
||||
plugins/modules/os_quota.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_recordset.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_recordset.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_router.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_router.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_security_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_security_group_rule.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_security_group_rule.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_server.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_server_action.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_server_action.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_group.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_metadata.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_server_metadata.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_server_volume.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_stack.py validate-modules:doc-default-does-not-match-spec
|
||||
plugins/modules/os_stack.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_stack.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_subnet.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_subnet.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_subnet.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_subnets_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_subnets_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user_group.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user_info.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_user_info.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_user_role.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_volume.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_volume.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/modules/os_volume.py validate-modules:undocumented-parameter
|
||||
plugins/modules/os_volume_snapshot.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_zone.py validate-modules:doc-choices-do-not-match-spec
|
||||
plugins/modules/os_zone.py validate-modules:doc-missing-type
|
||||
plugins/modules/os_zone.py validate-modules:parameter-type-not-in-doc
|
||||
plugins/doc_fragments/openstack.py future-import-boilerplate
|
||||
plugins/doc_fragments/openstack.py metaclass-boilerplate
|
||||
tests/unit/mock/path.py future-import-boilerplate
|
||||
tests/unit/mock/path.py metaclass-boilerplate
|
||||
tests/unit/mock/yaml_helper.py future-import-boilerplate
|
||||
tests/unit/mock/yaml_helper.py metaclass-boilerplate
|
||||
tests/unit/modules/cloud/openstack/test_os_server.py future-import-boilerplate
|
||||
tests/unit/modules/cloud/openstack/test_os_server.py metaclass-boilerplate
|
||||
tests/unit/modules/conftest.py future-import-boilerplate
|
||||
tests/unit/modules/conftest.py metaclass-boilerplate
|
||||
tests/unit/modules/utils.py future-import-boilerplate
|
||||
tests/unit/modules/utils.py metaclass-boilerplate
|
||||
4
tests/sanity/requirements.txt
Normal file
4
tests/sanity/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
packaging # needed for update-bundled and changelog
|
||||
sphinx ; python_version >= '3.5' # docs build requires python 3+
|
||||
sphinx-notfound-page ; python_version >= '3.5' # docs build requires python 3+
|
||||
straight.plugin ; python_version >= '3.5' # needed for hacking/build-ansible.py which will host changelog generation and requires python 3+
|
||||
0
tests/unit/__init__.py
Normal file
0
tests/unit/__init__.py
Normal file
0
tests/unit/compat/__init__.py
Normal file
0
tests/unit/compat/__init__.py
Normal file
33
tests/unit/compat/builtins.py
Normal file
33
tests/unit/compat/builtins.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
#
|
||||
# Compat for python2.7
|
||||
#
|
||||
|
||||
# One unittest needs to import builtins via __import__() so we need to have
|
||||
# the string that represents it
|
||||
try:
|
||||
import __builtin__
|
||||
except ImportError:
|
||||
BUILTINS = 'builtins'
|
||||
else:
|
||||
BUILTINS = '__builtin__'
|
||||
122
tests/unit/compat/mock.py
Normal file
122
tests/unit/compat/mock.py
Normal file
@@ -0,0 +1,122 @@
|
||||
# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
'''
|
||||
Compat module for Python3.x's unittest.mock module
|
||||
'''
|
||||
import sys
|
||||
|
||||
# Python 2.7
|
||||
|
||||
# Note: Could use the pypi mock library on python3.x as well as python2.x. It
|
||||
# is the same as the python3 stdlib mock library
|
||||
|
||||
try:
|
||||
# Allow wildcard import because we really do want to import all of mock's
|
||||
# symbols into this compat shim
|
||||
# pylint: disable=wildcard-import,unused-wildcard-import
|
||||
from unittest.mock import *
|
||||
except ImportError:
|
||||
# Python 2
|
||||
# pylint: disable=wildcard-import,unused-wildcard-import
|
||||
try:
|
||||
from mock import *
|
||||
except ImportError:
|
||||
print('You need the mock library installed on python2.x to run tests')
|
||||
|
||||
|
||||
# Prior to 3.4.4, mock_open cannot handle binary read_data
|
||||
if sys.version_info >= (3,) and sys.version_info < (3, 4, 4):
|
||||
file_spec = None
|
||||
|
||||
def _iterate_read_data(read_data):
|
||||
# Helper for mock_open:
|
||||
# Retrieve lines from read_data via a generator so that separate calls to
|
||||
# readline, read, and readlines are properly interleaved
|
||||
sep = b'\n' if isinstance(read_data, bytes) else '\n'
|
||||
data_as_list = [l + sep for l in read_data.split(sep)]
|
||||
|
||||
if data_as_list[-1] == sep:
|
||||
# If the last line ended in a newline, the list comprehension will have an
|
||||
# extra entry that's just a newline. Remove this.
|
||||
data_as_list = data_as_list[:-1]
|
||||
else:
|
||||
# If there wasn't an extra newline by itself, then the file being
|
||||
# emulated doesn't have a newline to end the last line remove the
|
||||
# newline that our naive format() added
|
||||
data_as_list[-1] = data_as_list[-1][:-1]
|
||||
|
||||
for line in data_as_list:
|
||||
yield line
|
||||
|
||||
def mock_open(mock=None, read_data=''):
|
||||
"""
|
||||
A helper function to create a mock to replace the use of `open`. It works
|
||||
for `open` called directly or used as a context manager.
|
||||
|
||||
The `mock` argument is the mock object to configure. If `None` (the
|
||||
default) then a `MagicMock` will be created for you, with the API limited
|
||||
to methods or attributes available on standard file handles.
|
||||
|
||||
`read_data` is a string for the `read` methoddline`, and `readlines` of the
|
||||
file handle to return. This is an empty string by default.
|
||||
"""
|
||||
def _readlines_side_effect(*args, **kwargs):
|
||||
if handle.readlines.return_value is not None:
|
||||
return handle.readlines.return_value
|
||||
return list(_data)
|
||||
|
||||
def _read_side_effect(*args, **kwargs):
|
||||
if handle.read.return_value is not None:
|
||||
return handle.read.return_value
|
||||
return type(read_data)().join(_data)
|
||||
|
||||
def _readline_side_effect():
|
||||
if handle.readline.return_value is not None:
|
||||
while True:
|
||||
yield handle.readline.return_value
|
||||
for line in _data:
|
||||
yield line
|
||||
|
||||
global file_spec
|
||||
if file_spec is None:
|
||||
import _io # pylint: disable=import-outside-toplevel
|
||||
file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
|
||||
|
||||
if mock is None:
|
||||
mock = MagicMock(name='open', spec=open)
|
||||
|
||||
handle = MagicMock(spec=file_spec)
|
||||
handle.__enter__.return_value = handle
|
||||
|
||||
_data = _iterate_read_data(read_data)
|
||||
|
||||
handle.write.return_value = None
|
||||
handle.read.return_value = None
|
||||
handle.readline.return_value = None
|
||||
handle.readlines.return_value = None
|
||||
|
||||
handle.read.side_effect = _read_side_effect
|
||||
handle.readline.side_effect = _readline_side_effect()
|
||||
handle.readlines.side_effect = _readlines_side_effect
|
||||
|
||||
mock.return_value = handle
|
||||
return mock
|
||||
38
tests/unit/compat/unittest.py
Normal file
38
tests/unit/compat/unittest.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
'''
|
||||
Compat module for Python2.7's unittest module
|
||||
'''
|
||||
|
||||
import sys
|
||||
|
||||
# Allow wildcard import because we really do want to import all of
|
||||
# unittests's symbols into this compat shim
|
||||
# pylint: disable=wildcard-import,unused-wildcard-import
|
||||
if sys.version_info < (2, 7):
|
||||
try:
|
||||
# Need unittest2 on python2.6
|
||||
from unittest2 import *
|
||||
except ImportError:
|
||||
print('You need unittest2 installed on python2.6.x to run tests')
|
||||
else:
|
||||
from unittest import *
|
||||
0
tests/unit/mock/__init__.py
Normal file
0
tests/unit/mock/__init__.py
Normal file
116
tests/unit/mock/loader.py
Normal file
116
tests/unit/mock/loader.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
|
||||
from ansible.errors import AnsibleParserError
|
||||
from ansible.parsing.dataloader import DataLoader
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
|
||||
|
||||
class DictDataLoader(DataLoader):
|
||||
|
||||
def __init__(self, file_mapping=None):
|
||||
file_mapping = {} if file_mapping is None else file_mapping
|
||||
assert type(file_mapping) == dict
|
||||
|
||||
super(DictDataLoader, self).__init__()
|
||||
|
||||
self._file_mapping = file_mapping
|
||||
self._build_known_directories()
|
||||
self._vault_secrets = None
|
||||
|
||||
def load_from_file(self, path, cache=True, unsafe=False):
|
||||
path = to_text(path)
|
||||
if path in self._file_mapping:
|
||||
return self.load(self._file_mapping[path], path)
|
||||
return None
|
||||
|
||||
# TODO: the real _get_file_contents returns a bytestring, so we actually convert the
|
||||
# unicode/text it's created with to utf-8
|
||||
def _get_file_contents(self, path):
|
||||
path = to_text(path)
|
||||
if path in self._file_mapping:
|
||||
return (to_bytes(self._file_mapping[path]), False)
|
||||
else:
|
||||
raise AnsibleParserError("file not found: %s" % path)
|
||||
|
||||
def path_exists(self, path):
|
||||
path = to_text(path)
|
||||
return path in self._file_mapping or path in self._known_directories
|
||||
|
||||
def is_file(self, path):
|
||||
path = to_text(path)
|
||||
return path in self._file_mapping
|
||||
|
||||
def is_directory(self, path):
|
||||
path = to_text(path)
|
||||
return path in self._known_directories
|
||||
|
||||
def list_directory(self, path):
|
||||
ret = []
|
||||
path = to_text(path)
|
||||
for x in (list(self._file_mapping.keys()) + self._known_directories):
|
||||
if x.startswith(path):
|
||||
if os.path.dirname(x) == path:
|
||||
ret.append(os.path.basename(x))
|
||||
return ret
|
||||
|
||||
def is_executable(self, path):
|
||||
# FIXME: figure out a way to make paths return true for this
|
||||
return False
|
||||
|
||||
def _add_known_directory(self, directory):
|
||||
if directory not in self._known_directories:
|
||||
self._known_directories.append(directory)
|
||||
|
||||
def _build_known_directories(self):
|
||||
self._known_directories = []
|
||||
for path in self._file_mapping:
|
||||
dirname = os.path.dirname(path)
|
||||
while dirname not in ('/', ''):
|
||||
self._add_known_directory(dirname)
|
||||
dirname = os.path.dirname(dirname)
|
||||
|
||||
def push(self, path, content):
|
||||
rebuild_dirs = False
|
||||
if path not in self._file_mapping:
|
||||
rebuild_dirs = True
|
||||
|
||||
self._file_mapping[path] = content
|
||||
|
||||
if rebuild_dirs:
|
||||
self._build_known_directories()
|
||||
|
||||
def pop(self, path):
|
||||
if path in self._file_mapping:
|
||||
del self._file_mapping[path]
|
||||
self._build_known_directories()
|
||||
|
||||
def clear(self):
|
||||
self._file_mapping = dict()
|
||||
self._known_directories = []
|
||||
|
||||
def get_basedir(self):
|
||||
return os.getcwd()
|
||||
|
||||
def set_vault_secrets(self, vault_secrets):
|
||||
self._vault_secrets = vault_secrets
|
||||
5
tests/unit/mock/path.py
Normal file
5
tests/unit/mock/path.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from ansible_collections.openstack.cloud.tests.unit.compat.mock import MagicMock
|
||||
from ansible.utils.path import unfrackpath
|
||||
|
||||
|
||||
mock_unfrackpath_noop = MagicMock(spec_set=unfrackpath, side_effect=lambda x, *args, **kwargs: x)
|
||||
90
tests/unit/mock/procenv.py
Normal file
90
tests/unit/mock/procenv.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# (c) 2016, Matt Davis <mdavis@ansible.com>
|
||||
# (c) 2016, Toshio Kuratomi <tkuratomi@ansible.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
from contextlib import contextmanager
|
||||
from io import BytesIO, StringIO
|
||||
from ansible_collections.openstack.cloud.tests.unit.compat import unittest
|
||||
from ansible.module_utils.six import PY3
|
||||
from ansible.module_utils._text import to_bytes
|
||||
|
||||
|
||||
@contextmanager
|
||||
def swap_stdin_and_argv(stdin_data='', argv_data=tuple()):
|
||||
"""
|
||||
context manager that temporarily masks the test runner's values for stdin and argv
|
||||
"""
|
||||
real_stdin = sys.stdin
|
||||
real_argv = sys.argv
|
||||
|
||||
if PY3:
|
||||
fake_stream = StringIO(stdin_data)
|
||||
fake_stream.buffer = BytesIO(to_bytes(stdin_data))
|
||||
else:
|
||||
fake_stream = BytesIO(to_bytes(stdin_data))
|
||||
|
||||
try:
|
||||
sys.stdin = fake_stream
|
||||
sys.argv = argv_data
|
||||
|
||||
yield
|
||||
finally:
|
||||
sys.stdin = real_stdin
|
||||
sys.argv = real_argv
|
||||
|
||||
|
||||
@contextmanager
|
||||
def swap_stdout():
|
||||
"""
|
||||
context manager that temporarily replaces stdout for tests that need to verify output
|
||||
"""
|
||||
old_stdout = sys.stdout
|
||||
|
||||
if PY3:
|
||||
fake_stream = StringIO()
|
||||
else:
|
||||
fake_stream = BytesIO()
|
||||
|
||||
try:
|
||||
sys.stdout = fake_stream
|
||||
|
||||
yield fake_stream
|
||||
finally:
|
||||
sys.stdout = old_stdout
|
||||
|
||||
|
||||
class ModuleTestCase(unittest.TestCase):
|
||||
def setUp(self, module_args=None):
|
||||
if module_args is None:
|
||||
module_args = {'_ansible_remote_tmp': '/tmp', '_ansible_keep_remote_files': False}
|
||||
|
||||
args = json.dumps(dict(ANSIBLE_MODULE_ARGS=module_args))
|
||||
|
||||
# unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
|
||||
self.stdin_swap = swap_stdin_and_argv(stdin_data=args)
|
||||
self.stdin_swap.__enter__()
|
||||
|
||||
def tearDown(self):
|
||||
# unittest doesn't have a clean place to use a context manager, so we have to enter/exit manually
|
||||
self.stdin_swap.__exit__(None, None, None)
|
||||
39
tests/unit/mock/vault_helper.py
Normal file
39
tests/unit/mock/vault_helper.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.module_utils._text import to_bytes
|
||||
|
||||
from ansible.parsing.vault import VaultSecret
|
||||
|
||||
|
||||
class TextVaultSecret(VaultSecret):
|
||||
'''A secret piece of text. ie, a password. Tracks text encoding.
|
||||
|
||||
The text encoding of the text may not be the default text encoding so
|
||||
we keep track of the encoding so we encode it to the same bytes.'''
|
||||
|
||||
def __init__(self, text, encoding=None, errors=None, _bytes=None):
|
||||
super(TextVaultSecret, self).__init__()
|
||||
self.text = text
|
||||
self.encoding = encoding or 'utf-8'
|
||||
self._bytes = _bytes
|
||||
self.errors = errors or 'strict'
|
||||
|
||||
@property
|
||||
def bytes(self):
|
||||
'''The text encoded with encoding, unless we specifically set _bytes.'''
|
||||
return self._bytes or to_bytes(self.text, encoding=self.encoding, errors=self.errors)
|
||||
121
tests/unit/mock/yaml_helper.py
Normal file
121
tests/unit/mock/yaml_helper.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import io
|
||||
import yaml
|
||||
|
||||
from ansible.module_utils.six import PY3
|
||||
from ansible.parsing.yaml.loader import AnsibleLoader
|
||||
from ansible.parsing.yaml.dumper import AnsibleDumper
|
||||
|
||||
|
||||
class YamlTestUtils(object):
|
||||
"""Mixin class to combine with a unittest.TestCase subclass."""
|
||||
def _loader(self, stream):
|
||||
"""Vault related tests will want to override this.
|
||||
|
||||
Vault cases should setup a AnsibleLoader that has the vault password."""
|
||||
return AnsibleLoader(stream)
|
||||
|
||||
def _dump_stream(self, obj, stream, dumper=None):
|
||||
"""Dump to a py2-unicode or py3-string stream."""
|
||||
if PY3:
|
||||
return yaml.dump(obj, stream, Dumper=dumper)
|
||||
else:
|
||||
return yaml.dump(obj, stream, Dumper=dumper, encoding=None)
|
||||
|
||||
def _dump_string(self, obj, dumper=None):
|
||||
"""Dump to a py2-unicode or py3-string"""
|
||||
if PY3:
|
||||
return yaml.dump(obj, Dumper=dumper)
|
||||
else:
|
||||
return yaml.dump(obj, Dumper=dumper, encoding=None)
|
||||
|
||||
def _dump_load_cycle(self, obj):
|
||||
# Each pass though a dump or load revs the 'generation'
|
||||
# obj to yaml string
|
||||
string_from_object_dump = self._dump_string(obj, dumper=AnsibleDumper)
|
||||
|
||||
# wrap a stream/file like StringIO around that yaml
|
||||
stream_from_object_dump = io.StringIO(string_from_object_dump)
|
||||
loader = self._loader(stream_from_object_dump)
|
||||
# load the yaml stream to create a new instance of the object (gen 2)
|
||||
obj_2 = loader.get_data()
|
||||
|
||||
# dump the gen 2 objects directory to strings
|
||||
string_from_object_dump_2 = self._dump_string(obj_2,
|
||||
dumper=AnsibleDumper)
|
||||
|
||||
# The gen 1 and gen 2 yaml strings
|
||||
self.assertEqual(string_from_object_dump, string_from_object_dump_2)
|
||||
# the gen 1 (orig) and gen 2 py object
|
||||
self.assertEqual(obj, obj_2)
|
||||
|
||||
# again! gen 3... load strings into py objects
|
||||
stream_3 = io.StringIO(string_from_object_dump_2)
|
||||
loader_3 = self._loader(stream_3)
|
||||
obj_3 = loader_3.get_data()
|
||||
|
||||
string_from_object_dump_3 = self._dump_string(obj_3, dumper=AnsibleDumper)
|
||||
|
||||
self.assertEqual(obj, obj_3)
|
||||
# should be transitive, but...
|
||||
self.assertEqual(obj_2, obj_3)
|
||||
self.assertEqual(string_from_object_dump, string_from_object_dump_3)
|
||||
|
||||
def _old_dump_load_cycle(self, obj):
|
||||
'''Dump the passed in object to yaml, load it back up, dump again, compare.'''
|
||||
stream = io.StringIO()
|
||||
|
||||
yaml_string = self._dump_string(obj, dumper=AnsibleDumper)
|
||||
self._dump_stream(obj, stream, dumper=AnsibleDumper)
|
||||
|
||||
yaml_string_from_stream = stream.getvalue()
|
||||
|
||||
# reset stream
|
||||
stream.seek(0)
|
||||
|
||||
loader = self._loader(stream)
|
||||
# loader = AnsibleLoader(stream, vault_password=self.vault_password)
|
||||
obj_from_stream = loader.get_data()
|
||||
|
||||
stream_from_string = io.StringIO(yaml_string)
|
||||
loader2 = self._loader(stream_from_string)
|
||||
# loader2 = AnsibleLoader(stream_from_string, vault_password=self.vault_password)
|
||||
obj_from_string = loader2.get_data()
|
||||
|
||||
stream_obj_from_stream = io.StringIO()
|
||||
stream_obj_from_string = io.StringIO()
|
||||
|
||||
if PY3:
|
||||
yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper)
|
||||
yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper)
|
||||
else:
|
||||
yaml.dump(obj_from_stream, stream_obj_from_stream, Dumper=AnsibleDumper, encoding=None)
|
||||
yaml.dump(obj_from_stream, stream_obj_from_string, Dumper=AnsibleDumper, encoding=None)
|
||||
|
||||
yaml_string_stream_obj_from_stream = stream_obj_from_stream.getvalue()
|
||||
yaml_string_stream_obj_from_string = stream_obj_from_string.getvalue()
|
||||
|
||||
stream_obj_from_stream.seek(0)
|
||||
stream_obj_from_string.seek(0)
|
||||
|
||||
if PY3:
|
||||
yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper)
|
||||
yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper)
|
||||
else:
|
||||
yaml_string_obj_from_stream = yaml.dump(obj_from_stream, Dumper=AnsibleDumper, encoding=None)
|
||||
yaml_string_obj_from_string = yaml.dump(obj_from_string, Dumper=AnsibleDumper, encoding=None)
|
||||
|
||||
assert yaml_string == yaml_string_obj_from_stream
|
||||
assert yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
|
||||
assert (yaml_string == yaml_string_obj_from_stream == yaml_string_obj_from_string == yaml_string_stream_obj_from_stream ==
|
||||
yaml_string_stream_obj_from_string)
|
||||
assert obj == obj_from_stream
|
||||
assert obj == obj_from_string
|
||||
assert obj == yaml_string_obj_from_stream
|
||||
assert obj == yaml_string_obj_from_string
|
||||
assert obj == obj_from_stream == obj_from_string == yaml_string_obj_from_stream == yaml_string_obj_from_string
|
||||
return {'obj': obj,
|
||||
'yaml_string': yaml_string,
|
||||
'yaml_string_from_stream': yaml_string_from_stream,
|
||||
'obj_from_stream': obj_from_stream,
|
||||
'obj_from_string': obj_from_string,
|
||||
'yaml_string_obj_from_string': yaml_string_obj_from_string}
|
||||
0
tests/unit/modules/__init__.py
Normal file
0
tests/unit/modules/__init__.py
Normal file
0
tests/unit/modules/cloud/__init__.py
Normal file
0
tests/unit/modules/cloud/__init__.py
Normal file
0
tests/unit/modules/cloud/openstack/__init__.py
Normal file
0
tests/unit/modules/cloud/openstack/__init__.py
Normal file
224
tests/unit/modules/cloud/openstack/test_os_server.py
Normal file
224
tests/unit/modules/cloud/openstack/test_os_server.py
Normal file
@@ -0,0 +1,224 @@
|
||||
import collections
|
||||
import inspect
|
||||
import mock
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible_collections.openstack.cloud.plugins.modules import os_server
|
||||
|
||||
|
||||
class AnsibleFail(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AnsibleExit(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def params_from_doc(func):
|
||||
'''This function extracts the docstring from the specified function,
|
||||
parses it as a YAML document, and returns parameters for the os_server
|
||||
module.'''
|
||||
|
||||
doc = inspect.getdoc(func)
|
||||
cfg = yaml.load(doc)
|
||||
|
||||
for task in cfg:
|
||||
for module, params in task.items():
|
||||
for k, v in params.items():
|
||||
if k in ['nics'] and isinstance(v, string_types):
|
||||
params[k] = [v]
|
||||
task[module] = collections.defaultdict(str,
|
||||
params)
|
||||
|
||||
return cfg[0]['os_server']
|
||||
|
||||
|
||||
class FakeCloud(object):
|
||||
ports = [
|
||||
{'name': 'port1', 'id': '1234'},
|
||||
{'name': 'port2', 'id': '4321'},
|
||||
]
|
||||
|
||||
networks = [
|
||||
{'name': 'network1', 'id': '5678'},
|
||||
{'name': 'network2', 'id': '8765'},
|
||||
]
|
||||
|
||||
images = [
|
||||
{'name': 'cirros', 'id': '1'},
|
||||
{'name': 'fedora', 'id': '2'},
|
||||
]
|
||||
|
||||
flavors = [
|
||||
{'name': 'm1.small', 'id': '1', 'flavor_ram': 1024},
|
||||
{'name': 'm1.tiny', 'id': '2', 'flavor_ram': 512},
|
||||
]
|
||||
|
||||
def _find(self, source, name):
|
||||
for item in source:
|
||||
if item['name'] == name or item['id'] == name:
|
||||
return item
|
||||
|
||||
def get_image_id(self, name, exclude=None):
|
||||
image = self._find(self.images, name)
|
||||
if image:
|
||||
return image['id']
|
||||
|
||||
def get_flavor(self, name):
|
||||
return self._find(self.flavors, name)
|
||||
|
||||
def get_flavor_by_ram(self, ram, include=None):
|
||||
for flavor in self.flavors:
|
||||
if flavor['ram'] >= ram and (include is None or include in
|
||||
flavor['name']):
|
||||
return flavor
|
||||
|
||||
def get_port(self, name):
|
||||
return self._find(self.ports, name)
|
||||
|
||||
def get_network(self, name):
|
||||
return self._find(self.networks, name)
|
||||
|
||||
def get_openstack_vars(self, server):
|
||||
return server
|
||||
|
||||
create_server = mock.MagicMock()
|
||||
|
||||
|
||||
class TestNetworkArgs(object):
|
||||
'''This class exercises the _network_args function of the
|
||||
os_server module. For each test, we parse the YAML document
|
||||
contained in the docstring to retrieve the module parameters for the
|
||||
test.'''
|
||||
|
||||
def setup_method(self, method):
|
||||
self.cloud = FakeCloud()
|
||||
self.module = mock.MagicMock()
|
||||
self.module.params = params_from_doc(method)
|
||||
|
||||
def test_nics_string_net_id(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics: net-id=1234
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['net-id'] == '1234')
|
||||
|
||||
def test_nics_string_net_id_list(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics: net-id=1234,net-id=4321
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['net-id'] == '1234')
|
||||
assert(args[1]['net-id'] == '4321')
|
||||
|
||||
def test_nics_string_port_id(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics: port-id=1234
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['port-id'] == '1234')
|
||||
|
||||
def test_nics_string_net_name(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics: net-name=network1
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['net-id'] == '5678')
|
||||
|
||||
def test_nics_string_port_name(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics: port-name=port1
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['port-id'] == '1234')
|
||||
|
||||
def test_nics_structured_net_id(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics:
|
||||
- net-id: '1234'
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['net-id'] == '1234')
|
||||
|
||||
def test_nics_structured_mixed(self):
|
||||
'''
|
||||
- os_server:
|
||||
nics:
|
||||
- net-id: '1234'
|
||||
- port-name: port1
|
||||
- 'net-name=network1,port-id=4321'
|
||||
'''
|
||||
args = os_server._network_args(self.module, self.cloud)
|
||||
assert(args[0]['net-id'] == '1234')
|
||||
assert(args[1]['port-id'] == '1234')
|
||||
assert(args[2]['net-id'] == '5678')
|
||||
assert(args[3]['port-id'] == '4321')
|
||||
|
||||
|
||||
class TestCreateServer(object):
|
||||
def setup_method(self, method):
|
||||
self.cloud = FakeCloud()
|
||||
self.module = mock.MagicMock()
|
||||
self.module.params = params_from_doc(method)
|
||||
self.module.fail_json.side_effect = AnsibleFail()
|
||||
self.module.exit_json.side_effect = AnsibleExit()
|
||||
|
||||
self.meta = mock.MagicMock()
|
||||
self.meta.gett_hostvars_from_server.return_value = {
|
||||
'id': '1234'
|
||||
}
|
||||
os_server.meta = self.meta
|
||||
|
||||
def test_create_server(self):
|
||||
'''
|
||||
- os_server:
|
||||
image: cirros
|
||||
flavor: m1.tiny
|
||||
nics:
|
||||
- net-name: network1
|
||||
meta:
|
||||
- key: value
|
||||
'''
|
||||
with pytest.raises(AnsibleExit):
|
||||
os_server._create_server(self.module, self.cloud)
|
||||
|
||||
assert(self.cloud.create_server.call_count == 1)
|
||||
assert(self.cloud.create_server.call_args[1]['image'] == self.cloud.get_image_id('cirros'))
|
||||
assert(self.cloud.create_server.call_args[1]['flavor'] == self.cloud.get_flavor('m1.tiny')['id'])
|
||||
assert(self.cloud.create_server.call_args[1]['nics'][0]['net-id'] == self.cloud.get_network('network1')['id'])
|
||||
|
||||
def test_create_server_bad_flavor(self):
|
||||
'''
|
||||
- os_server:
|
||||
image: cirros
|
||||
flavor: missing_flavor
|
||||
nics:
|
||||
- net-name: network1
|
||||
'''
|
||||
with pytest.raises(AnsibleFail):
|
||||
os_server._create_server(self.module, self.cloud)
|
||||
|
||||
assert('missing_flavor' in
|
||||
self.module.fail_json.call_args[1]['msg'])
|
||||
|
||||
def test_create_server_bad_nic(self):
|
||||
'''
|
||||
- os_server:
|
||||
image: cirros
|
||||
flavor: m1.tiny
|
||||
nics:
|
||||
- net-name: missing_network
|
||||
'''
|
||||
with pytest.raises(AnsibleFail):
|
||||
os_server._create_server(self.module, self.cloud)
|
||||
|
||||
assert('missing_network' in
|
||||
self.module.fail_json.call_args[1]['msg'])
|
||||
28
tests/unit/modules/conftest.py
Normal file
28
tests/unit/modules/conftest.py
Normal file
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) 2017 Ansible Project
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible.module_utils.six import string_types
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils.common._collections_compat import MutableMapping
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def patch_ansible_module(request, mocker):
|
||||
if isinstance(request.param, string_types):
|
||||
args = request.param
|
||||
elif isinstance(request.param, MutableMapping):
|
||||
if 'ANSIBLE_MODULE_ARGS' not in request.param:
|
||||
request.param = {'ANSIBLE_MODULE_ARGS': request.param}
|
||||
if '_ansible_remote_tmp' not in request.param['ANSIBLE_MODULE_ARGS']:
|
||||
request.param['ANSIBLE_MODULE_ARGS']['_ansible_remote_tmp'] = '/tmp'
|
||||
if '_ansible_keep_remote_files' not in request.param['ANSIBLE_MODULE_ARGS']:
|
||||
request.param['ANSIBLE_MODULE_ARGS']['_ansible_keep_remote_files'] = False
|
||||
args = json.dumps(request.param)
|
||||
else:
|
||||
raise Exception('Malformed data to the patch_ansible_module pytest fixture')
|
||||
|
||||
mocker.patch('ansible.module_utils.basic._ANSIBLE_ARGS', to_bytes(args))
|
||||
47
tests/unit/modules/utils.py
Normal file
47
tests/unit/modules/utils.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import json
|
||||
|
||||
from ansible_collections.openstack.cloud.tests.unit.compat import unittest
|
||||
from ansible_collections.openstack.cloud.tests.unit.compat.mock import patch
|
||||
from ansible.module_utils import basic
|
||||
from ansible.module_utils._text import to_bytes
|
||||
|
||||
|
||||
def set_module_args(args):
|
||||
if '_ansible_remote_tmp' not in args:
|
||||
args['_ansible_remote_tmp'] = '/tmp'
|
||||
if '_ansible_keep_remote_files' not in args:
|
||||
args['_ansible_keep_remote_files'] = False
|
||||
|
||||
args = json.dumps({'ANSIBLE_MODULE_ARGS': args})
|
||||
basic._ANSIBLE_ARGS = to_bytes(args)
|
||||
|
||||
|
||||
class AnsibleExitJson(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AnsibleFailJson(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def exit_json(*args, **kwargs):
|
||||
if 'changed' not in kwargs:
|
||||
kwargs['changed'] = False
|
||||
raise AnsibleExitJson(kwargs)
|
||||
|
||||
|
||||
def fail_json(*args, **kwargs):
|
||||
kwargs['failed'] = True
|
||||
raise AnsibleFailJson(kwargs)
|
||||
|
||||
|
||||
class ModuleTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.mock_module = patch.multiple(basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json)
|
||||
self.mock_module.start()
|
||||
self.mock_sleep = patch('time.sleep')
|
||||
self.mock_sleep.start()
|
||||
set_module_args({})
|
||||
self.addCleanup(self.mock_module.stop)
|
||||
self.addCleanup(self.mock_sleep.stop)
|
||||
0
tests/unit/plugins/__init__.py
Normal file
0
tests/unit/plugins/__init__.py
Normal file
0
tests/unit/plugins/inventory/__init__.py
Normal file
0
tests/unit/plugins/inventory/__init__.py
Normal file
90
tests/unit/plugins/inventory/test_openstack.py
Normal file
90
tests/unit/plugins/inventory/test_openstack.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2018 Lars Kellogg-Stedman <lars@redhat.com>
|
||||
#
|
||||
# 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, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import pytest
|
||||
|
||||
from ansible_collections.openstack.cloud.plugins.inventory.openstack import InventoryModule
|
||||
from ansible.inventory.data import InventoryData
|
||||
from ansible.template import Templar
|
||||
|
||||
|
||||
config_data = {
|
||||
'plugin': 'openstack',
|
||||
'compose': {
|
||||
'composed_var': '"testvar-" + testvar',
|
||||
},
|
||||
'groups': {
|
||||
'testgroup': '"host" in inventory_hostname',
|
||||
},
|
||||
'keyed_groups':
|
||||
[{
|
||||
'prefix': 'keyed',
|
||||
'key': 'testvar',
|
||||
}]
|
||||
}
|
||||
|
||||
hostvars = {
|
||||
'host0': {
|
||||
'inventory_hostname': 'host0',
|
||||
'testvar': '0',
|
||||
},
|
||||
'host1': {
|
||||
'inventory_hostname': 'host1',
|
||||
'testvar': '1',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def inventory():
|
||||
inventory = InventoryModule()
|
||||
inventory._config_data = config_data
|
||||
inventory.inventory = InventoryData()
|
||||
inventory.templar = Templar(loader=None)
|
||||
|
||||
for host in hostvars:
|
||||
inventory.inventory.add_host(host)
|
||||
|
||||
return inventory
|
||||
|
||||
|
||||
def test_simple_groups(inventory):
|
||||
inventory._set_variables(hostvars, {})
|
||||
groups = inventory.inventory.get_groups_dict()
|
||||
assert 'testgroup' in groups
|
||||
assert len(groups['testgroup']) == len(hostvars)
|
||||
|
||||
|
||||
def test_keyed_groups(inventory):
|
||||
inventory._set_variables(hostvars, {})
|
||||
assert 'keyed_0' in inventory.inventory.groups
|
||||
assert 'keyed_1' in inventory.inventory.groups
|
||||
|
||||
|
||||
def test_composed_vars(inventory):
|
||||
inventory._set_variables(hostvars, {})
|
||||
|
||||
for host in hostvars:
|
||||
assert host in inventory.inventory.hosts
|
||||
host = inventory.inventory.get_host(host)
|
||||
assert host.vars['composed_var'] == 'testvar-{testvar}'.format(**hostvars[host.name])
|
||||
42
tests/unit/requirements.txt
Normal file
42
tests/unit/requirements.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
boto3
|
||||
placebo
|
||||
pycrypto
|
||||
passlib
|
||||
pypsrp
|
||||
python-memcached
|
||||
pytz
|
||||
pyvmomi
|
||||
redis
|
||||
requests
|
||||
setuptools > 0.6 # pytest-xdist installed via requirements does not work with very old setuptools (sanity_ok)
|
||||
unittest2 ; python_version < '2.7'
|
||||
importlib ; python_version < '2.7'
|
||||
netaddr
|
||||
ipaddress
|
||||
netapp-lib
|
||||
solidfire-sdk-python
|
||||
|
||||
# requirements for F5 specific modules
|
||||
f5-sdk ; python_version >= '2.7'
|
||||
f5-icontrol-rest ; python_version >= '2.7'
|
||||
deepdiff
|
||||
|
||||
# requirement for Fortinet specific modules
|
||||
pyFMG
|
||||
|
||||
# requirement for aci_rest module
|
||||
xmljson
|
||||
|
||||
# requirement for winrm connection plugin tests
|
||||
pexpect
|
||||
|
||||
# requirement for the linode module
|
||||
linode-python # APIv3
|
||||
linode_api4 ; python_version > '2.6' # APIv4
|
||||
|
||||
# requirement for the gitlab module
|
||||
python-gitlab
|
||||
httmock
|
||||
|
||||
# requirment for kubevirt modules
|
||||
openshift ; python_version >= '2.7'
|
||||
Reference in New Issue
Block a user