From a0f1dcbd0fdcc1afb4eb4d435ceb20b4f38770f2 Mon Sep 17 00:00:00 2001 From: Lars Kellogg-Stedman Date: Wed, 14 Oct 2015 17:13:31 -0400 Subject: [PATCH 1/2] add some unit tests for the os_server module This commit adds some unit tests for the `cloud.openstack.os_server` module. These tests exercise `_network_args` thoroughly and `_create_server` lightly. These tests will **fail** until ansible/ansible-modules-core#2275 lands. To run the tests: pip install -r test-requirements.txt PYTHONPATH=$PWD py.test Originally from ansible/ansible-modules-core@3387526bca1dd52751a3719c462a599c6c094bb9 --- test/unit/cloud/openstack/test_os_server.py | 221 ++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 test/unit/cloud/openstack/test_os_server.py diff --git a/test/unit/cloud/openstack/test_os_server.py b/test/unit/cloud/openstack/test_os_server.py new file mode 100644 index 00000000000..bb1f79ad2f9 --- /dev/null +++ b/test/unit/cloud/openstack/test_os_server.py @@ -0,0 +1,221 @@ +import mock +import pytest +import yaml +import inspect +import collections + +from cloud.openstack 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 type(v) == str: + 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) + + 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 + ''' + 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']) From e24588902f95f4ef407b0b4769a9b99b2faf6854 Mon Sep 17 00:00:00 2001 From: Matt Clay Date: Mon, 31 Oct 2016 15:11:56 -0700 Subject: [PATCH 2/2] Move test_os_server and apply fixes. - Add missing meta value for test_create_server - Add .gitignore for pytest .cache directory Exclude test_os_server from nose test runs since it was designed for pytest. The test will work correctly when run using pytest. This is a temporary issue, as we'll be moving to pytest soon. --- .gitignore | 1 + Makefile | 4 ++-- test/units/modules/core/cloud/openstack/__init__.py | 0 .../modules/core}/cloud/openstack/test_os_server.py | 4 +++- 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 test/units/modules/core/cloud/openstack/__init__.py rename test/{unit => units/modules/core}/cloud/openstack/test_os_server.py (98%) diff --git a/.gitignore b/.gitignore index 4ebacf429ab..756055b2a60 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ credentials.yml *.out .coverage .tox +.cache results.xml coverage.xml /test/units/cover-html diff --git a/Makefile b/Makefile index 4dbede47224..6465b8bf530 100644 --- a/Makefile +++ b/Makefile @@ -106,10 +106,10 @@ NOSETESTS3 ?= nosetests-3.5 all: clean python tests: - PYTHONPATH=./lib $(NOSETESTS) -d -w test/units -v --with-coverage --cover-package=ansible --cover-branches --cover-erase + PYTHONPATH=./lib $(NOSETESTS) -d -w test/units -v --with-coverage --cover-package=ansible --cover-branches --cover-erase -e test_os_server tests-py3: - PYTHONPATH=./lib $(NOSETESTS3) -d -w test/units -v --with-coverage --cover-package=ansible --cover-branches --cover-erase + PYTHONPATH=./lib $(NOSETESTS3) -d -w test/units -v --with-coverage --cover-package=ansible --cover-branches --cover-erase -e test_os_server integration: test/utils/shippable/integration.sh diff --git a/test/units/modules/core/cloud/openstack/__init__.py b/test/units/modules/core/cloud/openstack/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/unit/cloud/openstack/test_os_server.py b/test/units/modules/core/cloud/openstack/test_os_server.py similarity index 98% rename from test/unit/cloud/openstack/test_os_server.py rename to test/units/modules/core/cloud/openstack/test_os_server.py index bb1f79ad2f9..a2c017edec2 100644 --- a/test/unit/cloud/openstack/test_os_server.py +++ b/test/units/modules/core/cloud/openstack/test_os_server.py @@ -4,7 +4,7 @@ import yaml import inspect import collections -from cloud.openstack import os_server +from ansible.modules.core.cloud.openstack import os_server class AnsibleFail(Exception): @@ -180,6 +180,8 @@ class TestCreateServer(object): flavor: m1.tiny nics: - net-name: network1 + meta: + - key: value ''' with pytest.raises(AnsibleExit): os_server._create_server(self.module, self.cloud)