diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py
index a155af4a..c93bf20a 100644
--- a/pyracf/common/security_admin.py
+++ b/pyracf/common/security_admin.py
@@ -309,14 +309,21 @@ def _get_profile(
]
def _get_field(
- self, profile: Union[dict, bytes], segment: str, field: str
+ self,
+ profile: Union[dict, bytes],
+ segment: str,
+ field: str,
+ string: bool = False,
) -> Union[bytes, Any, None]:
"""Extract the value of a field from a segment in a profile."""
if self.__generate_requests_only:
# Allows this function to work with "self.__generate_requests_only" mode.
return profile
try:
- return profile[segment][field]
+ field = profile[segment][field]
+ if string and field is not None:
+ return str(field)
+ return field
except KeyError:
return None
@@ -611,7 +618,7 @@ def __add_key_value_pairs_to_segment(
if current_key not in segment:
segment[current_key] = []
values = [
- self._cast_from_str(value)
+ str(self._cast_from_str(value))
for value in value.split()
if value != "NONE"
]
diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py
index 6b17e618..9302885c 100644
--- a/pyracf/user/user_admin.py
+++ b/pyracf/user/user_admin.py
@@ -335,6 +335,58 @@ def delete_all_class_authorizations(self, userid: str) -> Union[dict, bool, byte
return False
return self.remove_class_authorizations(userid, current_class_authorizations)
+ # ============================================================================
+ # Revoke Date
+ # ============================================================================
+ def get_revoke_date(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's revoke date."""
+ profile = self.extract(userid, profile_only=True)
+ return self._get_field(profile, "base", "revokeDate", string=True)
+
+ def set_revoke_date(self, userid: str, revoke_date: str) -> Union[dict, bytes]:
+ """Set a user's revoke date."""
+ result = self.alter(userid, traits={"base:revoke_date": revoke_date})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # Resume Date
+ # ============================================================================
+ def get_resume_date(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's resume date."""
+ profile = self.extract(userid, profile_only=True)
+ return self._get_field(profile, "base", "resumeDate", string=True)
+
+ def set_resume_date(self, userid: str, resume_date: str) -> Union[dict, bytes]:
+ """Set a user's resume date."""
+ result = self.alter(userid, traits={"base:resume_date": resume_date})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # Owner
+ # ============================================================================
+ def get_owner(self, userid: str) -> Union[str, bytes]:
+ """Get a user's owner."""
+ profile = self.extract(userid, profile_only=True)
+ return self._get_field(profile, "base", "owner", string=True)
+
+ def set_owner(self, userid: str, owner: str) -> Union[dict, bytes]:
+ """Set a user's owner."""
+ result = self.alter(userid, traits={"base:owner": owner})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # Name
+ # ============================================================================
+ def get_name(self, userid: str) -> Union[str, bytes]:
+ """Get a user's name."""
+ profile = self.extract(userid, profile_only=True)
+ return self._get_field(profile, "base", "name", string=True)
+
+ def set_name(self, userid: str, name: Union[str, bool]) -> Union[dict, bytes]:
+ """Set a user's name."""
+ result = self.alter(userid, traits={"base:name": name})
+ return self._to_steps(result)
+
# ============================================================================
# OMVS UID
# ============================================================================
@@ -343,45 +395,363 @@ def get_omvs_uid(self, userid: str) -> Union[int, None, bytes]:
profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
return self._get_field(profile, "omvs", "uid")
- def set_omvs_uid(self, userid: str, uid: int) -> Union[dict, bytes]:
+ def set_omvs_uid(self, userid: str, uid: Union[int, bool]) -> Union[dict, bytes]:
"""Set a user's OMVS UID."""
result = self.alter(userid, traits={"omvs:uid": uid})
return self._to_steps(result)
# ============================================================================
- # OMVS Home
+ # OMVS Max Address Space Size
+ # ============================================================================
+ def get_omvs_max_address_space_size(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max address space size."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxAddressSpaceSize")
+
+ def set_omvs_max_address_space_size(
+ self,
+ userid: str,
+ max_address_space_size: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max address space size."""
+ result = self.alter(
+ userid, traits={"omvs:max_address_space_size": max_address_space_size}
+ )
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max CPU Time
+ # ============================================================================
+ def get_omvs_max_cpu_time(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max cpu time."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxCpuTime")
+
+ def set_omvs_max_cpu_time(
+ self,
+ userid: str,
+ max_cpu_time: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max cpu time."""
+ result = self.alter(userid, traits={"omvs:max_cpu_time": max_cpu_time})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max Files Per Process
+ # ============================================================================
+ def get_omvs_max_files_per_process(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max files per process."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxFilesPerProcess")
+
+ def set_omvs_max_files_per_process(
+ self,
+ userid: str,
+ max_files_per_process: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max files per process."""
+ result = self.alter(
+ userid, traits={"omvs:max_files_per_process": max_files_per_process}
+ )
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max Non-Shared Memory
+ # ============================================================================
+ def get_omvs_max_non_shared_memory(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's OMVS max non-shared memory."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxNonSharedMemory", string=True)
+
+ def set_omvs_max_non_shared_memory(
+ self,
+ userid: str,
+ max_non_shared_memory: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max non-shared memory."""
+ result = self.alter(
+ userid, traits={"omvs:max_non_shared_memory": max_non_shared_memory}
+ )
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max File Mapping Pages
+ # ============================================================================
+ def get_omvs_max_file_mapping_pages(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max file mapping pages."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxFileMappingPages")
+
+ def set_omvs_max_file_mapping_pages(
+ self,
+ userid: str,
+ max_file_mapping_pages: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max file mapping pages."""
+ result = self.alter(
+ userid, traits={"omvs:max_file_mapping_pages": max_file_mapping_pages}
+ )
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max Processes
+ # ============================================================================
+ def get_omvs_max_processes(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max processes."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxProcesses")
+
+ def set_omvs_max_processes(
+ self,
+ userid: str,
+ max_processes: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max processes."""
+ result = self.alter(userid, traits={"omvs:max_processes": max_processes})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max Shared Memory
+ # ============================================================================
+ def get_omvs_max_shared_memory(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's OMVS max shared memory."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxSharedMemory", string=True)
+
+ def set_omvs_max_shared_memory(
+ self,
+ userid: str,
+ max_shared_memory: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max shared memory."""
+ result = self.alter(
+ userid, traits={"omvs:max_shared_memory": max_shared_memory}
+ )
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Max Threads
+ # ============================================================================
+ def get_omvs_max_threads(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's OMVS max threads."""
+ profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
+ return self._get_field(profile, "omvs", "maxThreads")
+
+ def set_omvs_max_threads(
+ self,
+ userid: str,
+ max_threads: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's OMVS max threads."""
+ result = self.alter(userid, traits={"omvs:max_threads": max_threads})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # OMVS Home Directory
# ============================================================================
def get_omvs_home_directory(self, userid: str) -> Union[str, None, bytes]:
"""Get a user's OMVS home directory."""
profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
- return self._get_field(profile, "omvs", "homeDirectory")
+ return self._get_field(profile, "omvs", "homeDirectory", string=True)
def set_omvs_home_directory(
self,
userid: str,
- home_directory: str,
+ home_directory: Union[str, bool],
) -> Union[dict, bytes]:
"""Set a user's OMVS home directory."""
result = self.alter(userid, traits={"omvs:home_directory": home_directory})
return self._to_steps(result)
# ============================================================================
- # OMVS Program
+ # OMVS Default Shell
# ============================================================================
def get_omvs_default_shell(self, userid: str) -> Union[str, None, bytes]:
- """Get a user's OMVS program."""
+ """Get a user's OMVS default shell."""
profile = self.extract(userid, segments={"omvs": True}, profile_only=True)
- return self._get_field(profile, "omvs", "defaultShell")
+ return self._get_field(profile, "omvs", "defaultShell", string=True)
def set_omvs_default_shell(
self,
userid: str,
- program: str,
+ program: Union[str, bool],
) -> Union[dict, bytes]:
- """Set a user's OMVS program."""
+ """Set a user's OMVS default shell."""
result = self.alter(userid, traits={"omvs:default_shell": program})
return self._to_steps(result)
+ # ============================================================================
+ # TSO Account Number
+ # ============================================================================
+ def get_tso_account_number(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO account number."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "accountNumber", string=True)
+
+ def set_tso_account_number(
+ self,
+ userid: str,
+ account_number: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO account number."""
+ result = self.alter(userid, traits={"tso:account_number": account_number})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Logon Command
+ # ============================================================================
+ def get_tso_logon_command(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO logon command."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "logonCommand", string=True)
+
+ def set_tso_logon_command(
+ self,
+ userid: str,
+ logon_command: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO logon command."""
+ result = self.alter(userid, traits={"tso:logon_command": logon_command})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Hold Class
+ # ============================================================================
+ def get_tso_hold_class(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO hold class."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "holdClass", string=True)
+
+ def set_tso_hold_class(
+ self,
+ userid: str,
+ hold_class: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO hold class."""
+ result = self.alter(userid, traits={"tso:hold_class": hold_class})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Max Region Size
+ # ============================================================================
+ def get_tso_max_region_size(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's TSO max region size."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "maxRegionSize")
+
+ def set_tso_max_region_size(
+ self,
+ userid: str,
+ max_region_size: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO max region size."""
+ result = self.alter(userid, traits={"tso:max_region_size": max_region_size})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Message Class
+ # ============================================================================
+ def get_tso_message_class(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO message class."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "messageClass", string=True)
+
+ def set_tso_message_class(
+ self,
+ userid: str,
+ message_class: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO message class."""
+ result = self.alter(userid, traits={"tso:message_class": message_class})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Logon Procedure
+ # ============================================================================
+ def get_tso_logon_procedure(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO logon procedure."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "logonProcedure", string=True)
+
+ def set_tso_logon_procedure(
+ self,
+ userid: str,
+ logon_procedure: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO logon procedure."""
+ result = self.alter(userid, traits={"tso:logon_procedure": logon_procedure})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Region Size
+ # ============================================================================
+ def get_tso_region_size(self, userid: str) -> Union[int, None, bytes]:
+ """Get a user's TSO region size."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "regionSize")
+
+ def set_tso_region_size(
+ self,
+ userid: str,
+ region_size: Union[int, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO region size."""
+ result = self.alter(userid, traits={"tso:region_size": region_size})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Sysout Class
+ # ============================================================================
+ def get_tso_sysout_class(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO sysout class."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "sysoutClass", string=True)
+
+ def set_tso_sysout_class(
+ self,
+ userid: str,
+ sysout_class: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO sysout class."""
+ result = self.alter(userid, traits={"tso:sysout_class": sysout_class})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO User Data
+ # ============================================================================
+ def get_tso_user_data(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO user data."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "userData", string=True)
+
+ def set_tso_user_data(
+ self,
+ userid: str,
+ user_data: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO user data."""
+ result = self.alter(userid, traits={"tso:user_data": user_data})
+ return self._to_steps(result)
+
+ # ============================================================================
+ # TSO Data Set Allocation Unit
+ # ============================================================================
+ def get_tso_data_set_allocation_unit(self, userid: str) -> Union[str, None, bytes]:
+ """Get a user's TSO data set allocation unit."""
+ profile = self.extract(userid, segments={"tso": True}, profile_only=True)
+ return self._get_field(profile, "tso", "dataSetAllocationUnit", string=True)
+
+ def set_tso_data_set_allocation_unit(
+ self,
+ userid: str,
+ data_set_allocation_unit: Union[str, bool],
+ ) -> Union[dict, bytes]:
+ """Set a user's TSO data set allocation unit."""
+ result = self.alter(
+ userid, traits={"tso:data_set_allocation_unit": data_set_allocation_unit}
+ )
+ return self._to_steps(result)
+
# ============================================================================
# Base Functions
# ============================================================================
diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py
index 75a12aa1..3f534166 100644
--- a/tests/user/test_user_constants.py
+++ b/tests/user/test_user_constants.py
@@ -88,6 +88,12 @@ def get_sample(sample_file: str) -> Union[str, bytes]:
TEST_EXTRACT_USER_RESULT_WITH_COMMAND_AUDIT_TRAIL_XML = get_sample(
"extract_user_result_with_command_audit_trail.xml"
)
+TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML = get_sample(
+ "extract_user_result_base_omvs_tso_revoke_resume.xml"
+)
+TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY = get_sample(
+ "extract_user_result_base_omvs_tso_revoke_resume.json"
+)
# Delete User
TEST_DELETE_USER_RESULT_SUCCESS_XML = get_sample("delete_user_result_success.xml")
@@ -103,6 +109,9 @@ def get_sample(sample_file: str) -> Union[str, bytes]:
# Add User
TEST_ADD_USER_REQUEST_XML = get_sample("add_user_request.xml")
+TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_XML = get_sample(
+ "add_user_request_base_omvs_tso_revoke_resume.xml"
+)
TEST_ADD_USER_REQUEST_PASSWORD_XML = get_sample("add_user_request_password.xml")
TEST_ADD_USER_REQUEST_PASSPHRASE_XML = get_sample("add_user_request_passphrase.xml")
TEST_ADD_USER_REQUEST_PASSPHRASE_AND_PASSWORD_XML = get_sample(
@@ -117,6 +126,35 @@ def get_sample(sample_file: str) -> Union[str, bytes]:
"omvs:home_directory": "/u/squidwrd",
"omvs:default_shell": "/bin/sh",
}
+TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_TRAITS = {
+ "base:name": "Squidward",
+ "base:password": "PASSWORD",
+ "base:owner": "LEONARD",
+ "base:revoke_date": "10/22/23",
+ "base:resume_date": "11/2/23",
+ "omvs:max_address_space_size": 10485760,
+ "omvs:max_cpu_time": 1500,
+ "omvs:max_files_per_process": 50,
+ "omvs:max_non_shared_memory": "4g",
+ "omvs:max_file_mapping_pages": 350,
+ "omvs:max_processes": 128,
+ "omvs:shared": True,
+ "omvs:max_shared_memory": "2g",
+ "omvs:max_therads": 48,
+ "omvs:uid": 1919,
+ "omvs:home_directory": "/u/squidward",
+ "omvs:default_shell": "/bin/sh",
+ "tso:account_number": "D999",
+ "tso:logon_command": "ISPF",
+ "tso:hold_class": "A",
+ "tso:max_region_size": 2048,
+ "tso:message_class": "O",
+ "tso:logon_procedure": "PROC",
+ "tso:region_size": 1024,
+ "tso:sysout_class": "O",
+ "tso:user_data": "ABCD",
+ "tso:data_set_allocation_unit": "SYSDA",
+}
TEST_ADD_USER_REQUEST_TRAITS_PASSWORD = dict(TEST_ADD_USER_REQUEST_TRAITS)
TEST_ADD_USER_REQUEST_TRAITS_PASSWORD["base:password"] = "GIyTTqdF"
TEST_ADD_USER_REQUEST_TRAITS_PASSWORD_SIMPLE = dict(TEST_ADD_USER_REQUEST_TRAITS)
diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py
index 83381564..a3e8d34a 100644
--- a/tests/user/test_user_request_builder.py
+++ b/tests/user/test_user_request_builder.py
@@ -29,6 +29,17 @@ def test_user_admin_build_add_user_request(self):
)
self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_XML)
+ def test_user_admin_build_add_user_base_omvs_tso_revoke_resume_request(self):
+ result = self.user_admin.add(
+ "squidwrd",
+ traits=TestUserConstants.TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_TRAITS,
+ )
+ print(result)
+ self.assertEqual(
+ result,
+ TestUserConstants.TEST_ADD_USER_BASE_OMVS_TSO_REVOKE_RESUME_REQUEST_XML,
+ )
+
def test_user_admin_build_alter_user_request(self):
result = self.user_admin.alter(
"squidwrd", traits=TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS
diff --git a/tests/user/test_user_result_parser.py b/tests/user/test_user_result_parser.py
index c3b0ef8e..99501a82 100644
--- a/tests/user/test_user_result_parser.py
+++ b/tests/user/test_user_result_parser.py
@@ -140,6 +140,18 @@ def test_user_admin_can_parse_extract_user_and_ignore_command_audit_trail_xml(
TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_DICTIONARY,
)
+ def test_user_admin_can_parse_extract_user_base_omvs_tso_revoke_resume_success_xml(
+ self,
+ call_racf_mock: Mock,
+ ):
+ call_racf_mock.return_value = (
+ TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OVMS_TSO_REVOKE_RESUME_XML
+ )
+ self.assertEqual(
+ self.user_admin.extract("squidwrd", segments={"omvs": True, "tso": True}),
+ TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_OMVS_TSO_REVOKE_RESUME_DICTIONARY,
+ )
+
# ============================================================================
# Password and Password Phrase Redaction
# ============================================================================
diff --git a/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml
new file mode 100644
index 00000000..a69e7455
--- /dev/null
+++ b/tests/user/user_request_samples/add_user_request_base_omvs_tso_revoke_resume.xml
@@ -0,0 +1,36 @@
+
+
+
+ Squidward
+ ********
+ LEONARD
+ 10/22/23
+ 11/2/23
+
+
+ 10485760
+ 1500
+ 50
+ 4g
+ 350
+ 128
+
+ 2g
+ 1919
+ /u/squidward
+ /bin/sh
+
+
+ D999
+ ISPF
+ A
+ 2048
+ O
+ PROC
+ 1024
+ O
+ ABCD
+ SYSDA
+
+
+
\ No newline at end of file
diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json
new file mode 100644
index 00000000..817d728d
--- /dev/null
+++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.json
@@ -0,0 +1,81 @@
+{
+ "securityResult": {
+ "user": {
+ "name": "SQUIDWRD",
+ "operation": "listdata",
+ "requestId": "UserRequest",
+ "commands": [
+ {
+ "safReturnCode": 0,
+ "returnCode": 0,
+ "reasonCode": 0,
+ "image": "LISTUSER SQUIDWRD OMVS TSO ",
+ "profiles": [
+ {
+ "base": {
+ "user": "squidwrd",
+ "name": "squidwrd",
+ "owner": "leonard",
+ "created": "10/21/2023",
+ "defaultGroup": "sys1",
+ "passwordDate": null,
+ "passwordInterval": 186,
+ "passphraseDate": null,
+ "attributes": [],
+ "revokeDate": "10/22/2023",
+ "resumeDate": "11/2/2023",
+ "lastAccess": "10/21/2023 12:20 PM",
+ "classAuthorizations": [],
+ "logonAllowedDays": "anyday",
+ "logonAllowedTime": "anytime",
+ "groups": {
+ "SYS1": {
+ "auth": "use",
+ "connectOwner": "leonard",
+ "connectDate": "10/21/2023",
+ "connects": 0,
+ "uacc": null,
+ "lastConnect": "unknown",
+ "connectAttributes": [],
+ "revokeDate": null,
+ "resumeDate": null
+ }
+ },
+ "securityLevel": null,
+ "categoryAuthorization": null,
+ "securityLabel": null
+ },
+ "omvs": {
+ "uid": 1919,
+ "homeDirectory": "/u/squidward",
+ "defaultShell": "/bin/sh",
+ "maxCpuTime": 1500,
+ "maxAddressSpaceSize": 10485760,
+ "maxFilesPerProcess": 50,
+ "maxProcesses": 128,
+ "maxThreads": null,
+ "maxFileMappingPages": 350,
+ "maxNonSharedMemory": "4g",
+ "maxSharedMemory": "2g"
+ },
+ "tso": {
+ "accountNumber": "d999",
+ "holdclass": "a",
+ "messageClass": "o",
+ "logonProcedure": "proc",
+ "regionSize": 1024,
+ "maxRegionSize": 2048,
+ "sysoutClass": "o",
+ "dataSetAllocationUnit": "sysda",
+ "userData": "abcd",
+ "logonCommand": "ispf"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "returnCode": 0,
+ "reasonCode": 0
+ }
+}
\ No newline at end of file
diff --git a/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml
new file mode 100644
index 00000000..f38c2573
--- /dev/null
+++ b/tests/user/user_result_samples/extract_user_result_base_omvs_tso_revoke_resume.xml
@@ -0,0 +1,59 @@
+
+
+
+
+ 0
+ 0
+ 0
+ LISTUSER SQUIDWRD OMVS TSO
+ USER=SQUIDWRD NAME=SQUIDWRD OWNER=LEONARD CREATED=23.294
+ DEFAULT-GROUP=SYS1 PASSDATE=00.000 PASS-INTERVAL=186 PHRASEDATE=N/A
+ ATTRIBUTES=NONE
+ REVOKE DATE=OCTOBER 22, 2023 RESUME DATE=NOVEMBER 2, 2023
+ LAST-ACCESS=23.294/12:20:06
+ CLASS AUTHORIZATIONS=NONE
+ NO-INSTALLATION-DATA
+ NO-MODEL-NAME
+ LOGON ALLOWED (DAYS) (TIME)
+ ---------------------------------------------
+ ANYDAY ANYTIME
+ GROUP=SYS1 AUTH=USE CONNECT-OWNER=LEONARD CONNECT-DATE=23.294
+ CONNECTS= 00 UACC=NONE LAST-CONNECT=UNKNOWN
+ CONNECT ATTRIBUTES=NONE
+ REVOKE DATE=NONE RESUME DATE=NONE
+ SECURITY-LEVEL=NONE SPECIFIED
+ CATEGORY-AUTHORIZATION
+ NONE SPECIFIED
+ SECURITY-LABEL=NONE SPECIFIED
+
+ OMVS INFORMATION
+ ----------------
+ UID= 0000001919
+ HOME= /u/squidward
+ PROGRAM= /bin/sh
+ CPUTIMEMAX= 0000001500
+ ASSIZEMAX= 0010485760
+ FILEPROCMAX= 00000050
+ PROCUSERMAX= 00000128
+ THREADSMAX= NONE
+ MMAPAREAMAX= 00000350
+ MEMLIMIT= 4G
+ SHMEMMAX= 2G
+
+ TSO INFORMATION
+ ---------------
+ ACCTNUM= D999
+ HOLDCLASS= A
+ MSGCLASS= O
+ PROC= PROC
+ SIZE= 00001024
+ MAXSIZE= 00002048
+ SYSOUTCLASS= O
+ UNIT= SYSDA
+ USERDATA= ABCD
+ COMMAND= ISPF
+
+
+ 0
+ 0
+
\ No newline at end of file