Skip to content

Commit

Permalink
Added unit tests for RMUTL new methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Samarinnayak authored and Tom-Latham committed Oct 29, 2024
1 parent 7289fd7 commit ed8e82e
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 52 deletions.
101 changes: 51 additions & 50 deletions plugins/module_utils/_global_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# FOR INTERNAL USE IN THE COLLECTION ONLY.

from __future__ import (absolute_import, division, print_function)
import os
__metaclass__ = type


Expand Down Expand Up @@ -100,6 +101,7 @@ def _validate_line_length(line, name):
"""
if len(line) > MAX_LINE_LENGTH:
raise ValueError(f"{name} line exceeds {MAX_LINE_LENGTH} characters: {len(line)}")
return True

def _validate_name_params(param):
if any(len(part) > MAX_NAME_LENGTH for part in param.split('.')):
Expand All @@ -114,63 +116,62 @@ def _run_dfhrmutl(
# type: (...) -> tuple[list[dict[str, str| int]], tuple[str | None, str | None]] | list[dict[str, str| int]]
_validate_name_params(location)
_validate_name_params(sdfhload)

qualified_file_path = _create_dfhrmutl_jcl(
location,
sdfhload,
cmd
)
#Use job submit to submit the above jcl
#After execution delete file os.remove(qualified_file_path)
executions = []

for x in range(MVS_CMD_RETRY_ATTEMPTS):
dfhrmutl_response, jcl_executions = _execute_dfhrmutl(qualified_file_path)
dfhrmutl_rc = dfhrmutl_response.get("ret_code").get("code")

allContent = []
for ddname in dfhrmutl_response.get("ddnames"):
allContent += ddname.get("content")
stdout_raw = "".join(allContent)

executions.append(jcl_executions)
executions.append(
_execution(
name="DFHRMUTL - {0} - Run {1}".format(
"Get current catalog" if cmd == "" else "Updating autostart override",
x + 1),
rc=dfhrmutl_rc,
stdout=stdout_raw,
stderr=dfhrmutl_response.get("ret_code").get("msg_txt", "")))

if dfhrmutl_rc not in (0, 16):
raise MVSExecutionException(
"DFHRMUTL failed with RC {0}".format(
dfhrmutl_rc), executions)

if dfhrmutl_rc == 0:
break
if dfhrmutl_rc == 16:
formatted_stdout_lines = [
"{0}".format(element.replace(" ", "").upper())
for element in stdout_raw.split("\n")
]
stdout_with_rc = list(filter(lambda x: "REASON:X" in x, formatted_stdout_lines))

reason_code = _get_reason_code(stdout_with_rc)
if reason_code and reason_code != "A8":
try:
for x in range(MVS_CMD_RETRY_ATTEMPTS):
dfhrmutl_response, jcl_executions = _execute_dfhrmutl(qualified_file_path)
dfhrmutl_rc = dfhrmutl_response.get("ret_code").get("code")

allContent = []
for ddname in dfhrmutl_response.get("ddnames"):
allContent += ddname.get("content")
stdout_raw = "".join(allContent)

executions.append(jcl_executions)
executions.append(
_execution(
name="DFHRMUTL - {0} - Run {1}".format(
"Get current catalog" if cmd == "" else "Updating autostart override",
x + 1),
rc=dfhrmutl_rc,
stdout=stdout_raw,
stderr=dfhrmutl_response.get("ret_code").get("msg_txt", "")))

if dfhrmutl_rc not in (0, 16):
raise MVSExecutionException(
"DFHRMUTL failed with RC 16 - {0}".format(stdout_with_rc[0]), executions
)
elif reason_code is None:
raise MVSExecutionException(
"DFHRMUTL failed with RC 16 but no reason code was found",
executions,
)

if cmd != "":
return executions

"DFHRMUTL failed with RC {0}".format(
dfhrmutl_rc), executions)

if dfhrmutl_rc == 0:
break
if dfhrmutl_rc == 16:
formatted_stdout_lines = [
"{0}".format(element.replace(" ", "").upper())
for element in stdout_raw.split("\n")
]
stdout_with_rc = list(filter(lambda x: "REASON:X" in x, formatted_stdout_lines))

reason_code = _get_reason_code(stdout_with_rc)
if reason_code and reason_code != "A8":
raise MVSExecutionException(
"DFHRMUTL failed with RC 16 - {0}".format(stdout_with_rc[0]), executions
)
elif reason_code is None:
raise MVSExecutionException(
"DFHRMUTL failed with RC 16 but no reason code was found",
executions,
)

if cmd != "":
return executions
finally:
os.remove(qualified_file_path)
return executions, _get_catalog_records(stdout_raw)


Expand Down
33 changes: 33 additions & 0 deletions tests/unit/helpers/data_set_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from textwrap import dedent
from ansible.module_utils.common.text.converters import to_bytes
from ansible.module_utils import basic
from ansible_collections.ibm.ibm_zos_cics.plugins.module_utils._response import _execution

PYTHON_LANGUAGE_FEATURES_MESSAGE = "Requires python 3 language features"

Expand Down Expand Up @@ -418,6 +419,32 @@ def CSDUP_add_group_stdout(data_set_name):
DFH5109 I END OF DFHCSDUP UTILITY JOB. HIGHEST RETURN CODE WAS: 0
""".format(data_set_name)

