Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed end2end test concept and testcases #510

Merged
merged 1 commit into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,16 @@ test_py_files := \
$(wildcard $(test_dir)/*/*.py) \
$(wildcard $(test_dir)/*/*/*.py) \

# Directory with hmc_definitions.yaml file for end2end tests
default_test_hmc_dir := ../python-zhmcclient/tests
ifndef TESTHMCDIR
TESTHMCDIR := $(default_test_hmc_dir)
# Path name of default HMC definitions file used for end2end tests.
default_testhmcfile := ~/.zhmc_hmc_definitions.yaml
ifndef TESTHMCFILE
TESTHMCFILE := $(default_testhmcfile)
endif

# Nickname of test HMC in hmc_definitions.yaml file for end2end tests
default_test_hmc := default
# Default HMC nickname in HMC definitions file
default_testhmc := default
ifndef TESTHMC
TESTHMC := $(default_test_hmc)
TESTHMC := $(default_testhmc)
endif

# Flake8 options
Expand Down Expand Up @@ -144,7 +144,11 @@ dist_dependent_files := \
sphinx_opts := -v

# Pytest options
pytest_opts := $(TESTOPTS) -s
ifdef TESTCASES
pytest_opts := --color=yes -s $(TESTOPTS) -k "$(TESTCASES)"
else
pytest_opts := --color=yes -s $(TESTOPTS)
endif
ifeq ($(python_m_n_version),3.4)
pytest_cov_opts :=
else
Expand Down Expand Up @@ -172,14 +176,18 @@ help:
@echo ' linkcheck - Check links in documentation'
@echo ' all - Do all of the above'
@echo ' end2end - Run end2end tests'
@echo ' upload - Publish the collection to Ansible Galaxy'
@echo ' upload - Publish the collection to Ansible Galaxy and AutomationHub'
@echo ' clobber - Remove any produced files'
@echo 'Environment variables:'
@echo ' TESTHMC=... - Nickname of HMC to be used in end2end tests. Default: $(default_test_hmc)'
@echo ' TESTHMCDIR=... - Path name of directory with hmc_definitions.yaml file. Default: $(default_test_hmc_dir)'
@echo ' TESTOPTS=... - Additional options for py.test (e.g. "-k test_module.py")'
@echo ' PACKAGE_LEVEL="minimum" - Install minimum version of dependent Python packages'
@echo ' PACKAGE_LEVEL="latest" - Default: Install latest version of dependent Python packages'
@echo " TESTCASES=... - Testcase filter for pytest -k (e.g. 'test_func' or 'test_mod.py')"
@echo " TESTOPTS=... - Additional options for pytest (e.g. '-x')"
@echo " TESTHMC=... - HMC nickname in HMC definitions file used in end2end tests. Default: $(default_testhmc)"
@echo " TESTHMCFILE=... - Path name of HMC definitions file used in end2end tests. Default: $(default_testhmcfile)"
@echo " PACKAGE_LEVEL - Package level to be used for installing dependent Python"
@echo " packages in 'install' and 'develop' targets:"
@echo " latest - Latest package versions available on Pypi"
@echo " minimum - A minimum version as defined in minimum-constraints.txt"
@echo " Optional, defaults to 'latest'."
@echo ' PYTHON_CMD=... - Name of python command. Default: python'
@echo ' PIP_CMD=... - Name of pip command. Default: pip'
@echo ' GALAXY_TOKEN=... - Your Ansible Galaxy API token, required for upload (see https://galaxy.ansible.com/me/preferences)'
Expand Down Expand Up @@ -212,7 +220,7 @@ linkcheck: _check_version develop_$(pymn).done $(doc_rst_files)

.PHONY: test
test: _check_version develop_$(pymn).done
bash -c 'PYTHONWARNINGS=default ANSIBLE_LIBRARY=$(module_py_dir) PYTHONPATH=. pytest $(pytest_cov_opts) $(pytest_opts) $(test_dir)/unit $(test_dir)/function'
bash -c 'PYTHONWARNINGS=default ANSIBLE_LIBRARY=$(module_py_dir) PYTHONPATH=. TESTHMCFILE=$(TESTHMCFILE) TESTHMC=$(TESTHMC) pytest $(pytest_cov_opts) $(pytest_opts) $(test_dir)/unit $(test_dir)/function'
@echo '$@ done.'

.PHONY: check
Expand All @@ -239,7 +247,7 @@ endif

.PHONY: end2end
end2end: _check_version develop_$(pymn).done
bash -c 'PYTHONWARNINGS=default TESTHMCDIR=$(TESTHMCDIR) TESTHMC=$(TESTHMC) py.test -v $(pytest_opts) $(test_dir)/end2end'
bash -c 'PYTHONWARNINGS=default ANSIBLE_LIBRARY=$(module_py_dir) PYTHONPATH=. TESTHMCFILE=$(TESTHMCFILE) TESTHMC=$(TESTHMC) pytest -v $(pytest_opts) $(test_dir)/end2end'
@echo '$@ done.'

.PHONY: upload
Expand Down
16 changes: 16 additions & 0 deletions docs/source/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,24 @@ Availability: `AutomationHub`_, `Galaxy`_, `GitHub`_
module, and made the module result in check mode consistent with non-check
mode. (issue #507)

* Test: Added missing env.vars in the pytest invocation for end2end tests.

* Test: Added missing optional module parameters in the end2end tests.

* Test: Added support for specifying 'hmc_auth.ca_certs' and 'hmc_auth.verify'
from the 'hmc_verify_cert' parameter in the HMC definition file in
end2end test cases for zhmc_partition and zhmc_user.

**Enhancements:**

* Test: Made end2end testing compatible with zhmcclient.testutils support for
HMC definition files.
The HMC definition file is now by default ~/.hmc_hmc_definitions.yaml, and
the env.var to override that is now TESTHMCFILE.

* Test: Added support for a TESTCASES env.var for filtering testcases with the
pytest -k option.

**Cleanup:**

**Known issues:**
Expand Down
44 changes: 34 additions & 10 deletions tests/end2end/test_zhmc_partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,29 @@

import pytest
import mock
import random
import requests.packages.urllib3
from ansible.module_utils import six
import zhmcclient
from zhmcclient.testutils.hmc_definition_fixtures import hmc_definition, hmc_session # noqa: F401, E501

from plugins.modules import zhmc_partition
from .utils import mock_ansible_module, get_failure_msg

requests.packages.urllib3.disable_warnings()


# Partition properties that are not always present, nbut only under certain
# Partition properties that are not always present, but only under certain
# conditions.
PARTITION_CONDITIONAL_PROPS = (
'boot-ftp-password',
'boot-network-nic-name',
'boot-storage-hba-name',
'ssc-master-pw',
'ssc-boot-selection',
'ssc-host-name',
'ssc-ipv4-gateway',
'ssc-dns-servers',
'ssc-master-userid',
)


Expand Down Expand Up @@ -101,35 +107,53 @@ def assert_partition_props(partition_props):

@pytest.mark.parametrize(
"check_mode", [False, True])
@pytest.mark.parametrize(
"partition_type", ['ssc', 'linux'])
@mock.patch("plugins.modules.zhmc_partition.AnsibleModule", autospec=True)
def test_partition_facts(ansible_mod_cls, check_mode, hmc_session): # noqa: F811, E501
def test_partition_facts(
ansible_mod_cls, partition_type, check_mode, hmc_session): # noqa: F811, E501
"""
Test fact gathering on a partition.
"""

hd = hmc_session.hmc_definition

hmc_auth = dict(userid=hd.hmc_userid, password=hd.hmc_password)
if isinstance(hd.hmc_verify_cert, six.string_types):
hmc_auth['ca_certs'] = hd.hmc_verify_cert
elif isinstance(hd.hmc_verify_cert, bool):
hmc_auth['verify'] = hd.hmc_verify_cert

# Determine one of the CPCs in the HMC definition file to test
cpc_names = hd.cpcs.keys()
cpc_names = list(hd.cpcs.keys())
assert len(cpc_names) >= 1
cpc_name = cpc_names[0]

# Determine an existing partition to test. This also validates that
# the CPC defined in the HMC definition file actually exists.
client = zhmcclient.Client(hmc_session)
cpc = client.cpcs.find_by_name(cpc_name)

# Determine a random existing partition of the desired type to test.
partitions = cpc.partitions.list()
assert len(partitions) >= 1
partition = partitions[0] # Pick first partition in list

# Prepare module input parameters
typed_partitions = [p for p in partitions
if p.get_property('type') == partition_type]
if len(typed_partitions) == 0:
pytest.skip("CPC '{c}' has no partitions of type '{t}'".
format(c=cpc_name, t=partition_type))
partition = random.choice(typed_partitions)

# Prepare module input parameters (must be all required + optional)
params = {
'hmc_host': hd.hmc_host,
'hmc_auth': dict(userid=hd.hmc_userid, password=hd.hmc_password),
'hmc_auth': hmc_auth,
'cpc_name': cpc_name,
'name': partition.name,
'state': 'facts',
'properties': {},
'expand_storage_groups': False,
'expand_crypto_adapters': False,
'log_file': None,
'_faked_session': None,
}

# Prepare mocks for AnsibleModule object
Expand Down
90 changes: 57 additions & 33 deletions tests/end2end/test_zhmc_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
import uuid
import pytest
import mock
import random
import requests.packages.urllib3
from collections import OrderedDict
from pprint import pformat
from ansible.module_utils import six
import zhmcclient
from zhmcclient.testutils.hmc_definition_fixtures import hmc_definition, hmc_session # noqa: F401, E501

Expand Down Expand Up @@ -207,48 +209,58 @@ def assert_user_props(user_props, expand):
@pytest.mark.parametrize(
"expand", [False, True])
@mock.patch("plugins.modules.zhmc_user.AnsibleModule", autospec=True)
def test_user_facts(ansible_mod_cls, expand, check_mode, hmc_session): # noqa: F811, E501
def test_user_facts(
ansible_mod_cls, expand, check_mode, hmc_session): # noqa: F811, E501
"""
Test fact gathering on all users of the HMC.
"""

hd = hmc_session.hmc_definition

hmc_auth = dict(userid=hd.hmc_userid, password=hd.hmc_password)
if isinstance(hd.hmc_verify_cert, six.string_types):
hmc_auth['ca_certs'] = hd.hmc_verify_cert
elif isinstance(hd.hmc_verify_cert, bool):
hmc_auth['verify'] = hd.hmc_verify_cert

# Determine an existing user to test.
client = zhmcclient.Client(hmc_session)
console = client.consoles.console

# Pick a random existing user to test
users = console.users.list()
assert len(users) >= 1

for user in users:

# Prepare module input parameters
params = {
'hmc_host': hd.hmc_host,
'hmc_auth': dict(userid=hd.hmc_userid, password=hd.hmc_password),
'name': user.name,
'state': 'facts',
'expand': expand,
'log_file': LOG_FILE,
}

# Prepare mocks for AnsibleModule object
mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

# Exercise the code to be tested
with pytest.raises(SystemExit) as exc_info:
zhmc_user.main()
exit_code = exc_info.value.args[0]

# Assert module exit code
assert exit_code == 0, \
"Module unexpectedly failed with this message:\n{0}". \
format(get_failure_msg(mod_obj))

# Assert module output
changed, user_props = get_module_output(mod_obj)
assert changed is False
assert_user_props(user_props, expand)
user = random.choice(users)

# Prepare module input parameters (must be all required + optional)
params = {
'hmc_host': hd.hmc_host,
'hmc_auth': hmc_auth,
'name': user.name,
'state': 'facts',
'properties': {},
'expand': expand,
'log_file': LOG_FILE,
'_faked_session': None,
}

# Prepare mocks for AnsibleModule object
mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

# Exercise the code to be tested
with pytest.raises(SystemExit) as exc_info:
zhmc_user.main()
exit_code = exc_info.value.args[0]

# Assert module exit code
assert exit_code == 0, \
"Module unexpectedly failed with this message:\n{0}". \
format(get_failure_msg(mod_obj))

# Assert module output
changed, user_props = get_module_output(mod_obj)
assert changed is False
assert_user_props(user_props, expand)


USER_ABSENT_PRESENT_TESTCASES = [
Expand Down Expand Up @@ -335,8 +347,16 @@ def test_user_absent_present(
"""
Test the zhmc_user module with all combinations of absent & present state.
"""
expand = False # Expansion is tested elsewhere

hd = hmc_session.hmc_definition

hmc_auth = dict(userid=hd.hmc_userid, password=hd.hmc_password)
if isinstance(hd.hmc_verify_cert, six.string_types):
hmc_auth['ca_certs'] = hd.hmc_verify_cert
elif isinstance(hd.hmc_verify_cert, bool):
hmc_auth['verify'] = hd.hmc_verify_cert

expand = False # Expansion is tested elsewhere
client = zhmcclient.Client(hmc_session)
console = client.consoles.console

Expand Down Expand Up @@ -368,16 +388,20 @@ def test_user_absent_present(

try:

# Prepare module input parameters (must be all required + optional)
params = {
'hmc_host': hd.hmc_host,
'hmc_auth': dict(userid=hd.hmc_userid, password=hd.hmc_password),
'hmc_auth': hmc_auth,
'name': user_name,
'state': input_state,
'expand': expand,
'log_file': LOG_FILE,
'_faked_session': None,
}
if input_props is not None:
params['properties'] = input_props
else:
params['properties'] = {}

mod_obj = mock_ansible_module(ansible_mod_cls, params, check_mode)

Expand Down
8 changes: 6 additions & 2 deletions tests/end2end/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@

def mock_ansible_module(ansible_mod_cls, params, check_mode):
"""
Prepare mocks for AnsibleModule object.
Prepare the mocked AnsibleModule object for the end2end test.

Note: Since this is a mocked object, the argument_spec defined in the
module is not applied, and the params must be the defaulted set of
all parameters in the module's argument_spec.
"""
mod_obj = ansible_mod_cls.return_value
mod_obj = ansible_mod_cls.return_value # the mocked object
mod_obj.params = params
mod_obj.check_mode = check_mode
mod_obj.fail_json.configure_mock(side_effect=SystemExit(1))
Expand Down