From 6356ee450c011a78447b02056dd9544743f455b9 Mon Sep 17 00:00:00 2001 From: Tasos Papaioannou Date: Thu, 1 Aug 2024 05:34:24 -0400 Subject: [PATCH 1/3] CSV formatting fixes (#15689) --- pytest_fixtures/component/satellite_auth.py | 4 +-- robottelo/cli/hammer.py | 36 +++++++-------------- robottelo/cli/repository.py | 2 +- tests/foreman/cli/test_ldapauthsource.py | 12 +++---- tests/foreman/destructive/test_auth.py | 6 ++-- 5 files changed, 24 insertions(+), 36 deletions(-) diff --git a/pytest_fixtures/component/satellite_auth.py b/pytest_fixtures/component/satellite_auth.py index cc057169a3c..a2a5fa046fe 100644 --- a/pytest_fixtures/component/satellite_auth.py +++ b/pytest_fixtures/component/satellite_auth.py @@ -463,10 +463,10 @@ def configure_hammer_no_negotiate(parametrized_enrolled_sat): def hammer_logout(parametrized_enrolled_sat): """Logout in Hammer.""" result = parametrized_enrolled_sat.cli.Auth.logout() - assert result.split("\n")[1] == LOGGEDOUT + assert result[0]['message'] == LOGGEDOUT yield result = parametrized_enrolled_sat.cli.Auth.logout() - assert result.split("\n")[1] == LOGGEDOUT + assert result[0]['message'] == LOGGEDOUT @pytest.fixture diff --git a/robottelo/cli/hammer.py b/robottelo/cli/hammer.py index 171cba6c0e3..e04db414cee 100644 --- a/robottelo/cli/hammer.py +++ b/robottelo/cli/hammer.py @@ -4,6 +4,8 @@ import json import re +from robottelo.logging import logger + def _normalize(header): """Replace empty spaces with '-' and lower all chars""" @@ -35,31 +37,17 @@ def _normalize_obj(obj): return obj -def is_csv(output): - """Verifies if the output string is eligible for converting into CSV""" - sniffer = csv.Sniffer() - try: - sniffer.sniff(output) - return True - except csv.Error: - return False - - def parse_csv(output): - """Parse CSV output from Hammer CLI and convert it to python dictionary.""" - # ignore warning about puppet and ostree deprecation - output.replace('Puppet and OSTree will no longer be supported in Katello 3.16\n', '') - is_rex = 'Job invocation' in output - is_pkg_list = 'Nvra' in output - # Validate if the output is eligible for CSV conversions else return as it is - if not is_csv(output) and not is_rex and not is_pkg_list: - return output - output = output.splitlines()[0:2] if is_rex else output.splitlines() - reader = csv.reader(output) - # Generate the key names, spaces will be converted to dashes "-" - keys = [_normalize(header) for header in next(reader)] - # For each entry, create a dict mapping each key with each value - return [dict(zip(keys, values, strict=True)) for values in reader if len(values) > 0] + """Parse CSV output from Hammer CLI and return a Python dictionary.""" + output = output.splitlines() + + # Normalize the column names to use when generating the dictionary + try: + keys = [_normalize(header) for header in next(csv.reader(output))] + return [value for value in csv.DictReader(output[1:], fieldnames=keys)] + except csv.Error as err: + logger.error(f'Exception while parsing CSV output {output}: {err}') + raise def parse_help(output): diff --git a/robottelo/cli/repository.py b/robottelo/cli/repository.py index a04000913df..d2c93fe11b5 100644 --- a/robottelo/cli/repository.py +++ b/robottelo/cli/repository.py @@ -62,7 +62,7 @@ def synchronize(cls, options, return_raw_response=None, timeout=3600000): cls.command_sub = 'synchronize' return cls.execute( cls._construct_command(options), - output_format='base', + output_format='csv', ignore_stderr=True, return_raw_response=return_raw_response, timeout=timeout, diff --git a/tests/foreman/cli/test_ldapauthsource.py b/tests/foreman/cli/test_ldapauthsource.py index 34b7c69cb9a..ca5d06a18e4 100644 --- a/tests/foreman/cli/test_ldapauthsource.py +++ b/tests/foreman/cli/test_ldapauthsource.py @@ -102,7 +102,7 @@ def test_positive_refresh_usergroup_with_ad(self, member_group, ad_data, module_ based on user-sync """ ad_data = ad_data() - LOGEDIN_MSG = "Using configured credentials for user '{0}'." + LOGGEDIN_MSG = "Using configured credentials for user '{0}'." auth_source = module_target_sat.cli_factory.ldap_auth_source( { 'name': gen_string('alpha'), @@ -134,7 +134,7 @@ def test_positive_refresh_usergroup_with_ad(self, member_group, ad_data, module_ result = module_target_sat.cli.Auth.with_user( username=ad_data['ldap_user_name'], password=ad_data['ldap_user_passwd'] ).status() - assert LOGEDIN_MSG.format(ad_data['ldap_user_name']) in result.split("\n")[1] + assert LOGGEDIN_MSG.format(ad_data['ldap_user_name']) in result[0]['message'] module_target_sat.cli.UserGroupExternal.refresh( {'user-group-id': user_group['id'], 'name': member_group} ) @@ -221,7 +221,7 @@ def test_usergroup_sync_with_refresh(self, default_ipa_host, module_target_sat): ipa_group_base_dn = default_ipa_host.group_base_dn.replace('foobargroup', 'foreman_group') member_username = 'foreman_test' member_group = 'foreman_group' - LOGEDIN_MSG = "Using configured credentials for user '{0}'." + LOGGEDIN_MSG = "Using configured credentials for user '{0}'." auth_source_name = gen_string('alpha') auth_source = module_target_sat.cli_factory.ldap_auth_source( { @@ -262,7 +262,7 @@ def test_usergroup_sync_with_refresh(self, default_ipa_host, module_target_sat): result = module_target_sat.cli.Auth.with_user( username=member_username, password=default_ipa_host.ldap_user_passwd ).status() - assert LOGEDIN_MSG.format(member_username) in result[0]['message'] + assert LOGGEDIN_MSG.format(member_username) in result[0]['message'] with pytest.raises(CLIReturnCodeError) as error: module_target_sat.cli.Role.with_user( username=member_username, password=default_ipa_host.ldap_user_passwd @@ -308,7 +308,7 @@ def test_usergroup_with_usergroup_sync(self, default_ipa_host, module_target_sat ipa_group_base_dn = default_ipa_host.group_base_dn.replace('foobargroup', 'foreman_group') member_username = 'foreman_test' member_group = 'foreman_group' - LOGEDIN_MSG = "Using configured credentials for user '{0}'." + LOGGEDIN_MSG = "Using configured credentials for user '{0}'." auth_source_name = gen_string('alpha') auth_source = module_target_sat.cli_factory.ldap_auth_source( { @@ -349,7 +349,7 @@ def test_usergroup_with_usergroup_sync(self, default_ipa_host, module_target_sat result = module_target_sat.cli.Auth.with_user( username=member_username, password=default_ipa_host.ldap_user_passwd ).status() - assert LOGEDIN_MSG.format(member_username) in result[0]['message'] + assert LOGGEDIN_MSG.format(member_username) in result[0]['message'] list = module_target_sat.cli.Role.with_user( username=member_username, password=default_ipa_host.ldap_user_passwd ).list() diff --git a/tests/foreman/destructive/test_auth.py b/tests/foreman/destructive/test_auth.py index cf218def68e..2bfb07e6828 100644 --- a/tests/foreman/destructive/test_auth.py +++ b/tests/foreman/destructive/test_auth.py @@ -18,7 +18,7 @@ from robottelo.config import settings from robottelo.constants import HAMMER_CONFIG -LOGEDIN_MSG = "Session exists, currently logged in as '{0}'" +LOGGEDIN_MSG = "Session exists, currently logged in as '{0}'" password = gen_string('alpha') pytestmark = pytest.mark.destructive @@ -45,7 +45,7 @@ def test_positive_password_reset(target_sat): {'username': settings.server.admin_username, 'password': reset_password} ) result = target_sat.cli.Auth.with_user().status() - assert LOGEDIN_MSG.format(settings.server.admin_username) in result.split("\n")[1] + assert LOGGEDIN_MSG.format(settings.server.admin_username) in result[0]['message'] assert target_sat.cli.Org.with_user().list() @@ -72,5 +72,5 @@ def test_positive_password_reset_chosen(target_sat): {'username': settings.server.admin_username, 'password': new_password} ) result = target_sat.cli.Auth.with_user().status() - assert LOGEDIN_MSG.format(settings.server.admin_username) in result.split("\n")[1] + assert LOGGEDIN_MSG.format(settings.server.admin_username) in result[0]['message'] assert target_sat.cli.Org.with_user().list() From 162875976ae0bb3ba1fd7eb5e3c93a693f27e6ff Mon Sep 17 00:00:00 2001 From: Peter Ondrejka Date: Thu, 1 Aug 2024 13:58:40 +0200 Subject: [PATCH 2/3] test timeout_to_kill (#15162) --- tests/foreman/cli/test_remoteexecution.py | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/foreman/cli/test_remoteexecution.py b/tests/foreman/cli/test_remoteexecution.py index 5210e667adb..d6a145ca0b1 100644 --- a/tests/foreman/cli/test_remoteexecution.py +++ b/tests/foreman/cli/test_remoteexecution.py @@ -134,6 +134,51 @@ def test_positive_run_default_job_template( assert 'Exit' in out assert 'Internal Server Error' not in out + @pytest.mark.tier3 + @pytest.mark.rhel_ver_list([8]) + def test_positive_timeout_to_kill(self, module_org, rex_contenthost, module_target_sat): + """Use timeout to kill setting to cancel the job + + :id: 580f886b-ac24-4afa-9aca-e9afc5cfdc9c + + :expectedresults: Verify the job was killed after specified times + + :parametrized: yes + + :Verifies: SAT-25243 + """ + client = rex_contenthost + command = r'for run in {1..160}; do sleep 1; done' + template_id = ( + module_target_sat.api.JobTemplate() + .search(query={'search': 'name="Run Command - Script Default"'})[0] + .id + ) + invocation_command = module_target_sat.api.JobInvocation().run( + synchronous=False, + data={ + 'job_template_id': template_id, + 'organization': module_org.name, + 'inputs': { + 'command': command, + }, + 'search_query': f'name = {client.hostname}', + 'targeting_type': 'static_query', + 'execution_timeout_interval': '5', + }, + ) + sleep(10) + result = module_target_sat.api.JobInvocation(id=invocation_command['id']).read() + assert result.failed == 1 + out = module_target_sat.cli.JobInvocation.get_output( + { + 'id': invocation_command['id'], + 'host': client.hostname, + 'organization-id': module_org.id, + } + ) + assert 'Timeout for execution passed, trying to stop the job' in out + @pytest.mark.tier3 @pytest.mark.pit_client @pytest.mark.pit_server From 6bc929b792107352d06b2e4f1936615d196f1048 Mon Sep 17 00:00:00 2001 From: Peter Ondrejka Date: Thu, 1 Aug 2024 17:58:23 +0200 Subject: [PATCH 3/3] removing attach and auto-attach related items from cli hosts (#15607) --- tests/foreman/cli/test_host.py | 312 +-------------------------------- 1 file changed, 6 insertions(+), 306 deletions(-) diff --git a/tests/foreman/cli/test_host.py b/tests/foreman/cli/test_host.py index 19102ddba4f..718c4da9398 100644 --- a/tests/foreman/cli/test_host.py +++ b/tests/foreman/cli/test_host.py @@ -32,10 +32,8 @@ PRDS, REPOS, REPOSET, - SM_OVERALL_STATUS, ) from robottelo.exceptions import CLIFactoryError, CLIReturnCodeError -from robottelo.hosts import ContentHostError from robottelo.logging import logger from robottelo.utils.datafactory import ( invalid_values_list, @@ -1847,7 +1845,7 @@ def ak_with_subscription( # -------------------------- HOST SUBSCRIPTION SUBCOMMAND SCENARIOS ------------------------- -@pytest.mark.rhel_ver_match('7') +@pytest.mark.rhel_ver_match('9') @pytest.mark.cli_host_subscription @pytest.mark.tier3 def test_positive_register( @@ -1903,147 +1901,10 @@ def test_positive_register( assert len(host_subscriptions) == 0 -@pytest.mark.rhel_ver_match('7') +@pytest.mark.rhel_ver_match('9') @pytest.mark.cli_host_subscription @pytest.mark.tier3 -def test_positive_attach( - module_org, - module_promoted_cv, - module_lce, - module_ak_with_cv, - module_rhst_repo, - default_subscription, - rhel_contenthost, - target_sat, -): - """Attempt to attach a subscription to host - - :id: d5825bfb-59e3-4d49-8df8-902cc7a9d66b - - :BZ: 1199515 - - :customerscenario: true - - :expectedresults: host successfully subscribed, subscription repository - enabled, and repository package installed - - :parametrized: yes - """ - # create an activation key without subscriptions - # register the client host - target_sat.cli.Host.subscription_register( - { - 'organization-id': module_org.id, - 'content-view-id': module_promoted_cv.id, - 'lifecycle-environment-id': module_lce.id, - 'name': rhel_contenthost.hostname, - } - ) - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - result = rhel_contenthost.register(module_org, None, module_ak_with_cv.name, target_sat) - assert result.status == 0 - assert rhel_contenthost.subscribed - # attach the subscription to host - target_sat.cli.Host.subscription_attach( - { - 'host-id': host['id'], - 'subscription-id': default_subscription.id, - 'quantity': 2, - } - ) - rhel_contenthost.enable_repo(module_rhst_repo) - # ensure that katello-host-tools can be installed - try: - rhel_contenthost.install_katello_host_tools() - except ContentHostError: - pytest.fail('ContentHostError raised unexpectedly!') - - -@pytest.mark.rhel_ver_match('7') -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -def test_positive_attach_with_lce( - module_org, - module_ak_with_cv, - module_rhst_repo, - default_subscription, - rhel_contenthost, - target_sat, -): - """Attempt to attach a subscription to host, registered by lce - - :id: a362b959-9dde-4d1b-ae62-136c6ef943ba - - :BZ: 1199515 - - :customerscenario: true - - :expectedresults: host successfully subscribed, subscription - repository enabled, and repository package installed - - :parametrized: yes - """ - res = rhel_contenthost.register(module_org, None, module_ak_with_cv.name, target_sat) - assert res.status == 0, f'Failed to register host: {res.stderr}' - assert rhel_contenthost.subscribed - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - target_sat.cli.Host.subscription_attach( - { - 'host-id': host['id'], - 'subscription-id': default_subscription.id, - 'quantity': 2, - } - ) - rhel_contenthost.enable_repo(module_rhst_repo) - # ensure that katello-host-tools can be installed - try: - rhel_contenthost.install_katello_host_tools() - except ContentHostError: - pytest.fail('ContentHostError raised unexpectedly!') - - -@pytest.mark.rhel_ver_match('7') -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -def test_negative_without_attach( - module_org, module_promoted_cv, module_lce, rhel_contenthost, target_sat -): - """Register content host from satellite, register client to uuid - of that content host, as there was no attach on the client, - Test if the list of the repository subscriptions is empty - - :id: 54a2c95f-be08-4353-a96c-4bc4d96ad03d - - :expectedresults: repository list is empty - - :parametrized: yes - """ - target_sat.cli.Host.subscription_register( - { - 'organization-id': module_org.id, - 'content-view-id': module_promoted_cv.id, - 'lifecycle-environment-id': module_lce.id, - 'name': rhel_contenthost.hostname, - } - ) - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - - rhel_contenthost.register_contenthost( - module_org.name, - lce=None, # required, to jump into right branch in register_contenthost method - consumerid=host['subscription-information']['uuid'], - force=False, - ) - client_status = rhel_contenthost.subscription_manager_status() - assert SM_OVERALL_STATUS['current'] in client_status.stdout - repo_list = rhel_contenthost.subscription_manager_list_repos() - assert "This system has no repositories available through subscriptions." in repo_list.stdout - - -@pytest.mark.rhel_ver_match('7') -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -def test_negative_without_attach_with_lce( +def test_positive_without_attach_with_lce( target_sat, rhel_contenthost, function_ak_with_cv, @@ -2057,7 +1918,7 @@ def test_negative_without_attach_with_lce( :id: fc469e70-a7cb-4fca-b0ea-3c9e3dfff849 - :expectedresults: Repository enabled due to SCA. Why is this "negative"? To keep history, because pre-6.16, this would have failed. + :expectedresults: Repository enabled due to SCA. :parametrized: yes """ @@ -2085,167 +1946,7 @@ def test_negative_without_attach_with_lce( assert f"Repository '{REPOS['rhsclient7']['id']}' is enabled for this system." in res.stdout -@pytest.mark.rhel_ver_match('7') -@pytest.mark.e2e -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -@pytest.mark.upgrade -def test_positive_remove( - module_org, - module_promoted_cv, - module_lce, - ak_with_subscription, - default_subscription, - rhel_contenthost, - target_sat, -): - """Attempt to remove a subscription from content host - - :id: 3833c349-1f5b-41ac-bbac-2c1f33232d76 - - :expectedresults: subscription successfully removed from host - - :parametrized: yes - """ - target_sat.cli.Host.subscription_register( - { - 'organization-id': module_org.id, - 'content-view-id': module_promoted_cv.id, - 'lifecycle-environment-id': module_lce.id, - 'name': rhel_contenthost.hostname, - } - ) - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - host_subscriptions = target_sat.cli.ActivationKey.subscriptions( - { - 'organization-id': module_org.id, - 'id': ak_with_subscription.id, - 'host-id': host['id'], - }, - output_format='json', - ) - assert default_subscription.name not in [sub['name'] for sub in host_subscriptions] - res = rhel_contenthost.register(module_org, None, ak_with_subscription.name, target_sat) - assert res.status == 0, f'Failed to register host: {res.stderr}' - target_sat.cli.Host.subscription_attach( - { - 'host-id': host['id'], - 'subscription-id': default_subscription.id, - } - ) - host_subscriptions = target_sat.cli.ActivationKey.subscriptions( - { - 'organization-id': module_org.id, - 'id': ak_with_subscription.id, - 'host-id': host['id'], - }, - output_format='json', - ) - assert default_subscription.name in [sub['name'] for sub in host_subscriptions] - target_sat.cli.Host.subscription_remove( - { - 'host-id': host['id'], - 'subscription-id': default_subscription.id, - } - ) - host_subscriptions = target_sat.cli.ActivationKey.subscriptions( - { - 'organization-id': module_org.id, - 'id': ak_with_subscription.id, - 'host-id': host['id'], - }, - output_format='json', - ) - assert default_subscription.name not in [sub['name'] for sub in host_subscriptions] - - -@pytest.mark.rhel_ver_match('7') -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -def test_positive_auto_attach( - module_org, - module_promoted_cv, - module_lce, - module_rhst_repo, - ak_with_subscription, - rhel_contenthost, - target_sat, -): - """Attempt to auto attach a subscription to content host - - :id: e3eebf72-d512-4892-828b-70165ea4b129 - - :expectedresults: host successfully subscribed, subscription - repository enabled, and repository package installed - - :parametrized: yes - """ - target_sat.cli.Host.subscription_register( - { - 'organization-id': module_org.id, - 'content-view-id': module_promoted_cv.id, - 'lifecycle-environment-id': module_lce.id, - 'name': rhel_contenthost.hostname, - } - ) - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - - res = rhel_contenthost.register(module_org, None, ak_with_subscription.name, target_sat) - assert res.status == 0, f'Failed to register host: {res.stderr}' - target_sat.cli.Host.subscription_auto_attach({'host-id': host['id']}) - rhel_contenthost.enable_repo(module_rhst_repo) - # ensure that katello-host-tools can be installed - try: - rhel_contenthost.install_katello_host_tools() - except ContentHostError: - pytest.fail('ContentHostError raised unexpectedly!') - - -@pytest.mark.rhel_ver_match('7') -@pytest.mark.cli_host_subscription -@pytest.mark.tier3 -def test_positive_unregister_host_subscription( - module_org, module_rhst_repo, ak_with_subscription, rhel_contenthost, target_sat -): - """Attempt to unregister host subscription - - :id: 608f5b6d-4688-478e-8be8-e946771d5247 - - :expectedresults: host subscription is unregistered - - :parametrized: yes - """ - # register the host client - res = rhel_contenthost.register(module_org, None, ak_with_subscription.name, target_sat) - assert res.status == 0, f'Failed to register host: {res.stderr}' - assert rhel_contenthost.subscribed - rhel_contenthost.run('subscription-manager attach --auto') - rhel_contenthost.enable_repo(module_rhst_repo) - assert rhel_contenthost.subscribed - host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) - host_subscriptions = target_sat.cli.ActivationKey.subscriptions( - { - 'organization-id': module_org.id, - 'id': ak_with_subscription.id, - 'host-id': host['id'], - }, - output_format='json', - ) - assert len(host_subscriptions) > 0 - target_sat.cli.Host.subscription_unregister({'host': rhel_contenthost.hostname}) - with pytest.raises(CLIReturnCodeError): - # raise error that the host was not registered by - # subscription-manager register - target_sat.cli.ActivationKey.subscriptions( - { - 'organization-id': module_org.id, - 'id': ak_with_subscription.id, - 'host-id': host['id'], - } - ) - - -@pytest.mark.rhel_ver_match('7') +@pytest.mark.rhel_ver_match('9') @pytest.mark.pit_client @pytest.mark.pit_server @pytest.mark.cli_host_subscription @@ -2285,7 +1986,6 @@ def test_syspurpose_end_to_end( res = rhel_contenthost.register(module_org, None, activation_key.name, target_sat) assert res.status == 0, f'Failed to register host: {res.stderr}' assert rhel_contenthost.subscribed - rhel_contenthost.run('subscription-manager attach --auto') rhel_contenthost.enable_repo(module_rhst_repo) host = target_sat.cli.Host.info({'name': rhel_contenthost.hostname}) # Assert system purpose values are set in the host as expected @@ -2689,7 +2389,7 @@ def test_positive_update_host_owner_and_verify_puppet_class_name( @pytest.mark.cli_puppet_enabled @pytest.mark.run_in_one_thread @pytest.mark.tier2 -@pytest.mark.rhel_ver_match('[8]') +@pytest.mark.rhel_ver_match('[9]') @pytest.mark.no_containers def test_positive_create_and_update_with_content_source( target_sat,