def get_job_output_execution(rc=0):
job = get_sample_job_output()
return _execution(
name="Get job output for {0}".format(job["job_id"]),
rc=rc,
stdout=job.get("ret_code").get("msg"),
stderr=job.get("ret_code").get("msg_txt")
)

def _get_job_dd_output(ddname, job_id):
return (
_get_job_dd_output_execution(rc=0, ddname=ddname, job_id=job_id),
RMUTL_stdout("AUTOINIT", job_id)
)

def _get_job_dd_output_execution(rc = 0, ddname="", job_id=""):
return _execution(
name=JOB_DD_return_name(ddname, job_id),
rc=rc,
stdout=RMUTL_stdout("AUTOINIT", job_id),
stderr="CC"
)

def JOB_DD_return_name(ddname, job_id):
return "Get job dd {0} output for {1}".format(ddname, job_id)

def get_sample_job_output(content="", rc=0, err="CC"):
return {
"class": "",
Expand Down Expand Up @@ -483,6 +510,12 @@ def get_sample_job_output(content="", rc=0, err="CC"):
"system": ""
}

def _get_sample_job_output_with_content():
job = get_sample_job_output()
for dd in job.get("ddnames"):
dd["content"] = RMUTL_stdout("AUTOINIT", job.get("job_id"))
return job


def read_data_set_content_run_name(data_set_name):
return "Read data set {0}".format(data_set_name)
Expand Down
154 changes: 153 additions & 1 deletion tests/unit/module_utils/test_dataset_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@
LISTDS_data_set,
LISTDS_data_set_doesnt_exist,
LISTDS_member_doesnt_exist,
LISTDS_run_name
LISTDS_run_name,
get_sample_job_output as JOB_OUTPUT,
get_job_output_execution as JOB_EXECUTION,
JOB_DD_return_name,
RMUTL_stdout,
_get_job_dd_output,
_get_job_dd_output_execution,
_get_sample_job_output_with_content

)
from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.dd_statement import DatasetDefinition
from ansible_collections.ibm.ibm_zos_core.plugins.module_utils.zos_mvs_raw import MVSCmdResponse
Expand Down Expand Up @@ -700,3 +708,147 @@ def test__write_jcl_to_data_set_fail():

assert e.value.message == "Failed to copy JCL content to data set"
assert e.value.executions == expected_executions

def test_data_set_utils_submit_jcl():
jcl_uss_path = "jcl/uss/path"
job_name = "Job_Name"
rc = 0
stdout = ""
stderr = ""
data_set_utils._execute_command = MagicMock(return_value=(rc, stdout, stderr))

expected_executions = [{
"name": "Submit jcl job {0} for {1}".format(jcl_uss_path, job_name),
"rc": 0,
"stdout": "",
"stderr": ""
}]

executions= data_set_utils._submit_jcl(jcl_uss_path, job_name)
assert expected_executions == executions

def test_data_set_utils_submit_jcl_failed():
jcl_uss_path = "jcl/uss/path"
job_name = "Job_Name"
rc = 16
stdout = "CC"
stderr = "CC"
data_set_utils._execute_command = MagicMock(return_value=(rc, stdout, stderr))

expected_executions = [{
"name": "Submit jcl job {0} for {1}".format(jcl_uss_path, job_name),
"rc": 16,
"stdout": "CC",
"stderr": "CC"
}]
with pytest.raises(MVSExecutionException) as e:
data_set_utils._submit_jcl(jcl_uss_path, job_name)
assert e.value.message == "RC {0} when submitting jcl from {1}".format(rc, jcl_uss_path)
assert e.value.executions == expected_executions



