Skip to content

Commit

Permalink
Merge branch '6.16.z' into cherry-pick-6.16.z-e34528585ec1e991a8f5a3d…
Browse files Browse the repository at this point in the history
…3505d352c3aa0427e
  • Loading branch information
synkd authored Nov 4, 2024
2 parents 07c2799 + 3130341 commit 94f7384
Show file tree
Hide file tree
Showing 17 changed files with 299 additions and 72 deletions.
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ repos:
- id: check-yaml
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9
rev: v0.7.1
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
Expand All @@ -28,6 +28,6 @@ repos:
types: [text]
require_serial: true
- repo: https://github.com/gitleaks/gitleaks
rev: v8.20.1
rev: v8.21.2
hooks:
- id: gitleaks
74 changes: 64 additions & 10 deletions pytest_plugins/requirements/req_updater.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
from functools import cached_property
import subprocess
import sys


class UsageError(Exception):
"""The UsageError raised when the package manager is different from uv or pip"""

pass


class ReqUpdater:
# Installed package name as key and its counterpart in requirements file as value
package_deviates = {
'Betelgeuse': 'betelgeuse',
'broker': 'broker[docker]',
'broker': 'broker[docker,podman,hussh]',
'dynaconf': 'dynaconf[vault]',
'Jinja2': 'jinja2',
'Sphinx': 'sphinx',
'pyyaml': 'PyYAML',
}

@cached_property
Expand All @@ -18,9 +26,9 @@ def installed_packages(self):
This also normalizes any package names that deviates in requirements file vs installed names
"""
installed_pkges = subprocess.run(
'pip list --format=freeze', capture_output=True, shell=True
).stdout.decode()
installer_args = [sys.executable, '-m', 'list', '--format=freeze']
installer_args[2:2] = self.packagae_manager.split(' ')
installed_pkges = subprocess.run(installer_args, capture_output=True).stdout.decode()
for pkg in self.package_deviates:
if pkg in installed_pkges:
# Replacing the installed package names with their names in requirements file
Expand Down Expand Up @@ -56,16 +64,62 @@ def opt_deviation(self):
"""Returns new and updates available packages in requirements-optional file"""
return set(self.optional_packages).difference(self.installed_packages)

@cached_property
def packagae_manager(self):
if (
subprocess.run(
[sys.executable, '-m', 'pip', '--version'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode
== 0
):
_manager = 'pip'
elif (
subprocess.run(
[sys.executable, '-m', 'uv', '--version'],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
).returncode
== 0
):
_manager = 'uv pip'
else:
raise UsageError(
'The package manager is not identifiable for performing package updates.'
'Currently only pip and uv is supported. Please manually update the packages '
'and rerun pytest command.'
)
return _manager

def install_req_deviations(self):
"""Installs new and updates available packages in requirements file"""
if self.req_deviation:
subprocess.run(
f"pip install {' '.join(self.req_deviation)}", shell=True, stdout=subprocess.PIPE
)
lst_of_reqs = ' '.join(f"'{req}'" for req in self.req_deviation)
if (
subprocess.run(
f"{self.packagae_manager} install {lst_of_reqs}",
shell=True,
stdout=subprocess.PIPE,
).returncode
== 0
):
print('Mandatory requirements are updated.')
else:
print('ERROR: Some issue occurred with updating the required requirements')

def install_opt_deviations(self):
"""Installs new and updates available packages in requirements-optional file"""
if self.opt_deviation:
subprocess.run(
f"pip install {' '.join(self.opt_deviation)}", shell=True, stdout=subprocess.PIPE
)
lst_of_reqs = ' '.join(f"'{req}'" for req in self.opt_deviation)
if (
subprocess.run(
f"{self.packagae_manager} install {lst_of_reqs}",
shell=True,
stdout=subprocess.PIPE,
).returncode
== 0
):
print('Optional requirements are updated.')
else:
print('ERROR: Some issue occurred with updating the optional requirements')
36 changes: 23 additions & 13 deletions pytest_plugins/requirements/update_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
updater = ReqUpdater()


def git_deviation_filter(deviation):
"""Packages installed from Git branch and the version cant be compared, so ignore them from reporting"""
git_packages = ['nailgun', 'airgun']
return all(git_pckg not in deviation for git_pckg in git_packages)


def pytest_addoption(parser):
"""Options to allow user to update the requirements"""
update_options = {
Expand All @@ -28,24 +34,28 @@ def pytest_report_header(config):
# Following will update the mandatory and optional requirements
# pytest tests/foreman --collect-only --update-all-reqs
"""
if updater.req_deviation:
print(f"Mandatory Requirements Mismatch: {' '.join(updater.req_deviation)}")
if config.getoption('update_required_reqs') or config.getoption('update_all_reqs'):
updater.install_req_deviations()
print('Mandatory requirements are installed to be up-to-date.')
req_deviations = updater.req_deviation
filtered_req_deviations = list(filter(git_deviation_filter, req_deviations))
if filtered_req_deviations:
print(f"Mandatory Requirements Mismatch: {' '.join(filtered_req_deviations)}")
else:
print('Mandatory Requirements are up to date.')

