Skip to content

Commit

Permalink
Adding more unit tests for cluster, cluster_ha, and cluster_drs modules
Browse files Browse the repository at this point in the history
  • Loading branch information
bardielle committed Feb 13, 2024
1 parent 8a5b00d commit a152614
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 32 deletions.
12 changes: 8 additions & 4 deletions plugins/modules/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,12 @@ def state_create_cluster(self):
"""
Create cluster with given configuration
"""
changed = False
try:
cluster_config_spec = vim.cluster.ConfigSpecEx()
if not self.module.check_mode:
self.datacenter.hostFolder.CreateClusterEx(self.cluster_name, cluster_config_spec)
self.module.exit_json(changed=True)
changed = True
except vmodl.fault.InvalidArgument as invalid_args:
self.module.fail_json(msg="Cluster configuration specification"
" parameter is invalid : %s" % to_native(invalid_args.msg))
Expand All @@ -144,17 +145,18 @@ def state_create_cluster(self):
self.module.fail_json(msg="Failed to create cluster"
" due to generic exception %s" % to_native(generic_exc))

self.module.exit_json(changed=changed)

def state_destroy_cluster(self):
"""
Destroy cluster
"""
changed, result = True, None
changed, result = False, None

try:
if not self.module.check_mode:
task = self.cluster.Destroy_Task()
changed, result = wait_for_task(task)
self.module.exit_json(changed=changed, result=result)
except vim.fault.VimFault as vim_fault:
self.module.fail_json(msg=to_native(vim_fault.msg))
except vmodl.RuntimeFault as runtime_fault:
Expand All @@ -165,6 +167,8 @@ def state_destroy_cluster(self):
self.module.fail_json(msg="Failed to destroy cluster"
" due to generic exception %s" % to_native(generic_exc))

self.module.exit_json(changed=changed, result=result)

def state_exit_unchanged(self):
"""
Exit without any change
Expand All @@ -178,7 +182,7 @@ def check_cluster_configuration(self):
"""
try:
self.datacenter = find_datacenter_by_name(self.content, self.datacenter_name)
self.datacenter = self.find_datacenter_by_name(self.content, self.datacenter_name)
if self.datacenter is None:
self.module.fail_json(msg="Datacenter %s does not exist." % self.datacenter_name)
self.cluster = self.find_cluster_by_name(cluster_name=self.cluster_name, datacenter_name=self.datacenter)
Expand Down
2 changes: 1 addition & 1 deletion plugins/modules/cluster_drs.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def __init__(self, module):
self.cluster = None
self.drs_vmotion_rate = [5, 4, 3, 2, 1][self.params.get('drs_vmotion_rate') - 1]

self.datacenter = find_datacenter_by_name(self.content, self.datacenter_name)
self.datacenter = self.find_datacenter_by_name(self.content, self.datacenter_name)
if self.datacenter is None:
self.module.fail_json(msg="Datacenter %s does not exist." % self.datacenter_name)

Expand Down
7 changes: 4 additions & 3 deletions plugins/modules/cluster_ha.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def __init__(self, module):
else:
self.ha_admission_control = False

self.datacenter = find_datacenter_by_name(self.content, self.datacenter_name)
self.datacenter = self.find_datacenter_by_name(self.content, self.datacenter_name)
if self.datacenter is None:
self.module.fail_json(msg="Datacenter %s does not exist." % self.datacenter_name)

Expand All @@ -293,6 +293,7 @@ def __init__(self, module):
else:
self.changed_advanced_settings = None