def test_data_set_utils_get_job_output():
job_id = "JOB12345"
expected_execution=[
JOB_EXECUTION(),
_execution(
name=JOB_DD_return_name("JESMSGLG", job_id),
rc=0,
stdout=RMUTL_stdout("AUTOINIT", job_id),
stderr="CC",
),
_execution(
name=JOB_DD_return_name("JESJCL", job_id),
rc=0,
stdout=RMUTL_stdout("AUTOINIT", job_id),
stderr="CC",
),
_execution(
name=JOB_DD_return_name("JESSYSMSG", job_id),
rc=0,
stdout=RMUTL_stdout("AUTOINIT", job_id),
stderr="CC",
),
_execution(
name=JOB_DD_return_name("SYSPRINT", job_id),
rc=0,
stdout=RMUTL_stdout("AUTOINIT", job_id),
stderr="CC",
)
]
expected_result = _get_sample_job_output_with_content()
data_set_utils.job_output = MagicMock(return_value=[JOB_OUTPUT()])
job_id= JOB_OUTPUT().get("job_id")
data_set_utils._get_job_dd = MagicMock(side_effect=[
_get_job_dd_output("JESMSGLG", job_id),
_get_job_dd_output("JESJCL", job_id),
_get_job_dd_output("JESSYSMSG", job_id),
_get_job_dd_output("SYSPRINT", job_id)
])
result, executions = data_set_utils._get_job_output(job_id=job_id, job_name="DFHRMUTL")

assert result == expected_result
assert executions == expected_execution

def test_data_set_utils_get_job_output_multiple_jobs_failure():
job_id = JOB_OUTPUT()["job_id"]
job_name = JOB_OUTPUT()["job_name"]

mock_jobs = [
JOB_OUTPUT(),
{"ret_code": {"code": 1, "msg": "Error", "msg_txt": "Job failed"}}
]
expected_executions = []
data_set_utils.job_output = MagicMock(return_value = mock_jobs)

with pytest.raises(MVSExecutionException) as e:
data_set_utils._get_job_output(job_id, job_name)

assert e.value.executions == expected_executions
assert f"Query for {job_name} job submitted under Job ID {job_id} failed" in e.value.message

def test_data_set_utils_get_job_output_get_dd_failure():
job_id = JOB_OUTPUT()["job_id"]
job_name = JOB_OUTPUT()["job_name"]

expected_executions = [JOB_EXECUTION()]
expected_exception = TypeError("Failed to get DD content")
data_set_utils.job_output = MagicMock(return_value=[JOB_OUTPUT()])
data_set_utils._get_job_dd = MagicMock(return_value=expected_exception)

with pytest.raises(MVSExecutionException) as e:
data_set_utils._get_job_output(job_id, job_name)

assert e.value.executions == expected_executions
assert f"Could not get all job DDs for {job_name}. An exception occured: " in str(e.value.message)

def test_data_set_utils_get_job_dd():
job_id = "JOB12345"
dd_name = "DD Name"
rc = 0
stdout = RMUTL_stdout("AUTOINIT", job_id)
stderr = "CC"
mock_dd_execution = [_get_job_dd_output_execution(rc, dd_name, job_id)]
data_set_utils._execute_command = MagicMock(return_value=(rc, stdout, stderr))
result_execution, result = data_set_utils._get_job_dd(job_id, dd_name)

assert result == stdout
assert result_execution == mock_dd_execution

def test_data_set_utils_get_job_dd_failure():
job_id = "JOB12345"
dd_name = "DD Name"
rc = 8
stdout = RMUTL_stdout("AUTOINIT", job_id)
stderr = "CC"

mock_dd_execution = [_get_job_dd_output_execution(rc, dd_name, job_id)]
data_set_utils._execute_command = MagicMock(return_value=(rc, stdout, stderr))

with pytest.raises(Exception) as e:
data_set_utils._get_job_dd(job_id, dd_name)

assert e.type == MVSExecutionException
assert f"RC 8 when getting job output for DD Name from {job_id}" in str(e.value)
assert e.value.executions == mock_dd_execution
Loading

0 comments on commit ed8e82e

Please sign in to comment.