if updater.opt_deviation:
print(f"Optional Requirements Mismatch: {' '.join(updater.opt_deviation)}")
if config.getoption('update_all_reqs'):
updater.install_opt_deviations()
print('Optional requirements are installed to be up-to-date.')
if req_deviations and (
config.getoption('update_required_reqs') or config.getoption('update_all_reqs')
):
updater.install_req_deviations()

opt_deviations = updater.opt_deviation
filtered_opt_deviations = list(filter(git_deviation_filter, opt_deviations))
if filtered_opt_deviations:
print(f"Optional Requirements Mismatch: {' '.join(filtered_opt_deviations)}")
else:
print('Optional Requirements are up to date.')
if opt_deviations and config.getoption('update_all_reqs'):
updater.install_opt_deviations()

if updater.req_deviation or updater.opt_deviation:
if req_deviations or opt_deviations:
print(
"To update mismatched requirements, run the pytest command with "
"To update requirements, run the pytest with "
"'--update-required-reqs' OR '--update-all-reqs' option."
)
8 changes: 4 additions & 4 deletions requirements-optional.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# For running tests and checking code quality using these modules.
pytest-cov==5.0.0
redis==5.1.1
pytest-cov==6.0.0
redis==5.2.0
pre-commit==4.0.1
ruff==0.7.0
ruff==0.7.2

# For generating documentation.
sphinx==8.1.3
sphinx-autoapi==3.3.2
sphinx-autoapi==3.3.3

# For 'manage' interactive shell
manage==0.1.15
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pytest==8.3.3
pytest-order==1.3.0
pytest-services==2.2.1
pytest-mock==3.14.0
pytest-reportportal==5.4.4
pytest-reportportal==5.4.5
pytest-xdist==3.6.1
pytest-fixturecollection==0.1.2
pytest-ibutsu==2.2.4
Expand Down
1 change: 1 addition & 0 deletions robottelo/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
'current': 'Overall Status: Current',
'invalid': 'Overall Status: Invalid',
'insufficient': 'Overall Status: Insufficient',
'disabled': 'Overall Status: Disabled',
'unknown': 'Overall Status: Unknown',
}

Expand Down
19 changes: 12 additions & 7 deletions robottelo/hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
RHSSO_RESET_PASSWORD,
RHSSO_USER_UPDATE,
SATELLITE_VERSION,
SM_OVERALL_STATUS,
)
from robottelo.exceptions import CLIFactoryError, DownloadFileError, HostPingFailed
from robottelo.host_helpers import CapsuleMixins, ContentHostMixins, SatelliteMixins
Expand Down Expand Up @@ -1429,8 +1430,6 @@ def install_tracer(self):