def get_failover_hosts(self):
"""
Get failover hosts for failover_host_admission_control policy
Expand Down Expand Up @@ -527,8 +528,8 @@ def main():
]
)

vmware_cluster_ha = VMwareCluster(module)
vmware_cluster_ha.configure_ha()
cluster_ha = VMwareCluster(module)
cluster_ha.configure_ha()


if __name__ == '__main__':
Expand Down
32 changes: 30 additions & 2 deletions tests/unit/plugins/modules/common/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from __future__ import absolute_import, division, print_function

__metaclass__ = type

import json

from ansible.module_utils import basic
from ansible.module_utils._text import to_bytes
from pyVmomi import vim

from mock import patch
import mock


def set_module_args(**args):
Expand All @@ -27,6 +29,10 @@ def set_module_args(**args):
basic._ANSIBLE_ARGS = to_bytes(args)


class DummyDatacenter:
pass


class AnsibleExitJson(Exception):
"""Exception class to be raised by module.exit_json and caught by the test case """
pass
Expand All @@ -36,6 +42,14 @@ class AnsibleFailJson(Exception):
pass


class AnsibleDummyException(Exception):
pass


def raise_dummy_exception(*args, **kwargs):
raise AnsibleDummyException()


def exit_json(*args, **kwargs):
if 'changed' not in kwargs:
kwargs['changed'] = False
Expand All @@ -48,9 +62,23 @@ def fail_json(*args, **kwargs):
raise AnsibleFailJson(kwargs)


def resource_task_success(*args, **kwargs):
task_mock = mock.Mock()
task_mock.info = mock.Mock()
task_mock.info.state = "success"
return task_mock


def resource_task_fail(*args, **kwargs):
task_mock = mock.Mock()
task_mock.info = mock.Mock()
task_mock.info.state = "error"
return task_mock


class ModuleTestCase:
def setup_method(self):
self.mock_module = patch.multiple(
self.mock_module = mock.patch.multiple(
basic.AnsibleModule, exit_json=exit_json, fail_json=fail_json,
)
self.mock_module.start()
Expand Down
163 changes: 163 additions & 0 deletions tests/unit/plugins/modules/test_cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
from __future__ import absolute_import, division, print_function

__metaclass__ = type

import sys
import pytest

from ansible_collections.vmware.vmware.plugins.modules import cluster
from unittest import mock

from .common.utils import (
AnsibleExitJson, ModuleTestCase, set_module_args, exit_json, fail_json,
resource_task_success, resource_task_fail, AnsibleFailJson, DummyDatacenter
)

pytestmark = pytest.mark.skipif(
sys.version_info < (2, 7), reason="requires python2.7 or higher"
)


class TestCluster(ModuleTestCase):

def __prepare(self, mocker):
init_mock = mocker.patch.object(cluster.PyVmomi, "__init__")
init_mock.return_value = None

cluster.VMwareCluster.content = {}
cluster.VMwareCluster.params = {
'slot_based_admission_control': "",
'failover_host_admission_control': "",
'reservation_based_admission_control': "",
'host_isolation_response': "none",
'advanced_settings': None,
'apd_response': 'disabled',
'pdl_response': 'warning',
}

cluster.VMwareCluster.module = mock.Mock()
cluster.VMwareCluster.module.check_mode = False
cluster.VMwareCluster.module.fail_json.side_effect = fail_json
cluster.VMwareCluster.module.exit_json.side_effect = exit_json

def prepare_cluster(self, mocker, exist=False, task_success=True):
find_cluster_by_name = mocker.patch.object(cluster.VMwareCluster, "find_cluster_by_name")
if exist:
cluster_by_name = mock.Mock()
if task_success:
cluster_by_name.Destroy_Task.side_effect = resource_task_success
else:
cluster_by_name.Destroy_Task.side_effect = resource_task_fail
find_cluster_by_name.return_value = cluster_by_name
else:
find_cluster_by_name.return_value = None

def prepare_datacenter(self, mocker, hostfolder_exist=False):
if hostfolder_exist:
datacenter = mock.Mock()
datacenter.hostFolder = mock.Mock()
datacenter.hostFolder.CreateClusterEx.return_value = None
else:
datacenter = DummyDatacenter()

find_datacenter_by_name = mocker.patch.object(cluster.VMwareCluster, "find_datacenter_by_name")
find_datacenter_by_name.return_value = datacenter

def test_create_success(self, mocker):
# desired state: present
# current state: absent
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=False)
self.prepare_datacenter(mocker, hostfolder_exist=True)

set_module_args(
state="present",
datacenter="test",
)

with pytest.raises(AnsibleExitJson) as c:
cluster.main()
assert c.value.args[0]["changed"]

def test_create_fail(self, mocker):
# desired state: present
# current state: absent
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=False)
self.prepare_datacenter(mocker, hostfolder_exist=False)

set_module_args(
state="present",
datacenter="test",
)

with pytest.raises(AnsibleFailJson) as c:
cluster.main()
assert "Failed to create cluster" in c.value.args[0]["msg"]

def test_exit_unchanged(self, mocker):
# desired state: present
# current state: present
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=True)
self.prepare_datacenter(mocker, hostfolder_exist=True)

set_module_args(
state="present",
datacenter="test",
)
# cluster exist
find_cluster_by_name = mocker.patch.object(cluster.VMwareCluster, "find_cluster_by_name")
find_cluster_by_name.return_value = mocker.Mock

with pytest.raises(AnsibleExitJson) as c:
cluster.main()
assert not c.value.args[0]["changed"]

def test_absent_exists_cluster_success(self, mocker):
# desired state: absent
# current state: present
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=True, task_success=True)
self.prepare_datacenter(mocker, hostfolder_exist=True)

set_module_args(
state="absent",
datacenter="test",
)

with pytest.raises(AnsibleExitJson) as c:
cluster.main()
assert c.value.args[0]["changed"]

def test_absent_exists_cluster_fail(self, mocker):
# desired state: absent
# current state: present
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=True, task_success=False)
self.prepare_datacenter(mocker, hostfolder_exist=True)

set_module_args(
state="absent",
datacenter="test",
)

with pytest.raises(AnsibleFailJson) as c:
cluster.main()
assert "Failed to destroy cluster" in c.value.args[0]["msg"]

def test_absent_non_exists_cluster(self, mocker):
# desired state: absent
# current state: absent
self.__prepare(mocker)
self.prepare_cluster(mocker, exist=False)
self.prepare_datacenter(mocker, hostfolder_exist=True)

set_module_args(
state="absent",
datacenter="test",
)

with pytest.raises(AnsibleExitJson) as c:
cluster.main()
assert not c.value.args[0]["changed"]
Loading

0 comments on commit a152614

Please sign in to comment.