From e6b65fb53cfb9d82b41f92f2516ebb730986b7da Mon Sep 17 00:00:00 2001 From: Jacob Callahan Date: Wed, 1 Sep 2021 16:54:31 -0400 Subject: [PATCH] Refactor ssh module This refactor completely removes paramiko as a ssh backend. All ssh interactions are now routed through broker Host objects or children of said objects. This refactor also reinforces and establishes new patterns for ssh interaction with a remote host. Finally, cleaned up tests that are no longer needed and changed behavior where necessary. --- README.rst | 3 +- docs/features/commands.rst | 2 +- docs/features/decorators.rst | 28 -- docs/features/ssh.rst | 44 +-- docs/index.rst | 14 +- pytest_fixtures/oscap_fixtures.py | 2 +- pytest_fixtures/satellite_auth.py | 5 +- pytest_fixtures/templatesync_fixtures.py | 9 +- requirements.txt | 1 - robottelo/api/utils.py | 2 +- robottelo/cli/base.py | 72 ++-- robottelo/cli/factory.py | 13 +- robottelo/cli/hammer.py | 41 +- robottelo/cli/report_template.py | 2 +- robottelo/content_info.py | 53 +++ robottelo/decorators/host.py | 65 ---- robottelo/helpers.py | 88 ++--- robottelo/host_info.py | 191 --------- robottelo/hosts.py | 26 +- robottelo/libvirt_discovery.py | 4 +- robottelo/logging.py | 1 - robottelo/manifests.py | 4 +- robottelo/remote_log.py | 44 --- robottelo/rh_cloud_utils.py | 2 +- robottelo/rhsso_utils.py | 14 +- robottelo/ssh.py | 362 +----------------- robottelo/utils/issue_handlers/bugzilla.py | 2 +- robottelo/virtwho_utils.py | 6 +- scripts/hammer_command_tree.py | 3 - tests/foreman/api/test_contentmanagement.py | 7 +- tests/foreman/api/test_contentview.py | 5 +- tests/foreman/api/test_discoveredhost.py | 21 +- tests/foreman/api/test_permission.py | 9 +- tests/foreman/api/test_template.py | 7 +- tests/foreman/api/test_templatesync.py | 95 +++-- tests/foreman/api/test_user.py | 17 +- tests/foreman/cli/test_activationkey.py | 7 +- tests/foreman/cli/test_auth.py | 14 +- tests/foreman/cli/test_content_credentials.py | 7 +- tests/foreman/cli/test_contentaccess.py | 17 +- tests/foreman/cli/test_contentview.py | 42 +- tests/foreman/cli/test_discoveredhost.py | 51 ++- tests/foreman/cli/test_hammer.py | 66 ++-- tests/foreman/cli/test_host.py | 13 +- tests/foreman/cli/test_ldapauthsource.py | 18 +- .../foreman/cli/test_lifecycleenvironment.py | 2 +- tests/foreman/cli/test_logging.py | 4 +- tests/foreman/cli/test_operatingsystem.py | 4 +- .../foreman/cli/test_oscap_tailoringfiles.py | 16 +- tests/foreman/cli/test_ostreebranch.py | 7 - tests/foreman/cli/test_ping.py | 14 +- tests/foreman/cli/test_product.py | 20 +- tests/foreman/cli/test_report.py | 5 +- tests/foreman/cli/test_reporttemplates.py | 5 +- tests/foreman/cli/test_repository.py | 128 ++++--- tests/foreman/cli/test_repository_set.py | 5 +- tests/foreman/cli/test_satellitesync.py | 152 ++++---- tests/foreman/cli/test_setting.py | 19 +- tests/foreman/cli/test_subscription.py | 5 +- tests/foreman/cli/test_syncplan.py | 9 +- tests/foreman/cli/test_templatesync.py | 13 +- tests/foreman/cli/test_user.py | 11 +- tests/foreman/endtoend/test_cli_endtoend.py | 3 +- tests/foreman/installer/test_installer.py | 16 +- tests/foreman/sys/test_dynflow.py | 9 +- tests/foreman/sys/test_fam.py | 15 +- tests/foreman/sys/test_foreman_rake.py | 6 +- tests/foreman/sys/test_hooks.py | 69 ++-- tests/foreman/sys/test_katello_certs_check.py | 2 +- tests/foreman/sys/test_pulp3_filesystem.py | 6 +- tests/foreman/sys/test_rename.py | 6 +- tests/foreman/ui/test_contenthost.py | 6 +- tests/foreman/ui/test_contentview.py | 13 +- tests/foreman/ui/test_discoveredhost.py | 4 +- tests/foreman/ui/test_ldap_authentication.py | 32 +- tests/foreman/ui/test_repository.py | 2 +- tests/foreman/ui/test_settings.py | 3 +- tests/foreman/ui/test_sync.py | 3 - tests/foreman/ui/test_templatesync.py | 11 +- tests/robottelo/test_cli.py | 34 +- tests/robottelo/test_decorators.py | 156 -------- tests/robottelo/test_hammer.py | 346 +++++++++-------- tests/robottelo/test_helpers.py | 6 +- tests/robottelo/test_host_info.py | 247 ------------ tests/robottelo/test_issue_handlers.py | 2 +- tests/robottelo/test_ssh.py | 195 +--------- tests/upgrades/test_contentview.py | 5 +- tests/upgrades/test_foreman_maintain.py | 19 +- tests/upgrades/test_performance_tuning.py | 2 +- tests/upgrades/test_satellitesync.py | 9 +- tests/upgrades/test_subscription.py | 6 +- 91 files changed, 920 insertions(+), 2231 deletions(-) create mode 100644 robottelo/content_info.py delete mode 100644 robottelo/decorators/host.py delete mode 100644 robottelo/host_info.py delete mode 100644 robottelo/remote_log.py delete mode 100644 tests/robottelo/test_host_info.py diff --git a/README.rst b/README.rst index 709e6b9b240..c3b7a27d403 100644 --- a/README.rst +++ b/README.rst @@ -25,7 +25,7 @@ automated, suited for use in a continuous integration environment, and `data driven`_. There are three types of tests: * UI tests, which rely on Selenium's `WebDriver`_ through `airgun`_. -* CLI tests, which currently rely on `Paramiko`_ , but are being converted to use `ssh2-python`_. +* CLI tests, which rely on `ssh2-python`_. * API tests, which rely on `Requests`_ through `nailgun`_. The `full documentation @@ -37,7 +37,6 @@ ReadTheDocs. It can also be generated locally:: make docs .. _data driven: http://en.wikipedia.org/wiki/Data-driven_testing -.. _Paramiko: http://www.paramiko.org/ .. _ssh2-python: https://pypi.org/project/ssh2-python/ .. _Requests: http://docs.python-requests.org/en/latest/ .. _Robottelo: https://github.com/SatelliteQE/robottelo diff --git a/docs/features/commands.rst b/docs/features/commands.rst index d5c780ea5f4..fcd06a26e76 100644 --- a/docs/features/commands.rst +++ b/docs/features/commands.rst @@ -67,7 +67,7 @@ Assuming you have ipython installed you will see a console like: In [1]: rt.ssh.command('uname -r') 2016-09-16 13:54:57 - robottelo.ssh - DEBUG - Connected to [foreman-server.com] - Out[1]: SSHCommandResult(stdout=['3.10.0-327.el7.x86_64', ''], stderr='', return_code=0, output_format=None) + Out[1]: result(stdout=['3.10.0-327.el7.x86_64', ''], stderr=(0, ''), status=0) In [2]: exit This is the Robottelo's interactive shell welcome screen and you can see some diff --git a/docs/features/decorators.rst b/docs/features/decorators.rst index 5917b178455..a4df6f90160 100644 --- a/docs/features/decorators.rst +++ b/docs/features/decorators.rst @@ -13,34 +13,6 @@ Robottelo decorators are located under control if a test must be skipped or executed accordingly with specific configurations. -skip_if_os ----------- - -``skip_if_os`` skips test based on Foreman/Satellite host os version. It -communicates with host defined on ``robottello.properties`` to get its os -version. Currently it checks only Red Hat Enterprise Linux versions. Example:: - - from robottelo.decorators.host import skip_if_os - - @skip_if_os('RHEL6') - def test_positive_create_custom_ostree_repo(self): - """Create Custom ostree repository""" - - @skip_if_os('RHEL6', 'RHEL5') - def test_negative_create_custom_ostree_repo(self): - """Create Custom ostree repository""" - -The first test will be skipped if host os is RHEL6.x.y, where x and y can be -any number. If ``RHEL6.1`` was used as parameter it would skip for any -RHEL6.1.z version and so on. - -Arbitrary number versions can be passed as parameters. On second test both RHEL -5 and 6 families would be skipped. - -This decorator is used to avoid false failures when an feature is supported -only on one os version. For example, ostree repository is available -in RHEL7 but not in RHEL6. - cacheable --------- diff --git a/docs/features/ssh.rst b/docs/features/ssh.rst index a9a7da06f0f..45c9482ebb3 100644 --- a/docs/features/ssh.rst +++ b/docs/features/ssh.rst @@ -12,25 +12,6 @@ Robottelo uses ssh extensively to access remote servers. Functions from ``robottello.ssh`` make ssh access easier and are explained on next sections. -SSHCommandResult ----------------- - -``SSHCommandResult`` represents the result of a ssh command. -It holds ``stdout`` on attribute with same name. -``stderr`` and ``return_code`` are available the same way. -An example of typical result is presented bellow:: - - SSHCommandResult( - stdout=['Red Hat Enterprise Linux Server release 7.2 (Maipo)', ''], - stderr='', - return_code=0, - output_format=None - ) - -Attribute ``output_format`` can be ``None``, ``csv`` or -``json``. -The former two options are heavily used to define output format on Hammer CLI. - Main Functions -------------- @@ -41,32 +22,15 @@ Its full signature is:: password=None, key_filename=None, timeout=10): """Executes SSH command(s) on remote hostname.""" -Most of parameters can be read from ``robottelo.properties`` file. +Most of parameters can be read from ``conf/server.yaml`` file. So in a properly configured project commands can be easily executed on host. -The function returns a ``SSHCommandResult`` instance. +The function returns a result object containing the attributes: stdout, stderr, and status. The following code was executed to generate the example of first section of this document:: >>> from robottelo import ssh >>> print(ssh.command('cat /etc/redhat-release')) - SSHCommandResult( - stdout=['Red Hat Enterprise Linux Server release 7.2 (Maipo)', ''], - stderr='', - return_code=0, - output_format=None - ) - -Another important function is ``execute_command``. -It is similar to ``command``. -But it reuses an existing connection. -So several commands can be executed on a single connection, saving resources -and execution time:: - - with ssh.get_connection(..) as connection: - ssh.execute_command('cp /orign /destiny', connection) - ssh.execute_command('chmod 0777 /destiny', connection) - ssh.execute_command("echo 'foo' > /destiny/bar") - + Red Hat Enterprise Linux Server release 7.2 (Maipo) Helper Functions ---------------- @@ -75,6 +39,4 @@ The module provide some helper functions which use ``command`` internally for common ssh operations: - **add_authorized_key**: Add public key to remote authorized keys; -- **upload_file**: Upload file to remote host; -- **download_file**: Download file from remote host; - **is_ssh_pub_key**: Validate public key. diff --git a/docs/index.rst b/docs/index.rst index 1d4c5041e21..b58e34c3c79 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -6,7 +6,7 @@ automated, suited for use in a continuous integration environment, and `data driven`_. There are three types of tests: * UI tests, which rely on Selenium's `WebDriver`_. -* CLI tests, which rely on `Paramiko`_. +* CLI tests, which rely on `ssh2-python`_. * API tests, which rely on `Requests`_. .. contents:: @@ -17,13 +17,12 @@ Quickstart The following is only a brief setup guide for `Robottelo`_. The section on `Running the Tests`_ provides a more comprehensive guide to using Robottelo. -Robottelo requires SSH access to the Satellite 6 system under test, and this -SSH access is implemented by Paramiko. Install the headers for the following to -ensure that Paramiko's dependencies build correctly: +Robottelo requires SSH access to the Satellite system under test, and this +SSH access is implemented by ssh2-python. Install the headers for the following to +ensure that ssh2-python's dependencies build correctly: * OpenSSL * Python development headers -* libffi Recommendation: Create a virtual python environment for the following setup. @@ -41,9 +40,6 @@ For python3.x:: dnf install -y gcc git libffi-devel openssl-devel python38-devel \ redhat-rpm-config libcurl-devel libxml2-devel -For more information, see `Paramiko: Installing -`_. - Get the source code and install dependencies:: $ git clone git://github.com/SatelliteQE/robottelo.git @@ -289,7 +285,7 @@ The design and development for this software is led by `Og Maciel`_. .. _graphviz: http://graphviz.org/ .. _nose: https://nose.readthedocs.org/en/latest/index.html .. _Og Maciel: http://www.ogmaciel.com -.. _Paramiko: http://www.paramiko.org/ +.. _ssh2-python: https://pypi.org/project/ssh2-python/ .. _Pytest: https://docs.pytest.org/en/latest/contents.html .. _Requests: http://docs.python-requests.org/en/latest/ .. _Robottelo: https://github.com/SatelliteQE/robottelo diff --git a/pytest_fixtures/oscap_fixtures.py b/pytest_fixtures/oscap_fixtures.py index b9f15504cab..d7af8f0059a 100644 --- a/pytest_fixtures/oscap_fixtures.py +++ b/pytest_fixtures/oscap_fixtures.py @@ -25,7 +25,7 @@ def tailoring_file_path(): def oscap_content_path(default_sat): """Download scap content from satellite and return local path of it.""" local_file = robottelo_tmp_dir.joinpath(PurePath(settings.oscap.content_path).name) - default_sat.download(remote_path=settings.oscap.content_path, local_path=local_file) + default_sat.put(remote_path=settings.oscap.content_path, local_path=local_file) return local_file diff --git a/pytest_fixtures/satellite_auth.py b/pytest_fixtures/satellite_auth.py index 6d0a015ab4c..252a7dcc2a7 100644 --- a/pytest_fixtures/satellite_auth.py +++ b/pytest_fixtures/satellite_auth.py @@ -335,10 +335,9 @@ def enroll_ad_and_configure_external_auth(request, ad_data): # update the AD name server run_command(cmd='chattr -i /etc/resolv.conf') - result = run_command( + line_number = run_command( cmd="awk -v search='nameserver' '$0~search{print NR; exit}' /etc/resolv.conf" ) - line_number = int(''.join(result)) run_command(cmd=f'sed -i "{line_number}i nameserver {ad_data.nameserver}" /etc/resolv.conf') run_command(cmd='chattr +i /etc/resolv.conf') @@ -350,7 +349,7 @@ def enroll_ad_and_configure_external_auth(request, ad_data): # gather the apache id result = run_command(cmd='id -u apache') - id_apache = "".join(result) + id_apache = result http_conf_content = ( f'[service/HTTP]\nmechs = krb5\ncred_store = keytab:/etc/krb5.keytab' f'\ncred_store = ccache:/var/lib/gssproxy/clients/krb5cc_%U' diff --git a/pytest_fixtures/templatesync_fixtures.py b/pytest_fixtures/templatesync_fixtures.py index e93119c4624..ee2fe9d5c22 100644 --- a/pytest_fixtures/templatesync_fixtures.py +++ b/pytest_fixtures/templatesync_fixtures.py @@ -1,12 +1,11 @@ import pytest from fauxfactory import gen_string -from robottelo import ssh from robottelo.constants import FOREMAN_TEMPLATE_ROOT_DIR @pytest.fixture() -def create_import_export_local_dir(): +def create_import_export_local_dir(default_sat): """Creates a local directory inside root_dir on satellite from where the templates will be imported from or exported to. @@ -18,13 +17,13 @@ def create_import_export_local_dir(): root_dir = FOREMAN_TEMPLATE_ROOT_DIR dir_path = f'{root_dir}/{dir_name}' # Creating the directory and set the write context - ssh.command( + default_sat.execute( f'mkdir -p {dir_path} && ' f'chown foreman -R {root_dir} && ' f'restorecon -R -v {root_dir} && ' f'chcon -t httpd_sys_rw_content_t {dir_path} -R' ) # Copying the file to new directory to be modified by tests - ssh.command(f'cp example_template.erb {dir_path}') + default_sat.execute(f'cp example_template.erb {dir_path}') yield dir_name, dir_path - ssh.command(f'rm -rf {dir_path}') + default_sat.execute(f'rm -rf {dir_path}') diff --git a/requirements.txt b/requirements.txt index 1ea500d39fb..e68e3108be2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,6 @@ fauxfactory==3.1.0 Inflector==3.0.1 jinja2==3.0.1 navmazing==1.1.6 -paramiko==2.7.2 pexpect==4.8.0 productmd==1.32 pyotp==2.6.0 diff --git a/robottelo/api/utils.py b/robottelo/api/utils.py index 4fe195284bf..2943f322eeb 100644 --- a/robottelo/api/utils.py +++ b/robottelo/api/utils.py @@ -630,7 +630,7 @@ def wait_for_syncplan_tasks(repo_backend_id=None, timeout=10, repo_name=None): # Fetch the Pulp password pulp_pass = ssh.command( 'grep "^default_password" /etc/pulp/server.conf | awk \'{print $2}\'' - ).stdout[0] + ).stdout.splitlinies()[0] # Set the Timeout value timeup = time.time() + int(timeout) * 60 # Search Filter to filter out the task based on backend-id and sync action diff --git a/robottelo/cli/base.py b/robottelo/cli/base.py index 6fd29635712..6554cfe25cd 100644 --- a/robottelo/cli/base.py +++ b/robottelo/cli/base.py @@ -17,30 +17,30 @@ class CLIBaseError(Exception): """Indicates that a CLI command has finished with return code different from zero. - :param return_code: CLI command return code + :param status: CLI command return code :param stderr: contents of the ``stderr`` :param msg: explanation of the error """ - def __init__(self, return_code, stderr, msg): - self.return_code = return_code + def __init__(self, status, stderr, msg): + self.status = status self.stderr = stderr self.msg = msg super().__init__(msg) self.message = msg def __str__(self): - """Include class name, return_code, stderr and msg to string repr so + """Include class name, status, stderr and msg to string repr so assertRaisesRegexp can be used to assert error present on any attribute """ return repr(self) def __repr__(self): - """Include class name return_code, stderr and msg to improve logging""" - return '{}(return_code={!r}, stderr={!r}, msg={!r}'.format( - type(self).__name__, self.return_code, self.stderr, self.msg + """Include class name status, stderr and msg to improve logging""" + return '{}(status={!r}, stderr={!r}, msg={!r}'.format( + type(self).__name__, self.status, self.stderr, self.msg ) @@ -73,25 +73,30 @@ class Base: @classmethod def _handle_response(cls, response, ignore_stderr=None): - """Verify ``return_code`` of the CLI command. + """Verify ``status`` of the CLI command. Check for a non-zero return code or any stderr contents. - :param response: a ``SSHCommandResult`` object, returned by - :mod:`robottelo.ssh.command`. + :param response: a result object, returned by :mod:`robottelo.ssh.command`. :param ignore_stderr: indicates whether to throw a warning in logs if ``stderr`` is not empty. :returns: contents of ``stdout``. :raises robottelo.cli.base.CLIReturnCodeError: If return code is different from zero. """ - if response.return_code != 0: + if isinstance(response.stderr, tuple): + # the current contents of response.stderr is a tuple with the following properties + # (,). + # This behavior could (and maybe should) change in the near future. + # In the meantime, we don't need it here so we just use the message itself + response.stderr = response.stderr[1] + if response.status != 0: full_msg = ( f'Command "{cls.command_base} {cls.command_sub}" ' - f'finished with return_code {response.return_code}\n' + f'finished with status {response.status}\n' f'stderr contains:\n{response.stderr}' ) - error_data = (response.return_code, response.stderr, full_msg) + error_data = (response.status, response.stderr, full_msg) if cls._db_error_regex.search(full_msg): raise CLIDataBaseError(*error_data) raise CLIReturnCodeError(*error_data) @@ -107,9 +112,7 @@ def add_operating_system(cls, options=None): cls.command_sub = 'add-operatingsystem' - result = cls.execute(cls._construct_command(options)) - - return result + return cls.execute(cls._construct_command(options)) @classmethod def create(cls, options=None, timeout=None): @@ -222,13 +225,10 @@ def execute( timeout=None, ignore_stderr=None, return_raw_response=None, - connection_timeout=None, ): """Executes the cli ``command`` on the server via ssh""" user, password = cls._get_username_password(user, password) - time_hammer = False - if settings.performance: - time_hammer = settings.performance.time_hammer + time_hammer = settings.performance.time_hammer # add time to measure hammer performance cmd = 'LANG={} {} hammer -v {} {} {} {}'.format( @@ -244,7 +244,6 @@ def execute( hostname=hostname or cls.hostname, output_format=output_format, timeout=timeout, - connection_timeout=connection_timeout, ) if return_raw_response: return response @@ -310,12 +309,13 @@ def list(cls, options=None, per_page=True, output_format='csv'): if 'per-page' not in options and per_page: options['per-page'] = 10000 - if cls.command_requires_org and 'organization-id' not in options: - raise CLIError(f'organization-id option is required for {cls.__name__}.list') - - result = cls.execute(cls._construct_command(options), output_format=output_format) + # With the introduction of hammer defaults, a default organization can be set + # this makes getting around this check awkward. + # should we completely remove this or implement a workaround? + # if cls.command_requires_org and 'organization-id' not in options: + # raise CLIError(f'organization-id option is required for {cls.__name__}.list') - return result + return cls.execute(cls._construct_command(options), output_format=output_format) @classmethod def puppetclasses(cls, options=None): @@ -325,9 +325,7 @@ def puppetclasses(cls, options=None): cls.command_sub = 'puppet-classes' - result = cls.execute(cls._construct_command(options), output_format='csv') - - return result + return cls.execute(cls._construct_command(options), output_format='csv') @classmethod def remove_operating_system(cls, options=None): @@ -337,9 +335,7 @@ def remove_operating_system(cls, options=None): cls.command_sub = 'remove-operatingsystem' - result = cls.execute(cls._construct_command(options)) - - return result + return cls.execute(cls._construct_command(options)) @classmethod def sc_params(cls, options=None): @@ -349,9 +345,7 @@ def sc_params(cls, options=None): cls.command_sub = 'sc-params' - result = cls.execute(cls._construct_command(options), output_format='csv') - - return result + return cls.execute(cls._construct_command(options), output_format='csv') @classmethod def set_parameter(cls, options=None): @@ -361,9 +355,7 @@ def set_parameter(cls, options=None): cls.command_sub = 'set-parameter' - result = cls.execute(cls._construct_command(options)) - - return result + return cls.execute(cls._construct_command(options)) @classmethod def update(cls, options=None, return_raw_response=None): @@ -373,14 +365,12 @@ def update(cls, options=None, return_raw_response=None): cls.command_sub = 'update' - result = cls.execute( + return cls.execute( cls._construct_command(options), output_format='csv', return_raw_response=return_raw_response, ) - return result - @classmethod def with_user(cls, username=None, password=None): """Context Manager for credentials""" diff --git a/robottelo/cli/factory.py b/robottelo/cli/factory.py index b73fb30d9f1..57b04a513e8 100644 --- a/robottelo/cli/factory.py +++ b/robottelo/cli/factory.py @@ -75,7 +75,6 @@ from robottelo.helpers import get_available_capsule_port from robottelo.helpers import update_dictionary from robottelo.logging import logger -from robottelo.ssh import upload_file ORG_KEYS = ['organization', 'organization-id', 'organization-label'] @@ -365,7 +364,7 @@ def make_gpg_key(options=None): } # Upload file to server - ssh.upload_file(local_file=key_filename, remote_file=args['key']) + ssh.get_client().put(key_filename, args['key']) return create_object(GPGKey, args, options) @@ -405,7 +404,7 @@ def make_content_credential(options=None): } # Upload file to server - ssh.upload_file(local_file=key_filename, remote_file=args['path']) + ssh.get_client().put(key_filename, args['path']) return create_object(ContentCredential, args, options) @@ -489,7 +488,7 @@ def make_partition_table(options=None): } # Upload file to server - ssh.upload_file(local_file=layout, remote_file=args['file']) + ssh.get_client().put(layout, args['file']) return create_object(PartitionTable, args, options) @@ -1586,7 +1585,7 @@ def make_template(options=None): with open(layout, 'w') as ptable: ptable.write(content) # Upload file to server - ssh.upload_file(local_file=layout, remote_file=args['file']) + ssh.get_client().put(layout, args['file']) # End - Special handling for template factory return create_object(Template, args, options) @@ -1833,7 +1832,7 @@ def _setup_org_for_a_rh_repo(options=None): env_id = options['lifecycle-environment-id'] # Clone manifest and upload it with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + ssh.get_client().put(manifest.content, manifest.filename) try: Subscription.upload({'file': manifest.filename, 'organization-id': org_id}) except CLIReturnCodeError as err: @@ -1971,7 +1970,7 @@ def setup_org_for_a_rh_repo(options=None, force_manifest_upload=False, force_use result = setup_org_for_a_custom_repo(options) if force_manifest_upload: with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + ssh.get_client().put(manifest.content, manifest.filename) try: Subscription.upload( {'file': manifest.filename, 'organization-id': result.get('organization-id')} diff --git a/robottelo/cli/hammer.py b/robottelo/cli/hammer.py index df3214d97f4..f6ddb11b4f3 100644 --- a/robottelo/cli/hammer.py +++ b/robottelo/cli/hammer.py @@ -1,35 +1,9 @@ """Helpers to interact with hammer command line utility.""" import csv -import io import json import re -def _csv_reader(output): - """An unicode CSV reader which processes unicode strings and return unicode - strings data. - - This is needed because the builtin module does not support unicode strings, - from Python 2 docs:: - - Note: This version of the csv module doesn't support Unicode input. - Also, there are currently some issues regarding ASCII NUL characters. - Accordingly, all input should be UTF-8 or printable ASCII to be safe;" - - On Python 3 this generator is not needed because the default string type is - unicode. - - :param output: can be any object which supports the iterator protocol and - returns a unicode string each time its next() method is called. - :return: generator that will yield a list of unicode string values. - - """ - data = '\n'.join(output) - handler = io.StringIO(data) - - yield from csv.reader(handler) - - def _normalize(header): """Replace empty spaces with '-' and lower all chars""" return header.replace(' ', '-').lower() @@ -62,14 +36,9 @@ def _normalize_obj(obj): def parse_csv(output): """Parse CSV output from Hammer CLI and convert it to python dictionary.""" - try: - warning_index = output.index( - 'Puppet and OSTree will no longer be supported in Katello 3.16' - ) - output = output[warning_index + 1 :] # noqa: E203 - except ValueError: - pass - reader = _csv_reader(output) + # ignore warning about puppet and ostree deprecation + output.replace('Puppet and OSTree will no longer be supported in Katello 3.16\n', '') + reader = csv.reader(output.splitlines()) # 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 @@ -93,7 +62,7 @@ def parse_help(output): ) subcommand_regex = re.compile(r'^ (?P[\w-]+)?(, [\w-]+)?\s+(?P.*)$') - for line in output: + for line in output.splitlines(): if len(line.strip()) == 0: continue if line.startswith('Subcommands:'): @@ -202,7 +171,7 @@ def parse_info(output): sub_num = None # is not None when list of properties second_level_key = None # is set when a possible second level is detected - for line in output: + for line in output.splitlines(): # skip empty lines and dividers if line == '' or line == '---': continue diff --git a/robottelo/cli/report_template.py b/robottelo/cli/report_template.py index 698da0f50c2..8940531248d 100644 --- a/robottelo/cli/report_template.py +++ b/robottelo/cli/report_template.py @@ -69,7 +69,7 @@ def create(cls, options=None): file_data = file.read() with open(layout, 'w') as rt: rt.write(file_data) - ssh.upload_file(local_file=layout, remote_file=layout) + ssh.get_client().put(layout, layout) # -------------------------------------- # options['file'] = layout diff --git a/robottelo/content_info.py b/robottelo/content_info.py new file mode 100644 index 00000000000..5e6cde39914 --- /dev/null +++ b/robottelo/content_info.py @@ -0,0 +1,53 @@ +"""Module that gather several informations about host""" +from robottelo import ssh +from robottelo.cli.base import CLIReturnCodeError + + +def get_repo_files(repo_path, extension='rpm', hostname=None): + """Returns a list of repo files (for example rpms) in specific repository + directory. + + :param str repo_path: unix path to the repo, e.g. '/var/lib/pulp/fooRepo/' + :param str extension: extension of searched files. Defaults to 'rpm' + :param str optional hostname: hostname or IP address of the remote host. If + ``None`` the hostname will be get from ``main.server.hostname`` config. + :return: list representing rpm package names + :rtype: list + """ + if not repo_path.endswith('/'): + repo_path += '/' + result = ssh.command( + f"find {repo_path} -name '*.{extension}' | awk -F/ '{{print $NF}}'", + hostname=hostname, + ) + if result.status != 0: + raise CLIReturnCodeError(result.status, result.stderr, f'No .{extension} found') + # strip empty lines and sort alphabetically (as order may be wrong because + # of different paths) + return sorted(repo_file for repo_file in result.stdout.splitlines() if repo_file) + + +def get_repomd_revision(repo_path, hostname=None): + """Fetches a revision of repository. + + :param str repo_path: unix path to the repo, e.g. '/var/lib/pulp/fooRepo' + :param str optional hostname: hostname or IP address of the remote host. If + ``None`` the hostname will be get from ``main.server.hostname`` config. + :return: string containing repository revision + :rtype: str + """ + repomd_path = 'repodata/repomd.xml' + result = ssh.command( + f"grep -oP '(?<=).*?(?=)' {repo_path}/{repomd_path}", + hostname=hostname, + ) + # strip empty lines + stdout = [line for line in result.stdout.splitlines() if line] + if result.status != 0 or len(stdout) != 1: + raise CLIReturnCodeError( + result.status, + result.stderr, + f'Unable to fetch revision for {repo_path}. Please double check your ' + 'hostname, path and contents of repomd.xml', + ) + return stdout[0] diff --git a/robottelo/decorators/host.py b/robottelo/decorators/host.py deleted file mode 100644 index 3ff1040722f..00000000000 --- a/robottelo/decorators/host.py +++ /dev/null @@ -1,65 +0,0 @@ -"""Implements decorator regarding satellite host""" -from functools import wraps - -import unittest2 - -from robottelo.config import settings -from robottelo.host_info import get_host_os_version -from robottelo.logging import logger - - -def skip_if_os(*versions): - """Decorator to skip tests based on host version - - If the calling function uses 'RHEL6' - test will be skipped for RHEL6, - but will run for whatever another version, e.g, RHEL5, RHEL6.1, RHEL7, - and so on - - Note: If the version can't be obtained, tests will run - - Usage: - - To skip a specific test:: - - from robottelo.decorators.host import skip_if_host_is - - @skip_if_os('RHEL6') - def test_hostgroup_create(): - # test code continues here - - :param tuple versions: args containing host versions for which test - must be skipped - :returns: ``unittest2.skipIf`` - """ - versions = set(map(lambda s: s.upper(), versions)) - - def decorator(func): - """Wrap test methods in order to skip them accordingly with host - version. - """ - - @wraps(func) - def wrapper(*args, **kwargs): - """Wrapper that will skip the test if one of defined versions - match host's version. - """ - - def log_version_info(msg, template): - logger.debug(template, func.__name__, func.__module__, msg) - - if not settings.configured: - settings.configure() - - host_version = get_host_os_version() - - if any(host_version.startswith(version) for version in versions): - skip_msg = f'host {host_version} in ignored versions {versions}' - skip_template = 'Skipping test %s in module %s due to %s' - log_version_info(skip_msg, skip_template) - raise unittest2.SkipTest(skip_msg) - - return func(*args, **kwargs) - - return wrapper - - return decorator diff --git a/robottelo/helpers.py b/robottelo/helpers.py index 44c3f60847c..cb937671efb 100644 --- a/robottelo/helpers.py +++ b/robottelo/helpers.py @@ -8,6 +8,9 @@ from urllib.parse import urljoin # noqa import requests +from cryptography.hazmat.backends import default_backend as crypto_default_backend +from cryptography.hazmat.primitives import serialization as crypto_serialization +from cryptography.hazmat.primitives.asymmetric import rsa from nailgun.config import ServerConfig from robottelo import ssh @@ -20,6 +23,21 @@ from robottelo.logging import logger +def gen_ssh_keypairs(): + key = rsa.generate_private_key( + backend=crypto_default_backend(), public_exponent=65537, key_size=2048 + ) + private = key.private_bytes( + crypto_serialization.Encoding.PEM, + crypto_serialization.PrivateFormat.TraditionalOpenSSL, + crypto_serialization.NoEncryption(), + ) + public = key.public_key().public_bytes( + crypto_serialization.Encoding.OpenSSH, crypto_serialization.PublicFormat.OpenSSH + ) + return private.decode('utf-8'), public.decode('utf-8') + + class DataFileError(Exception): """Indicates any issue when reading a data file.""" @@ -107,7 +125,7 @@ def file_downloader(file_url, local_path=None, file_name=None, hostname=None): # download on any server. else: result = ssh.command(f'wget -O {local_path}{file_name} {file_url}', hostname=hostname) - if result.return_code != 0: + if result.status != 0: raise DownloadFileError(f'Unable to download {file_name}') return [f'{local_path}{file_name}', file_name] @@ -201,9 +219,9 @@ def md5_by_url(url, hostname=None): f'wget -qO - {url} | tee {filename} | md5sum | awk \'{{print $1}}\'', hostname=hostname, ) - if result.return_code != 0: + if result.status != 0: raise AssertionError(f'Failed to calculate md5 checksum of {filename}') - return result.stdout[0] + return result.stdout def validate_ssh_pub_key(key): @@ -263,11 +281,13 @@ def get_available_capsule_port(port_pool=None): # converts a List of strings to a List of integers try: print(ss_cmd) - used_ports = map(int, [val for val in ss_cmd.stdout[:-1] if val != 'Cannot stat file ']) + used_ports = map( + int, [val for val in ss_cmd.stdout.splitlines()[:-1] if val != 'Cannot stat file '] + ) except ValueError: raise CapsuleTunnelError( - f'Failed parsing the port numbers from stdout: {ss_cmd.stdout[:-1]}' + f'Failed parsing the port numbers from stdout: {ss_cmd.stdout.splitlines()[:-1]}' ) try: # take the list of available ports and return randomly selected one @@ -287,6 +307,7 @@ def default_url_on_new_port(oldport, newport): :rtype: str """ + # TODO!!! domain = settings.server.hostname with ssh.get_connection() as connection: @@ -412,8 +433,8 @@ def create_repo(name, repo_fetch_url=None, packages=None, wipe_repodata=False, h """ repo_path = f'{PULP_PUBLISHED_YUM_REPOS_PATH}/{name}' result = ssh.command(f'sudo -u apache mkdir -p {repo_path}', hostname=hostname) - if result.return_code != 0: - raise CLIReturnCodeError(result.return_code, result.stderr, 'Unable to create repo dir') + if result.status != 0: + raise CLIReturnCodeError(result.status, result.stderr, 'Unable to create repo dir') if repo_fetch_url: # Add trailing slash if it's not there already if not repo_fetch_url.endswith('/'): @@ -423,22 +444,22 @@ def create_repo(name, repo_fetch_url=None, packages=None, wipe_repodata=False, h f'wget -P {repo_path} {urljoin(repo_fetch_url, package)}', hostname=hostname, ) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, + result.status, result.stderr, f'Unable to download package {package}', ) if wipe_repodata: result = ssh.command(f'rm -rf {repo_path}/repodata/', hostname=hostname) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, result.stderr, 'Unable to delete repodata folder' + result.status, result.stderr, 'Unable to delete repodata folder' ) result = ssh.command(f'createrepo {repo_path}', hostname=hostname) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, + result.status, result.stderr, f'Unable to create repository. stderr contains following info:\n{result.stderr}', ) @@ -468,20 +489,20 @@ def repo_add_updateinfo(name, updateinfo_url=None, hostname=None): updatefile_path = f'{repo_path}/{updatefile}' if updateinfo_url: result = ssh.command(f'find {updatefile_path}', hostname=hostname) - if result.return_code == 0 and updatefile in result.stdout[0]: + if result.status == 0 and updatefile in result.stdout: result = ssh.command( f'mv -f {updatefile_path} {updatefile_path}.bak', hostname=hostname ) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, + result.status, result.stderr, f'Unable to backup existing {updatefile}', ) result = ssh.command(f'wget -O {updatefile_path} {updateinfo_url}', hostname=hostname) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, result.stderr, f'Unable to download {updateinfo_url}' + result.status, result.stderr, f'Unable to download {updateinfo_url}' ) result = ssh.command(f'modifyrepo {updatefile_path} {repo_path}/repodata/') @@ -489,35 +510,6 @@ def repo_add_updateinfo(name, updateinfo_url=None, hostname=None): return result -def extract_capsule_satellite_installer_command(text): - """Extract satellite installer command from capsule-certs-generate command - output - """ - cmd_start_with = 'satellite-installer' - cmd_lines = [] - if text: - if isinstance(text, (list, tuple)): - lines = text - else: - lines = text.split('\n') - cmd_start_found = False - cmd_end_found = False - for line in lines: - if line.lstrip().startswith(cmd_start_with): - cmd_start_found = True - if cmd_start_found and not cmd_end_found: - cmd_lines.append(line.strip('\\')) - if not line.endswith('\\'): - cmd_end_found = True - if cmd_lines: - cmd = ' '.join(cmd_lines) - # remove empty spaces - while ' ' in cmd: - cmd = cmd.replace(' ', ' ') - return cmd - return None - - def extract_ui_token(input): """Extracts and returns the CSRF protection token from a given HTML string""" @@ -560,7 +552,7 @@ def host_provisioning_check(ip_addr): result = ssh.command( f'for i in {{1..60}}; do ping -c1 {ip_addr} && exit 0; sleep 20; done; exit 1' ) - if result.return_code != 0: + if result.status != 0: raise ProvisioningCheckError(f'Failed to ping virtual machine Error:{result.stdout}') diff --git a/robottelo/host_info.py b/robottelo/host_info.py deleted file mode 100644 index 9b9218512db..00000000000 --- a/robottelo/host_info.py +++ /dev/null @@ -1,191 +0,0 @@ -"""Module that gather several informations about host""" -import functools -import re - -import requests -from packaging.version import Version -from ssh2.exceptions import AuthenticationError - -from robottelo import ssh -from robottelo.cli.base import CLIReturnCodeError -from robottelo.config import settings -from robottelo.constants import SATELLITE_VERSION -from robottelo.hosts import ContentHostError -from robottelo.hosts import Satellite -from robottelo.logging import logger - - -@functools.lru_cache(maxsize=1) -def get_host_os_version(): - """Fetches host's OS version through SSH - :return: str with version - """ - cmd = ssh.command('cat /etc/redhat-release') - if cmd.stdout: - version_description = cmd.stdout[0] - version_re = r'Red Hat Enterprise Linux Server release (?P\d(\.\d)*)' - result = re.search(version_re, version_description) - if result: - host_os_version = f'RHEL{result.group("version")}' - logger.debug(f'Host version: {host_os_version}') - return host_os_version - - logger.warning(f'Host version not available: {cmd!r}') - return 'Not Available' - - -_SAT_6_2_VERSION_COMMAND = 'rpm -q satellite' - -_SAT_6_1_VERSION_COMMAND = 'grep "VERSION" /usr/share/foreman/lib/satellite/version.rb' - - -@functools.lru_cache(maxsize=1) -def get_host_sat_version(): - """Fetches host's Satellite version through SSH - :return: Satellite version - :rtype: version - """ - commands = ( - _extract_sat_version(c) for c in (_SAT_6_2_VERSION_COMMAND, _SAT_6_1_VERSION_COMMAND) - ) - for version, ssh_result in commands: - if version != 'Not Available': - logger.debug(f'Host Satellite version: {version}') - return version - - logger.warning(f'Host Satellite version not available: {ssh_result!r}') - return version - - -def _extract_sat_version(ssh_cmd): - """Extracts Satellite version if possible or 'Not Available' otherwise - - :param ssh_cmd: str ssh command - :return: Satellite version - :rtype: str - """ - ssh_result = ssh.command(ssh_cmd) - if ssh_result.stdout: - version_description = ssh_result.stdout[0] - version_re = r'[^\d]*(?P\d(\.\d){1})' - result = re.search(version_re, version_description) - if result: - host_sat_version = result.group('version') - return host_sat_version, ssh_result - - return 'Not Available', ssh_result - - -def get_repo_files(repo_path, extension='rpm', hostname=None): - """Returns a list of repo files (for example rpms) in specific repository - directory. - - :param str repo_path: unix path to the repo, e.g. '/var/lib/pulp/fooRepo/' - :param str extension: extension of searched files. Defaults to 'rpm' - :param str optional hostname: hostname or IP address of the remote host. If - ``None`` the hostname will be get from ``main.server.hostname`` config. - :return: list representing rpm package names - :rtype: list - """ - if not repo_path.endswith('/'): - repo_path += '/' - result = ssh.command( - f"find {repo_path} -name '*.{extension}' | awk -F/ '{{print $NF}}'", - hostname=hostname, - ) - if result.return_code != 0: - raise CLIReturnCodeError(result.return_code, result.stderr, f'No .{extension} found') - # strip empty lines and sort alphabetically (as order may be wrong because - # of different paths) - return sorted(repo_file for repo_file in result.stdout if repo_file) - - -def get_repo_files_by_url(url, extension='rpm'): - """Returns a list of repo files (for example rpms) in a specific repository - published at some url. - - :param url: url where the repo or CV is published - :param extension: extension of searched files. Defaults to 'rpm' - :return: list representing rpm package names - """ - if not url.endswith('/'): - url += '/' - - result = requests.get(url, verify=False) - if result.status_code != 200: - raise requests.HTTPError(f'{url} is not accessible') - - links = re.findall(r'(?<=href=").*?(?=">)', result.text) - - if 'Packages/' not in links: - return sorted(line for line in links if extension in line) - - files = [] - subs = get_repo_files_by_url(f'{url}Packages/', extension='/') - for sub in subs: - files.extend(get_repo_files_by_url(f'{url}Packages/{sub}', extension)) - - return sorted(files) - - -def get_repomd_revision(repo_url): - """Fetches a revision of a repository. - - :param str repo_url: the 'Published_At' link of a repo - :return: string containing repository revision - :rtype: str - """ - repomd_path = 'repodata/repomd.xml' - result = requests.get(f'{repo_url}/{repomd_path}', verify=False) - if result.status_code != 200: - raise requests.HTTPError(f'{repo_url}/{repomd_path} is not accessible') - - match = re.search('(?<=).*?(?=)', result.text) - if not match: - raise ValueError(f' not found in {repo_url}/{repomd_path}') - - return match.group(0) - - -class SatVersionDependentValues: - """Class which return values depending on Satellite host version""" - - def __init__(self, *dcts, **kwargs): - """ - Hold values for different Satellite versions. - Each value of ``dcts`` must be a dictionary with form {version:dict} - :param dcts: dct - """ - self._common = kwargs.get('common', {}) - self._versioned_values = {} - for dct in dcts: - self._versioned_values.update(dct) - - def __getitem__(self, item): - """ - Return value dependent on Satellite version - :param item: str - :return: respective Satellite version values - """ - - sat_version = get_host_sat_version() - try: - return self._versioned_values[sat_version][item] - except KeyError: - return self._common[item] - - -def get_sat_version(): - """Try to read sat_version from envvar SATELLITE_VERSION - if not available fallback to ssh connection to get it.""" - - try: - sat_version = Satellite().version - except (AuthenticationError, ContentHostError): - if hasattr(settings.server.version, 'release'): - sat_version = str(settings.server.version.release) - elif hasattr(settings.robottelo, 'satellite_version'): - sat_version = settings.robottelo.satellite_version - else: - sat_version = SATELLITE_VERSION - return Version('9999' if 'nightly' in sat_version else sat_version) diff --git a/robottelo/hosts.py b/robottelo/hosts.py index c1a847c442f..1dd96aaef30 100644 --- a/robottelo/hosts.py +++ b/robottelo/hosts.py @@ -13,6 +13,7 @@ from fauxfactory import gen_string from nailgun import entities from packaging.version import Version +from ssh2.exceptions import AuthenticationError from wait_for import TimedOutError from wait_for import wait_for from wrapanapi.entities.vm import VmState @@ -27,6 +28,7 @@ from robottelo.constants import CUSTOM_PUPPET_MODULE_REPOS_PATH from robottelo.constants import CUSTOM_PUPPET_MODULE_REPOS_VERSION from robottelo.constants import HAMMER_CONFIG +from robottelo.constants import SATELLITE_VERSION from robottelo.helpers import get_data_file from robottelo.helpers import InstallerCommand from robottelo.helpers import validate_ssh_pub_key @@ -40,6 +42,22 @@ } +def get_sat_version(): + """Try to read sat_version from envvar SATELLITE_VERSION + if not available fallback to ssh connection to get it.""" + + try: + sat_version = Satellite().version + except (AuthenticationError, ContentHostError): + if hasattr(settings.server.version, 'release'): + sat_version = str(settings.server.version.release) + elif hasattr(settings.robottelo, 'satellite_version'): + sat_version = settings.robottelo.satellite_version + else: + sat_version = SATELLITE_VERSION + return Version('9999' if 'nightly' in sat_version else sat_version) + + def setup_capsule(satellite, capsule, registration_args=None, installation_args=None): """Given satellite and capsule instances, run the commands needed to set up the capsule @@ -293,10 +311,10 @@ def install_katello_ca(self, satellite): installed. """ self.execute(f'rpm -Uvh {satellite.url_katello_ca_rpm}') - # Not checking the return_code here, as rpm could be installed before + # Not checking the status here, as rpm could be installed before # and installation may fail result = self.execute(f'rpm -q katello-ca-consumer-{satellite.hostname}') - # Checking the return_code here to verify katello-ca rpm is actually + # Checking the status here to verify katello-ca rpm is actually # present in the system if result.status != 0: ContentHostError('Failed to download and install the katello-ca rpm') @@ -307,10 +325,10 @@ def remove_katello_ca(self): :return: None. :raises robottelo.hosts.ContentHostError: If katello-ca wasn't removed. """ - # Not checking the return_code here, as rpm can be not even installed + # Not checking the status here, as rpm can be not even installed # and deleting may fail self.execute('yum erase -y $(rpm -qa |grep katello-ca-consumer)') - # Checking the return_code here to verify katello-ca rpm is actually + # Checking the status here to verify katello-ca rpm is actually # not present in the system result = self.execute('rpm -qa |grep katello-ca-consumer') if result.status == 0: diff --git a/robottelo/libvirt_discovery.py b/robottelo/libvirt_discovery.py index fb010047c49..5dda8a07733 100644 --- a/robottelo/libvirt_discovery.py +++ b/robottelo/libvirt_discovery.py @@ -162,7 +162,7 @@ def create(self): result = ssh.command(command, self.libvirt_server) - if result.return_code != 0: + if result.status != 0: raise LibvirtGuestError(f'Failed to run virt-install: {result.stderr}') self._created = True @@ -203,7 +203,7 @@ def attach_nic(self): result = ssh.command(command, self.libvirt_server) - if result.return_code != 0: + if result.status != 0: raise LibvirtGuestError(f'Failed to run virsh attach-interface: {result.stderr}') def __enter__(self): diff --git a/robottelo/logging.py b/robottelo/logging.py index f184823f597..506a76873f1 100644 --- a/robottelo/logging.py +++ b/robottelo/logging.py @@ -42,7 +42,6 @@ def configure_third_party_logging(): 'broker', 'easyprocess', 'nailgun', - 'paramiko', 'requests.packages.urllib3.connectionpool', 'robozilla', 'selenium.webdriver.remote.remote_connection', diff --git a/robottelo/manifests.py b/robottelo/manifests.py index 9d593cb29ae..de05038e0fe 100644 --- a/robottelo/manifests.py +++ b/robottelo/manifests.py @@ -12,12 +12,12 @@ from cryptography.hazmat.primitives.asymmetric import padding from nailgun import entities +from robottelo import ssh from robottelo.cli.subscription import Subscription from robottelo.config import settings from robottelo.constants import INTERFACE_API from robottelo.constants import INTERFACE_CLI from robottelo.decorators.func_locker import lock_function -from robottelo.ssh import upload_file class ManifestCloner: @@ -241,7 +241,7 @@ def upload_manifest_locked(org_id, manifest=None, interface=INTERFACE_API, timeo else: # interface is INTERFACE_CLI with manifest: - upload_file(manifest.content, manifest.filename) + ssh.get_client().put(manifest.content, manifest.filename) result = Subscription.upload( {'file': manifest.filename, 'organization-id': org_id}, timeout=timeout diff --git a/robottelo/remote_log.py b/robottelo/remote_log.py deleted file mode 100644 index 770f7f68206..00000000000 --- a/robottelo/remote_log.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Utilities to help work with log files""" -import os -import re - -from robottelo import ssh -from robottelo.config import robottelo_root_dir - -LOGS_DATA_DIR = os.path.join(robottelo_root_dir, 'data', 'logs') - - -class LogFile: - """ - References a remote log file. The log file will be downloaded to allow - operate on it using python - """ - - def __init__(self, remote_path, pattern=None): - self.remote_path = remote_path - self.pattern = pattern - - if not os.path.isdir(LOGS_DATA_DIR): - os.makedirs(LOGS_DATA_DIR) - self.local_path = os.path.join(LOGS_DATA_DIR, os.path.basename(remote_path)) - ssh.download_file(remote_path, self.local_path) - with open(self.local_path) as file_: - self.data = file_.readlines() - - def filter(self, pattern=None): - """ - Filter the log file using the pattern argument or object's pattern - """ - - if pattern is None: - pattern = self.pattern - - compiled = re.compile(pattern) - - result = [] - - for line in self.data: - if compiled.search(line) is not None: - result.append(line) - - return result diff --git a/robottelo/rh_cloud_utils.py b/robottelo/rh_cloud_utils.py index b05205c1ba6..5fa3aee3999 100644 --- a/robottelo/rh_cloud_utils.py +++ b/robottelo/rh_cloud_utils.py @@ -79,7 +79,7 @@ def get_remote_report_checksum(org_id): for path in remote_paths: result = ssh.command(f'sha256sum {path}', output_format='plain') - if result.return_code != 0: + if result.status != 0: continue checksum, _ = result.stdout.split(maxsplit=1) return checksum diff --git a/robottelo/rhsso_utils.py b/robottelo/rhsso_utils.py index 3419cfd16b2..f33dbe3c943 100644 --- a/robottelo/rhsso_utils.py +++ b/robottelo/rhsso_utils.py @@ -24,9 +24,9 @@ def run_command(cmd, hostname=None, timeout=None): result = ssh.command(cmd=cmd, hostname=hostname, timeout=timeout) else: result = ssh.command(cmd=cmd, hostname=hostname) - if result.return_code != 0: + if result.status != 0: raise CLIReturnCodeError( - result.return_code, + result.status, result.stderr, f"Failed to run the command : {cmd}", ) @@ -53,10 +53,10 @@ def get_rhsso_client_id(): ) result = run_command( - cmd=f"{KEY_CLOAK_CLI} get clients --fields id,clientId", + cmd=f'{KEY_CLOAK_CLI} get clients --fields id,clientId', hostname=settings.rhsso.host_name, ) - result_json = json.loads("[{{{0}".format("".join(result))) + result_json = json.loads(f'[{{{result}') client_id = None for client in result_json: if client_name in client['clientId']: @@ -71,7 +71,7 @@ def get_rhsso_user_details(username): cmd=f"{KEY_CLOAK_CLI} get users -r {settings.rhsso.realm} -q username={username}", hostname=settings.rhsso.host_name, ) - result_json = json.loads("[{{{0}".format("".join(result))) + result_json = json.loads(f'[{{{result}') return result_json[0] @@ -81,7 +81,7 @@ def get_rhsso_groups_details(group_name): cmd=f"{KEY_CLOAK_CLI} get groups -r {settings.rhsso.realm} -q group_name={group_name}", hostname=settings.rhsso.host_name, ) - result_json = json.loads("[{{{0}".format("".join(result))) + result_json = json.loads(f'[{{{result}') return result_json[0] @@ -89,7 +89,7 @@ def upload_rhsso_entity(json_content, entity_name): """Helper method upload the entity json request as file on RHSSO Server""" with open(entity_name, "w") as file: json.dump(json_content, file) - ssh.upload_file(entity_name, entity_name, hostname=settings.rhsso.host_name) + ssh.get_client(hostname=settings.rhsso.host_name).put(entity_name) def create_mapper(json_content, client_id): diff --git a/robottelo/ssh.py b/robottelo/ssh.py index 8b0eb61c193..be2bb4fb42f 100644 --- a/robottelo/ssh.py +++ b/robottelo/ssh.py @@ -1,297 +1,39 @@ """Utility module to handle the shared ssh connection.""" -import os -import re -import time -from contextlib import contextmanager -from fnmatch import fnmatch -from io import StringIO - -import paramiko +from functools import lru_cache from robottelo.cli import hammer -from robottelo.logging import logger - - -class SSHCommandTimeoutError(Exception): - """Raised when the SSH command has not finished executing after a - predefined period of time. - """ - - -def decode_to_utf8(text): # pragma: no cover - """Paramiko returns bytes object and we need to ensure it is utf-8 before - parsing - """ - try: - return text.decode('utf-8') - except (AttributeError, UnicodeEncodeError): - return text - - -class SSHCommandResult: - """Structure that returns in all ssh commands results.""" - - def __init__(self, stdout=None, stderr=None, return_code=0, output_format=None): - self.stdout = stdout - self.stderr = stderr - self.return_code = return_code - self.output_format = output_format - # Does not make sense to return suspicious output if ($? <> 0) - if output_format and self.return_code == 0: - if output_format == 'csv': - self.stdout = hammer.parse_csv(stdout) if stdout else {} - if output_format == 'json': - self.stdout = hammer.parse_json(stdout) if stdout else None - - def __repr__(self): - tmpl = ( - 'SSHCommandResult(stdout={stdout!r}, stderr={stderr!r}, ' - + 'return_code={return_code!r}, output_format={output_format!r})' - ) - return tmpl.format(**self.__dict__) - - -class SSHClient(paramiko.SSHClient): - """Extended SSHClient allowing custom methods""" - - def run(self, cmd, *args, **kwargs): - """This method exists to allow the reuse of existing connections when - running multiple ssh commands as in the following example of use: - - with robottelo.ssh.get_connection() as connection: - connection.run('ls /tmp') - connection.run('another command') - - `self` is always passed as the connection when used in context manager - only when using `ssh.get_connection` function. - - Note: This method is named `run` to avoid conflicts with existing - `exec_command` and local function `execute_command`. - """ - return execute_command(cmd, self, *args, **kwargs) - - -def _call_paramiko_sshclient(): # pragma: no cover - """Call ``paramiko.SSHClient``. - - This function does not alter the behaviour of ``paramiko.SSHClient``. It - exists solely for the sake of easing unit testing: it can be overridden for - mocking purposes. - - """ - return SSHClient() +@lru_cache def get_client( hostname=None, username=None, password=None, - key_filename=None, - key_string=None, - timeout=None, port=22, ): - """Returns a SSH client connected to given hostname + """Returns a host object that provides an ssh connection Processes ssh credentials in the order: password, key_filename, ssh_key Config validation enforces one of the three must be set in settings.server """ - # temporary workaround due to import order. from robottelo.config import settings + from robottelo.hosts import ContentHost - hostname = hostname or settings.server.hostname - username = username or settings.server.ssh_username - password = password or settings.server.ssh_password - if password is None: - key_filename = key_filename or settings.server.ssh_key - if password is None and key_filename is None: - key_string = key_string or settings.server.ssh_key_string - key_string = paramiko.rsakey.RSAKey.from_private_key(StringIO(str(key_string))) - timeout = timeout or settings.server.ssh_client.connection_timeout - client = _call_paramiko_sshclient() - client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - client.connect( - hostname=hostname, - username=username, - key_filename=key_filename, - pkey=key_string, - password=password, - timeout=timeout, - port=port, - allow_agent=False if password else True, - look_for_keys=False if password else True, + client = ContentHost( + hostname=hostname or settings.server.hostname, + username=username or settings.server.ssh_username, + password=password or settings.server.ssh_password, ) - client._id = hex(id(client)) return client -@contextmanager -def get_connection( - hostname=None, - username=None, - password=None, - key_filename=None, - key_string=None, - timeout=None, - port=22, -): - """Yield an ssh connection object. - - The connection will be configured with the specified arguments or will - fall-back to server configuration in the configuration file. - - Yield this SSH connection. The connection is automatically closed when the - caller is done using it using ``contextlib``, so clients should use the - ``with`` statement to handle the object:: - - with get_connection() as connection: - ... - - kwargs are passed through to get_client - - :return: An SSH connection. - :rtype: ``paramiko.SSHClient`` - - """ - client = get_client( - hostname=hostname, - username=username, - password=password, - key_filename=key_filename, - key_string=key_string, - timeout=timeout, - port=port, - ) - try: - logger.debug(f'Instantiated Paramiko client {client._id}') - logger.info('Connected to [%s]', hostname) - yield client - finally: - client.close() - logger.debug(f'Destroyed Paramiko client {client._id}') - - -@contextmanager -def get_sftp_session( - hostname=None, username=None, password=None, key_filename=None, key_string=None, timeout=None -): - """Yield a SFTP session object. - - The session will be configured with the host whose hostname is - passed as - argument. - - Yield this SFTP Session. The session is automatically closed when - the caller is done using it using ``contextlib``, so clients should use - the``with`` statement to handle the object:: - - with get_sftp_session() as session: - ... - - kwargs are passed through to get_connection - """ - with get_connection( - hostname=hostname, - username=username, - password=password, - key_filename=key_filename, - key_string=key_string, - timeout=timeout, - ) as connection: - try: - sftp = connection.open_sftp() - yield sftp - finally: - sftp.close() - - -def upload_file(local_file, remote_file, key_filename=None, key_string=None, hostname=None): - """Upload a local file to a remote machine - - :param local_file: either a file path or a file-like object to be uploaded. - :param remote_file: a remote file path where the uploaded file will be - placed. - :param hostname: target machine hostname. If not provided will be used the - ``server.hostname`` from the configuration. - :param str key_filename: The path of the ssh private key to use when - connecting to the server. If it is ``None`` ``key_filename`` from - configuration's ``server`` section will be used. - """ - - with get_sftp_session( - hostname=hostname, key_filename=key_filename, key_string=key_string - ) as sftp: - _upload_file(sftp, local_file, remote_file) - - -def upload_files( - local_dir, remote_dir, file_search='*.txt', hostname=None, key_filename=None, key_string=None -): - """Upload all files from directory to a remote directory - - :param local_dir: all files from local path to be uploaded. - :param remote_dir: a remote path where the uploaded files will be - placed. - :param file_search: filter only files contains the type extension - :param hostname: target machine hostname. If not provided will be used the - ``server.hostname`` from the configuration. - :param str key_filename: The path of the ssh private key to use when - connecting to the server. If it is ``None`` ``key_filename`` from - configuration's ``server`` section will be used. - """ - command(f"mkdir -p {remote_dir}") - # making only one SFTP Session to transfer all files - with get_sftp_session(hostname=hostname, key_filename=key_filename) as sftp: - for root, dirs, files in os.walk(local_dir): - for local_filename in files: - if fnmatch(local_filename, file_search): - remote_file = f"{remote_dir}/{local_filename}" - local_file = os.path.join(local_dir, local_filename) - _upload_file(sftp, local_file, remote_file) - - -def _upload_file(sftp, local_file, remote_file): - """Upload a file using existent sftp session - - :param sftp: sftp session object - :param local_file: either a file path or a file-like object to be uploaded. - :param remote_file: a remote file path where the uploaded file will be - placed. - - """ - # Check if local_file is a file-like object and use the proper - # paramiko function to upload it to the remote machine. - if hasattr(local_file, 'read'): - sftp.putfo(local_file, remote_file) - else: - sftp.put(local_file, remote_file) - - -def download_file(remote_file, local_file=None, hostname=None): - """Download a remote file to the local machine. If ``hostname`` is not - provided will be used the server. - - """ - if local_file is None: # pragma: no cover - local_file = remote_file - with get_connection(hostname=hostname) as connection: # pragma: no cover - try: - sftp = connection.open_sftp() - sftp.get(remote_file, local_file) - finally: - sftp.close() - - def command( cmd, hostname=None, output_format=None, username=None, password=None, - key_filename=None, - key_string=None, timeout=None, - connection_timeout=None, port=22, ): """Executes SSH command(s) on remote hostname. @@ -303,86 +45,16 @@ def command( :param int timeout: Time to wait for the ssh command to finish. :param connection_timeout: Time to wait for establishing the connection. """ - # temporary workaround due to import order. - from robottelo.config import settings - - hostname = hostname or settings.server.hostname - timeout = timeout or settings.server.ssh_client.command_timeout - connection_timeout = connection_timeout or settings.server.ssh_client.connection_timeout - with get_connection( + client = get_client( hostname=hostname, username=username, password=password, - key_filename=key_filename, - key_string=key_string, - timeout=connection_timeout, port=port, - ) as connection: - return execute_command(cmd, connection, output_format, timeout, connection_timeout) - - -def execute_command(cmd, connection, output_format=None, timeout=None, connection_timeout=None): - """Execute a command via ssh in the given connection - - :param cmd: a command to be executed via ssh - :param connection: SSH Paramiko client connection - :param output_format: base|json|csv|list valid only for hammer commands - :param timeout: Time to wait for the ssh command to finish. - :param connection_timeout: Time to wait for establishing the connection. - :return: SSHCommandResult - """ - # temporary workaround due to import order. - from robottelo.config import settings - - if timeout is None: - timeout = settings.server.ssh_client.command_timeout - if connection_timeout is None: - connection_timeout = settings.server.ssh_client.connection_timeout - logger.info('>>> %s', cmd) - _, stdout, stderr = connection.exec_command(cmd, timeout=connection_timeout) - if timeout: - # wait for the exit status ready - end_time = time.time() + timeout - while time.time() < end_time: - if stdout.channel.exit_status_ready(): - break - time.sleep(1) - else: - logger.error( - 'ssh command did not respond in the predefined time' - ' (timeout=%s) and will be interrupted', - timeout, - ) - stdout.channel.close() - stderr.channel.close() - logger.error(f'[Captured stdout]\n{stdout.read()}\n-----\n') - logger.error(f'[Captured stderr]\n{stderr.read()}\n-----\n') - raise SSHCommandTimeoutError( - 'ssh command: {} \n did not respond in the predefined time ' - '(timeout={})'.format(cmd, timeout) - ) - - errorcode = stdout.channel.recv_exit_status() - - stdout = stdout.read() - stderr = stderr.read() - # Remove escape code for colors displayed in the output - regex = re.compile(r'\x1b\[\d\d?m') - if stdout: - # Convert to unicode string - stdout = decode_to_utf8(stdout) - logger.info('<<< stdout\n%s', stdout) - if stderr: - # Convert to unicode string and remove all color codes characters - stderr = regex.sub('', decode_to_utf8(stderr)) - logger.info('<<< stderr\n%s', stderr) - # Skip converting to list if 'plain', or the hammer options 'json' or 'base' are passed - if stdout and output_format not in ('json', 'base', 'plain'): - # Mostly only for hammer commands - # for output we don't really want to see all of Rails traffic - # information, so strip it out. - # Empty fields are returned as "" which gives us '""' - stdout = stdout.replace('""', '') - stdout = ''.join(stdout).split('\n') - stdout = [regex.sub('', line) for line in stdout if not line.startswith('[')] - return SSHCommandResult(stdout, stderr, errorcode, output_format) + ) + result = client.execute(cmd, timeout=timeout) + if output_format and result.status == 0: + if output_format == 'csv': + result.stdout = hammer.parse_csv(result.stdout) if result.stdout else {} + if output_format == 'json': + result.stdout = hammer.parse_json(result.stdout) if result.stdout else None + return result diff --git a/robottelo/utils/issue_handlers/bugzilla.py b/robottelo/utils/issue_handlers/bugzilla.py index e12eef3ca38..55a10a47377 100644 --- a/robottelo/utils/issue_handlers/bugzilla.py +++ b/robottelo/utils/issue_handlers/bugzilla.py @@ -12,7 +12,7 @@ from robottelo.constants import CLOSED_STATUSES from robottelo.constants import OPEN_STATUSES from robottelo.constants import WONTFIX_RESOLUTIONS -from robottelo.host_info import get_sat_version +from robottelo.hosts import get_sat_version from robottelo.logging import logger diff --git a/robottelo/virtwho_utils.py b/robottelo/virtwho_utils.py index f72a7911777..c7917676077 100644 --- a/robottelo/virtwho_utils.py +++ b/robottelo/virtwho_utils.py @@ -84,9 +84,7 @@ def runcmd(cmd, system=None, timeout=600, output_format='base'): """ system = system or get_system('satellite') result = ssh.command(cmd, **system, timeout=timeout, output_format=output_format) - ret = result.return_code - stdout = result.stdout.strip() - return ret, stdout + return result.status, result.stdout.strip() def register_system(system, activation_key=None, org='Default_Organization', env='Library'): @@ -288,7 +286,7 @@ def deploy_configure_by_script(script_content, hypervisor_type, debug=False): register_system(get_system(hypervisor_type)) with open(script_filename, 'w') as fp: fp.write(script_content) - ssh.upload_file(script_filename, script_filename) + ssh.get_client().put(script_filename) ret, stdout = runcmd(f'sh {script_filename}') if ret != 0 or 'Finished successfully' not in stdout: raise VirtWhoError(f"Failed to deploy configure by {script_filename}") diff --git a/scripts/hammer_command_tree.py b/scripts/hammer_command_tree.py index 11b7d8c11b5..010af5ad9f5 100755 --- a/scripts/hammer_command_tree.py +++ b/scripts/hammer_command_tree.py @@ -6,7 +6,6 @@ from robottelo import ssh from robottelo.cli import hammer -from robottelo.config import settings def generate_command_tree(command): @@ -22,8 +21,6 @@ def generate_command_tree(command): return contents -settings.configure() - # Generate the json file in the working directory with open('hammer_commands.json', 'w') as f: f.write(json.dumps(generate_command_tree('hammer'), indent=2, sort_keys=True)) diff --git a/tests/foreman/api/test_contentmanagement.py b/tests/foreman/api/test_contentmanagement.py index f36b16a24d3..42740cbb948 100644 --- a/tests/foreman/api/test_contentmanagement.py +++ b/tests/foreman/api/test_contentmanagement.py @@ -31,14 +31,13 @@ from robottelo.api.utils import promote from robottelo.api.utils import upload_manifest from robottelo.config import settings +from robottelo.content_info import get_repo_files +from robottelo.content_info import get_repomd_revision from robottelo.helpers import create_repo from robottelo.helpers import form_repo_path from robottelo.helpers import form_repo_url from robottelo.helpers import get_data_file from robottelo.helpers import md5_by_url -from robottelo.host_info import get_repo_files -from robottelo.host_info import get_repo_files_by_url -from robottelo.host_info import get_repomd_revision class TestSatelliteContentManagement: @@ -377,7 +376,7 @@ def test_positive_checksum_sync(self, capsule_configured): f'grep -o \'checksum type="sha1"\' {lce_repo_path}/{REPOMD_PATH}', ) - assert result.return_code == 0 + assert result.status == 0 assert len(result.stdout) > 0 @pytest.mark.tier4 diff --git a/tests/foreman/api/test_contentview.py b/tests/foreman/api/test_contentview.py index af5413b46e4..a9dba0aa7eb 100644 --- a/tests/foreman/api/test_contentview.py +++ b/tests/foreman/api/test_contentview.py @@ -42,7 +42,6 @@ from robottelo.datafactory import invalid_names_list from robottelo.datafactory import parametrized from robottelo.datafactory import valid_data_list -from robottelo.decorators.host import skip_if_os from robottelo.helpers import get_nailgun_config # Some tests repeatedly publish content views or promote content view versions. @@ -684,7 +683,7 @@ def test_positive_publish_multiple_repos(self, content_view, module_org): @pytest.mark.skipif( (not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url' ) - def test_composite_content_view_with_same_repos(self, module_org): + def test_composite_content_view_with_same_repos(self, module_org, default_sat): """Create a Composite Content View with content views having same yum repo. Add filter on the content views and check the package count for composite content view should not be changed. @@ -1253,7 +1252,6 @@ def test_negative_non_readonly_user_actions(content_view, function_role, module_ class TestOstreeContentView: """Tests for ostree contents in content views.""" - @skip_if_os('RHEL6') @pytest.mark.skipif( (not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url' ) @@ -1366,7 +1364,6 @@ class TestContentViewRedHatOstreeContent: """Tests for publishing and promoting cv with RH ostree contents.""" @pytest.mark.run_in_one_thread - @skip_if_os('RHEL6') @pytest.mark.skip_if_not_set('fake_manifest') @pytest.fixture(scope='class', autouse=True) def initiate_testclass(self, request, module_org): diff --git a/tests/foreman/api/test_discoveredhost.py b/tests/foreman/api/test_discoveredhost.py index 4f9606d2584..50914a8a774 100644 --- a/tests/foreman/api/test_discoveredhost.py +++ b/tests/foreman/api/test_discoveredhost.py @@ -28,12 +28,12 @@ from wait_for import TimedOutError from wait_for import wait_for +from robottelo import ssh from robottelo.cli.factory import configure_env_for_provision from robottelo.datafactory import valid_data_list from robottelo.helpers import get_nailgun_config from robottelo.libvirt_discovery import LibvirtGuest from robottelo.logging import logger -from robottelo.ssh import get_client from robottelo.utils.issue_handlers import is_open @@ -389,7 +389,9 @@ def test_positive_provision_pxe_host(self, _module_user, discovery_settings, pro cfg.auth = (_module_user[0].login, _module_user[1]) # open a ssh channel and attach it to foreman-tail output - with get_client().invoke_shell() as channel: + # TODO!! + ssh_client = ssh.get_client() + with ssh_client.invoke_shell() as channel: channel.send('foreman-tail\r') with LibvirtGuest() as pxe_host: @@ -448,7 +450,9 @@ def test_positive_auto_provision_pxe_host( cfg.auth = (_module_user[0].login, _module_user[1]) # open a ssh channel and attach it to foreman-tail output - with get_client().invoke_shell() as channel: + # TODO!! + ssh_client = ssh.get_client() + with ssh_client.invoke_shell() as channel: channel.send('foreman-tail\r') with LibvirtGuest() as pxe_host: @@ -558,7 +562,9 @@ def test_positive_reboot_pxe_host(self, _module_user, discovery_settings, provis cfg.auth = (_module_user[0].login, _module_user[1]) # open a ssh channel and attach it to foreman-tail output - with get_client().invoke_shell() as channel: + # TODO!! + ssh_client = ssh.get_client() + with ssh_client.invoke_shell() as channel: channel.send('foreman-tail\r') with LibvirtGuest() as pxe_host: @@ -607,7 +613,8 @@ def test_positive_reboot_all_pxe_hosts( cfg.auth = (_module_user[0].login, _module_user[1]) # open ssh channels and attach them to foreman-tail output - channel_1, channel_2 = get_client().invoke_shell(), get_client().invoke_shell() + # TODO!! + channel_1, channel_2 = ssh.get_client().invoke_shell(), ssh.get_client().invoke_shell() channel_1.send('foreman-tail\r') channel_2.send('foreman-tail\r') @@ -685,7 +692,9 @@ def test_positive_provision_pxe_host_dhcp_change( new_dhcp_conf_to = subnet.to[: subnet.to.rfind('.') + 1] + str(int(old_sub_to_4o) - 10) cfg = get_nailgun_config() - with get_client().invoke_shell() as channel: + # TODO!! + ssh_client = ssh.get_client() + with ssh_client.invoke_shell() as channel: channel.send('foreman-tail\r') try: # updating the ranges in component and in dhcp.conf diff --git a/tests/foreman/api/test_permission.py b/tests/foreman/api/test_permission.py index ced53c0df6a..da1da96beab 100644 --- a/tests/foreman/api/test_permission.py +++ b/tests/foreman/api/test_permission.py @@ -30,7 +30,6 @@ from nailgun.entity_fields import OneToManyField from requests.exceptions import HTTPError -from robottelo import ssh from robottelo.constants import PERMISSIONS from robottelo.datafactory import parametrized from robottelo.helpers import get_nailgun_config @@ -53,15 +52,15 @@ def create_permissions(self, default_sat): cls.permissions[None].remove('view_cases') cls.permissions[None].remove('view_log_viewer') - result = ssh.command('rpm -qa | grep rubygem-foreman_openscap') - if result.return_code != 0: + result = default_sat.execute('rpm -qa | grep rubygem-foreman_openscap') + if result.status != 0: cls.permissions.pop('ForemanOpenscap::Policy') cls.permissions.pop('ForemanOpenscap::ScapContent') cls.permissions[None].remove('destroy_arf_reports') cls.permissions[None].remove('view_arf_reports') cls.permissions[None].remove('create_arf_reports') - result = ssh.command('rpm -qa | grep rubygem-foreman_remote_execution') - if result.return_code != 0: + result = default_sat.execute('rpm -qa | grep rubygem-foreman_remote_execution') + if result.status != 0: cls.permissions.pop('JobInvocation') cls.permissions.pop('JobTemplate') cls.permissions.pop('RemoteExecutionFeature') diff --git a/tests/foreman/api/test_template.py b/tests/foreman/api/test_template.py index fa3b2bd3d05..8a566628268 100644 --- a/tests/foreman/api/test_template.py +++ b/tests/foreman/api/test_template.py @@ -28,7 +28,6 @@ from nailgun import entities from requests.exceptions import HTTPError -from robottelo import ssh from robottelo.config import get_credentials from robottelo.config import settings from robottelo.datafactory import invalid_names_list @@ -115,7 +114,7 @@ def tftpboot(module_org, default_sat): kinds = entities.TemplateKind().search(query={"search": "name ~ PXE"}) # clean the already-deployed default pxe configs - ssh.command('rm {}'.format(' '.join([i['path'] for i in default_templates.values()]))) + default_sat.execute('rm {}'.format(' '.join([i['path'] for i in default_templates.values()]))) # create custom Templates per kind for template in default_templates.values(): @@ -136,7 +135,7 @@ def tftpboot(module_org, default_sat): yield default_templates # delete the deployed tftp files - ssh.command('rm {}'.format(' '.join([i['path'] for i in default_templates.values()]))) + default_sat.execute('rm {}'.format(' '.join([i['path'] for i in default_templates.values()]))) # set the settings back to defaults for setting in default_settings: if setting.value is None: @@ -255,7 +254,7 @@ def test_positive_build_pxe_default(self, tftpboot, default_sat): r.raise_for_status() rendered = r.text else: - rendered = ssh.command(f"cat {template['path']}").stdout[0] + rendered = default_sat.execute(f'cat {template["path"]}').stdout.splitlines()[0] assert ( rendered == f"{settings.server.scheme}://" f"{default_sat.hostname} {template['kind']}" diff --git a/tests/foreman/api/test_templatesync.py b/tests/foreman/api/test_templatesync.py index a0ae410d058..ca8b651088b 100644 --- a/tests/foreman/api/test_templatesync.py +++ b/tests/foreman/api/test_templatesync.py @@ -22,7 +22,6 @@ from requests import get from requests.exceptions import HTTPError -from robottelo import ssh from robottelo.constants import FOREMAN_TEMPLATE_IMPORT_URL from robottelo.constants import FOREMAN_TEMPLATE_ROOT_DIR from robottelo.constants import FOREMAN_TEMPLATE_TEST_TEMPLATE @@ -35,7 +34,7 @@ class TestTemplateSyncTestCase: """ @pytest.fixture(scope='module', autouse=True) - def setUpClass(self): + def setUpClass(self, default_sat): """Setup for TemplateSync functional testing :setup: @@ -55,7 +54,7 @@ def setUpClass(self): raise HTTPError('The foreman templates git url is not accessible') # Download the Test Template in test running folder - ssh.command(f'[ -f example_template.erb ] || wget {FOREMAN_TEMPLATE_TEST_TEMPLATE}') + default_sat.execute(f'[ -f example_template.erb ] || wget {FOREMAN_TEMPLATE_TEST_TEMPLATE}') @pytest.mark.tier2 def test_positive_import_filtered_templates_from_git(self, module_org, module_location): @@ -192,6 +191,7 @@ def test_positive_import_and_associate( module_org, default_org, default_location, + default_sat, ): """Assure imported templates are associated/not_associated with taxonomies based on `associate` option and templates metadata. @@ -254,7 +254,7 @@ def test_positive_import_and_associate( ) assert not ptemplate # Associate New - ssh.command( + default_sat.execute( f'cp {dir_path}/example_template.erb {dir_path}/another_template.erb && ' f'sed -ie "s/name: .*/name: another_template/" {dir_path}/another_template.erb' ) @@ -359,7 +359,7 @@ def test_positive_import_to_subdirectory(self, module_org): @pytest.mark.tier2 def test_positive_export_filtered_templates_to_localdir( - self, module_org, create_import_export_local_dir + self, module_org, create_import_export_local_dir, default_sat ): """Assure only templates with a given filter regex are pushed to local directory (new templates are created, existing updated). @@ -391,12 +391,12 @@ def test_positive_export_filtered_templates_to_localdir( template['exported'] for template in exported_temps['message']['templates'] ].count(True) assert exported_count == int( - ssh.command(f'find {dir_path} -type f -name *ansible* | wc -l').stdout[0] + default_sat.execute(f'find {dir_path} -type f -name *ansible* | wc -l').stdout.strip() ) @pytest.mark.tier2 def test_positive_export_filtered_templates_negate( - self, module_org, create_import_export_local_dir + self, module_org, create_import_export_local_dir, default_sat ): """Assure templates with a given filter regex are not exported. @@ -423,12 +423,15 @@ def test_positive_export_filtered_templates_negate( 'negate': True, } ) - assert ssh.command(f'find {dir_path} -type f -name *ansible* | wc -l').stdout[0] == '0' - assert ssh.command(f'find {dir_path} -type f | wc -l').stdout[0] != '0' + assert ( + default_sat.execute(f'find {dir_path} -type f -name *ansible* | wc -l').stdout.strip() + == '0' + ) + assert default_sat.execute(f'find {dir_path} -type f | wc -l').stdout.strip() != '0' @pytest.mark.tier2 def test_positive_export_and_import_with_metadata( - self, create_import_export_local_dir, module_org, module_location + self, create_import_export_local_dir, module_org, module_location, default_sat ): """Assure exported template contains metadata. @@ -470,10 +473,10 @@ def test_positive_export_and_import_with_metadata( 'filter': prefix, } ) - result = ssh.command( + result = default_sat.execute( f'grep {module_org.name} {dir_path}/provisioning_templates/user_data/{export_file}' ) - assert result.return_code == 0 + assert result.status == 0 # Export same template to local dir with keeping metadata entities.Template().exports( data={ @@ -484,10 +487,10 @@ def test_positive_export_and_import_with_metadata( 'filter': prefix, } ) - result = ssh.command( + result = default_sat.execute( f'grep {module_org.name} {dir_path}/provisioning_templates/user_data/{export_file}' ) - assert result.return_code == 1 + assert result.status == 1 # Export same template to local dir with removed metadata entities.Template().exports( data={ @@ -498,10 +501,10 @@ def test_positive_export_and_import_with_metadata( 'filter': prefix, } ) - result = ssh.command( + result = default_sat.execute( f'grep organizations: {dir_path}/provisioning_templates/user_data/{export_file}' ) - assert result.return_code == 1 + assert result.status == 1 # Take Templates out of Tech Preview Feature Tests @pytest.mark.tier3 @@ -599,7 +602,7 @@ def test_positive_import_json_output_verbose_false(self, module_org): @pytest.mark.tier2 def test_positive_import_json_output_changed_key_true( - self, create_import_export_local_dir, module_org + self, create_import_export_local_dir, module_org, default_sat ): """Assert template imports output `changed` key returns `True` when template data gets updated @@ -627,7 +630,7 @@ def test_positive_import_json_output_changed_key_true( data={'repo': dir_path, 'organization_ids': [module_org.id], 'prefix': prefix} ) assert bool(pre_template['message']['templates'][0]['imported']) - ssh.command(f'echo " Updating Template data." >> {dir_path}/example_template.erb') + default_sat.execute(f'echo " Updating Template data." >> {dir_path}/example_template.erb') post_template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id], 'prefix': prefix} ) @@ -668,7 +671,9 @@ def test_positive_import_json_output_changed_key_false( assert not bool(post_template['message']['templates'][0]['changed']) @pytest.mark.tier2 - def test_positive_import_json_output_name_key(self, create_import_export_local_dir, module_org): + def test_positive_import_json_output_name_key( + self, create_import_export_local_dir, module_org, default_sat + ): """Assert template imports output `name` key returns correct name :id: a5639368-3d23-4a37-974a-889e2ec0916e @@ -687,7 +692,9 @@ def test_positive_import_json_output_name_key(self, create_import_export_local_d """ template_name = gen_string('alpha') _, dir_path = create_import_export_local_dir - ssh.command(f'sed -ie "s/name: .*/name: {template_name}/" {dir_path}/example_template.erb') + default_sat.execute( + f'sed -ie "s/name: .*/name: {template_name}/" {dir_path}/example_template.erb' + ) template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id]} ) @@ -748,7 +755,7 @@ def test_positive_import_json_output_file_key(self, create_import_export_local_d @pytest.mark.tier2 def test_positive_import_json_output_corrupted_metadata( - self, create_import_export_local_dir, module_org + self, create_import_export_local_dir, module_org, default_sat ): """Assert template imports output returns corrupted metadata error for incorrect metadata in template @@ -770,7 +777,7 @@ def test_positive_import_json_output_corrupted_metadata( :CaseImportance: Medium """ _, dir_path = create_import_export_local_dir - ssh.command(f'sed -ie "s/<%#/$#$#@%^$^@@RT$$/" {dir_path}/example_template.erb') + default_sat.execute(f'sed -ie "s/<%#/$#$#@%^$^@@RT$$/" {dir_path}/example_template.erb') template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id]} ) @@ -818,7 +825,7 @@ def test_positive_import_json_output_filtered_skip_message( @pytest.mark.tier2 def test_positive_import_json_output_no_name_error( - self, create_import_export_local_dir, module_org + self, create_import_export_local_dir, module_org, default_sat ): """Assert template imports output returns no name error for template without name @@ -840,7 +847,7 @@ def test_positive_import_json_output_no_name_error( :CaseImportance: Low """ _, dir_path = create_import_export_local_dir - ssh.command(f'sed -ie "s/name: .*/name: /" {dir_path}/example_template.erb') + default_sat.execute(f'sed -ie "s/name: .*/name: /" {dir_path}/example_template.erb') template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id]} ) @@ -852,7 +859,7 @@ def test_positive_import_json_output_no_name_error( @pytest.mark.tier2 def test_positive_import_json_output_no_model_error( - self, create_import_export_local_dir, module_org + self, create_import_export_local_dir, module_org, default_sat ): """Assert template imports output returns no model error for template without model @@ -874,7 +881,7 @@ def test_positive_import_json_output_no_model_error( :CaseImportance: Low """ _, dir_path = create_import_export_local_dir - ssh.command(f'sed -ie "/model: .*/d" {dir_path}/example_template.erb') + default_sat.execute(f'sed -ie "/model: .*/d" {dir_path}/example_template.erb') template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id]} ) @@ -886,7 +893,7 @@ def test_positive_import_json_output_no_model_error( @pytest.mark.tier2 def test_positive_import_json_output_blank_model_error( - self, create_import_export_local_dir, module_org + self, create_import_export_local_dir, module_org, default_sat ): """Assert template imports output returns blank model name error for template without template name @@ -908,7 +915,7 @@ def test_positive_import_json_output_blank_model_error( :CaseImportance: Low """ _, dir_path = create_import_export_local_dir - ssh.command(f'sed -ie "s/model: .*/model: /" {dir_path}/example_template.erb') + default_sat.execute(f'sed -ie "s/model: .*/model: /" {dir_path}/example_template.erb') template = entities.Template().imports( data={'repo': dir_path, 'organization_ids': [module_org.id]} ) @@ -919,7 +926,9 @@ def test_positive_import_json_output_blank_model_error( ) @pytest.mark.tier2 - def test_positive_export_json_output(self, create_import_export_local_dir, module_org): + def test_positive_export_json_output( + self, create_import_export_local_dir, module_org, default_sat + ): """Assert template export output returns template names :id: 141b893d-72a3-47c2-bb03-004c757bcfc9 @@ -961,17 +970,17 @@ def test_positive_export_json_output(self, create_import_export_local_dir, modul assert exported_count == 18 assert 'name' in exported_templates['message']['templates'][0].keys() assert ( - ssh.command( + default_sat.execute( f'[ -d {dir_path}/job_templates ] && ' f'[ -d {dir_path}/partition_tables_templates ] && ' f'[ -d {dir_path}/provisioning_templates ] && ' f'[ -d {dir_path}/report_templates ]' - ).return_code + ).status == 0 ) @pytest.mark.tier3 - def test_positive_import_log_to_production(self, module_org): + def test_positive_import_log_to_production(self, module_org, default_sat): """Assert template import logs are logged to production logs :id: 19ed0e6a-ee77-4e28-86c9-49db1adec479 @@ -998,13 +1007,18 @@ def test_positive_import_log_to_production(self, module_org): } ) time.sleep(5) - result = ssh.command( - 'grep -i \'Started POST "/api/v2/templates/import"\' /var/log/foreman/production.log' + assert ( + default_sat.execute( + 'grep -i \'Started POST "/api/v2/templates/import"\'' + ' /var/log/foreman/production.log' + ).status + == 0 ) - assert result.return_code == 0 @pytest.mark.tier3 - def test_positive_export_log_to_production(self, create_import_export_local_dir, module_org): + def test_positive_export_log_to_production( + self, create_import_export_local_dir, module_org, default_sat + ): """Assert template export logs are logged to production logs :id: 8ae370b1-84e8-436e-a7d7-99cd0b8f45b1 @@ -1035,7 +1049,10 @@ def test_positive_export_log_to_production(self, create_import_export_local_dir, data={'repo': dir_path, 'organization_ids': [module_org.id], 'filter': 'empty'} ) time.sleep(5) - result = ssh.command( - 'grep -i \'Started POST "/api/v2/templates/export"\' /var/log/foreman/production.log' + assert ( + default_sat.execute( + 'grep -i \'Started POST "/api/v2/templates/export"\'' + ' /var/log/foreman/production.log' + ).status + == 0 ) - assert result.return_code == 0 diff --git a/tests/foreman/api/test_user.py b/tests/foreman/api/test_user.py index fc1c854b891..d4ed0474f74 100644 --- a/tests/foreman/api/test_user.py +++ b/tests/foreman/api/test_user.py @@ -23,7 +23,6 @@ import json import re -import paramiko import pytest from nailgun import entities from nailgun.config import ServerConfig @@ -41,6 +40,7 @@ from robottelo.datafactory import valid_data_list from robottelo.datafactory import valid_emails_list from robottelo.datafactory import valid_usernames_list +from robottelo.helpers import gen_ssh_keypairs from robottelo.helpers import read_data_file @@ -453,13 +453,6 @@ def test_positive_update(self, create_user, make_roles, number_of_roles): class TestSshKeyInUser: """Implements the SSH Key in User Tests""" - def gen_ssh_rsakey(self): - """Generates RSA type ssh key using ssh module - - :return: string type well formatted RSA key - """ - return f'ssh-rsa {paramiko.RSAKey.generate(2048).get_base64()}' - @pytest.fixture(scope='class') def create_user(self): """Create an user and import different keys from data json file""" @@ -486,7 +479,7 @@ def test_positive_CRD_ssh_key(self): """ user = entities.User().create() ssh_name = gen_string('alpha') - ssh_key = self.gen_ssh_rsakey() + ssh_key = gen_ssh_keypairs[1] user_sshkey = entities.SSHKey(user=user, name=ssh_name, key=ssh_key).create() assert ssh_name == user_sshkey.name assert ssh_key == user_sshkey.key @@ -565,7 +558,7 @@ def test_negative_create_ssh_key_with_invalid_name(self, create_user): invalid_ssh_key_name = gen_string('alpha', length=300) with pytest.raises(HTTPError) as context: entities.SSHKey( - user=create_user['user'], name=invalid_ssh_key_name, key=self.gen_ssh_rsakey() + user=create_user['user'], name=invalid_ssh_key_name, key=gen_ssh_keypairs[1] ).create() assert re.search("Name is too long", context.value.response.text) @@ -584,7 +577,7 @@ def test_positive_create_multiple_ssh_key_types(self, create_user): :expectedresults: Multiple types of supported ssh keys can be added to user """ - rsa = self.gen_ssh_rsakey() + rsa = gen_ssh_keypairs[1] dsa = create_user['data_keys']['ssh_keys']['dsa'] ecdsa = create_user['data_keys']['ssh_keys']['ecdsa'] ed = create_user['data_keys']['ssh_keys']['ed'] @@ -615,7 +608,7 @@ def test_positive_ssh_key_in_host_enc(self, default_sat): org = entities.Organization().create() loc = entities.Location(organization=[org]).create() user = entities.User(organization=[org], location=[loc]).create() - ssh_key = self.gen_ssh_rsakey() + ssh_key = gen_ssh_keypairs[1] entities.SSHKey(user=user, name=gen_string('alpha'), key=ssh_key).create() host = entities.Host(owner=user, owner_type='User', organization=org, location=loc).create() sshkey_updated_for_host = f'{ssh_key} {user.login}@{default_sat.hostname}' diff --git a/tests/foreman/cli/test_activationkey.py b/tests/foreman/cli/test_activationkey.py index 98ee5a4800b..c959b672685 100644 --- a/tests/foreman/cli/test_activationkey.py +++ b/tests/foreman/cli/test_activationkey.py @@ -54,7 +54,6 @@ from robottelo.datafactory import parametrized from robottelo.datafactory import valid_data_list from robottelo.hosts import ContentHost -from robottelo.ssh import upload_file from robottelo.utils.issue_handlers import is_open @@ -1204,7 +1203,7 @@ def test_update_ak_with_syspurpose_values(module_org, module_manifest_org): @pytest.mark.run_in_one_thread @pytest.mark.skip_if_not_set('fake_manifest') @pytest.mark.tier2 -def test_positive_add_subscription_by_id(module_org): +def test_positive_add_subscription_by_id(module_org, default_sat): """Test that subscription can be added to activation key :id: b884be1c-b35d-440a-9a9d-c854c83e10a7 @@ -1224,7 +1223,7 @@ def test_positive_add_subscription_by_id(module_org): :BZ: 1463685 """ with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) org_id = make_org()['id'] ackey_id = make_activation_key({'organization-id': org_id})['id'] Subscription.upload({'file': manifest.filename, 'organization-id': org_id}) @@ -1293,7 +1292,7 @@ def test_negative_copy_with_same_name(module_org): 'organization-id': module_org.id, } ) - assert raise_ctx.value.return_code == 65 + assert raise_ctx.value.status == 65 assert "Validation failed: Name has already been taken" in raise_ctx.value.message diff --git a/tests/foreman/cli/test_auth.py b/tests/foreman/cli/test_auth.py index e195cb498aa..8ee70e42d8e 100644 --- a/tests/foreman/cli/test_auth.py +++ b/tests/foreman/cli/test_auth.py @@ -42,17 +42,17 @@ def configure_sessions(enable=True, add_default_creds=False): """Enables the `use_sessions` option in hammer config""" result = ssh.command( - '''sed -i -e '/username/d;/password/d;/use_sessions/d' {0};\ - echo ' :use_sessions: {1}' >> {0}'''.format( + "sed -i -e '/username/d;/password/d;/use_sessions/d' {0};\ + echo ' :use_sessions: {1}' >> {0}".format( HAMMER_CONFIG, 'true' if enable else 'false' ) ) - if result.return_code == 0 and add_default_creds: + if result.status == 0 and add_default_creds: result = ssh.command( f'''{{ echo ' :username: "{settings.server.admin_username}"';\ echo ' :password: "{settings.server.admin_password}"'; }} >> {HAMMER_CONFIG}''' ) - return result.return_code + return result.status @pytest.fixture(scope='module') @@ -202,7 +202,7 @@ def test_positive_change_session(admin_user, non_admin_user): @pytest.mark.tier1 -def test_positive_session_survives_unauthenticated_call(admin_user): +def test_positive_session_survives_unauthenticated_call(admin_user, default_sat): """Check if session stays up after unauthenticated call :id: 8bc304a0-70ea-489c-9c3f-ea8343c5284c @@ -224,8 +224,8 @@ def test_positive_session_survives_unauthenticated_call(admin_user): assert LOGEDIN_MSG.format(admin_user['login']) in result[0]['message'] # list organizations without supplying credentials Org.with_user().list() - result = ssh.command('hammer ping') - assert result.return_code == 0, 'Failed to run hammer ping' + result = default_sat.execute('hammer ping') + assert result.status == 0, 'Failed to run hammer ping' result = Auth.with_user().status() assert LOGEDIN_MSG.format(admin_user['login']) in result[0]['message'] Org.with_user().list() diff --git a/tests/foreman/cli/test_content_credentials.py b/tests/foreman/cli/test_content_credentials.py index 0a7b380a964..3b979930e22 100644 --- a/tests/foreman/cli/test_content_credentials.py +++ b/tests/foreman/cli/test_content_credentials.py @@ -26,7 +26,6 @@ from fauxfactory import gen_integer from fauxfactory import gen_string -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.content_credentials import ContentCredential from robottelo.cli.factory import CLIFactoryError @@ -272,7 +271,7 @@ def test_positive_update_name(new_name, module_org): @pytest.mark.parametrize('name', **parametrized(valid_data_list())) @pytest.mark.tier1 -def test_positive_update_key(name, module_org): +def test_positive_update_key(name, module_org, default_sat): """Create gpg key with valid name and valid gpg key via file import then update its gpg key file @@ -289,8 +288,8 @@ def test_positive_update_key(name, module_org): assert gpg_key['content'] != content local_key = create_gpg_key_file(content) assert gpg_key, 'GPG Key file must be created' - key = '/tmp/%s' % gen_alphanumeric() - ssh.upload_file(local_file=local_key, remote_file=key) + key = f'/tmp/{gen_alphanumeric()}' + default_sat.put(local_key, key) ContentCredential.update( {'path': key, 'name': gpg_key['name'], 'organization-id': module_org.id} ) diff --git a/tests/foreman/cli/test_contentaccess.py b/tests/foreman/cli/test_contentaccess.py index 99d0e0b3e02..793a86d60d2 100644 --- a/tests/foreman/cli/test_contentaccess.py +++ b/tests/foreman/cli/test_contentaccess.py @@ -20,7 +20,6 @@ from nailgun import entities from robottelo import manifests -from robottelo import ssh from robottelo.api.utils import promote from robottelo.cli.host import Host from robottelo.cli.package import Package @@ -163,7 +162,7 @@ def test_positive_erratum_installable(vm): @pytest.mark.tier2 -def test_negative_rct_not_shows_golden_ticket_enabled(): +def test_negative_rct_not_shows_golden_ticket_enabled(default_sat): """Assert restricted manifest has no Golden Ticket enabled . :id: 754c1be7-468e-4795-bcf9-258a38f3418b @@ -183,14 +182,14 @@ def test_negative_rct_not_shows_golden_ticket_enabled(): # upload organization manifest with org environment access disabled manifest = manifests.clone() manifests.upload_manifest_locked(org.id, manifest, interface=manifests.INTERFACE_CLI) - result = ssh.command(f'rct cat-manifest {manifest.filename}') - assert result.return_code == 0 - assert 'Content Access Mode: Simple Content Access' not in ''.join(result.stdout) + result = default_sat.execute(f'rct cat-manifest {manifest.filename}') + assert result.status == 0 + assert 'Content Access Mode: Simple Content Access' not in result.stdout @pytest.mark.tier2 @pytest.mark.upgrade -def test_positive_rct_shows_golden_ticket_enabled(module_gt_manifest_org): +def test_positive_rct_shows_golden_ticket_enabled(module_gt_manifest_org, default_sat): """Assert unrestricted manifest has Golden Ticket enabled . :id: 0c6e2f88-1a86-4417-9248-d7bd20584197 @@ -204,6 +203,6 @@ def test_positive_rct_shows_golden_ticket_enabled(module_gt_manifest_org): :CaseImportance: Medium """ - result = ssh.command(f'rct cat-manifest {module_gt_manifest_org.manifest_filename}') - assert result.return_code == 0 - assert 'Content Access Mode: Simple Content Access' in ''.join(result.stdout) + result = default_sat.execute(f'rct cat-manifest {module_gt_manifest_org.manifest_filename}') + assert result.status == 0 + assert 'Content Access Mode: Simple Content Access' in result.stdout diff --git a/tests/foreman/cli/test_contentview.py b/tests/foreman/cli/test_contentview.py index 0e7751fa21a..567d72adf75 100644 --- a/tests/foreman/cli/test_contentview.py +++ b/tests/foreman/cli/test_contentview.py @@ -16,7 +16,6 @@ :Upstream: No """ -import os import random import pytest @@ -26,7 +25,6 @@ from wrapanapi.entities.vm import VmState from robottelo import constants -from robottelo import ssh from robottelo.api.utils import create_sync_custom_repo from robottelo.cli import factory as cli_factory from robottelo.cli.activationkey import ActivationKey @@ -49,7 +47,6 @@ from robottelo.datafactory import invalid_names_list from robottelo.datafactory import parametrized from robottelo.datafactory import valid_names_list -from robottelo.decorators.host import skip_if_os from robottelo.helpers import create_repo from robottelo.helpers import get_data_file from robottelo.helpers import repo_add_updateinfo @@ -82,7 +79,6 @@ def module_rhel_content(module_manifest_org): return repo -@skip_if_os('RHEL6') @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') @pytest.fixture(scope='class') def all_content_type(module_org): @@ -3752,7 +3748,7 @@ def test_positive_inc_update_no_lce(self, module_org, module_product): repo_name, f'{settings.repos.inc_upd.url}{constants.FAKE_0_INC_UPD_OLD_UPDATEFILE}', ) - assert result.return_code == 0 + assert result.status == 0 repo = cli_factory.make_repository({'product-id': module_product.id, 'url': repo_url}) Repository.synchronize({'id': repo['id']}) content_view = cli_factory.make_content_view( @@ -3772,7 +3768,7 @@ def test_positive_inc_update_no_lce(self, module_org, module_product): repo_name, f'{settings.repos.inc_upd.url}{constants.FAKE_0_INC_UPD_NEW_UPDATEFILE}', ) - assert result.return_code == 0 + assert result.status == 0 Repository.synchronize({'id': repo['id']}) result = ContentView.version_incremental_update( {'content-view-version-id': cvv['id'], 'errata-ids': constants.FAKE_0_INC_UPD_ERRATA} @@ -4097,24 +4093,18 @@ class TestContentViewFileRepo: arbitrary files """ - def make_file_repository_upload_contents(self, module_org, module_product, options=None): + def make_file_repository_upload_contents( + self, module_org, module_product, satellite, options=None + ): """Makes a new File repository, Upload File/Multiple Files and asserts its success""" - if options is None: options = {'product-id': module_product.id, 'content-type': 'file'} if not options.get('content-type'): raise cli_factory.CLIFactoryError('Please provide a valid Content Type.') new_repo = cli_factory.make_repository(options) remote_path = f'/tmp/{constants.RPM_TO_UPLOAD}' - if 'multi_upload' not in options or not options['multi_upload']: - ssh.upload_file( - local_file=get_data_file(constants.RPM_TO_UPLOAD), remote_file=remote_path - ) - else: - remote_path = f'/tmp/{gen_string("alpha")}/' - ssh.upload_files(local_dir=f'{os.getcwd()}/../data/', remote_dir=remote_path) - + satellite.put(get_data_file(constants.RPM_TO_UPLOAD), remote_path) Repository.upload_content( { 'name': new_repo['name'], @@ -4129,7 +4119,7 @@ def make_file_repository_upload_contents(self, module_org, module_product, optio @pytest.mark.skip_if_open('BZ:1610309') @pytest.mark.tier3 - def test_positive_arbitrary_file_repo_addition(self, module_org, module_product): + def test_positive_arbitrary_file_repo_addition(self, module_org, module_product, default_sat): """Check a File Repository with Arbitrary File can be added to a Content View @@ -4153,7 +4143,9 @@ def test_positive_arbitrary_file_repo_addition(self, module_org, module_product) :BZ: 1610309, 1908465 """ - repo = self.make_file_repository_upload_contents(module_org, module_product) + repo = self.make_file_repository_upload_contents( + module_org, module_product, satellite=default_sat + ) cv = cli_factory.make_content_view({'organization-id': module_org.id}) # Associate repo to CV with names. ContentView.add_repository( @@ -4219,7 +4211,7 @@ def test_positive_arbitrary_file_sync_over_capsule(self): """ @pytest.mark.tier3 - def test_positive_arbitrary_file_repo_promotion(self, module_org, module_product): + def test_positive_arbitrary_file_repo_promotion(self, module_org, module_product, default_sat): """Check arbitrary files availability for Content view version after content-view promotion. @@ -4246,7 +4238,9 @@ def test_positive_arbitrary_file_repo_promotion(self, module_org, module_product """ cv = cli_factory.make_content_view({'organization-id': module_org.id}) - repo = self.make_file_repository_upload_contents(module_product, module_product) + repo = self.make_file_repository_upload_contents( + module_product, module_product, satellite=default_sat + ) ContentView.add_repository( {'id': cv['id'], 'repository-id': repo['id'], 'organization-id': module_org.id} ) @@ -4268,7 +4262,7 @@ def test_positive_arbitrary_file_repo_promotion(self, module_org, module_product assert repo['name'] in expected_repo @pytest.mark.tier3 - def test_positive_katello_repo_rpms_max_int(self): + def test_positive_katello_repo_rpms_max_int(self, default_sat): """Checking that datatype for katello_repository_rpms table is a bigint for id for a closed loop bz. @@ -4282,5 +4276,7 @@ def test_positive_katello_repo_rpms_max_int(self): :BZ: 1793701 """ - result = ssh.command('sudo -u postgres psql -d foreman -c "\\d katello_repository_rpms"') - assert 'id|bigint' in result.stdout[3].replace(' ', '') + result = default_sat.execute( + 'sudo -u postgres psql -d foreman -c "\\d katello_repository_rpms"' + ) + assert 'id|bigint' in result.stdout.splitlines()[3].replace(' ', '') diff --git a/tests/foreman/cli/test_discoveredhost.py b/tests/foreman/cli/test_discoveredhost.py index a3449281bc5..8236a59332c 100644 --- a/tests/foreman/cli/test_discoveredhost.py +++ b/tests/foreman/cli/test_discoveredhost.py @@ -18,7 +18,6 @@ import pytest -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.discoveredhost import DiscoveredHost from robottelo.cli.factory import configure_env_for_provision @@ -33,7 +32,7 @@ pytestmark = [pytest.mark.run_in_one_thread] -def _assertdiscoveredhost(self, hostname): +def _assertdiscoveredhost(hostname): """Check if host is discovered and information about it can be retrieved back @@ -51,7 +50,7 @@ def _assertdiscoveredhost(self, hostname): @pytest.mark.skip_if_not_set('vlan_networking') @pytest.fixture(scope='class') -def foreman_discovery(self): +def foreman_discovery(default_sat): """Steps to Configure foreman discovery 1. Build PXE default template @@ -64,11 +63,11 @@ def foreman_discovery(self): # Build PXE default template to get default PXE file Template.build_pxe_default() # let's just modify the timeouts to speed things up - ssh.command( - "sed -ie 's/TIMEOUT [[:digit:]]\\+/TIMEOUT 1/g' " "/var/lib/tftpboot/pxelinux.cfg/default" + default_sat.execute( + "sed -ie 's/TIMEOUT [[:digit:]]\\+/TIMEOUT 1/g' /var/lib/tftpboot/pxelinux.cfg/default" ) - ssh.command( - "sed -ie '/APPEND initrd/s/$/ fdi.countdown=1/' " "/var/lib/tftpboot/pxelinux.cfg/default" + default_sat.execute( + "sed -ie '/APPEND initrd/s/$/ fdi.countdown=1/' /var/lib/tftpboot/pxelinux.cfg/default" ) # Create Org and location @@ -104,7 +103,7 @@ def foreman_discovery(self): @pytest.mark.libvirt_discovery @pytest.mark.tier3 -def test_positive_pxe_based_discovery(self): +def test_positive_pxe_based_discovery(): """Discover a host via PXE boot by setting "proxy.type=proxy" in PXE default @@ -122,14 +121,14 @@ def test_positive_pxe_based_discovery(self): """ with LibvirtGuest() as pxe_host: hostname = pxe_host.guest_name - host = self._assertdiscoveredhost(hostname) + host = _assertdiscoveredhost(hostname) assert host is not None @pytest.mark.tier3 @pytest.mark.libvirt_discovery @pytest.mark.upgrade -def test_positive_provision_pxeless_bios_syslinux(self, foreman_discovery): +def test_positive_provision_pxeless_bios_syslinux(foreman_discovery): """Provision and discover the pxe-less BIOS host from cli using SYSLINUX loader @@ -166,7 +165,7 @@ def test_positive_provision_pxeless_bios_syslinux(self, foreman_discovery): with LibvirtGuest(boot_iso=True) as pxe_host: hostname = pxe_host.guest_name # fixme: assertion #1 - discovered_host = self._assertdiscoveredhost(hostname) + discovered_host = _assertdiscoveredhost(hostname) assert discovered_host is not None # Provision just discovered host DiscoveredHost.provision( @@ -206,7 +205,7 @@ def test_positive_provision_pxeless_bios_syslinux(self, foreman_discovery): @pytest.mark.tier3 @pytest.mark.libvirt_discovery @pytest.mark.upgrade -def test_positive_provision_pxe_host_with_bios_syslinux(self, foreman_discovery): +def test_positive_provision_pxe_host_with_bios_syslinux(foreman_discovery): """Provision the pxe-based BIOS discovered host from cli using SYSLINUX loader @@ -258,7 +257,7 @@ def test_positive_provision_pxe_host_with_bios_syslinux(self, foreman_discovery) hostname = pxe_host.guest_name # fixme: assertion #2-3 # assertion #4 - discovered_host = self._assertdiscoveredhost(hostname) + discovered_host = _assertdiscoveredhost(hostname) assert discovered_host is not None # Provision just discovered host DiscoveredHost.provision( @@ -297,7 +296,7 @@ def test_positive_provision_pxe_host_with_bios_syslinux(self, foreman_discovery) @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_provision_pxe_host_with_uefi_grub2(self): +def test_positive_provision_pxe_host_with_uefi_grub2(): """Provision the pxe-based UEFI discovered host from cli using PXEGRUB2 loader @@ -348,7 +347,7 @@ def test_positive_provision_pxe_host_with_uefi_grub2(self): @pytest.mark.tier3 @pytest.mark.libvirt_discovery -def test_positive_delete(self): +def test_positive_delete(): """Delete the selected discovered host :id: c4103de8-145c-4a7d-b837-a1dec97231a2 @@ -361,7 +360,7 @@ def test_positive_delete(self): """ with LibvirtGuest() as pxe_host: hostname = pxe_host.guest_name - host = self._assertdiscoveredhost(hostname) + host = _assertdiscoveredhost(hostname) assert host is not None DiscoveredHost.delete({'id': host['id']}) with pytest.raises(CLIReturnCodeError): @@ -370,7 +369,7 @@ def test_positive_delete(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_refresh_facts_pxe_host(self): +def test_positive_refresh_facts_pxe_host(): """Refresh the facts of pxe based discovered hosts by adding a new NIC :id: 410eaa5d-cc6a-44f7-8c6f-e8cfa81610f0 @@ -387,7 +386,7 @@ def test_positive_refresh_facts_pxe_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_refresh_facts_of_pxeless_host(self): +def test_positive_refresh_facts_of_pxeless_host(): """Refresh the facts of pxeless discovered hosts by adding a new NIC :id: 2e199eaa-9651-47b1-a2fd-622778dfe68e @@ -404,7 +403,7 @@ def test_positive_refresh_facts_of_pxeless_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_reboot_pxe_host(self): +def test_positive_reboot_pxe_host(): """Reboot pxe based discovered hosts :id: 9cc17742-f810-4be7-b410-a6c68e6cc64a @@ -421,7 +420,7 @@ def test_positive_reboot_pxe_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_reboot_pxeless_host(self): +def test_positive_reboot_pxeless_host(): """Reboot pxe-less discovered hosts :id: e72e1607-8778-45b6-b8b9-8215514546f0 @@ -438,7 +437,7 @@ def test_positive_reboot_pxeless_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_auto_provision_pxe_host(self): +def test_positive_auto_provision_pxe_host(): """Discover a pxe based host and auto-provision it with discovery rule and by enabling auto-provision flag @@ -454,7 +453,7 @@ def test_positive_auto_provision_pxe_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_auto_provision_pxeless_host(self): +def test_positive_auto_provision_pxeless_host(): """Discover a pxe-less host and auto-provision it with discovery rule and by enabling auto-provision flag @@ -470,7 +469,7 @@ def test_positive_auto_provision_pxeless_host(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_assign_discovery_manager_role(self): +def test_positive_assign_discovery_manager_role(): """Assign 'Discovery_Manager' role to a normal user :id: f694c361-5fbb-4c3a-b2ff-6dfe6ea14820 @@ -486,7 +485,7 @@ def test_positive_assign_discovery_manager_role(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_assign_discovery_role(self): +def test_positive_assign_discovery_role(): """Assign 'Discovery" role to a normal user :id: 873e8411-563d-4bf9-84ce-62e522410cfe @@ -502,7 +501,7 @@ def test_positive_assign_discovery_role(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_update_discover_hostname_settings(self): +def test_positive_update_discover_hostname_settings(): """Update the hostname_prefix and Hostname_facts settings and discover a host. @@ -518,7 +517,7 @@ def test_positive_update_discover_hostname_settings(self): @pytest.mark.stubbed @pytest.mark.tier3 -def test_positive_list_facts(self): +def test_positive_list_facts(): """Check if defined facts of a discovered host are correctly displayed under host's facts diff --git a/tests/foreman/cli/test_hammer.py b/tests/foreman/cli/test_hammer.py index 1efab5f25b4..9240132d04b 100644 --- a/tests/foreman/cli/test_hammer.py +++ b/tests/foreman/cli/test_hammer.py @@ -23,7 +23,6 @@ import pytest from fauxfactory import gen_string -from robottelo import ssh from robottelo.cli import hammer from robottelo.cli.admin import Admin from robottelo.cli.defaults import Defaults @@ -83,13 +82,18 @@ def format_commands_diff(commands_diff): return output_value -def traverse_command_tree(): - """Walk through the hammer commands tree and assert that the expected - options are present. +@pytest.mark.upgrade +def test_positive_all_options(default_sat): + """check all provided options for every hammer command + :id: 1203ab9f-896d-4039-a166-9e2d36925b5b + + :expectedresults: All expected options are present + + :CaseImportance: Critical """ differences = {} - raw_output = ssh.command('hammer full-help', output_format='plain').stdout + raw_output = default_sat.execute('hammer full-help').stdout commands = re.split(r'.*\n(?=hammer.*\n^[-]+)', raw_output, flags=re.M) commands.pop(0) # remove "Hammer CLI help" line for raw_command in commands: @@ -122,27 +126,13 @@ def traverse_command_tree(): diff['removed_subcommands'] = removed_subcommands differences[command] = diff - return differences - - -@pytest.mark.upgrade -def test_positive_all_options(): - """check all provided options for every hammer command - - :id: 1203ab9f-896d-4039-a166-9e2d36925b5b - - :expectedresults: All expected options are present - - :CaseImportance: Critical - """ - diff = traverse_command_tree() - if diff: + if differences: pytest.fail(format_commands_diff(diff)) @pytest.mark.upgrade @pytest.mark.run_in_one_thread -def test_positive_disable_hammer_defaults(): +def test_positive_disable_hammer_defaults(default_sat): """Verify hammer disable defaults command. :id: d0b65f36-b91f-4f2f-aaf8-8afda3e23708 @@ -164,26 +154,26 @@ def test_positive_disable_hammer_defaults(): try: Defaults.add({'param-name': 'organization_id', 'param-value': default_org['id']}) # list templates for BZ#1368173 - result = ssh.command('hammer job-template list') - assert result.return_code == 0 + result = default_sat.execute('hammer job-template list') + assert result.status == 0 # Verify --organization-id is not required to pass if defaults are set - result = ssh.command('hammer product list') - assert result.return_code == 0 + result = default_sat.execute('hammer product list') + assert result.status == 0 # Verify product list fail without using defaults - result = ssh.command('hammer --no-use-defaults product list') - assert result.return_code != 0 - assert default_product_name not in "".join(result.stdout) + result = default_sat.execute('hammer --no-use-defaults product list') + assert result.status != 0 + assert default_product_name not in result.stdout # Verify --organization-id is not required to pass if defaults are set - result = ssh.command('hammer --use-defaults product list') - assert result.return_code == 0 - assert default_product_name in ''.join(result.stdout) + result = default_sat.execute('hammer --use-defaults product list') + assert result.status == 0 + assert default_product_name in result.stdout finally: Defaults.delete({'param-name': 'organization_id'}) - result = ssh.command('hammer defaults list') - assert default_org['id'] not in ''.join(result.stdout) + result = default_sat.execute('hammer defaults list') + assert default_org['id'] not in result.stdout -def test_positive_check_debug_log_levels(): +def test_positive_check_debug_log_levels(default_sat): """Enabling debug log level in candlepin via hammer logging :id: 029c80f1-2bc5-494e-a04a-7d6beb0f769a @@ -198,12 +188,12 @@ def test_positive_check_debug_log_levels(): """ Admin.logging({'all': True, 'level-debug': True}) # Verify value of `log4j.logger.org.candlepin` as `DEBUG` - result = ssh.command('grep DEBUG /etc/candlepin/candlepin.conf') - assert result.return_code == 0 + result = default_sat.execute('grep DEBUG /etc/candlepin/candlepin.conf') + assert result.status == 0 assert 'log4j.logger.org.candlepin = DEBUG' in result.stdout Admin.logging({"all": True, "level-production": True}) # Verify value of `log4j.logger.org.candlepin` as `WARN` - result = ssh.command('grep WARN /etc/candlepin/candlepin.conf') - assert result.return_code == 0 + result = default_sat.execute('grep WARN /etc/candlepin/candlepin.conf') + assert result.status == 0 assert 'log4j.logger.org.candlepin = WARN' in result.stdout diff --git a/tests/foreman/cli/test_host.py b/tests/foreman/cli/test_host.py index 4666eb81391..ac768a0b002 100644 --- a/tests/foreman/cli/test_host.py +++ b/tests/foreman/cli/test_host.py @@ -30,7 +30,6 @@ from fauxfactory import gen_string from nailgun import entities -from robottelo import ssh from robottelo.api.utils import promote from robottelo.api.utils import wait_for_errata_applicability_task from robottelo.cli.activationkey import ActivationKey @@ -1462,7 +1461,7 @@ def test_positive_set_multi_line_and_with_spaces_parameter_value(function_host): response = Host.info( {'id': function_host['id']}, output_format='yaml', return_raw_response=True ) - assert response.return_code == 0 + assert response.status == 0 yaml_content = yaml.load('\n'.join(response.stdout), yaml.SafeLoader) host_initial_params = yaml_content.get('Parameters') # set parameter @@ -1470,7 +1469,7 @@ def test_positive_set_multi_line_and_with_spaces_parameter_value(function_host): response = Host.info( {'id': function_host['id']}, output_format='yaml', return_raw_response=True ) - assert response.return_code == 0 + assert response.status == 0 yaml_content = yaml.load('\n'.join(response.stdout), yaml.SafeLoader) host_parameters = yaml_content.get('Parameters') # check that number of params increased by one @@ -2478,7 +2477,7 @@ def test_syspurpose_end_to_end(module_host_subscription, host_subscription_clien # -------------------------- HOST ERRATA SUBCOMMAND SCENARIOS ------------------------- @pytest.mark.tier1 -def test_positive_errata_list_of_sat_server(): +def test_positive_errata_list_of_sat_server(default_sat): """Check if errata list doesn't raise exception. Check BZ for details. :id: 6b22f0c0-9c4b-11e6-ab93-68f72889dc7f @@ -2489,14 +2488,14 @@ def test_positive_errata_list_of_sat_server(): :CaseImportance: Critical """ - hostname = ssh.command('hostname').stdout[0] + hostname = default_sat.execute('hostname').stdout.strip() host = Host.info({'name': hostname}) assert isinstance(Host.errata_list({'host-id': host['id']}), list) # -------------------------- HOST ENC SUBCOMMAND SCENARIOS ------------------------- @pytest.mark.tier1 -def test_positive_dump_enc_yaml(): +def test_positive_dump_enc_yaml(default_sat): """Dump host's ENC YAML. Check BZ for details. :id: 50bf2530-788c-4710-a382-d034d73d5d4d @@ -2509,5 +2508,5 @@ def test_positive_dump_enc_yaml(): :CaseImportance: Critical """ - hostname = ssh.command('hostname').stdout[0] + hostname = default_sat.execute('hostname').stdout.strip() assert isinstance(Host.enc_dump({'name': hostname}), list) diff --git a/tests/foreman/cli/test_ldapauthsource.py b/tests/foreman/cli/test_ldapauthsource.py index 5401d356a35..adbd290b7de 100644 --- a/tests/foreman/cli/test_ldapauthsource.py +++ b/tests/foreman/cli/test_ldapauthsource.py @@ -177,25 +177,21 @@ class TestIPAAuthSource: """Implements FreeIPA ldap auth feature tests in CLI""" def _add_user_in_IPA_usergroup(self, member_username, member_group): - ssh.command( + self.ipa_host.execute( f'echo {self.ldap_ipa_user_passwd} | kinit admin', - hostname=self.ldap_ipa_hostname, ) - ssh.command( + self.ipa_host.execute( f'ipa group-add-member {member_group} --users={member_username}', - hostname=self.ldap_ipa_hostname, ) def _remove_user_in_IPA_usergroup(self, member_username, member_group): - ssh.command( + self.ipa_host.execute( f'echo {self.ldap_ipa_user_passwd} | kinit admin', - hostname=self.ldap_ipa_hostname, ) - result = ssh.command( + result = self.ipa_host.execute( f'ipa group-remove-member {member_group} --users={member_username}', - hostname=self.ldap_ipa_hostname, ) - if result.return_code != 0: + if result.status != 0: raise AssertionError('failed to remove the user from user-group') def _clean_up_previous_ldap(self): @@ -264,7 +260,7 @@ def test_usergroup_sync_with_refresh(self, ipa_data, ldap_tear_down): :CaseImportance: Medium """ self._clean_up_previous_ldap() - self.ldap_ipa_hostname = ipa_data['ldap_hostname'] + self.ipa_host = ssh.get_client(hostname=ipa_data['ldap_hostname']) self.ldap_ipa_user_passwd = ipa_data['ldap_user_passwd'] ipa_group_base_dn = ipa_data['group_base_dn'].replace('foobargroup', 'foreman_group') member_username = 'foreman_test' @@ -340,7 +336,7 @@ def test_usergroup_with_usergroup_sync(self, ipa_data, ldap_tear_down): :CaseImportance: Medium """ self._clean_up_previous_ldap() - self.ldap_ipa_hostname = ipa_data['ldap_hostname'] + self.ipa_host = ssh.get_client(hostname=ipa_data['ldap_hostname']) self.ldap_ipa_user_passwd = ipa_data['ldap_user_passwd'] ipa_group_base_dn = ipa_data['group_base_dn'].replace('foobargroup', 'foreman_group') member_username = 'foreman_test' diff --git a/tests/foreman/cli/test_lifecycleenvironment.py b/tests/foreman/cli/test_lifecycleenvironment.py index eeb289a7fda..74d82ea965e 100644 --- a/tests/foreman/cli/test_lifecycleenvironment.py +++ b/tests/foreman/cli/test_lifecycleenvironment.py @@ -175,7 +175,7 @@ def test_positve_list_paths(module_org): result = LifecycleEnvironment.paths( {'organization-id': module_org.id, 'permission-type': 'readable'} ) - assert f"Library >> {lc_env['name']}" in ''.join(result) + assert f"Library >> {lc_env['name']}" in result class LifeCycleEnvironmentPaginationTestCase: diff --git a/tests/foreman/cli/test_logging.py b/tests/foreman/cli/test_logging.py index 4a93fab6b2d..1b49ade1f2f 100644 --- a/tests/foreman/cli/test_logging.py +++ b/tests/foreman/cli/test_logging.py @@ -255,8 +255,8 @@ def test_positive_logging_from_pulp3(module_org, default_sat): # Get the id of repository sync from task task_out = default_sat.execute( "hammer task list | grep -F \'Synchronize repository {\"text\"=>\"repository\'" - ).stdout.split('\n')[0][:8] - prod_log_out = default_sat.execute(f'grep {task_out} {source_log}').stdout + ).stdout.splitlines()[0][:8] + prod_log_out = default_sat.execute(f'grep {task_out} {source_log}').stdout.splitlines()[0] # Get correlation id of pulp from production logs pulp_correlation_id = re.search(r'\[I\|bac\|\w{8}\]', prod_log_out).group()[7:15] # verify pulp correlation id in message diff --git a/tests/foreman/cli/test_operatingsystem.py b/tests/foreman/cli/test_operatingsystem.py index ad53d5e5843..473e73a2076 100644 --- a/tests/foreman/cli/test_operatingsystem.py +++ b/tests/foreman/cli/test_operatingsystem.py @@ -384,7 +384,7 @@ def test_positive_os_list_with_default_organization_set(satellite_latest): ) result = satellite_latest.execute('hammer defaults list') assert result.status == 0 - assert DEFAULT_ORG in "".join(result.stdout) + assert DEFAULT_ORG in result.stdout os_list_after_default = satellite_latest.cli.OperatingSys.list() assert len(os_list_after_default) > 0 @@ -392,4 +392,4 @@ def test_positive_os_list_with_default_organization_set(satellite_latest): satellite_latest.cli.Defaults.delete({'param-name': 'organization'}) result = satellite_latest.execute('hammer defaults list') assert result.status == 0 - assert DEFAULT_ORG not in "".join(result.stdout) + assert DEFAULT_ORG not in result.stdout diff --git a/tests/foreman/cli/test_oscap_tailoringfiles.py b/tests/foreman/cli/test_oscap_tailoringfiles.py index 63b18113752..b22b0e5a618 100644 --- a/tests/foreman/cli/test_oscap_tailoringfiles.py +++ b/tests/foreman/cli/test_oscap_tailoringfiles.py @@ -19,7 +19,6 @@ import pytest from fauxfactory import gen_string -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.factory import CLIFactoryError from robottelo.cli.factory import make_tailoringfile @@ -122,7 +121,7 @@ def test_positive_list_tailoring_file(self, tailoring_file_path): assert name in [tailoringfile['name'] for tailoringfile in result] @pytest.mark.tier1 - def test_negative_create_with_invalid_file(self): + def test_negative_create_with_invalid_file(self, default_sat): """Create Tailoring files with invalid file :id: 86f5ce13-856c-4e58-997f-fa21093edd04 @@ -135,10 +134,7 @@ def test_negative_create_with_invalid_file(self): :CaseImportance: Critical """ - ssh.upload_file( - local_file=get_data_file(SNIPPET_DATA_FILE), - remote_file=f'/tmp/{SNIPPET_DATA_FILE}', - ) + default_sat.put(get_data_file(SNIPPET_DATA_FILE), f'/tmp/{SNIPPET_DATA_FILE}') name = gen_string('alphanumeric') with pytest.raises(CLIFactoryError): make_tailoringfile({'name': name, 'scap-file': f'/tmp/{SNIPPET_DATA_FILE}'}) @@ -185,7 +181,7 @@ def test_negative_associate_tailoring_file_with_different_scap(self): @pytest.mark.skip_if_open("BZ:1857572") @pytest.mark.tier2 - def test_positive_download_tailoring_file(self, tailoring_file_path): + def test_positive_download_tailoring_file(self, tailoring_file_path, default_sat): """Download the tailoring file from satellite @@ -210,9 +206,9 @@ def test_positive_download_tailoring_file(self, tailoring_file_path): assert tailoring_file['name'] == name result = TailoringFiles.download_tailoring_file({'name': name, 'path': '/var/tmp/'}) assert file_path in result[0] - result = ssh.command(f'find {file_path} 2> /dev/null') - assert result.return_code == 0 - assert file_path == result.stdout[0] + result = default_sat.execute(f'find {file_path} 2> /dev/null') + assert result.status == 0 + assert file_path == result.stdout.strip() @pytest.mark.tier1 @pytest.mark.upgrade diff --git a/tests/foreman/cli/test_ostreebranch.py b/tests/foreman/cli/test_ostreebranch.py index 722a2ba87ca..4f5b3c1328f 100644 --- a/tests/foreman/cli/test_ostreebranch.py +++ b/tests/foreman/cli/test_ostreebranch.py @@ -30,7 +30,6 @@ from robottelo.cli.repository import Repository from robottelo.config import settings from robottelo.constants.repos import OSTREE_REPO -from robottelo.decorators.host import skip_if_os pytestmark = [ pytest.mark.skipif( @@ -75,7 +74,6 @@ def ostree_repo_with_user(ostree_user_credentials): return {'cv': cv, 'org': org, 'ostree_repo': ostree_repo, 'product': product} -@skip_if_os('RHEL6') @pytest.mark.skip_if_open("BZ:1625783") def test_positive_list(ostree_user_credentials, ostree_repo_with_user): """List Ostree Branches @@ -88,7 +86,6 @@ def test_positive_list(ostree_user_credentials, ostree_repo_with_user): assert len(result) > 0 -@skip_if_os('RHEL6') @pytest.mark.upgrade def test_positive_list_by_repo_id(ostree_repo_with_user, ostree_user_credentials): """List Ostree branches by repo id @@ -104,7 +101,6 @@ def test_positive_list_by_repo_id(ostree_repo_with_user, ostree_user_credentials assert len(result) > 0 -@skip_if_os('RHEL6') @pytest.mark.skip_if_open("BZ:1625783") def test_positive_list_by_product_id(ostree_repo_with_user, ostree_user_credentials): """List Ostree branches by product id @@ -119,7 +115,6 @@ def test_positive_list_by_product_id(ostree_repo_with_user, ostree_user_credenti assert len(result) > 0 -@skip_if_os('RHEL6') @pytest.mark.skip_if_open("BZ:1625783") def test_positive_list_by_org_id(ostree_repo_with_user, ostree_user_credentials): """List Ostree branches by org id @@ -134,7 +129,6 @@ def test_positive_list_by_org_id(ostree_repo_with_user, ostree_user_credentials) assert len(result) > 0 -@skip_if_os('RHEL6') @pytest.mark.skip_if_open("BZ:1625783") def test_positive_list_by_cv_id(ostree_repo_with_user, ostree_user_credentials): """List Ostree branches by cv id @@ -150,7 +144,6 @@ def test_positive_list_by_cv_id(ostree_repo_with_user, ostree_user_credentials): assert len(result) > 0 -@skip_if_os('RHEL6') @pytest.mark.skip_if_open("BZ:1625783") def test_positive_info_by_id(ostree_user_credentials, ostree_repo_with_user): """Get info for Ostree branch by id diff --git a/tests/foreman/cli/test_ping.py b/tests/foreman/cli/test_ping.py index 2f7c948d13a..38e49ee1f33 100644 --- a/tests/foreman/cli/test_ping.py +++ b/tests/foreman/cli/test_ping.py @@ -18,12 +18,10 @@ """ import pytest -from robottelo import ssh - @pytest.mark.tier1 @pytest.mark.upgrade -def test_positive_ping(): +def test_positive_ping(default_sat): """hammer ping return code :id: dfa3ab4f-a64f-4a96-8c7f-d940df22b8bf @@ -35,13 +33,13 @@ def test_positive_ping(): :expectedresults: hammer ping returns a right return code """ - result = ssh.command('hammer ping') - assert result.stderr.decode() == '' + result = default_sat.execute('hammer ping') + assert result.stderr[1].decode() == '' status_count = 0 ok_count = 0 # Exclude message from stdout for services candlepin_events and katello_events - result.stdout = [line for line in result.stdout if 'message' not in line] + result.stdout = [line for line in result.stdout.splitlines() if 'message' not in line] # iterate over the lines grouping every 3 lines # example [1, 2, 3, 4, 5, 6] will return [(1, 2, 3), (4, 5, 6)] @@ -53,9 +51,9 @@ def test_positive_ping(): ok_count += 1 if status_count == ok_count: - assert result.return_code == 0, 'Return code should be 0 if all services are ok' + assert result.status == 0, 'Return code should be 0 if all services are ok' else: - assert result.return_code != 0, 'Return code should not be 0 if any service is not ok' + assert result.status != 0, 'Return code should not be 0 if any service is not ok' @pytest.mark.destructive diff --git a/tests/foreman/cli/test_product.py b/tests/foreman/cli/test_product.py index 57435a6a8aa..4f7e284dbee 100644 --- a/tests/foreman/cli/test_product.py +++ b/tests/foreman/cli/test_product.py @@ -22,7 +22,6 @@ from fauxfactory import gen_string from fauxfactory import gen_url -from robottelo import ssh from robottelo.api.utils import wait_for_tasks from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.defaults import Defaults @@ -175,7 +174,7 @@ def test_negative_create_with_label(label, module_org): @pytest.mark.run_in_one_thread @pytest.mark.tier2 @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') -def test_product_list_with_default_settings(module_org): +def test_product_list_with_default_settings(module_org, default_sat): """Listing product of an organization apart from default organization using hammer does not return output if a defaults settings are applied on org. @@ -206,14 +205,15 @@ def test_product_list_with_default_settings(module_org): ) Defaults.add({'param-name': 'organization_id', 'param-value': org_id}) - result = ssh.command('hammer defaults list') - assert org_id in "".join(result.stdout) + result = default_sat.cli.Defaults.list(per_page=False) + assert any([res['value'] == org_id for res in result if res['parameter'] == 'organization_id']) + try: # Verify --organization-id is not required to pass if defaults are set - result = ssh.command('hammer product list') - assert default_product_name in "".join(result.stdout) - result = ssh.command('hammer repository list') - assert default_product_name in "".join(result.stdout) + result = default_sat.cli.Product.list() + assert any([res['name'] == default_product_name for res in result]) + result = default_sat.cli.Repository.list() + assert any([res['product'] == default_product_name for res in result]) # verify that defaults setting should not affect other entities product_list = Product.list({'organization-id': non_default_org['id']}) @@ -223,8 +223,8 @@ def test_product_list_with_default_settings(module_org): finally: Defaults.delete({'param-name': 'organization_id'}) - result = ssh.command('hammer defaults list') - assert org_id not in "".join(result.stdout) + result = default_sat.cli.Defaults.list(per_page=False) + assert not [res for res in result if res['parameter'] == 'organization_id'] @pytest.mark.tier2 diff --git a/tests/foreman/cli/test_report.py b/tests/foreman/cli/test_report.py index d30109473ca..8f53061aed6 100644 --- a/tests/foreman/cli/test_report.py +++ b/tests/foreman/cli/test_report.py @@ -20,18 +20,17 @@ import pytest -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.report import Report @pytest.fixture(scope='module', autouse=True) -def run_puppet_agent(): +def run_puppet_agent(default_sat): """Retrieves the client configuration from the puppet master and applies it to the local host. This is required to make sure that we have reports available. """ - ssh.command('puppet agent -t') + default_sat.execute('puppet agent -t') @pytest.mark.tier1 diff --git a/tests/foreman/cli/test_reporttemplates.py b/tests/foreman/cli/test_reporttemplates.py index e6653df1e2a..fe170a624b0 100644 --- a/tests/foreman/cli/test_reporttemplates.py +++ b/tests/foreman/cli/test_reporttemplates.py @@ -64,15 +64,14 @@ from robottelo.constants import REPOS from robottelo.constants import REPOSET from robottelo.hosts import ContentHost -from robottelo.ssh import upload_file @pytest.fixture(scope='module') -def local_org(): +def local_org(default_sat): """Create org with CLI factory and upload cloned manifest""" org = make_org() with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) return org diff --git a/tests/foreman/cli/test_repository.py b/tests/foreman/cli/test_repository.py index e7bd8a56d44..eed5910cc6c 100644 --- a/tests/foreman/cli/test_repository.py +++ b/tests/foreman/cli/test_repository.py @@ -24,7 +24,6 @@ from nailgun import entities from wait_for import wait_for -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.content_export import ContentExport from robottelo.cli.content_import import ContentImport @@ -934,7 +933,7 @@ def test_negative_synchronize_auth_yum_repo(self, creds, repo): response.stderr ) else: - assert 'Error retrieving metadata: Unauthorized' in ''.join(response.stderr) + assert 'Error retrieving metadata: Unauthorized' in response.stderr[1] @pytest.mark.tier2 @pytest.mark.upgrade @@ -1239,7 +1238,9 @@ def test_mirror_on_sync_removes_rpm(self, module_org, repo, repo_options_2): ), indirect=True, ) - def test_positive_synchronize_rpm_repo_ignore_content(self, module_org, module_product, repo): + def test_positive_synchronize_rpm_repo_ignore_content( + self, module_org, module_product, repo, default_sat + ): """Synchronize yum repository with ignore content setting :id: fa32ff10-e2e2-4ee0-b444-82f66f4a0e96 @@ -1262,13 +1263,13 @@ def test_positive_synchronize_rpm_repo_ignore_content(self, module_org, module_p assert repo['content-counts']['errata'] == '0', 'content not ignored correctly' assert repo['content-counts']['source-rpms'] == '0', 'content not ignored correctly' # drpm check requires a different method - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/Library" f"/custom/{module_product.label}/{repo['label']}/drpms/ | grep .drpm" ) # expecting No such file or directory for drpms - assert result.return_code == 1 - assert 'No such file or directory' in result.stderr + assert result.status == 1 + assert 'No such file or directory' in result.stderr[1] # Find repo packages and remove them packages = Package.list({'repository-id': repo['id']}) @@ -1292,12 +1293,13 @@ def test_positive_synchronize_rpm_repo_ignore_content(self, module_org, module_p assert repo['content-counts']['source-rpms'] == '3', 'content not synced correctly' if not is_open('BZ:1682951'): - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/Library" f"/custom/{module_product.label}/{repo['label']}/drpms/ | grep .drpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 4, 'content not synced correctly' + assert result.status == 0 + # this isn't a good pattern, a better assertion would be on stdout contents + assert len(result.stdout.splitlines()) >= 4, 'content not synced correctly' @pytest.mark.tier1 @pytest.mark.parametrize( @@ -1664,7 +1666,7 @@ def test_positive_remove_content_rpm(self, repo): assert repo['content-counts']['packages'] == '0' @pytest.mark.tier1 - def test_positive_upload_content(self, repo): + def test_positive_upload_content(self, repo, default_sat): """Create repository and upload content :id: eb0ec599-2bf1-483a-8215-66652f948d67 @@ -1679,8 +1681,8 @@ def test_positive_upload_content(self, repo): :CaseImportance: Critical """ - ssh.upload_file( - local_file=get_data_file(RPM_TO_UPLOAD), remote_file=f"/tmp/{RPM_TO_UPLOAD}" + default_sat.put( + local_path=get_data_file(RPM_TO_UPLOAD), remote_path=f"/tmp/{RPM_TO_UPLOAD}" ) result = Repository.upload_content( { @@ -1699,7 +1701,7 @@ def test_positive_upload_content(self, repo): **parametrized([{'content-type': 'file', 'url': CUSTOM_FILE_REPO}]), indirect=True, ) - def test_positive_upload_content_to_file_repo(self, repo): + def test_positive_upload_content_to_file_repo(self, repo, default_sat): """Create file repository and upload content to it :id: 5e24b416-2928-4533-96cf-6bffbea97a95 @@ -1718,9 +1720,9 @@ def test_positive_upload_content_to_file_repo(self, repo): # Verify it has finished new_repo = Repository.info({'id': repo['id']}) assert int(new_repo['content-counts']['files']) == CUSTOM_FILE_REPO_FILES_COUNT - ssh.upload_file( - local_file=get_data_file(OS_TEMPLATE_DATA_FILE), - remote_file=f"/tmp/{OS_TEMPLATE_DATA_FILE}", + default_sat.put( + local_path=get_data_file(OS_TEMPLATE_DATA_FILE), + remote_path=f"/tmp/{OS_TEMPLATE_DATA_FILE}", ) result = Repository.upload_content( { @@ -1895,7 +1897,7 @@ def test_negative_restricted_user_cv_add_repository(self, module_org, repo): assert len(repos) == 0 @pytest.mark.tier2 - def test_positive_upload_remove_srpm_content(self, repo): + def test_positive_upload_remove_srpm_content(self, repo, default_sat): """Create repository, upload and remove an SRPM content :id: 706dc3e2-dacb-4fdd-8eef-5715ce498888 @@ -1910,8 +1912,8 @@ def test_positive_upload_remove_srpm_content(self, repo): :BZ: 1378442 """ - ssh.upload_file( - local_file=get_data_file(SRPM_TO_UPLOAD), remote_file=f"/tmp/{SRPM_TO_UPLOAD}" + default_sat.put( + local_path=get_data_file(SRPM_TO_UPLOAD), remote_path=f"/tmp/{SRPM_TO_UPLOAD}" ) # Upload SRPM result = Repository.upload_content( @@ -1938,7 +1940,7 @@ def test_positive_upload_remove_srpm_content(self, repo): @pytest.mark.upgrade @pytest.mark.tier2 - def test_positive_srpm_list_end_to_end(self, repo): + def test_positive_srpm_list_end_to_end(self, repo, default_sat): """Create repository, upload, list and remove an SRPM content :id: 98ad4228-f2e5-438a-9210-5ce6561769f2 @@ -1954,8 +1956,8 @@ def test_positive_srpm_list_end_to_end(self, repo): :CaseImportance: High """ - ssh.upload_file( - local_file=get_data_file(SRPM_TO_UPLOAD), remote_file=f"/tmp/{SRPM_TO_UPLOAD}" + default_sat.put( + local_path=get_data_file(SRPM_TO_UPLOAD), remote_path=f"/tmp/{SRPM_TO_UPLOAD}" ) # Upload SRPM Repository.upload_content( @@ -2384,7 +2386,7 @@ class TestSRPMRepository: @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_SRPM_REPO}]), indirect=True ) - def test_positive_sync(self, repo, module_org, module_product): + def test_positive_sync(self, repo, module_org, module_product, default_sat): """Synchronize repository with SRPMs :id: eb69f840-122d-4180-b869-1bd37518480c @@ -2394,19 +2396,19 @@ def test_positive_sync(self, repo, module_org, module_product): :expectedresults: srpms can be listed in repository """ Repository.synchronize({'id': repo['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/Library" f"/custom/{module_product.label}/{repo['label']}/Packages/t/ | grep .src.rpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout @pytest.mark.tier2 @pytest.mark.skip("Uses deprecated SRPM repository") @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_SRPM_REPO}]), indirect=True ) - def test_positive_sync_publish_cv(self, module_org, module_product, repo): + def test_positive_sync_publish_cv(self, module_org, module_product, repo, default_sat): """Synchronize repository with SRPMs, add repository to content view and publish content view @@ -2420,13 +2422,13 @@ def test_positive_sync_publish_cv(self, module_org, module_product, repo): cv = make_content_view({'organization-id': module_org.id}) ContentView.add_repository({'id': cv['id'], 'repository-id': repo['id']}) ContentView.publish({'id': cv['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/content_views/" f"{cv['label']}/1.0/custom/{module_product.label}/{repo['label']}/Packages/t/" " | grep .src.rpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout @pytest.mark.tier2 @pytest.mark.upgrade @@ -2434,7 +2436,7 @@ def test_positive_sync_publish_cv(self, module_org, module_product, repo): @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_SRPM_REPO}]), indirect=True ) - def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product): + def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product, default_sat): """Synchronize repository with SRPMs, add repository to content view, publish and promote content view to lifecycle environment @@ -2453,13 +2455,13 @@ def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product content_view = ContentView.info({'id': cv['id']}) cvv = content_view['versions'][0] ContentView.version_promote({'id': cvv['id'], 'to-lifecycle-environment-id': lce['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/{lce['label']}/" f"{cv['label']}/custom/{module_product.label}/{repo['label']}/Packages/t" " | grep .src.rpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout class TestAnsibleCollectionRepository: @@ -2569,7 +2571,7 @@ class TestMD5Repository: @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_MD5_REPO}]), indirect=True ) - def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product): + def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product, default_sat): """Synchronize MD5 signed repository with add repository to content view, publish and promote content view to lifecycle environment @@ -2588,13 +2590,13 @@ def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product content_view = ContentView.info({'id': cv['id']}) cvv = content_view['versions'][0] ContentView.version_promote({'id': cvv['id'], 'to-lifecycle-environment-id': lce['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/{lce['label']}/" f"{cv['label']}/custom/{module_product.label}/{repo['label']}/Packages/b" " | grep bear-4.1-1.noarch.rpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout @pytest.mark.skip_if_open("BZ:1682951") @@ -2606,7 +2608,7 @@ class TestDRPMRepository: @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_DRPM_REPO}]), indirect=True ) - def test_positive_sync(self, repo, module_org, module_product): + def test_positive_sync(self, repo, module_org, module_product, default_sat): """Synchronize repository with DRPMs :id: a645966c-750b-40ef-a264-dc3bb632b9fd @@ -2616,19 +2618,19 @@ def test_positive_sync(self, repo, module_org, module_product): :expectedresults: drpms can be listed in repository """ Repository.synchronize({'id': repo['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/Library" f"/custom/{module_product.label}/{repo['label']}/drpms/ | grep .drpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout @pytest.mark.tier2 @pytest.mark.skip("Uses deprecated DRPM repository") @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_DRPM_REPO}]), indirect=True ) - def test_positive_sync_publish_cv(self, repo, module_org, module_product): + def test_positive_sync_publish_cv(self, repo, module_org, module_product, default_sat): """Synchronize repository with DRPMs, add repository to content view and publish content view @@ -2642,12 +2644,12 @@ def test_positive_sync_publish_cv(self, repo, module_org, module_product): cv = make_content_view({'organization-id': module_org.id}) ContentView.add_repository({'id': cv['id'], 'repository-id': repo['id']}) ContentView.publish({'id': cv['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/content_views/" f"{cv['label']}/1.0/custom/{module_product.label}/{repo['label']}/drpms/ | grep .drpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout @pytest.mark.tier2 @pytest.mark.upgrade @@ -2655,7 +2657,7 @@ def test_positive_sync_publish_cv(self, repo, module_org, module_product): @pytest.mark.parametrize( 'repo_options', **parametrized([{'url': FAKE_YUM_DRPM_REPO}]), indirect=True ) - def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product): + def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product, default_sat): """Synchronize repository with DRPMs, add repository to content view, publish and promote content view to lifecycle environment @@ -2674,12 +2676,12 @@ def test_positive_sync_publish_promote_cv(self, repo, module_org, module_product content_view = ContentView.info({'id': cv['id']}) cvv = content_view['versions'][0] ContentView.version_promote({'id': cvv['id'], 'to-lifecycle-environment-id': lce['id']}) - result = ssh.command( + result = default_sat.execute( f"ls /var/lib/pulp/published/yum/https/repos/{module_org.label}/{lce['label']}" f"/{cv['label']}/custom/{module_product.label}/{repo['label']}/drpms/ | grep .drpm" ) - assert result.return_code == 0 - assert len(result.stdout) >= 1 + assert result.status == 0 + assert result.stdout class TestGitPuppetMirror: @@ -2909,7 +2911,7 @@ class TestFileRepository: **parametrized([{'content-type': 'file', 'url': CUSTOM_FILE_REPO}]), indirect=True, ) - def test_positive_upload_file_to_file_repo(self, repo_options, repo): + def test_positive_upload_file_to_file_repo(self, repo_options, repo, default_sat): """Check arbitrary file can be uploaded to File Repository :id: 134d668d-bd63-4475-bf7b-b899bb9fb7bb @@ -2926,8 +2928,8 @@ def test_positive_upload_file_to_file_repo(self, repo_options, repo): :CaseImportance: Critical """ - ssh.upload_file( - local_file=get_data_file(RPM_TO_UPLOAD), remote_file=f"/tmp/{RPM_TO_UPLOAD}" + default_sat.put( + local_path=get_data_file(RPM_TO_UPLOAD), remote_path=f"/tmp/{RPM_TO_UPLOAD}" ) result = Repository.upload_content( { @@ -2972,7 +2974,7 @@ def test_positive_file_permissions(self): **parametrized([{'content-type': 'file', 'url': CUSTOM_FILE_REPO}]), indirect=True, ) - def test_positive_remove_file(self, repo): + def test_positive_remove_file(self, repo, default_sat): """Check arbitrary file can be removed from File Repository :id: 07ca9c8d-e764-404e-866d-30d8cd2ca2b6 @@ -2990,8 +2992,8 @@ def test_positive_remove_file(self, repo): :CaseImportance: Critical """ - ssh.upload_file( - local_file=get_data_file(RPM_TO_UPLOAD), remote_file=f"/tmp/{RPM_TO_UPLOAD}" + default_sat.put( + local_path=get_data_file(RPM_TO_UPLOAD), remote_path=f"/tmp/{RPM_TO_UPLOAD}" ) result = Repository.upload_content( { @@ -3055,7 +3057,7 @@ def test_positive_remote_directory_sync(self, repo): **parametrized([{'content-type': 'file', 'url': f'file://{CUSTOM_LOCAL_FOLDER}'}]), indirect=True, ) - def test_positive_file_repo_local_directory_sync(self, repo): + def test_positive_file_repo_local_directory_sync(self, repo, default_sat): """Check an entire local directory can be synced to File Repository :id: ee91ecd2-2f07-4678-b782-95a7e7e57159 @@ -3077,8 +3079,8 @@ def test_positive_file_repo_local_directory_sync(self, repo): :CaseImportance: Critical """ # Making Setup For Creating Local Directory using Pulp Manifest - ssh.command(f"mkdir -p {CUSTOM_LOCAL_FOLDER}") - ssh.command( + default_sat.execute(f'mkdir -p {CUSTOM_LOCAL_FOLDER}') + default_sat.execute( f'wget -P {CUSTOM_LOCAL_FOLDER} -r -np -nH --cut-dirs=5 -R "index.html*" ' f'{CUSTOM_FILE_REPO}' ) @@ -3092,7 +3094,7 @@ def test_positive_file_repo_local_directory_sync(self, repo): **parametrized([{'content-type': 'file', 'url': f'file://{CUSTOM_LOCAL_FOLDER}'}]), indirect=True, ) - def test_positive_symlinks_sync(self, repo): + def test_positive_symlinks_sync(self, repo, default_sat): """Check symlinks can be synced to File Repository :id: b0b0a725-b754-450b-bc0d-572d0294307a @@ -3115,12 +3117,12 @@ def test_positive_symlinks_sync(self, repo): :CaseAutomation: Automated """ # Downloading the pulp repository into Satellite Host - ssh.command(f"mkdir -p {CUSTOM_LOCAL_FOLDER}") - ssh.command( + default_sat.execute(f'mkdir -p {CUSTOM_LOCAL_FOLDER}') + default_sat.execute( f'wget -P {CUSTOM_LOCAL_FOLDER} -r -np -nH --cut-dirs=5 -R "index.html*" ' f'{CUSTOM_FILE_REPO}' ) - ssh.command(f"ln -s {CUSTOM_LOCAL_FOLDER} /{gen_string('alpha')}") + default_sat.execute(f'ln -s {CUSTOM_LOCAL_FOLDER} /{gen_string("alpha")}') Repository.synchronize({'id': repo['id']}) repo = Repository.info({'id': repo['id']}) diff --git a/tests/foreman/cli/test_repository_set.py b/tests/foreman/cli/test_repository_set.py index 16a734b9e4e..c831806826b 100644 --- a/tests/foreman/cli/test_repository_set.py +++ b/tests/foreman/cli/test_repository_set.py @@ -25,7 +25,6 @@ from robottelo.cli.subscription import Subscription from robottelo.constants import PRDS from robottelo.constants import REPOSET -from robottelo.ssh import upload_file pytestmark = [pytest.mark.run_in_one_thread, pytest.mark.tier1] @@ -119,10 +118,10 @@ def org(): @pytest.fixture -def manifest_org(org): +def manifest_org(org, default_sat): """Upload a manifest to the organization.""" with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.upload({'file': manifest.filename, 'organization-id': org['id']}) return org diff --git a/tests/foreman/cli/test_satellitesync.py b/tests/foreman/cli/test_satellitesync.py index a7596974454..ffac84e2a3b 100644 --- a/tests/foreman/cli/test_satellitesync.py +++ b/tests/foreman/cli/test_satellitesync.py @@ -25,7 +25,6 @@ from nailgun import entities from robottelo import manifests -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.contentview import ContentView from robottelo.cli.factory import make_content_view @@ -49,33 +48,35 @@ @pytest.fixture(scope='class') -def class_export_directory(): +def class_export_directory(default_sat): """Create a directory for export, configure permissions and satellite settings, at the end remove the export directory with all exported repository archives""" export_dir = gen_string('alphanumeric') # Create a new 'export' directory on the Satellite system - result = ssh.command(f'mkdir /mnt/{export_dir}') - assert result.return_code == 0 + result = default_sat.execute(f'mkdir /mnt/{export_dir}') + assert result.status == 0 - result = ssh.command(f'chown foreman.foreman /mnt/{export_dir}') - assert result.return_code == 0 + result = default_sat.execute(f'chown foreman.foreman /mnt/{export_dir}') + assert result.status == 0 - result = ssh.command(f'ls -Z /mnt/ | grep {export_dir}') - assert result.return_code == 0 + result = default_sat.execute(f'ls -Z /mnt/ | grep {export_dir}') + assert result.status == 0 assert len(result.stdout) >= 1 assert 'unconfined_u:object_r:mnt_t:s0' in result.stdout[0] # Fix SELinux policy for new directory - result = ssh.command(f'semanage fcontext -a -t foreman_var_run_t "/mnt/{export_dir}(/.*)?"') - assert result.return_code == 0 + result = default_sat.execute( + f'semanage fcontext -a -t foreman_var_run_t "/mnt/{export_dir}(/.*)?"' + ) + assert result.status == 0 - result = ssh.command(f'restorecon -Rv /mnt/{export_dir}') - assert result.return_code == 0 + result = default_sat.execute(f'restorecon -Rv /mnt/{export_dir}') + assert result.status == 0 # Assert that we have the correct policy - result = ssh.command(f'ls -Z /mnt/ | grep {export_dir}') - assert result.return_code == 0 + result = default_sat.execute(f'ls -Z /mnt/ | grep {export_dir}') + assert result.status == 0 assert len(result.stdout) >= 1 assert 'unconfined_u:object_r:foreman_var_run_t:s0' in result.stdout[0] @@ -83,7 +84,7 @@ def class_export_directory(): Settings.set({'name': 'pulp_export_destination', 'value': f'/mnt/{export_dir}'}) # Create an organization to reuse in tests yield export_dir - ssh.command(f'rm -rf /mnt/{export_dir}') + default_sat.execute(f'rm -rf /mnt/{export_dir}') class ExportDirectoryNotSet(Exception): @@ -95,7 +96,7 @@ class TestRepositoryExport: """Tests for exporting a repository via CLI""" @pytest.mark.tier3 - def test_positive_export_custom_product(self, class_export_directory, module_org): + def test_positive_export_custom_product(self, class_export_directory, module_org, default_sat): """Export a repository from the custom product :id: 9c855866-b9b1-4e32-b3eb-7342fdaa7116 @@ -124,7 +125,7 @@ def test_positive_export_custom_product(self, class_export_directory, module_org Repository.export({'id': repo['id']}) # Verify export directory is empty - result = ssh.command(f'find {repo_export_dir} -name "*.rpm"') + result = default_sat.execute(f'find {repo_export_dir} -name "*.rpm"') assert len(result.stdout) == 0 # Synchronize the repository @@ -134,14 +135,14 @@ def test_positive_export_custom_product(self, class_export_directory, module_org Repository.export({'id': repo['id']}) # Verify RPMs were successfully exported - result = ssh.command(f'find {repo_export_dir} -name "*.rpm"') - assert result.return_code == 0 + result = default_sat.execute(f'find {repo_export_dir} -name "*.rpm"') + assert result.status == 0 assert len(result.stdout) >= 1 @pytest.mark.skip_if_not_set('fake_manifest') @pytest.mark.tier3 @pytest.mark.upgrade - def test_positive_export_rh_product(self, class_export_directory, module_org): + def test_positive_export_rh_product(self, class_export_directory, module_org, default_sat): """Export a repository from the Red Hat product :id: e17898db-ca92-4121-a723-0d4b3cf120eb @@ -153,7 +154,7 @@ def test_positive_export_rh_product(self, class_export_directory, module_org): """ # Enable RH repository with manifests.clone() as manifest: - ssh.upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.upload({'file': manifest.filename, 'organization-id': module_org.id}) RepositorySet.enable( { @@ -184,7 +185,7 @@ def test_positive_export_rh_product(self, class_export_directory, module_org): Repository.export({'id': repo['id']}) # Verify export directory is empty - result = ssh.command(f'find {repo_export_dir} -name "*.rpm"') + result = default_sat.execute(f'find {repo_export_dir} -name "*.rpm"') assert len(result.stdout) == 0 # Synchronize the repository @@ -194,15 +195,15 @@ def test_positive_export_rh_product(self, class_export_directory, module_org): Repository.export({'id': repo['id']}) # Verify RPMs were successfully exported - result = ssh.command(f'find {repo_export_dir} -name "*.rpm"') - assert result.return_code == 0 + result = default_sat.execute(f'find {repo_export_dir} -name "*.rpm"') + assert result.status == 0 assert len(result.stdout) >= 1 @pytest.fixture(scope='class') -def class_export_entities(): +def class_export_entities(default_sat): """Create Directory for all CV Sync Tests in export_base directory""" - if ssh.command(f'[ -d {get_export_base()} ]').return_code == 1: + if default_sat.execute(f'[ -d {get_export_base()} ]').status == 1: raise ExportDirectoryNotSet(f'Export Directory "{get_export_base()}" is not set/found.') exporting_org = make_org() exporting_prod_name = gen_string('alpha') @@ -231,13 +232,13 @@ def class_export_entities(): @pytest.fixture(scope='function') -def function_export_cv_directory(): +def function_export_cv_directory(default_sat): """Create directory for CV export and at the end remove it""" export_dir = f'{get_export_base()}/{gen_string("alpha")}' - ssh.command(f'mkdir {export_dir}') + default_sat.execute(f'mkdir {export_dir}') yield export_dir # Deletes directory created for CV export Test - ssh.command(f'rm -rf {export_dir}') + default_sat.execute(f'rm -rf {export_dir}') def get_export_base(): @@ -310,7 +311,7 @@ def _enable_rhel_content(organization, repo_name, releasever=None, product=None, return repo -def _update_json(json_path): +def _update_json(json_path, host_obj): """Updates the major and minor version in the exported json file :param json_path: json file path on server @@ -318,22 +319,22 @@ def _update_json(json_path): """ new_major = gen_integer(2, 1000) new_minor = gen_integer(2, 1000) - result = ssh.command(f'[ -f {json_path} ]') - if result.return_code == 0: - ssh.command(f'sed -i \'s/\"major\": [0-9]\\+/\"major\": {new_major}/\' {json_path}') - ssh.command(f'sed -i \'s/\"minor\": [0-9]\\+/\"minor\": {new_minor}/\' {json_path}') + result = host_obj.execute(f'[ -f {json_path} ]') + if result.status == 0: + host_obj.execute(f'sed -i \'s/\"major\": [0-9]\\+/\"major\": {new_major}/\' {json_path}') + host_obj.execute(f'sed -i \'s/\"minor\": [0-9]\\+/\"minor\": {new_minor}/\' {json_path}') return new_major, new_minor raise OSError(f'Json File {json_path} not found to alternate the major/minor versions') -def _assert_exported_cvv_exists(export_dir, content_view_name, content_view_version): +def _assert_exported_cvv_exists(export_dir, content_view_name, content_view_version, host_obj): """Verify an exported tar exists :return: The path to the tar (if it exists). """ exported_tar = f'{export_dir}/export-{content_view_name}-{content_view_version}.tar' - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = host_obj.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 return exported_tar @@ -383,7 +384,7 @@ class TestContentViewSync: @pytest.mark.upgrade @pytest.mark.tier3 def test_positive_export_import_default_org_view( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Export Default Organization View version contents in directory and Import them. @@ -432,8 +433,8 @@ def test_positive_export_import_default_org_view( exported_tar = ( f'{function_export_cv_directory}/export-{cview_label}-{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': default_cvv_id}) assert len(exported_packages) > 0 # importing @@ -465,7 +466,7 @@ def test_positive_export_import_default_org_view( @pytest.mark.tier3 def test_positive_export_import_filtered_cvv( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """CV Version with filtered contents only can be exported and imported. @@ -531,8 +532,8 @@ def test_positive_export_import_filtered_cvv( f'{function_export_cv_directory}/export-' f'{exporting_cv_name}-{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': exporting_cvv_id}) assert len(exported_packages) == 1 imported_entities = _import_entities( @@ -554,7 +555,9 @@ def test_positive_export_import_filtered_cvv( assert len(imported_packages) == 1 @pytest.mark.tier3 - def test_positive_export_import_cv(self, class_export_entities, function_export_cv_directory): + def test_positive_export_import_cv( + self, class_export_entities, function_export_cv_directory, default_sat + ): """Export CV version contents in directory and Import them. :id: b4fb9386-9b6a-4fc5-a8bf-96d7c80af93e @@ -593,8 +596,8 @@ def test_positive_export_import_cv(self, class_export_entities, function_export_ f'{function_export_cv_directory}/export-{class_export_entities["exporting_cv_name"]}-' f'{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list( {'content-view-version-id': class_export_entities['exporting_cvv_id']} ) @@ -621,7 +624,7 @@ def test_positive_export_import_cv(self, class_export_entities, function_export_ @pytest.mark.tier3 @pytest.mark.upgrade def test_positive_export_import_redhat_cv( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Export CV version redhat contents in directory and Import them @@ -669,8 +672,8 @@ def test_positive_export_import_redhat_cv( exported_tar = ( f'{function_export_cv_directory}/export-{rhva_cv_name}-{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': exporting_cvv_id}) assert len(exported_packages) > 0 Subscription.delete_manifest( @@ -691,7 +694,7 @@ def test_positive_export_import_redhat_cv( @pytest.mark.tier4 def test_positive_export_import_redhat_cv_with_huge_contents( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Export CV version redhat contents in directory and Import them @@ -739,8 +742,8 @@ def test_positive_export_import_redhat_cv_with_huge_contents( exported_tar = ( f'{function_export_cv_directory}/export-{rhel_cv_name}-{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': exporting_cvv_id}) assert len(exported_packages) > 0 Subscription.delete_manifest( @@ -761,7 +764,7 @@ def test_positive_export_import_redhat_cv_with_huge_contents( @pytest.mark.tier2 def test_positive_exported_cv_tar_contents( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Exported CV version contents in export directory are same as CVv contents @@ -792,9 +795,9 @@ def test_positive_exported_cv_tar_contents( f'{function_export_cv_directory}/export-{class_export_entities["exporting_cv_name"]}-' f'{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 - result = ssh.command(f'tar -t -f {exported_tar}') + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 + result = default_sat.execute(f'tar -t -f {exported_tar}') contents_tar = ( f'export-{class_export_entities["exporting_cv_name"]}-{exporting_cvv_version}/export-' f'{class_export_entities["exporting_cv_name"]}-{exporting_cvv_version}-repos.tar' @@ -804,8 +807,8 @@ def test_positive_exported_cv_tar_contents( {'content-view-version-id': class_export_entities['exporting_cvv_id']} ) assert len(cvv_packages) > 0 - ssh.command(f'tar -xf {exported_tar} -C {function_export_cv_directory}') - exported_packages = ssh.command( + default_sat.execute(f'tar -xf {exported_tar} -C {function_export_cv_directory}') + exported_packages = default_sat.execute( f'tar -tf {function_export_cv_directory}/{contents_tar} | grep .rpm | wc -l' ) assert len(cvv_packages) == int(exported_packages.stdout[0]) @@ -813,7 +816,7 @@ def test_positive_exported_cv_tar_contents( @pytest.mark.tier1 @pytest.mark.upgrade def test_positive_export_import_promoted_cv( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Export promoted CV version contents in directory and Import them. @@ -856,8 +859,8 @@ def test_positive_export_import_promoted_cv( f'{function_export_cv_directory}/export-{class_export_entities["exporting_cv_name"]}-' f'{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': promoted_cvv_id}) imported_entities = _import_entities( class_export_entities['exporting_prod_name'], @@ -933,7 +936,7 @@ def test_positive_repo_contents_of_imported_cv( @pytest.mark.tier2 def test_negative_reimport_cv_with_same_major_minor( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Reimport CV version with same major and minor fails @@ -965,8 +968,8 @@ def test_negative_reimport_cv_with_same_major_minor( f'{function_export_cv_directory}/export-{class_export_entities["exporting_cv_name"]}-' f'{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 imported_entities = _import_entities( class_export_entities['exporting_prod_name'], class_export_entities['exporting_repo_name'], @@ -1324,7 +1327,7 @@ def test_negative_export_cv_with_puppet_repo(self, function_export_cv_directory) @pytest.mark.tier3 def test_postive_export_cv_with_mixed_content_repos( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Exporting CV version having yum and non-yum(puppet) is successful @@ -1397,12 +1400,15 @@ def test_postive_export_cv_with_mixed_content_repos( {'export-dir': f'{function_export_cv_directory}', 'id': export_cvv_info['id']} ) _assert_exported_cvv_exists( - function_export_cv_directory, content_view['name'], export_cvv_info['version'] + function_export_cv_directory, + content_view['name'], + export_cvv_info['version'], + default_sat, ) @pytest.mark.tier2 def test_positive_import_cv_with_customized_major_minor( - self, class_export_entities, function_export_cv_directory + self, class_export_entities, function_export_cv_directory, default_sat ): """Import the CV version with customized major and minor @@ -1435,15 +1441,15 @@ def test_positive_import_cv_with_customized_major_minor( f'{function_export_cv_directory}/export-{class_export_entities["exporting_cv_name"]}-' f'{exporting_cvv_version}.tar' ) - result = ssh.command(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 imported_entities = _import_entities( class_export_entities['exporting_prod_name'], class_export_entities['exporting_repo_name'], class_export_entities['exporting_cv_name'], ) # Updating the json in exported tar - ssh.command(f'tar -xf {exported_tar} -C {function_export_cv_directory}') + default_sat.execute(f'tar -xf {exported_tar} -C {function_export_cv_directory}') extracted_directory_name = ( f'export-{class_export_entities["exporting_cv_name"]}-{exporting_cvv_version}' ) @@ -1451,9 +1457,9 @@ def test_positive_import_cv_with_customized_major_minor( f'{function_export_cv_directory}/{extracted_directory_name}/' f'{extracted_directory_name}.json' ) - new_major, new_minor = _update_json(json_path) + new_major, new_minor = _update_json(json_path, default_sat) custom_cvv_tar = f'{function_export_cv_directory}/{extracted_directory_name}.tar' - ssh.command( + default_sat.execute( f'tar -cvf {custom_cvv_tar} {function_export_cv_directory}/{extracted_directory_name}' ) # Importing the updated tar @@ -1516,7 +1522,7 @@ def test_positive_exported_cvv_json_contents( f'-{exporting_cvv_version}.tar' ) result = default_sat.execute(f'[ -f {exported_tar} ]') - assert result.return_code == 0 + assert result.status == 0 # Updating the json in exported tar default_sat.execute(f'tar -xf {exported_tar} -C {function_export_cv_directory}') extracted_directory_name = ( diff --git a/tests/foreman/cli/test_setting.py b/tests/foreman/cli/test_setting.py index 38a2aa13876..355466b3c73 100644 --- a/tests/foreman/cli/test_setting.py +++ b/tests/foreman/cli/test_setting.py @@ -21,7 +21,6 @@ import pytest -from robottelo import ssh from robottelo.cli.base import CLIReturnCodeError from robottelo.cli.settings import Settings from robottelo.config import settings @@ -426,7 +425,7 @@ def test_negative_update_send_welcome_email(value): @pytest.mark.tier3 @pytest.mark.run_in_one_thread @pytest.mark.parametrize('setting_update', ['failed_login_attempts_limit'], indirect=True) -def test_positive_failed_login_attempts_limit(setting_update): +def test_positive_failed_login_attempts_limit(setting_update, default_sat): """automate brute force protection limit configurable function :id: f95407ed-451b-4387-ac9b-2959ae2f51ae @@ -455,14 +454,14 @@ def test_positive_failed_login_attempts_limit(setting_update): username = settings.server.admin_username password = settings.server.admin_password - result = ssh.command(f'hammer -u {username} -p {password} user list') - assert result.return_code == 0 + result = default_sat.execute(f'hammer -u {username} -p {password} user list') + assert result.status == 0 Settings.set({'name': 'failed_login_attempts_limit', 'value': '5'}) for i in range(5): - output = ssh.command(f'hammer -u {username} -p BAD_PASS user list') - assert output.return_code == 129 - result = ssh.command(f'hammer -u {username} -p {password} user list') - assert result.return_code == 129 + output = default_sat.execute(f'hammer -u {username} -p BAD_PASS user list') + assert output.status == 129 + result = default_sat.execute(f'hammer -u {username} -p {password} user list') + assert result.status == 129 sleep(301) - result = ssh.command(f'hammer -u {username} -p {password} user list') - assert result.return_code == 0 + result = default_sat.execute(f'hammer -u {username} -p {password} user list') + assert result.status == 0 diff --git a/tests/foreman/cli/test_subscription.py b/tests/foreman/cli/test_subscription.py index 3215fb020b0..1b59cf893ef 100644 --- a/tests/foreman/cli/test_subscription.py +++ b/tests/foreman/cli/test_subscription.py @@ -33,7 +33,6 @@ from robottelo.constants import PRDS from robottelo.constants import REPOS from robottelo.constants import REPOSET -from robottelo.ssh import upload_file pytestmark = [pytest.mark.run_in_one_thread] @@ -179,7 +178,7 @@ def test_positive_subscription_list(function_org, manifest_clone_upload): @pytest.mark.tier2 -def test_positive_delete_manifest_as_another_user(): +def test_positive_delete_manifest_as_another_user(default_sat): """Verify that uploaded manifest if visible and deletable by a different user than the one who uploaded it @@ -204,7 +203,7 @@ def test_positive_delete_manifest_as_another_user(): ).create() # use the first admin to upload a manifest with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.with_user(username=user1.login, password=user1_password).upload( {'file': manifest.filename, 'organization-id': org.id} ) diff --git a/tests/foreman/cli/test_syncplan.py b/tests/foreman/cli/test_syncplan.py index a20caaaf1a5..f05c452c7c0 100644 --- a/tests/foreman/cli/test_syncplan.py +++ b/tests/foreman/cli/test_syncplan.py @@ -44,7 +44,6 @@ from robottelo.datafactory import parametrized from robottelo.datafactory import valid_data_list from robottelo.logging import logger -from robottelo.ssh import upload_file SYNC_DATE_FMT = '%Y-%m-%d %H:%M:%S' @@ -556,7 +555,7 @@ def test_positive_synchronize_custom_products_future_sync_date(module_org): @pytest.mark.run_in_one_thread @pytest.mark.tier4 @pytest.mark.upgrade -def test_positive_synchronize_rh_product_past_sync_date(): +def test_positive_synchronize_rh_product_past_sync_date(default_sat): """Create a sync plan with past datetime as a sync date, add a RH product and verify the product gets synchronized on the next sync occurrence @@ -573,7 +572,7 @@ def test_positive_synchronize_rh_product_past_sync_date(): delay = 2 * 60 org = make_org() with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.upload({'file': manifest.filename, 'organization-id': org['id']}) RepositorySet.enable( { @@ -624,7 +623,7 @@ def test_positive_synchronize_rh_product_past_sync_date(): @pytest.mark.run_in_one_thread @pytest.mark.tier4 @pytest.mark.upgrade -def test_positive_synchronize_rh_product_future_sync_date(): +def test_positive_synchronize_rh_product_future_sync_date(default_sat): """Create a sync plan with sync date in a future and sync one RH product with it automatically. @@ -639,7 +638,7 @@ def test_positive_synchronize_rh_product_future_sync_date(): delay = 2 * 60 # delay for sync date in seconds org = make_org() with manifests.clone() as manifest: - upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.upload({'file': manifest.filename, 'organization-id': org['id']}) RepositorySet.enable( { diff --git a/tests/foreman/cli/test_templatesync.py b/tests/foreman/cli/test_templatesync.py index 26e1d64bb99..62af4e80a9b 100644 --- a/tests/foreman/cli/test_templatesync.py +++ b/tests/foreman/cli/test_templatesync.py @@ -20,7 +20,6 @@ from requests import get from requests.exceptions import HTTPError -from robottelo import ssh from robottelo.cli.template import Template from robottelo.cli.template_sync import TemplateSync from robottelo.constants import FOREMAN_TEMPLATE_IMPORT_URL @@ -29,7 +28,7 @@ class TestTemplateSyncTestCase: @pytest.fixture(scope='module', autouse=True) - def setUpClass(self): + def setUpClass(self, default_sat): """Setup for TemplateSync functional testing :setup: @@ -50,11 +49,11 @@ def setUpClass(self): raise HTTPError('The foreman templates git url is not accessible') # Download the Test Template in test running folder - ssh.command(f'[ -f example_template.erb ] || wget {FOREMAN_TEMPLATE_TEST_TEMPLATE}') + default_sat.execute(f'[ -f example_template.erb ] || wget {FOREMAN_TEMPLATE_TEST_TEMPLATE}') @pytest.mark.tier2 def test_positive_import_force_locked_template( - self, module_org, create_import_export_local_dir + self, module_org, create_import_export_local_dir, default_sat ): """Assure locked templates are updated from repository when `force` is specified. @@ -87,7 +86,7 @@ def test_positive_import_force_locked_template( if ptemplate: assert ptemplate[0].read().locked update_txt = 'updated a little' - ssh.command(f"echo {update_txt} >> {dir_path}/example_template.erb") + default_sat.execute(f"echo {update_txt} >> {dir_path}/example_template.erb") TemplateSync.imports( {'repo': dir_path, 'prefix': prefix, 'organization-id': module_org.id} ) @@ -125,7 +124,7 @@ def test_positive_export_filtered_templates_to_git(self): """ @pytest.mark.tier2 - def test_positive_export_filtered_templates_to_temp_dir(self, module_org): + def test_positive_export_filtered_templates_to_temp_dir(self, module_org, default_sat): """Assure templates can be exported to /tmp directory without right permissions :id: e0427ee8-698e-4868-952f-5f4723ccee87 @@ -144,5 +143,5 @@ def test_positive_export_filtered_templates_to_temp_dir(self, module_org): ) exported_count = [row == 'Exported: true' for row in output].count(True) assert exported_count == int( - ssh.command(f'find {dir_path} -type f -name *ansible* | wc -l').stdout[0] + default_sat.execute(f'find {dir_path} -type f -name *ansible* | wc -l').stdout.strip() ) diff --git a/tests/foreman/cli/test_user.py b/tests/foreman/cli/test_user.py index d5e498aa0ef..e04a160f52f 100644 --- a/tests/foreman/cli/test_user.py +++ b/tests/foreman/cli/test_user.py @@ -26,7 +26,6 @@ import random from time import sleep -import paramiko import pytest from fauxfactory import gen_alphanumeric from fauxfactory import gen_string @@ -329,14 +328,6 @@ def test_positive_add_and_delete_roles(self, module_roles): class TestSshKeyInUser: """Implements the SSH Key in User Tests""" - @pytest.fixture(scope='function') - def ssh_key(self): - """Generates RSA type ssh key using ssh module - - :return: string type well formatted RSA key - """ - return f'ssh-rsa {paramiko.RSAKey.generate(2048).get_base64()}' - @pytest.fixture(scope='module') def module_user(self): """Create an user""" @@ -375,7 +366,7 @@ def test_positive_create_ssh_key_super_admin_from_file(self, ssh_key, default_sa :CaseImportance: Critical """ ssh_name = gen_string('alpha') - result = default_sat.execute(f'''echo '{ssh_key}' > test_key.pub''') + result = default_sat.execute(f"echo '{ssh_key}' > test_key.pub") assert result.status == 0, 'key file not created' User.ssh_keys_add({'user': 'admin', 'key-file': 'test_key.pub', 'name': ssh_name}) result = User.ssh_keys_list({'user': 'admin'}) diff --git a/tests/foreman/endtoend/test_cli_endtoend.py b/tests/foreman/endtoend/test_cli_endtoend.py index fa15939a0a4..337cead36ca 100644 --- a/tests/foreman/endtoend/test_cli_endtoend.py +++ b/tests/foreman/endtoend/test_cli_endtoend.py @@ -21,7 +21,6 @@ from fauxfactory import gen_ipaddr from robottelo import manifests -from robottelo import ssh from robottelo.cli.activationkey import ActivationKey from robottelo.cli.computeresource import ComputeResource from robottelo.cli.contentview import ContentView @@ -141,7 +140,7 @@ def test_positive_cli_end_to_end(fake_manifest_is_set, rhel6_contenthost, defaul # step 2.2: Clone and upload manifest if fake_manifest_is_set: with manifests.clone() as manifest: - ssh.upload_file(manifest.content, manifest.filename) + default_sat.put(manifest.content, manifest.filename) Subscription.upload({'file': manifest.filename, 'organization-id': org['id']}) # step 2.3: Create a new lifecycle environment diff --git a/tests/foreman/installer/test_installer.py b/tests/foreman/installer/test_installer.py index b341bcca13d..13e10686acc 100644 --- a/tests/foreman/installer/test_installer.py +++ b/tests/foreman/installer/test_installer.py @@ -1282,7 +1282,7 @@ def extract_help(filter='params'): :return: generator with params or sections depends on filter parameter """ stdout = ssh.command('satellite-installer --full-help').stdout - for line in stdout or []: + for line in stdout.splitlines() or []: line = line.strip() if filter == 'sections': if line.startswith('= '): @@ -1296,7 +1296,7 @@ def extract_help(filter='params'): @pytest.mark.upgrade @pytest.mark.tier1 -def test_positive_foreman_module(): +def test_positive_foreman_module(default_sat): """Check if SELinux foreman module has the right version :id: a0736b3a-3d42-4a09-a11a-28c1d58214a5 @@ -1309,17 +1309,17 @@ def test_positive_foreman_module(): :expectedresults: Foreman RPM and SELinux module versions match """ - rpm_result = ssh.command('rpm -q foreman-selinux') - assert rpm_result.return_code == 0 + rpm_result = default_sat.execute('rpm -q foreman-selinux') + assert rpm_result.status == 0 - semodule_result = ssh.command('semodule -l | grep foreman') - assert semodule_result.return_code == 0 + semodule_result = default_sat.execute('semodule -l | grep foreman') + assert semodule_result.status == 0 # Sample rpm output: foreman-selinux-1.7.2.8-1.el7sat.noarch version_regex = re.compile(r'((\d\.?)+[-.]\d)') - rpm_version = version_regex.search(''.join(rpm_result.stdout)).group(1) + rpm_version = version_regex.search(rpm_result.stdout).group(1) # Sample semodule output: foreman 1.7.2.8 - semodule_version = version_regex.search(''.join(semodule_result.stdout)).group(1) + semodule_version = version_regex.search(semodule_result.stdout).group(1) rpm_version = rpm_version[:-2] assert rpm_version.replace('-', '.') == semodule_version diff --git a/tests/foreman/sys/test_dynflow.py b/tests/foreman/sys/test_dynflow.py index 1154cf85e49..39873c08b5c 100644 --- a/tests/foreman/sys/test_dynflow.py +++ b/tests/foreman/sys/test_dynflow.py @@ -18,11 +18,9 @@ """ import pytest -from robottelo import ssh - @pytest.mark.tier2 -def test_positive_setup_dynflow(): +def test_positive_setup_dynflow(default_sat): """Set dynflow parameters, restart it and check it adheres to them :id: a5aaab5e-bc18-453e-a284-64aef752ec88 @@ -38,5 +36,6 @@ def test_positive_setup_dynflow(): "grep -q ' of 6 busy' ; do sleep 0.5 ; done", ] # if thread count is not respected or the process is not running, this should timeout - ssh.command(' && '.join(commands)) - ssh.command("systemctl stop 'dynflow-sidekiq@test'; rm /etc/foreman/dynflow/test.yml") + # how is this a test? Nothing is asserted. + default_sat.execute(' && '.join(commands)) + default_sat.execute("systemctl stop 'dynflow-sidekiq@test'; rm /etc/foreman/dynflow/test.yml") diff --git a/tests/foreman/sys/test_fam.py b/tests/foreman/sys/test_fam.py index 1705f120e09..31f07f255ae 100644 --- a/tests/foreman/sys/test_fam.py +++ b/tests/foreman/sys/test_fam.py @@ -18,14 +18,13 @@ """ import pytest -from robottelo import ssh from robottelo.constants import FAM_MODULE_PATH from robottelo.constants import FOREMAN_ANSIBLE_MODULES @pytest.mark.destructive @pytest.mark.run_in_one_thread -def test_positive_ansible_modules_installation(): +def test_positive_ansible_modules_installation(default_sat): """Foreman ansible modules installation test :id: 553a927e-2665-4227-8542-0258d7b1ccc4 @@ -34,19 +33,19 @@ def test_positive_ansible_modules_installation(): available and supported modules are contained """ - result = ssh.command( + result = default_sat.execute( 'yum install -y ansible-collection-redhat-satellite --disableplugin=foreman-protector' ) - assert result.return_code == 0 + assert result.status == 0 # list installed modules - result = ssh.command(f'ls {FAM_MODULE_PATH} | sed "s/.[^.]*$//"') - assert result.return_code == 0 + result = default_sat.execute(f'ls {FAM_MODULE_PATH} | sed "s/.[^.]*$//"') + assert result.status == 0 installed_modules = result.stdout installed_modules.remove('') # see help for installed modules for module_name in installed_modules: - result = ssh.command(f'ansible-doc redhat.satellite.{module_name} -s') - assert result.return_code == 0 + result = default_sat.execute(f'ansible-doc redhat.satellite.{module_name} -s') + assert result.status == 0 doc_name = result.stdout[1].lstrip()[:-1] assert doc_name == module_name # check installed modules against the expected list diff --git a/tests/foreman/sys/test_foreman_rake.py b/tests/foreman/sys/test_foreman_rake.py index ef4c8cf561a..92792708c72 100644 --- a/tests/foreman/sys/test_foreman_rake.py +++ b/tests/foreman/sys/test_foreman_rake.py @@ -14,13 +14,11 @@ """ import pytest -from robottelo import ssh - @pytest.mark.destructive @pytest.mark.run_in_one_thread @pytest.mark.tier3 -def test_positive_katello_reimport(): +def test_positive_katello_reimport(destructive_sat): """Close loop bug for running katello:reimport. Making sure that katello:reimport works and doesn't throw an error. @@ -39,6 +37,6 @@ def test_positive_katello_reimport(): :customerscenario: true """ - result = ssh.command('foreman-rake katello:reimport') + result = destructive_sat.execute('foreman-rake katello:reimport') assert 'NoMethodError:' not in result.stdout assert 'rake aborted!' not in result.stdout diff --git a/tests/foreman/sys/test_hooks.py b/tests/foreman/sys/test_hooks.py index 03724a11b20..44c3a12c136 100644 --- a/tests/foreman/sys/test_hooks.py +++ b/tests/foreman/sys/test_hooks.py @@ -21,7 +21,6 @@ from nailgun import entities from requests.exceptions import HTTPError -from robottelo import ssh from robottelo.datafactory import valid_hostgroups_list from robottelo.datafactory import valid_hosts_list @@ -34,21 +33,21 @@ @pytest.fixture(scope='function') -def logger_hook(default_org): +def logger_hook(default_org, default_sat): """Create logger script to be executed via hooks""" - ssh.command( + default_sat.execute( '''printf '#!/bin/sh\necho "$(date): Executed $1 hook''' + f''' on object $2" > {LOGS_DIR}' > {SCRIPT_PATH}''' ) - ssh.command(f'chmod 774 {SCRIPT_PATH}') - ssh.command(f'chown foreman:foreman {SCRIPT_PATH}') - ssh.command(f'restorecon -RvF {HOOKS_DIR}') + default_sat.execute(f'chmod 774 {SCRIPT_PATH}') + default_sat.execute(f'chown foreman:foreman {SCRIPT_PATH}') + default_sat.execute(f'restorecon -RvF {HOOKS_DIR}') yield - ssh.command(f'rm -rf {HOOKS_DIR}/*') + default_sat.execute(f'rm -rf {HOOKS_DIR}/*') -def test_positive_host_hooks(logger_hook): +def test_positive_host_hooks(logger_hook, default_sat): """Create hooks to be executed on host create, update and destroy :id: 4fe35fda-1524-44f7-9221-96d1aeafc75c @@ -70,37 +69,37 @@ def test_positive_host_hooks(logger_hook): destroy_event = 'destroy' for event in [create_event, destroy_event, update_event]: hook_dir = f'{HOOKS_DIR}/host/managed/{event}' - ssh.command(f'mkdir -p {hook_dir}') - ssh.command(f'ln -sf {SCRIPT_PATH} {hook_dir}/') - result = ssh.command('systemctl restart httpd') - assert result.return_code == 0 + default_sat.execute(f'mkdir -p {hook_dir}') + default_sat.execute(f'ln -sf {SCRIPT_PATH} {hook_dir}/') + result = default_sat.execute('systemctl restart httpd') + assert result.status == 0 # delete host, check logs for hook activity host = entities.Host(name=host_name).create() assert host.name == f'{host_name}.{host.domain.read().name}' - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(create_event, host_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(create_event, host_name) in result.stdout # update host, check logs for hook activity new_ip = gen_ipaddr() host.ip = new_ip host = host.update(['ip']) assert host.ip == new_ip - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(update_event, host_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(update_event, host_name) in result.stdout # delete host, check logs for hook activity host.delete() with pytest.raises(HTTPError): host.read() - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(destroy_event, host_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(destroy_event, host_name) in result.stdout -def test_positive_hostgroup_hooks(logger_hook, default_org): +def test_positive_hostgroup_hooks(logger_hook, default_org, default_sat): """Create hooks to be executed on hostgroup create, udpdate and destroy :id: 7e935dec-e4fe-47d8-be02-8c687a99ae7a @@ -123,31 +122,31 @@ def test_positive_hostgroup_hooks(logger_hook, default_org): destroy_event = 'before_destroy' for event in [create_event, update_event, destroy_event]: hook_dir = f'{HOOKS_DIR}/hostgroup/{event}' - ssh.command(f'mkdir -p {hook_dir}') - ssh.command(f'ln -sf {SCRIPT_PATH} {hook_dir}/') - result = ssh.command('systemctl restart httpd') - assert result.return_code == 0 + default_sat.execute(f'mkdir -p {hook_dir}') + default_sat.execute(f'ln -sf {SCRIPT_PATH} {hook_dir}/') + result = default_sat.execute('systemctl restart httpd') + assert result.status == 0 # create hg, check logs for hook activity hg = entities.HostGroup(name=hg_name, organization=[default_org.id]).create() assert hg.name == hg_name - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(create_event, hg_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(create_event, hg_name) in result.stdout # update hg, check logs for hook activity new_arch = entities.Architecture().create() hg.architecture = new_arch hg = hg.update(['architecture']) assert hg.architecture.read().name == new_arch.name - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(update_event, hg_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(update_event, hg_name) in result.stdout # delete hg, check logs for hook activity hg.delete() with pytest.raises(HTTPError): hg.read() - result = ssh.command(f'cat {LOGS_DIR}') - assert result.return_code == 0 - assert expected_msg.format(destroy_event, hg_name) in result.stdout[0] + result = default_sat.execute(f'cat {LOGS_DIR}') + assert result.status == 0 + assert expected_msg.format(destroy_event, hg_name) in result.stdout diff --git a/tests/foreman/sys/test_katello_certs_check.py b/tests/foreman/sys/test_katello_certs_check.py index bdfff00c4a2..5f8f524fbf8 100644 --- a/tests/foreman/sys/test_katello_certs_check.py +++ b/tests/foreman/sys/test_katello_certs_check.py @@ -147,7 +147,7 @@ def validate_output(self, result, cert_data): assert set(options) == expected_result @pytest.mark.tier1 - def test_positive_validate_katello_certs_check_output(self, cert_setup_teardown): + def test_positive_validate_katello_certs_check_output(self, cert_setup_teardown, default_sat): """Validate that katello-certs-check generates correct output. :id: 4c9e4c6e-8d8e-4953-87a1-09cb55df3adf diff --git a/tests/foreman/sys/test_pulp3_filesystem.py b/tests/foreman/sys/test_pulp3_filesystem.py index 6b3762b7895..463d0e911c8 100644 --- a/tests/foreman/sys/test_pulp3_filesystem.py +++ b/tests/foreman/sys/test_pulp3_filesystem.py @@ -73,13 +73,13 @@ def test_pulp_service_definitions(default_sat): # check pulpcore settings result = default_sat.execute('systemctl cat pulpcore-content.socket') assert result.status == 0 - assert 'ListenStream=/run/pulpcore-content.sock' in result.stdout.split('\n') + assert 'ListenStream=/run/pulpcore-content.sock' in result.stdout result = default_sat.execute('systemctl cat pulpcore-content.service') assert result.status == 0 - assert 'Requires=pulpcore-content.socket' in result.stdout.split('\n') + assert 'Requires=pulpcore-content.socket' in result.stdout result = default_sat.execute('systemctl cat pulpcore-api.service') assert result.status == 0 - assert 'Requires=pulpcore-api.socket' in result.stdout.split('\n') + assert 'Requires=pulpcore-api.socket' in result.stdout # check pulp3 configuration file present result = default_sat.execute('test -f /etc/pulp/settings.py') assert result.status == 0 diff --git a/tests/foreman/sys/test_rename.py b/tests/foreman/sys/test_rename.py index 7354f7cc233..ccb5043e5da 100644 --- a/tests/foreman/sys/test_rename.py +++ b/tests/foreman/sys/test_rename.py @@ -147,7 +147,7 @@ def test_negative_rename_sat_to_invalid_hostname(self, destructive_sat): """ username = settings.server.admin_username password = settings.server.admin_password - original_name = destructive_sat.execute('hostname').stdout + original_name = destructive_sat.hostname hostname = gen_string('alpha') result = destructive_sat.execute( f'satellite-change-hostname -y {hostname} -u {username} -p {password}' @@ -171,7 +171,7 @@ def test_negative_rename_sat_no_credentials(self, destructive_sat): :CaseAutomation: Automated """ - original_name = destructive_sat.execute('hostname').stdout + original_name = destructive_sat.hostname hostname = gen_string('alpha') result = destructive_sat.execute(f'satellite-change-hostname -y {hostname}') assert result.status == 1 @@ -195,7 +195,7 @@ def test_negative_rename_sat_wrong_passwd(self, destructive_sat): :CaseAutomation: Automated """ username = settings.server.admin_username - original_name = destructive_sat.execute('hostname').stdout + original_name = destructive_sat.hostname new_hostname = f'new-{original_name}' password = gen_string('alpha') result = destructive_sat.execute( diff --git a/tests/foreman/ui/test_contenthost.py b/tests/foreman/ui/test_contenthost.py index 3953a0d64ef..fee01855256 100644 --- a/tests/foreman/ui/test_contenthost.py +++ b/tests/foreman/ui/test_contenthost.py @@ -669,13 +669,13 @@ def test_positive_virt_who_hypervisor_subscription_status(session, rhel7_content checkin_time1 = session.contenthost.search(provisioning_server)[0]['Last Checkin'] result = rhel7_contenthost.run('service virt-who stop') if result.status != 0: - raise CLIFactoryError(f'Failed to stop the virt-who service:\n{result.stderr}') + raise CLIFactoryError(f'Failed to stop the virt-who service:\n{result.stderr[1]}') result = rhel7_contenthost.run('virt-who --one-shot') if result.status != 0: - raise CLIFactoryError(f'Failed when executing virt-who --one-shot:\n{result.stderr}') + raise CLIFactoryError(f'Failed when executing virt-who --one-shot:\n{result.stderr[1]}') result = rhel7_contenthost.run('service virt-who start') if result.status != 0: - raise CLIFactoryError(f'Failed to start the virt-who service:\n{result.stderr}') + raise CLIFactoryError(f'Failed to start the virt-who service:\n{result.stderr[1]}') checkin_time2 = session.contenthost.search(provisioning_server)[0]['Last Checkin'] assert checkin_time2 > checkin_time1 diff --git a/tests/foreman/ui/test_contentview.py b/tests/foreman/ui/test_contentview.py index 1777389626d..9296a73c122 100644 --- a/tests/foreman/ui/test_contentview.py +++ b/tests/foreman/ui/test_contentview.py @@ -67,7 +67,6 @@ from robottelo.constants import RHEL_7_MAJOR_VERSION from robottelo.constants.repos import FEDORA27_OSTREE_REPO from robottelo.datafactory import gen_string -from robottelo.decorators.host import skip_if_os from robottelo.helpers import create_repo from robottelo.helpers import get_data_file from robottelo.helpers import repo_add_updateinfo @@ -2950,7 +2949,6 @@ def test_positive_delete_with_kickstart_repo_and_host_group(session, default_sat @pytest.mark.skip_if_open("BZ:1625783") -@skip_if_os('RHEL6') @pytest.mark.tier3 @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') def test_positive_custom_ostree_end_to_end(session, module_org): @@ -3008,7 +3006,6 @@ def test_positive_custom_ostree_end_to_end(session, module_org): @pytest.mark.skip_if_open("BZ:1625783") -@skip_if_os('RHEL6') @pytest.mark.tier3 def test_positive_rh_ostree_end_to_end(session): """Create content view with RH ostree contents, publish and promote it @@ -3066,7 +3063,6 @@ def test_positive_rh_ostree_end_to_end(session): @pytest.mark.skip_if_open("BZ:1625783") -@skip_if_os('RHEL6') @pytest.mark.upgrade @pytest.mark.tier3 @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') @@ -3133,7 +3129,6 @@ def test_positive_mixed_content_end_to_end(session, module_org): assert session.contentview.search_version(cv_name, VERSION)[0]['Version'] != VERSION -@skip_if_os('RHEL6') @pytest.mark.upgrade @pytest.mark.tier3 def test_positive_rh_mixed_content_end_to_end(session): @@ -3214,7 +3209,7 @@ def test_positive_errata_inc_update_list_package(session): result = repo_add_updateinfo( repo_name, f'{settings.repos.inc_upd.url}{FAKE_0_INC_UPD_OLD_UPDATEFILE}' ) - assert result.return_code == 0 + assert result.status == 0 # Create org, product, repo, sync & publish it org = entities.Organization().create() custom_repo_id = create_sync_custom_repo(org.id, repo_url=repo_url) @@ -3231,7 +3226,7 @@ def test_positive_errata_inc_update_list_package(session): result = repo_add_updateinfo( repo_name, f'{settings.repos.inc_upd.url}{FAKE_0_INC_UPD_NEW_UPDATEFILE}' ) - assert result.return_code == 0 + assert result.status == 0 # Sync the repo entities.Repository(id=custom_repo_id).sync() # Publish new CVV with the new errata @@ -3311,7 +3306,7 @@ def test_positive_composite_child_inc_update(session, rhel7_contenthost, default result = repo_add_updateinfo( repo_name, f'{settings.repos.inc_upd.url}{FAKE_0_INC_UPD_OLD_UPDATEFILE}' ) - assert result.return_code == 0 + assert result.status == 0 org = entities.Organization().create() lce = entities.LifecycleEnvironment(organization=org).create() repos_collection = RepositoryCollection( @@ -3339,7 +3334,7 @@ def test_positive_composite_child_inc_update(session, rhel7_contenthost, default result = repo_add_updateinfo( repo_name, f'{settings.repos.settings.repos.inc_upd.url.url}{FAKE_0_INC_UPD_NEW_UPDATEFILE}' ) - assert result.return_code == 0 + assert result.status == 0 entities.Repository(id=repos_collection.custom_repos_info[-1]['id']).sync() with session: session.organization.select(org.name) diff --git a/tests/foreman/ui/test_discoveredhost.py b/tests/foreman/ui/test_discoveredhost.py index 4fcfc41fe78..2e1dcd19c2b 100644 --- a/tests/foreman/ui/test_discoveredhost.py +++ b/tests/foreman/ui/test_discoveredhost.py @@ -104,9 +104,9 @@ def _is_host_reachable(host, retries=12, iteration_sleep=5, expect_reachable=Tru cmd.format(retries, host, operator, iteration_sleep), connection_timeout=30 ) if expect_reachable: - return not result.return_code + return not result.status else: - return bool(result.return_code) + return bool(result.status) @pytest.mark.skip_if_not_set('compute_resources', 'vlan_networking') diff --git a/tests/foreman/ui/test_ldap_authentication.py b/tests/foreman/ui/test_ldap_authentication.py index fc2b65b21ea..9501b4a9a19 100644 --- a/tests/foreman/ui/test_ldap_authentication.py +++ b/tests/foreman/ui/test_ldap_authentication.py @@ -65,19 +65,19 @@ def set_certificate_in_satellite(server_type, default_sat, hostname=None): ) elif server_type == 'AD': assert hostname is not None - ssh.command('yum -y --disableplugin=foreman-protector install cifs-utils') + default_sat.execute('yum -y --disableplugin=foreman-protector install cifs-utils') command = r'mount -t cifs -o username=administrator,pass={0} //{1}/c\$ /mnt' - ssh.command(command.format(settings.ldap.password, hostname)) - result = ssh.command( + default_sat.execute(command.format(settings.ldap.password, hostname)) + result = default_sat.execute( f'cp /mnt/Users/Administrator/Desktop/satqe-QE-SAT6-AD-CA.cer {CERT_PATH}' ) - if result.return_code != 0: + if result.status != 0: raise AssertionError('Failed to copy the AD server certificate at right path') - result = ssh.command(f'update-ca-trust extract && restorecon -R {CERT_PATH}') - if result.return_code != 0: + result = default_sat.execute(f'update-ca-trust extract && restorecon -R {CERT_PATH}') + if result.status != 0: raise AssertionError('Failed to update and trust the certificate') - result = ssh.command('systemctl restart httpd') - if result.return_code != 0: + result = default_sat.execute('systemctl restart httpd') + if result.status != 0: raise AssertionError(f'Failed to restart the httpd after applying {server_type} cert') @@ -120,7 +120,7 @@ def subscribe_satellite(clean_rhsm): has_success_msg = 'Successfully attached a subscription' attach_cmd = f'subscription-manager attach --pool={settings.subscription.rhn_poolid}' result = run_command(attach_cmd) - if has_success_msg in ''.join(result): + if has_success_msg in result: run_command( f'subscription-manager repos --enable "rhel-{RHEL_7_MAJOR_VERSION}-server-extras-rpms"' ) @@ -199,18 +199,18 @@ def ipa_add_user(): result = ssh.command( cmd=f'echo {settings.ipa.password} | kinit admin', hostname=settings.ipa.hostname ) - assert result.return_code == 0 + assert result.status == 0 test_user = gen_string('alpha') add_user_cmd = ( f'echo {settings.ipa.password} | ipa user-add {test_user} --first' f'={test_user} --last={test_user} --password' ) result = ssh.command(cmd=add_user_cmd, hostname=settings.ipa.hostname) - assert result.return_code == 0 + assert result.status == 0 yield test_user result = ssh.command(cmd=f'ipa user-del {test_user}', hostname=settings.ipa.hostname) - assert result.return_code == 0 + assert result.status == 0 def generate_otp(secret): @@ -974,7 +974,6 @@ def test_single_sign_on_ldap_ipa_server( else: curl_command = f'curl -k -u : --negotiate {default_sat.url}/users/extlogin/' result = run_command(curl_command) - result = ''.join(result) assert 'redirected' in result assert f'{default_sat.url}/hosts' in result assert 'You are being' in result @@ -1032,7 +1031,6 @@ def test_single_sign_on_ldap_ad_server( else: curl_command = f'curl -k -u : --negotiate {default_sat.url}/users/extlogin/' result = run_command(curl_command) - result = ''.join(result) assert 'redirected' in result assert f'{default_sat.url}/hosts' in result finally: @@ -1515,18 +1513,18 @@ def test_deleted_idm_user_should_not_be_able_to_login(auth_source_ipa, ldap_tear result = ssh.command( cmd=f"echo {settings.ipa.password} | kinit admin", hostname=settings.ipa.hostname ) - assert result.return_code == 0 + assert result.status == 0 test_user = gen_string('alpha') add_user_cmd = ( f'echo {settings.ipa.password} | ipa user-add {test_user} --first' f'={test_user} --last={test_user} --password' ) result = ssh.command(cmd=add_user_cmd, hostname=settings.ipa.hostname) - assert result.return_code == 0 + assert result.status == 0 with Session(user=test_user, password=settings.ipa.password) as ldapsession: ldapsession.bookmark.search('controller = hosts') result = ssh.command(cmd=f'ipa user-del {test_user}', hostname=settings.ipa.hostname) - assert result.return_code == 0 + assert result.status == 0 with Session(user=test_user, password=settings.ipa.password) as ldapsession: with pytest.raises(NavigationTriesExceeded) as error: ldapsession.user.search('') diff --git a/tests/foreman/ui/test_repository.py b/tests/foreman/ui/test_repository.py index 2cb08b49727..061e18cbb8c 100644 --- a/tests/foreman/ui/test_repository.py +++ b/tests/foreman/ui/test_repository.py @@ -39,7 +39,7 @@ from robottelo.constants.repos import ANSIBLE_GALAXY from robottelo.datafactory import gen_string from robottelo.helpers import read_data_file -from robottelo.host_info import get_sat_version +from robottelo.hosts import get_sat_version from robottelo.products import SatelliteToolsRepository # from robottelo.constants.repos import FEDORA26_OSTREE_REPO diff --git a/tests/foreman/ui/test_settings.py b/tests/foreman/ui/test_settings.py index 54e0dd19b23..a6aba25c047 100644 --- a/tests/foreman/ui/test_settings.py +++ b/tests/foreman/ui/test_settings.py @@ -23,7 +23,6 @@ from fauxfactory import gen_url from nailgun import entities -from robottelo import ssh from robottelo.cleanup import setting_cleanup from robottelo.cli.user import User from robottelo.datafactory import filtered_datapoint @@ -407,7 +406,7 @@ def test_positive_update_email_delivery_method_sendmail(session, default_sat): session.settings.update(mail_content, mail_content_value) test_mail_response = session.settings.send_test_mail(property_name)[0] assert test_mail_response == "Email was sent successfully" - assert ssh.command(command).return_code == 0 + assert default_sat.execute(command).status == 0 finally: for key, value in mail_config_default_param.items(): setting_cleanup(setting_name=key, setting_value=value.value) diff --git a/tests/foreman/ui/test_sync.py b/tests/foreman/ui/test_sync.py index cc6b23d8dd9..dbd41054216 100644 --- a/tests/foreman/ui/test_sync.py +++ b/tests/foreman/ui/test_sync.py @@ -32,7 +32,6 @@ from robottelo.constants import REPOS from robottelo.constants import REPOSET from robottelo.constants.repos import FEDORA27_OSTREE_REPO -from robottelo.decorators.host import skip_if_os from robottelo.products import RepositoryCollection from robottelo.products import RHELCloudFormsTools from robottelo.products import SatelliteCapsuleRepository @@ -111,7 +110,6 @@ def test_positive_sync_rh_repos(session, module_org_with_manifest): @pytest.mark.skip_if_open("BZ:1625783") -@skip_if_os('RHEL6') @pytest.mark.tier2 @pytest.mark.upgrade @pytest.mark.skipif((not settings.robottelo.REPOS_HOSTING_URL), reason='Missing repos_hosting_url') @@ -142,7 +140,6 @@ def test_positive_sync_custom_ostree_repo(session, module_custom_product): @pytest.mark.run_in_one_thread @pytest.mark.skip_if_open("BZ:1625783") -@skip_if_os('RHEL6') @pytest.mark.skip_if_not_set('fake_manifest') @pytest.mark.tier2 @pytest.mark.upgrade diff --git a/tests/foreman/ui/test_templatesync.py b/tests/foreman/ui/test_templatesync.py index 59bdc12a2e1..7609f98e3a7 100644 --- a/tests/foreman/ui/test_templatesync.py +++ b/tests/foreman/ui/test_templatesync.py @@ -18,7 +18,6 @@ from fauxfactory import gen_string from nailgun import entities -from robottelo import ssh from robottelo.constants import FOREMAN_TEMPLATE_IMPORT_URL from robottelo.constants import FOREMAN_TEMPLATE_ROOT_DIR @@ -92,7 +91,7 @@ def test_positive_import_templates(session, templates_org, templates_loc): @pytest.mark.tier2 @pytest.mark.upgrade -def test_positive_export_templates(session, create_import_export_local_dir): +def test_positive_export_templates(session, create_import_export_local_dir, default_sat): """Export the satellite templates to local directory :id: 1c24cf51-7198-48aa-a70a-8c0441333374 @@ -131,8 +130,8 @@ def test_positive_export_templates(session, create_import_export_local_dir): ) assert export_title == f'Export to {FOREMAN_TEMPLATE_ROOT_DIR} as user {session._user}' exported_file = f'{dir_path}/provisioning_templates/PXELinux/kickstart_default_pxelinux.erb' - result = ssh.command(f'find {exported_file} -type f') - assert result.return_code == 0 + result = default_sat.execute(f'find {exported_file} -type f') + assert result.status == 0 search_string = f'name: {export_template}' - result = ssh.command(f"grep -F '{search_string}' {exported_file}") - assert result.return_code == 0 + result = default_sat.execute(f"grep -F '{search_string}' {exported_file}") + assert result.status == 0 diff --git a/tests/robottelo/test_cli.py b/tests/robottelo/test_cli.py index e690ccc3b72..24e056ed9b7 100644 --- a/tests/robottelo/test_cli.py +++ b/tests/robottelo/test_cli.py @@ -74,7 +74,7 @@ def test_handle_response_success(self): """ base = Base() response = mock.Mock() - response.return_code = 0 + response.status = 0 response.stderr = [] assert response.stdout == base._handle_response(response) @@ -83,7 +83,7 @@ def test_handle_response_logging_when_stderr_not_empty(self, warning): """Check handle_response log stderr when it is not empty""" base = Base() response = mock.Mock() - response.return_code = 0 + response.status = 0 response.stderr = ['not empty'] assert response.stdout == base._handle_response(response) warning.assert_called_once_with(f'stderr contains following message:\n{response.stderr}') @@ -93,13 +93,13 @@ def test_handle_response_logging_when_stderr_not_empty(self, warning): def test_handle_response_error(self): """Check handle_response raise ``CLIReturnCodeError`` when - return_code is not 0 + status is not 0 """ self.assert_response_error(CLIReturnCodeError) def test_handle_data_base_response_error(self): """Check handle_response raise ``CLIDataBaseError`` when - return_code is not 0 and error is related to DB error. + status is not 0 and error is related to DB error. See https://github.com/SatelliteQE/robottelo/issues/3790. """ msgs = ( @@ -134,7 +134,7 @@ def assert_response_error(self, expected_error, stderr='some error'): """ base = Base() response = mock.Mock() - response.return_code = 1 + response.status = 1 response.stderr = [stderr] with pytest.raises(expected_error): base._handle_response(response) @@ -248,7 +248,7 @@ def test_dump(self, construct, execute): def test_execute_with_raw_response(self, settings, command): """Check executed build ssh method and returns raw response""" settings.robottelo.locale = 'en_US' - settings.performance = False + settings.performance.time_hammer = False settings.server.admin_username = 'admin' settings.server.admin_password = 'password' response = Base.execute('some_cmd', return_raw_response=True) @@ -258,7 +258,6 @@ def test_execute_with_raw_response(self, settings, command): hostname=mock.ANY, output_format=None, timeout=None, - connection_timeout=None, ) assert response is command.return_value @@ -278,7 +277,6 @@ def test_execute_with_performance(self, settings, command, handle_resp): hostname=mock.ANY, output_format='json', timeout=None, - connection_timeout=None, ) handle_resp.assert_called_once_with(command.return_value, ignore_stderr=None) assert response is handle_resp.return_value @@ -334,13 +332,13 @@ def test_info_parsing_response(self, construct, execute, parse): ) parse.called_once_with('some_response') - @mock.patch('robottelo.cli.base.Base.command_requires_org') - def test_list_requires_organization_id(self, _): - """Check list raises CLIError with organization-id is not present in - options - """ - with pytest.raises(CLIError): - Base.list() + # @mock.patch('robottelo.cli.base.Base.command_requires_org') + # def test_list_requires_organization_id(self, _): + # """Check list raises CLIError with organization-id is not present in + # options + # """ + # with pytest.raises(CLIError): + # Base.list() @mock.patch('robottelo.cli.base.Base.execute') @mock.patch('robottelo.cli.base.Base._construct_command') @@ -409,13 +407,13 @@ class CLIBaseErrorTestCase(unittest2.TestCase): def test_init(self): """Check properties initialization""" error = CLIBaseError(1, 'stderr', 'msg') - assert error.return_code == 1 + assert error.status == 1 assert error.stderr == 'stderr' assert error.msg == 'msg' assert error.message == error.msg - def test_return_code_is_exposed(self): - """Check if return_code is exposed to assertRaisesRegex""" + def test_status_is_exposed(self): + """Check if status is exposed to assertRaisesRegex""" with pytest.raises(CLIBaseError, match='1'): raise CLIBaseError(1, 'stderr', 'msg') diff --git a/tests/robottelo/test_decorators.py b/tests/robottelo/test_decorators.py index de87e8340a6..c49b1d709b2 100644 --- a/tests/robottelo/test_decorators.py +++ b/tests/robottelo/test_decorators.py @@ -1,9 +1,7 @@ """Unit tests for :mod:`robottelo.decorators`.""" -from itertools import chain from unittest import mock import pytest -from unittest2 import SkipTest from robottelo import decorators @@ -44,157 +42,3 @@ def test_return_from_cache(self, make_foo): decorators.OBJECT_CACHE['foo'] = cache_obj obj = make_foo(cached=True) assert id(cache_obj) == id(obj) - - -class TestHostSkipIf: - """Tests for :func:`robottelo.decorators.host.skip_if_host_is` when host - version isn't available - """ - - DOWN_VERSIONS = '6 6.1 6.1.1'.split() - UP_VERSIONS = '7.1.1 7.2 7.2.1'.split() - VERSIONS = tuple('RHEL' + v for v in chain(DOWN_VERSIONS, UP_VERSIONS)) - - @pytest.fixture(scope="class") - def settings_mock(self): - settings_patch = mock.patch('robottelo.decorators.host.settings') - mocker = settings_patch.start() - - yield mock - mocker.stop() - - @pytest.fixture(scope="class") - def version_unknown_mock(self, settings_mock): - """Setup versions above and below version 7.1 - - Mocking setting so robottello.properties is not need to run this test - Mocking get_host_os_version to define host version to 'Not Available' - so it emulates an error when trying to fetch it through ssh - """ - host_os_patch = mock.patch('robottelo.decorators.host.get_host_os_version') - host_os_mock = host_os_patch.start() - host_os_mock.return_value = 'Not Available' - - yield host_os_mock - host_os_mock.stop() - - def assert_not_skipped(self, dummy): - """Assert a dummy function is not skipped""" - try: - assert dummy() - except SkipTest: - pytest.fail('Should not be skipped') - - @pytest.mark.parametrize('single_version', VERSIONS) - def test_dont_skipping_with_single_version(self, version_unknown_mock, single_version): - """Check don't skip if os version isn't available""" - - @decorators.host.skip_if_os(single_version) - def dummy(): - return True - - self.assert_not_skipped(dummy) - - def test_dont_skipping_with_multiple_versions(self, version_unknown_mock): - """Check don't skip if os version isn't available with multiple - versions - """ - - @decorators.host.skip_if_os(*self.VERSIONS) - def dummy(): - return True - - self.assert_not_skipped(dummy) - - @pytest.fixture(scope="class") - def version_known_mock(self, version_unknown_mock): - """Mocking dependencies just like superclass, but set host version to - RHEL7.1.0 - - Warning: mutates its ancestor fixture instance - """ - version_unknown_mock._host_version = 'RHEL7.1.0' - version_unknown_mock.return_value = version_unknown_mock._host_version - - return version_unknown_mock # leave teardown to the ancestor - - def test_skipping_with_patch_version(self, version_known_mock): - """Test skipping when decorator param is exactly equals to host - version - """ - - @decorators.host.skip_if_os(version_known_mock._host_version) - def dummy(): - return True - - with pytest.raises(SkipTest): - dummy() - - def test_skipping_with_single_minor_version(self, version_known_mock): - """Test skipping when decorator param is equals to host version but - omits patch - """ - - @decorators.host.skip_if_os('RHEL7.1') - def dummy(): - return True - - with pytest.raises(SkipTest): - dummy() - - def test_skipping_with_single_major_version(self, version_known_mock): - """Test skipping when decorator param is equals to host version but - omits minor and patch - """ - - @decorators.host.skip_if_os('RHEL7') - def dummy(): - return True - - with pytest.raises(SkipTest): - dummy() - - def test_skipping_with_multiple_versions(self, version_known_mock): - """Test skipping when decorator params contains host version""" - versions = self.VERSIONS + (version_known_mock._host_version,) - - @decorators.host.skip_if_os(*versions) - def dummy(): - return True - - with pytest.raises(SkipTest): - dummy() - - @pytest.mark.parametrize( - 'version', - [ - f'{v}7.1.0' - for v in [ - 'rhel', - 'Rhel', - 'rHel', - 'RHel', - 'rhEl', - 'RhEl', - 'rHEl', - 'RHEl', - 'rheL', - 'RheL', - 'rHeL', - 'RHeL', - 'rhEL', - 'RhEL', - 'rHEL', - 'RHEL', - ] - ], - ) - def test_skipping_non_normalized_version(self, version_known_mock, version): - """Test skipping occurs even if version prefix is not normalized""" - - @decorators.host.skip_if_os(version) - def dummy(): - return True - - with pytest.raises(SkipTest): - dummy() diff --git a/tests/robottelo/test_hammer.py b/tests/robottelo/test_hammer.py index f5153d70790..ea58b9f393b 100644 --- a/tests/robottelo/test_hammer.py +++ b/tests/robottelo/test_hammer.py @@ -6,13 +6,15 @@ class TestParseCSV: """Tests for parsing CSV hammer output""" def test_parse_csv(self): - output_lines = [ - 'Header,Header 2', - 'header value 1,header with spaces value', - 'MixEd CaSe ValUe,ALL CAPS VALUE', - '"""double quote escaped value""","," escaped value', - 'unicode,chårs', - ] + output_lines = '\n'.join( + [ + 'Header,Header 2', + 'header value 1,header with spaces value', + 'MixEd CaSe ValUe,ALL CAPS VALUE', + '"""double quote escaped value""","," escaped value', + 'unicode,chårs', + ] + ) assert hammer.parse_csv(output_lines) == [ {'header': 'header value 1', 'header-2': 'header with spaces value'}, {'header': 'MixEd CaSe ValUe', 'header-2': 'ALL CAPS VALUE'}, @@ -100,10 +102,12 @@ def test_parsed_json_match_parsed_csv(self): } """ - csv_ouput_lines = [ - "ID,Name,Organization,Content", - "160,QUWTHo0WzF,ANtbiU,qJxB1FX1UrssYiGGhRcZDF9eY8U", - ] + csv_ouput_lines = '\n'.join( + [ + "ID,Name,Organization,Content", + "160,QUWTHo0WzF,ANtbiU,qJxB1FX1UrssYiGGhRcZDF9eY8U", + ] + ) assert hammer.parse_json(json_output) == hammer.parse_csv(csv_ouput_lines)[0] @@ -114,46 +118,48 @@ class TestParseHelp: def test_parse_help(self): """Can parse hammer help output""" self.maxDiff = None - output = [ - 'Usage:', - ' hammer [OPTIONS] SUBCOMMAND [ARG] ...', - '', - 'Parameters:', - 'SUBCOMMAND subcommand', - '[ARG] ... subcommand arguments', - '', - 'Subcommands:', - ' activation-key Manipulate activation keys.', - ' capsule Manipulate capsule', - ' compute-resource Manipulate compute resources.', - ' content-host Manipulate content hosts on the', - ' server', - ' gpg Manipulate GPG Key actions on the', - ' server', - ' list, index List all architectures', - 'Options:', - ' --autocomplete LINE Get list of possible endings', - ' --name, --deprecation-name An option with a deprecation name', - ' --csv Output as CSV (same as', - ' --output=csv)', - ' --csv-separator SEPARATOR Character to separate the values', - ' --output ADAPTER Set output format. One of [base,', - ' table, silent, csv, yaml, json]', - ' -p, --password PASSWORD password to access the remote', - ' system', - ' -r, --reload-cache force reload of Apipie cache', - ' -v, --[no-]verbose Be verbose (or not). True by default', - ( - ' --location[-id|-title] Set the current location context for' - ' the request. Name/Title/Id can be used' - ), - ' --location[s|-ids|-titles] REPLACE locations with given Names/Titles/Ids', - ' Comma separated list of values.', - ( - ' --lifecycle-environment[-id] Set the current environment context' - ' for the request. Name/Id can be used' - ), - ] + output = '\n'.join( + [ + 'Usage:', + ' hammer [OPTIONS] SUBCOMMAND [ARG] ...', + '', + 'Parameters:', + 'SUBCOMMAND subcommand', + '[ARG] ... subcommand arguments', + '', + 'Subcommands:', + ' activation-key Manipulate activation keys.', + ' capsule Manipulate capsule', + ' compute-resource Manipulate compute resources.', + ' content-host Manipulate content hosts on the', + ' server', + ' gpg Manipulate GPG Key actions on the', + ' server', + ' list, index List all architectures', + 'Options:', + ' --autocomplete LINE Get list of possible endings', + ' --name, --deprecation-name An option with a deprecation name', + ' --csv Output as CSV (same as', + ' --output=csv)', + ' --csv-separator SEPARATOR Character to separate the values', + ' --output ADAPTER Set output format. One of [base,', + ' table, silent, csv, yaml, json]', + ' -p, --password PASSWORD password to access the remote', + ' system', + ' -r, --reload-cache force reload of Apipie cache', + ' -v, --[no-]verbose Be verbose (or not). True by default', + ( + ' --location[-id|-title] Set the current location context for' + ' the request. Name/Title/Id can be used' + ), + ' --location[s|-ids|-titles] REPLACE locations with given Names/Titles/Ids', + ' Comma separated list of values.', + ( + ' --lifecycle-environment[-id] Set the current environment context' + ' for the request. Name/Id can be used' + ), + ] + ) assert hammer.parse_help(output) == { 'subcommands': [ {'name': 'activation-key', 'description': 'Manipulate activation keys.'}, @@ -296,16 +302,18 @@ class TestParseInfo: def test_parse_simple(self): """Can parse a simple info output""" - output = [ - 'Id: 19', - 'Full name: 4iv01o2u 10.5', - 'Release name:', - '', - 'Family:', - 'Name: 4iv01o2u', - 'Major version: 10', - 'Minor version: 5', - ] + output = '\n'.join( + [ + 'Id: 19', + 'Full name: 4iv01o2u 10.5', + 'Release name:', + '', + 'Family:', + 'Name: 4iv01o2u', + 'Major version: 10', + 'Minor version: 5', + ] + ) assert hammer.parse_info(output) == { 'id': '19', 'full-name': '4iv01o2u 10.5', @@ -318,27 +326,31 @@ def test_parse_simple(self): def test_parse_numbered_list_attributes(self): """Can parse numbered list attributes""" - output = ['Partition tables:', ' 1) ptable1', ' 2) ptable2', ' 3) ptable3', ' 4) ptable4'] + output = '\n'.join( + ['Partition tables:', ' 1) ptable1', ' 2) ptable2', ' 3) ptable3', ' 4) ptable4'] + ) assert hammer.parse_info(output) == { 'partition-tables': ['ptable1', 'ptable2', 'ptable3', 'ptable4'] } def test_parse_list_attributes(self): """Can parse list attributes""" - output = ['Partition tables:', ' ptable1', ' ptable2', ' ptable3', ' ptable4'] + output = '\n'.join(['Partition tables:', ' ptable1', ' ptable2', ' ptable3', ' ptable4']) assert hammer.parse_info(output) == { 'partition-tables': ['ptable1', 'ptable2', 'ptable3', 'ptable4'] } def test_parse_dict_attributes(self): """Can parse dict attributes""" - output = [ - 'Content:', - ' 1) Repo Name: repo1', - ' URL: /custom/url1', - ' 2) Repo Name: repo2', - ' URL: /custom/url2', - ] + output = '\n'.join( + [ + 'Content:', + ' 1) Repo Name: repo1', + ' URL: /custom/url1', + ' 2) Repo Name: repo2', + ' URL: /custom/url2', + ] + ) assert hammer.parse_info(output) == { 'content': [ {'repo-name': 'repo1', 'url': '/custom/url1'}, @@ -348,26 +360,28 @@ def test_parse_dict_attributes(self): def test_parse_info(self): """Can parse info output""" - output = [ - 'Sync State: not_synced', - 'Sync Plan ID:', - 'GPG:', - ' GPG Key ID: 1', - ' GPG Key: key name', - 'Organizations:', - ' 1) Org 1', - ' 2) Org 2', - 'Locations:', - ' Loc 1', - ' Loc 2', - 'Repositories:', - ' 1) Repo Name: repo1', - ' Repo ID: 10', - ' 2) Repo Name: repo2', - ' Repo ID: 20', - ' 3) Repo Name => repo3', - ' Repo ID => 30', - ] + output = '\n'.join( + [ + 'Sync State: not_synced', + 'Sync Plan ID:', + 'GPG:', + ' GPG Key ID: 1', + ' GPG Key: key name', + 'Organizations:', + ' 1) Org 1', + ' 2) Org 2', + 'Locations:', + ' Loc 1', + ' Loc 2', + 'Repositories:', + ' 1) Repo Name: repo1', + ' Repo ID: 10', + ' 2) Repo Name: repo2', + ' Repo ID: 20', + ' 3) Repo Name => repo3', + ' Repo ID => 30', + ] + ) assert hammer.parse_info(output) == { 'sync-state': 'not_synced', 'sync-plan-id': {}, @@ -383,81 +397,83 @@ def test_parse_info(self): def test_parse(self): """Can parse actual host info""" - output = [ - 'Id: 31', - 'Name: name1', - 'Organization: org1', - 'Location: Default Location', - 'Cert name: cert name', - 'Managed: no', - 'Installed at:', - 'Last report:', - 'Uptime (seconds): 67', - 'Status:', - ' Global Status: Error', - 'Network:', - ' IPv4 address: ip1', - ' MAC: mac1', - ' Domain: domain1', - 'Network interfaces:', - ' 1) Id: 34', - ' Identifier: ens3', - ' Type: interface (primary, provision)', - ' MAC address: mac2', - ' IPv4 address: ip2', - ' FQDN: name1.domain', - 'Operating system:', - ' Architecture: x86_64', - ' Operating System: os1', - ' Build: no', - ' Custom partition table:', - 'Parameters:', - '', - 'All parameters:', - ' enable-puppet5 => true', - ' enable-epel => false', - 'Additional info:', - ' Owner: Anonymous Admin', - ' Owner Type: User', - ' Enabled: yes', - ' Model: Standard PC (i440FX + PIIX, 1996)', - ' Comment:', - 'OpenSCAP Proxy:', - 'Content Information:', - ' Content View:', - ' ID: 38', - ' Name: content view1', - ' Lifecycle Environment:', - ' ID: 40', - ' Name: lifecycle environment1', - ' Content Source:', - ' ID:', - ' Name:', - ' Kickstart Repository:', - ' ID:', - ' Name:', - ' Applicable Packages: 0', - ' Upgradable Packages: 0', - ' Applicable Errata:', - ' Enhancement: 0', - ' Bug Fix: 0', - ' Security: 0', - 'Subscription Information:', - ' UUID: uuid1', - ' Last Checkin: 2019-12-13 00:00:00 UTC', - ' Release Version:', - ' Autoheal: true', - ' Registered To: tier3', - ' Registered At: 2019-12-13 00:00:00 UTC', - ' Registered by Activation Keys:', - ' 1) ak1', - ' System Purpose:', - ' Service Level:', - ' Purpose Usage:', - ' Purpose Role:', - ' Purpose Addons:', - 'Host Collections:', - ] + output = '\n'.join( + [ + 'Id: 31', + 'Name: name1', + 'Organization: org1', + 'Location: Default Location', + 'Cert name: cert name', + 'Managed: no', + 'Installed at:', + 'Last report:', + 'Uptime (seconds): 67', + 'Status:', + ' Global Status: Error', + 'Network:', + ' IPv4 address: ip1', + ' MAC: mac1', + ' Domain: domain1', + 'Network interfaces:', + ' 1) Id: 34', + ' Identifier: ens3', + ' Type: interface (primary, provision)', + ' MAC address: mac2', + ' IPv4 address: ip2', + ' FQDN: name1.domain', + 'Operating system:', + ' Architecture: x86_64', + ' Operating System: os1', + ' Build: no', + ' Custom partition table:', + 'Parameters:', + '', + 'All parameters:', + ' enable-puppet5 => true', + ' enable-epel => false', + 'Additional info:', + ' Owner: Anonymous Admin', + ' Owner Type: User', + ' Enabled: yes', + ' Model: Standard PC (i440FX + PIIX, 1996)', + ' Comment:', + 'OpenSCAP Proxy:', + 'Content Information:', + ' Content View:', + ' ID: 38', + ' Name: content view1', + ' Lifecycle Environment:', + ' ID: 40', + ' Name: lifecycle environment1', + ' Content Source:', + ' ID:', + ' Name:', + ' Kickstart Repository:', + ' ID:', + ' Name:', + ' Applicable Packages: 0', + ' Upgradable Packages: 0', + ' Applicable Errata:', + ' Enhancement: 0', + ' Bug Fix: 0', + ' Security: 0', + 'Subscription Information:', + ' UUID: uuid1', + ' Last Checkin: 2019-12-13 00:00:00 UTC', + ' Release Version:', + ' Autoheal: true', + ' Registered To: tier3', + ' Registered At: 2019-12-13 00:00:00 UTC', + ' Registered by Activation Keys:', + ' 1) ak1', + ' System Purpose:', + ' Service Level:', + ' Purpose Usage:', + ' Purpose Role:', + ' Purpose Addons:', + 'Host Collections:', + ] + ) assert hammer.parse_info(output) == { 'id': '31', 'name': 'name1', diff --git a/tests/robottelo/test_helpers.py b/tests/robottelo/test_helpers.py index 5752e6e035e..a9f1fe28712 100644 --- a/tests/robottelo/test_helpers.py +++ b/tests/robottelo/test_helpers.py @@ -11,10 +11,10 @@ class FakeSSHResult: - def __init__(self, stdout=None, return_code=None, stderr=None): + def __init__(self, stdout=None, status=None, stderr=None): self.stdout = stdout self.stderr = stderr - self.return_code = return_code + self.status = status class TestPubKey: @@ -121,6 +121,6 @@ class TestGetAvailableCapsulePort: @mock.patch('robottelo.helpers.ssh') def test_return_port(self, ssh): """get_available_capsule_port returns a port number.""" - ssh.command = mock.MagicMock(return_value=FakeSSHResult(['""'], 0)) + ssh.command = mock.MagicMock(return_value=FakeSSHResult('""', 0)) port = get_available_capsule_port() assert port, "No available capsule port found." diff --git a/tests/robottelo/test_host_info.py b/tests/robottelo/test_host_info.py deleted file mode 100644 index 1a664cfb8a1..00000000000 --- a/tests/robottelo/test_host_info.py +++ /dev/null @@ -1,247 +0,0 @@ -from unittest import mock -from unittest.mock import call - -import pytest -from attrdict import AttrDict - -from robottelo import host_info -from robottelo.ssh import SSHCommandResult - - -class TestGetHostOsVersion: - """Tests for get_host_os_version version""" - - @pytest.fixture(scope="function") - def ssh_result(self): - """Mocking ssh""" - patcher = mock.patch('robottelo.host_info.ssh.command') - yield patcher.start() - - host_info.get_host_os_version.cache_clear() - patcher.stop() - - def assert_rhel_version(self, ssh_version, parsed_version, ssh_result): - """Encapsulate assertion logic regarding host os parsing - - :param ssh_version: version returned from ssh - :param parsed_version: parsed version - """ - ssh_result.return_value.stdout = [ssh_version] - assert parsed_version == host_info.get_host_os_version.__wrapped__() - ssh_result.assert_called_once_with('cat /etc/redhat-release') - - def test_rhel_major_version_parsing(self, ssh_result): - """Check if can parse major versions. - - Semantic version example: 1.2.3 - 1 is major - 2 is minor - 3 is patch - """ - self.assert_rhel_version( - 'Red Hat Enterprise Linux Server release 6 (Maipo)', 'RHEL6', ssh_result - ) - - def test_rhel_minor_version_parsing(self, ssh_result): - """Check if can parse minor versions""" - self.assert_rhel_version( - 'Red Hat Enterprise Linux Server release 7.2 (Maipo)', 'RHEL7.2', ssh_result - ) - - def test_rhel_patch_version_parsing(self, ssh_result): - """Check if can parse patch versions""" - self.assert_rhel_version( - 'Red Hat Enterprise Linux Server release 7.2.1 (Maipo)', 'RHEL7.2.1', ssh_result - ) - - def test_cache(self, request, ssh_result): - """Check get_host_os_version() calls are cached""" - ssh_result.return_value.stdout = ['Red Hat Enterprise Linux Server release 7.2.1 (Maipo)'] - assert 'RHEL7.2.1' == host_info.get_host_os_version() - ssh_result.assert_called_once_with('cat /etc/redhat-release') - ssh_result.return_value.stdout = ['Doesnt matter because because its cached'] - assert 'RHEL7.2.1' == host_info.get_host_os_version() - # if called more than once cache didn't worked - ssh_result.assert_called_once_with('cat /etc/redhat-release') - - @mock.patch('robottelo.host_info.logger') - def test_command_error(self, logger, ssh_result): - """Check returns 'Not Available' on error""" - cmd = SSHCommandResult( - stdout=[], - stderr='bash: generate: command not found\n', - return_code=127, - output_format=None, - ) - ssh_result.return_value = cmd - - os_version = host_info.get_host_os_version.__wrapped__() - assert 'Not Available' == os_version - ssh_result.assert_called_once_with('cat /etc/redhat-release') - logger.warning.assert_called_once_with('Host version not available: %r' % cmd) - - @mock.patch('robottelo.host_info.logger') - def test_command_parsing_error(self, logger, ssh_result): - """Test return not available on Fedora machines - It can be changed to handle other OS if needed - """ - cmd = SSHCommandResult(stdout=['Fedora release 23 (Twenty Three)'], return_code=0) - ssh_result.return_value = cmd - os_version = host_info.get_host_os_version.__wrapped__() - assert 'Not Available' == os_version - ssh_result.assert_called_once_with('cat /etc/redhat-release') - logger.warning.assert_called_once_with('Host version not available: %r' % cmd) - - -class TestGetHostSatVersion: - """Tests for get_host_sat_version version""" - - SSH_RESULT_ERROR = SSHCommandResult( - stdout=[], - stderr=('grep: /usr/share/foreman/lib/satellite/version.rb: No such file or directory'), - return_code=127, - output_format=None, - ) - - @pytest.fixture(scope="function") - def ssh_result(self): - """Mocking ssh""" - patcher = mock.patch('robottelo.host_info.ssh.command') - yield patcher.start() - - host_info.get_host_sat_version.cache_clear() - patcher.stop() - - def test_sat_6_dot_2(self, ssh_result): - """Check if can parse major 6.2.x versions""" - ssh_result.return_value.stdout = ['satellite-6.2.0-21.1.el7sat.noarch'] - assert '6.2' == host_info.get_host_sat_version.__wrapped__() - ssh_result.assert_called_once_with(host_info._SAT_6_2_VERSION_COMMAND) - - def test_sat_6_dot_1(self, ssh_result): - """Check if can parse major 6.2.x versions""" - ssh_result_success = mock.Mock() - ssh_result_success.return_code = 0 - ssh_result_success.stdout = [' VERSION = "6.1.8"'] - - ssh_result.side_effect = (self.SSH_RESULT_ERROR, ssh_result_success) - sat_version = host_info.get_host_sat_version.__wrapped__() - - assert "6.1" == sat_version - calls = [ - call(host_info._SAT_6_2_VERSION_COMMAND), - call(host_info._SAT_6_1_VERSION_COMMAND), - ] - ssh_result.assert_has_calls(calls) - - def test_cache(self, ssh_result): - """Check get_host_sat_version() calls are cached""" - ssh_result.return_value.stdout = [' SATELLITE_SHORT_VERSION = "6.2"'] - assert '6.2' == host_info.get_host_sat_version() - ssh_result.assert_called_once_with(host_info._SAT_6_2_VERSION_COMMAND) - ssh_result.return_value.stdout = ['Doesnt matter because because its cached'] - assert '6.2' == host_info.get_host_sat_version() - # if called more than once cache didn't worked - ssh_result.assert_called_once_with(host_info._SAT_6_2_VERSION_COMMAND) - - @mock.patch('robottelo.host_info.logger') - def test_command_error(self, logger, ssh_result): - """Check returns 'Not Available' on error""" - ssh_result.return_value = self.SSH_RESULT_ERROR - - sat_version = host_info.get_host_sat_version.__wrapped__() - assert 'Not Available' == sat_version - calls = [ - call(host_info._SAT_6_2_VERSION_COMMAND), - call(host_info._SAT_6_1_VERSION_COMMAND), - ] - ssh_result.assert_has_calls(calls) - logger.warning.assert_called_once_with( - 'Host Satellite version not available: %r' % self.SSH_RESULT_ERROR - ) - - -class TestSatVersionDependentValues: - """Tests for SatVersionDependentValues class""" - - rpms_61 = {'id': 'rhel-7-server-satellite-tools-6.1-rpms'} - rpms_62 = {'id': 'rhel-7-server-satellite-tools-6.2-rpms'} - - @pytest.fixture(scope="class") - def dep_versions_data(self): - """Set up version dependent values for all test""" - - versions = AttrDict( - { - 'd_6_1': self.rpms_61, - 'd_6_2': self.rpms_62, - 'sat_dep_values': host_info.SatVersionDependentValues( - {"6.1": self.rpms_61}, {"6.2": self.rpms_62} - ), - } - ) - yield versions - - host_info.get_host_sat_version.cache_clear() - - @mock.patch("robottelo.host_info.get_host_sat_version") - def test_init(self, get_host_sat_version, dep_versions_data): - """Test __init__ and check the is no call to get os Satellite version""" - assert dep_versions_data.sat_dep_values._versioned_values == { - "6.1": dep_versions_data.d_6_1, - "6.2": dep_versions_data.d_6_2, - } - assert not get_host_sat_version.called - - @mock.patch("robottelo.host_info.get_host_sat_version") - def test_getitem(self, get_host_sat_version, dep_versions_data): - """Check __getitem__ returns values dependent on Satellite version""" - get_host_sat_version.return_value = '6.1' - assert dep_versions_data.d_6_1['id'] == dep_versions_data.sat_dep_values['id'] - assert get_host_sat_version.called - - get_host_sat_version.return_value = '6.2' - assert dep_versions_data.d_6_2['id'] == dep_versions_data.sat_dep_values['id'] - - @pytest.fixture(scope="function") - def common_versions_data(self, dep_versions_data): - dep_versions_data.common = {} - dep_versions_data.sat_dep_values = host_info.SatVersionDependentValues( - {"6.1": dep_versions_data.d_6_1}, {"6.2": dep_versions_data.d_6_2}, common={} - ) - return dep_versions_data - - @mock.patch("robottelo.host_info.get_host_sat_version") - def test_common_dct(self, get_host_sat_version, common_versions_data): - """Check common dct handle missing keys""" - get_host_sat_version.return_value = '6.1' - assert common_versions_data.d_6_1['id'] == common_versions_data.sat_dep_values['id'] - assert get_host_sat_version.called - - get_host_sat_version.return_value = '6.2' - assert common_versions_data.d_6_2['id'] == common_versions_data.sat_dep_values['id'] - - with pytest.raises(KeyError): - common_versions_data.sat_dep_values['missing_version'] - common_versions_data.sat_dep_values = host_info.SatVersionDependentValues( - common={'missing_version': 'fallback'} - ) - # no keyerror with it added to common - assert 'fallback' == common_versions_data.sat_dep_values['missing_version'] - - @mock.patch("robottelo.host_info.get_host_sat_version") - def test_common_dct_override(self, get_host_sat_version, common_versions_data): - """Check common is overridden by version dct""" - get_host_sat_version.return_value = '6.1' - common_versions_data.sat_dep_values = host_info.SatVersionDependentValues( - {"6.1": self.rpms_61}, {"6.2": self.rpms_62}, common={'missing_version': 'fallback'} - ) - assert 'fallback' == common_versions_data.sat_dep_values['missing_version'] - common_versions_data.sat_dep_values = host_info.SatVersionDependentValues( - {"6.1": {'missing_version': 'override'}}, common={'missing_version': 'fallback'} - ) - assert 'override' == common_versions_data.sat_dep_values['missing_version'] - common_versions_data.sat_dep_values = host_info.SatVersionDependentValues( - {"6.1": self.rpms_61}, common={'missing_version': 'fallback'} - ) - assert 'fallback' == common_versions_data.sat_dep_values['missing_version'] diff --git a/tests/robottelo/test_issue_handlers.py b/tests/robottelo/test_issue_handlers.py index 8ded31d6824..bcdf0e58fba 100644 --- a/tests/robottelo/test_issue_handlers.py +++ b/tests/robottelo/test_issue_handlers.py @@ -19,7 +19,7 @@ class TestBugzillaIssueHandler: @pytest.fixture(autouse=True) def set_env_version(self, mocker): """Mock the return of get_sat_version to avoid ssh attempts""" - mocker.patch('robottelo.host_info.get_sat_version', return_value=Version('6.6')) + mocker.patch('robottelo.hosts.get_sat_version', return_value=Version('6.6')) mocker.patch( 'robottelo.utils.issue_handlers.bugzilla.get_sat_version', return_value=Version('6.6') ) diff --git a/tests/robottelo/test_ssh.py b/tests/robottelo/test_ssh.py index e992e1b7ad3..09f5a7d8e51 100644 --- a/tests/robottelo/test_ssh.py +++ b/tests/robottelo/test_ssh.py @@ -1,10 +1,6 @@ """Tests for module ``robottelo.ssh``.""" -import os -from io import StringIO from unittest import mock -import paramiko - from robottelo import ssh @@ -30,9 +26,9 @@ def read(self): class MockSSHClient: - """A mock ``paramiko.SSHClient`` object.""" + """A mock ``broker.Host`` object.""" - def __init__(self): + def __init__(self, **kwargs): """Set several debugging counters to 0. Whenever a method in this mock class is called, a corresponding counter @@ -64,10 +60,6 @@ def connect( pkey=None, key_filename=None, timeout=None, - allow_agent=True, - look_for_keys=True, - compress=False, - sock=None, ): """ "A stub method that records some of the parameters passed in. @@ -90,147 +82,16 @@ def close(self): """A no-op stub method.""" self.close_ += 1 - def exec_command(self, cmd, *args, **kwargs): + def execute(self, cmd, *args, **kwargs): return (self.ret_code, MockStdout(cmd, self.ret_code), MockStdout('', self.ret_code)) class TestSSH: """Tests for module ``robottelo.ssh``.""" - @mock.patch('robottelo.config.settings') - def test_get_connection_key(self, settings): - """Test method ``get_connection`` using key file to connect to the - server. - - Mock up ``paramiko.SSHClient`` (by overriding method - ``_call_paramiko_sshclient``) before calling ``get_connection``. - Assert that certain parameters are passed to the (mock) - ``paramiko.SSHClient`` object, and that certain methods on that object - are called. - """ - ssh._call_paramiko_sshclient = MockSSHClient - - key_filename = os.path.join(os.path.abspath(__name__), 'data', 'test_dsa.key') - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_password = None - settings.server.ssh_key = key_filename - settings.server.ssh_key_string = None - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - with ssh.get_connection() as connection: - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 0 - assert connection.hostname == 'example.com' - assert connection.username == 'nobody' - assert connection.key_filename == key_filename - assert connection.password is None - assert connection.pkey is None - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 1 - - @mock.patch('robottelo.config.settings') - def test_get_connection_pass(self, settings): - """Test method ``get_connection`` using password of user to connect to - the server - - Mock up ``paramiko.SSHClient`` (by overriding method - ``_call_paramiko_sshclient``) before calling ``get_connection``. - Assert that certain parameters are passed to the (mock) - ``paramiko.SSHClient`` object, and that certain methods on that object - are called. - """ - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_key_string = None - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - with ssh.get_connection() as connection: - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 0 - assert connection.hostname == 'example.com' - assert connection.username == 'nobody' - assert connection.password == 'test_password' - assert connection.key_filename is None - assert connection.pkey is None - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 1 - - @mock.patch('robottelo.config.settings') - def test_get_connection_key_string(self, settings): - """Test method ``get_connection`` using key file to connect to the - server. - - Mock up ``paramiko.SSHClient`` (by overriding method - ``_call_paramiko_sshclient``) before calling ``get_connection``. - Assert that certain parameters are passed to the (mock) - ``paramiko.SSHClient`` object, and that certain methods on that object - are called. - """ - ssh._call_paramiko_sshclient = MockSSHClient - key_string = StringIO('') - rsa_key = paramiko.rsakey.RSAKey.generate(512) - rsa_key.write_private_key(key_string) - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_password = None - settings.server.ssh_key = None - settings.server.ssh_key_string = key_string.getvalue() # resolve StringIO stream - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - with ssh.get_connection() as connection: - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 0 - assert connection.hostname == 'example.com' - assert connection.username == 'nobody' - assert connection.password is None - assert connection.key_filename is None - assert connection.pkey == rsa_key # PKey.__cmp__ - assert connection.set_missing_host_key_policy_ == 1 - assert connection.connect_ == 1 - assert connection.close_ == 1 - - @mock.patch('robottelo.config.settings') - def test_execute_command(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - - with ssh.get_connection() as connection: - ret = ssh.execute_command('ls -la', connection) - assert ret.stdout == ['ls -la'] - assert isinstance(ret, ssh.SSHCommandResult) - - @mock.patch('robottelo.config.settings') - def test_execute_command_base_output(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - - with ssh.get_connection() as connection: - ret = ssh.execute_command('ls -la', connection, output_format='base') - assert ret.stdout == 'ls -la' - assert isinstance(ret, ssh.SSHCommandResult) - @mock.patch('robottelo.config.settings') def test_command(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient + ssh.get_client = MockSSHClient settings.server.hostname = 'example.com' settings.server.ssh_username = 'nobody' settings.server.ssh_key = None @@ -239,50 +100,4 @@ def test_command(self, settings): settings.server.ssh_client.connection_timeout = 10 ret = ssh.command('ls -la') - assert ret.stdout == ['ls -la'] - assert isinstance(ret, ssh.SSHCommandResult) - - @mock.patch('robottelo.config.settings') - def test_command_base_output(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - - ret = ssh.command('ls -la', output_format='base') - assert ret.stdout == 'ls -la' - assert isinstance(ret, ssh.SSHCommandResult) - - @mock.patch('robottelo.config.settings') - def test_parse_csv(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - - ret = ssh.command('a,b,c\n1,2,3', output_format='csv') - assert ret.stdout == [{'a': '1', 'b': '2', 'c': '3'}] - assert isinstance(ret, ssh.SSHCommandResult) - - @mock.patch('robottelo.config.settings') - def test_parse_json(self, settings): - ssh._call_paramiko_sshclient = MockSSHClient - settings.server.hostname = 'example.com' - settings.server.ssh_username = 'nobody' - settings.server.ssh_key = None - settings.server.ssh_password = 'test_password' - settings.server.ssh_client.command_timeout = 300 - settings.server.ssh_client.connection_timeout = 10 - - ret = ssh.command('{"a": 1, "b": true}', output_format='json') - assert ret.stdout == {'a': '1', 'b': True} - assert isinstance(ret, ssh.SSHCommandResult) - - def test_call_paramiko_client(self): - assert isinstance(ssh._call_paramiko_sshclient(), (paramiko.SSHClient, MockSSHClient)) + assert ret[1].cmd == 'ls -la' diff --git a/tests/upgrades/test_contentview.py b/tests/upgrades/test_contentview.py index d804032b792..13001f2370d 100644 --- a/tests/upgrades/test_contentview.py +++ b/tests/upgrades/test_contentview.py @@ -20,7 +20,6 @@ from upgrade_tests import post_upgrade from upgrade_tests import pre_upgrade -from robottelo import ssh from robottelo.config import settings from robottelo.constants import RPM_TO_UPLOAD from robottelo.helpers import get_data_file @@ -32,7 +31,7 @@ class TestContentView: """ @pre_upgrade - def test_cv_preupgrade_scenario(self, request): + def test_cv_preupgrade_scenario(self, request, default_sat): """Pre-upgrade scenario that creates content-view with various repositories. :id: a4ebbfa1-106a-4962-9c7c-082833879ae8 @@ -58,7 +57,7 @@ def test_cv_preupgrade_scenario(self, request): remote_file_path = f"/tmp/{RPM_TO_UPLOAD}" - ssh.upload_file(local_file=get_data_file(RPM_TO_UPLOAD), remote_file=remote_file_path) + default_sat.put(get_data_file(RPM_TO_UPLOAD), remote_file_path) with open(f'{get_data_file(RPM_TO_UPLOAD)}', "rb") as content: file_repository.upload_content(files={'content': content}) assert RPM_TO_UPLOAD in file_repository.files()["results"][0]['name'] diff --git a/tests/upgrades/test_foreman_maintain.py b/tests/upgrades/test_foreman_maintain.py index 237f26448d5..3c9f4dd6339 100644 --- a/tests/upgrades/test_foreman_maintain.py +++ b/tests/upgrades/test_foreman_maintain.py @@ -19,8 +19,6 @@ from upgrade_tests import post_upgrade from upgrade_tests import pre_upgrade -from robottelo import ssh - class TestForemanMaintain: """The test class contains pre-upgrade and post-upgrade scenarios to test @@ -34,7 +32,7 @@ class TestForemanMaintain: """ @staticmethod - def satellite_upgradable_version_list(): + def satellite_upgradable_version_list(sat_obj): """ This function is used to collect the details of satellite version and upgradable version list. @@ -43,12 +41,13 @@ def satellite_upgradable_version_list(): """ cmd = "rpm -q satellite > /dev/null && rpm -q satellite --queryformat=%{VERSION}" - satellite_version = ssh.command(cmd) - if satellite_version.return_code == 0: + # leaving this section as-is for now but this could be refactored to use sat_obj.version + satellite_version = sat_obj.execute(cmd) + if satellite_version.status == 0: satellite_version = satellite_version.stdout else: return [], [], None, None - forman_maintain_version = ssh.command( + forman_maintain_version = sat_obj.execute( "foreman-maintain upgrade list-versions --disable-self-upgrade" ) upgradeable_version = [ @@ -99,7 +98,7 @@ def version_details( return zstream_version, next_version @pre_upgrade - def test_pre_foreman_maintain_upgrade_list_versions(self): + def test_pre_foreman_maintain_upgrade_list_versions(self, default_sat): """Pre-upgrade sceanrio that tests list of satellite version which satellite can be upgraded. @@ -116,7 +115,7 @@ def test_pre_foreman_maintain_upgrade_list_versions(self): upgradable_version, major_version_change, y_version, - ) = self.satellite_upgradable_version_list() + ) = self.satellite_upgradable_version_list(default_sat) if satellite_version: # In future If foreman-maintain packages update add before # pre-upgrade test case execution then next version kind of @@ -129,7 +128,7 @@ def test_pre_foreman_maintain_upgrade_list_versions(self): assert zstream_version in upgradable_version @post_upgrade - def test_post_foreman_maintain_upgrade_list_versions(self): + def test_post_foreman_maintain_upgrade_list_versions(self, default_sat): """Post-upgrade sceanrio that tests list of satellite version which satellite can be upgraded. @@ -146,7 +145,7 @@ def test_post_foreman_maintain_upgrade_list_versions(self): upgradable_version, major_version_change, y_version, - ) = self.satellite_upgradable_version_list() + ) = self.satellite_upgradable_version_list(default_sat) if satellite_version: zstream_version, next_version = self.version_details( satellite_version[0], major_version_change, y_version, upgrade_stage="post-upgrade" diff --git a/tests/upgrades/test_performance_tuning.py b/tests/upgrades/test_performance_tuning.py index 162498b29bf..cc5f5d9078b 100644 --- a/tests/upgrades/test_performance_tuning.py +++ b/tests/upgrades/test_performance_tuning.py @@ -306,7 +306,7 @@ def test_post_performance_tuning_apply(self, default_sat): local_path="custom-hiera-after-upgrade.yaml", remote_path="/etc/foreman-installer/custom-hiera.yaml", ) - assert filecmp.cmp("custom-hiera.yaml", "custom-hiera-after-upgrade.yaml") + assert filecmp.cmp('custom-hiera.yaml', 'custom-hiera-after-upgrade.yaml') cmd = 'grep "tuning: default" /etc/foreman-installer/scenarios.d/satellite.yaml' assert default_sat.execute(cmd).status == 0 diff --git a/tests/upgrades/test_satellitesync.py b/tests/upgrades/test_satellitesync.py index 0e8ca1ddde0..3836f3b17a9 100644 --- a/tests/upgrades/test_satellitesync.py +++ b/tests/upgrades/test_satellitesync.py @@ -21,7 +21,6 @@ from upgrade_tests import post_upgrade from upgrade_tests import pre_upgrade -from robottelo import ssh from robottelo.cli.contentview import ContentView from robottelo.cli.package import Package @@ -77,7 +76,7 @@ def test_pre_version_cv_export_import(self, request): indirect=True, ) def test_post_version_cv_export_import( - self, request, set_importing_org, dependent_scenario_name + self, request, set_importing_org, dependent_scenario_name, default_sat ): """After upgrade, content view version import and export works on the existing content view(that we created before the upgrade). @@ -114,8 +113,8 @@ def test_post_version_cv_export_import( ContentView.version_export({'export-dir': f'{export_base}', 'id': exporting_cvv_id}) exported_tar = f'{export_base}/export-{exporting_cv.name}-{exporting_cvv_version}.tar' - result = ssh.command(f"[ -f {exported_tar} ]") - assert result.return_code == 0 + result = default_sat.execute(f'[ -f {exported_tar} ]') + assert result.status == 0 exported_packages = Package.list({'content-view-version-id': exporting_cvv_id}) assert len(exported_packages) > 0 @@ -128,7 +127,7 @@ def test_post_version_cv_export_import( imported_packages = Package.list({'content-view-version-id': importing_cvv[0].id}) assert len(imported_packages) > 0 assert len(exported_packages) == len(imported_packages) - ssh.command(f'rm -rf {export_base}/*') + default_sat.execute(f'rm -rf {export_base}/*') exporting_cv_json = exporting_cv.read_json() importing_cv_json = importing_cv.read_json() exporting_cv_env_id = exporting_cv_json['environments'][0]['id'] diff --git a/tests/upgrades/test_subscription.py b/tests/upgrades/test_subscription.py index a41d2c93306..a96176dda50 100644 --- a/tests/upgrades/test_subscription.py +++ b/tests/upgrades/test_subscription.py @@ -91,7 +91,7 @@ class TestSubscriptionAutoAttach: """ @pre_upgrade - def test_pre_subscription_scenario_autoattach(self, request): + def test_pre_subscription_scenario_autoattach(self, request, default_sat): """Create content host and register with Satellite :id: preupgrade-940fc78c-ffa6-4d9a-9c4b-efa1b9480a22 @@ -146,7 +146,9 @@ def test_pre_subscription_scenario_autoattach(self, request): assert org.name in status @post_upgrade(depend_on=test_pre_subscription_scenario_autoattach) - def test_post_subscription_scenario_autoattach(self, request, dependent_scenario_name): + def test_post_subscription_scenario_autoattach( + self, request, dependent_scenario_name, default_sat + ): """Run subscription auto-attach on pre-upgrade content host registered with Satellite.