def register_to_cdn(self, pool_ids=None, enable_proxy=False):
"""Subscribe satellite to CDN"""
if pool_ids is None:
pool_ids = [settings.subscription.rhn_poolid]
self.reset_rhsm()
cmd_result = self.register_contenthost(
org=None,
Expand All @@ -1443,11 +1442,17 @@ def register_to_cdn(self, pool_ids=None, enable_proxy=False):
raise ContentHostError(
f'Error during registration, command output: {cmd_result.stdout}'
)
cmd_result = self.subscription_manager_attach_pool(pool_ids)[0]
if cmd_result.status != 0:
raise ContentHostError(
f'Error during pool attachment, command output: {cmd_result.stdout}'
)
# Attach a pool only if the Org isn't SCA yet
sub_status = self.subscription_manager_status().stdout
if SM_OVERALL_STATUS['disabled'] not in sub_status:
if pool_ids in [None, []]:
pool_ids = [settings.subscription.rhn_poolid]
for pid in pool_ids:
int(pid, 16) # raises ValueError if not a HEX number
cmd_result = self.subscription_manager_attach_pool(pool_ids)
for res in cmd_result:
if res.status != 0:
raise ContentHostError(f'Pool attachment failed with output: {res.stdout}')

def ping_host(self, host):
"""Check the provisioned host status by pinging the ip of host
Expand Down
15 changes: 12 additions & 3 deletions robottelo/utils/datafactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,26 +496,35 @@ def valid_http_credentials(url_encoded=False):
'quote': False,
'http_valid': True,
},
{'login': 'admin', 'pass': '', 'quote': False, 'http_valid': False},
{'login': '', 'pass': 'mypassword', 'quote': False, 'http_valid': False},
{'login': '', 'pass': '', 'quote': False, 'http_valid': False},
{'login': 'admin', 'pass': '', 'quote': False, 'http_valid': False, 'yum_compatible': True},
{
'login': '',
'pass': 'mypassword',
'quote': False,
'http_valid': False,
'yum_compatible': False,
},
{'login': '', 'pass': '', 'quote': False, 'http_valid': False, 'yum_compatible': True},
{
'login': gen_string('alpha', gen_integer(1, 512)),
'pass': gen_string('alpha'),
'quote': False,
'http_valid': False,
'yum_compatible': False,
},
{
'login': gen_string('alphanumeric', gen_integer(1, 512)),
'pass': gen_string('alphanumeric'),
'quote': False,
'http_valid': False,
'yum_compatible': False,
},
{
'login': gen_string('utf8', gen_integer(1, 50)),
'pass': gen_string('utf8'),
'quote': True,
'http_valid': False,
'yum_compatible': False,
'encoding': 'utf8',
},
]
Expand Down
9 changes: 4 additions & 5 deletions robottelo/utils/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ def get_local_file_data(path):
checksum = hashlib.sha256(file_content).hexdigest()

try:
tarobj = tarfile.open(path, mode='r')
host_counts = get_host_counts(tarobj)
tarobj.close()
extractable = True
json_files_parsable = True
with tarfile.open(path, mode='r') as tarobj:
host_counts = get_host_counts(tarobj)
extractable = True
json_files_parsable = True
except (tarfile.TarError, json.JSONDecodeError):
host_counts = {}
extractable = False
Expand Down
2 changes: 1 addition & 1 deletion tests/foreman/api/test_provisioningtemplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ def test_positive_end_to_end_crud(
# clone
template_origin = template.read_json()
# remove unique keys
unique_keys = ('updated_at', 'created_at', 'id', 'name')
unique_keys = ('updated_at', 'created_at', 'id', 'name', 'cloned_from_id')
template_origin = {
key: value for key, value in template_origin.items() if key not in unique_keys
}
Expand Down
2 changes: 1 addition & 1 deletion tests/foreman/api/test_reporttemplates.py
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ def test_positive_installed_products(
)
assert rake.status == 0, f'Rake call failed with this output:\n({rake.stdout}).'

pattern = re.compile(r'name: "(.*?)".*?cp_product_id: "(.*?)"')
pattern = re.compile(r'name: "(.*?)"\s*.*?\s*cp_product_id: "(.*?)"')
matches = pattern.findall(rake.stdout)
products = [f'{match[0]} ({match[1]})' for match in matches]
assert len(products), 'No installed products to compare.'
Expand Down
21 changes: 10 additions & 11 deletions tests/foreman/cli/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,16 +716,14 @@ def test_positive_synchronize_file_repo(self, repo_options, repo, target_sat):
'repo_options',
**parametrized(
[
(
{
'content-type': 'yum',
'url': FAKE_5_YUM_REPO,
'upstream-username': creds['login'],
'upstream-password': creds['pass'],
}
for creds in valid_http_credentials()
if not creds['http_valid']
)
{
'content-type': 'yum',
'url': FAKE_5_YUM_REPO,
'upstream-username': creds['login'],
'upstream-password': creds['pass'],
}
for creds in valid_http_credentials()
if not creds['http_valid'] and creds.get('yum_compatible')
]
),
indirect=['repo_options'],
Expand All @@ -747,7 +745,8 @@ def test_negative_synchronize_auth_yum_repo(self, repo, target_sat):
response = target_sat.cli.Task.progress(
{'id': repo_sync[0]['id']}, return_raw_response=True
)
assert "Error: 401, message='Unauthorized'" in response.stderr[1].decode('utf-8')

assert "Error: 401, message='Unauthorized'" in response.stderr

@pytest.mark.tier2
@pytest.mark.upgrade
Expand Down
2 changes: 2 additions & 0 deletions tests/foreman/destructive/test_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def test_positive_cockpit(self, cockpit_host, class_cockpit_sat, class_org):
:Verifies: SAT-27411
:customerscenario: true
:parametrized: yes
"""
with class_cockpit_sat.ui_session() as session:
Expand Down
Loading

0 comments on commit 94f7384

Please sign in to comment.