-
Notifications
You must be signed in to change notification settings - Fork 146
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add unit tests for leftover packages actors and move them to common repo
Actors: - checkleftoverpackages - removeleftoverpackages - reportleftoverpackages * Refactor actors code from el7toel8 to common * Put their processes into library * Create unit tests for actors Jira: OAMG-1254
- Loading branch information
1 parent
346b741
commit b584b7f
Showing
12 changed files
with
433 additions
and
164 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
repos/system_upgrade/common/actors/checkleftoverpackages/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import checkleftoverpackages | ||
from leapp.models import InstalledUnsignedRPM, LeftoverPackages, TransactionCompleted | ||
from leapp.tags import IPUWorkflowTag, RPMUpgradePhaseTag | ||
|
||
|
||
class CheckLeftoverPackages(Actor): | ||
""" | ||
Check if there are any RHEL 7 packages present after upgrade. | ||
Actor produces message containing these packages. Message is empty if there are no el7 package left. | ||
""" | ||
|
||
name = 'check_leftover_packages' | ||
consumes = (TransactionCompleted, InstalledUnsignedRPM) | ||
produces = (LeftoverPackages,) | ||
tags = (RPMUpgradePhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
checkleftoverpackages.process() |
41 changes: 41 additions & 0 deletions
41
repos/system_upgrade/common/actors/checkleftoverpackages/libraries/checkleftoverpackages.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import re | ||
|
||
from leapp.libraries.common.config.version import get_source_major_version | ||
from leapp.libraries.common.rpms import get_installed_rpms | ||
from leapp.libraries.stdlib import api | ||
from leapp.models import InstalledUnsignedRPM, LeftoverPackages, RPM | ||
|
||
|
||
def process(): | ||
LEAPP_PACKAGES = ['leapp', 'leapp-repository', 'snactor', 'leapp-repository-deps-el8', 'leapp-deps-el8', | ||
'python2-leapp'] | ||
installed_rpms = get_installed_rpms() | ||
if not installed_rpms: | ||
return | ||
|
||
to_remove = LeftoverPackages() | ||
unsigned = [pkg.name for pkg in next(api.consume(InstalledUnsignedRPM), InstalledUnsignedRPM()).items] | ||
|
||
for rpm in installed_rpms: | ||
rpm = rpm.strip() | ||
if not rpm: | ||
continue | ||
name, version, release, epoch, packager, arch, pgpsig = rpm.split('|') | ||
|
||
version_pattern = r'el(\d+)' | ||
match = re.search(version_pattern, release) | ||
|
||
if match: | ||
RHEL_version = match.group(1) | ||
if int(RHEL_version) <= int(get_source_major_version()) and name not in LEAPP_PACKAGES + unsigned: | ||
to_remove.items.append(RPM( | ||
name=name, | ||
version=version, | ||
epoch=epoch, | ||
packager=packager, | ||
arch=arch, | ||
release=release, | ||
pgpsig=pgpsig | ||
)) | ||
|
||
api.produce(to_remove) |
51 changes: 51 additions & 0 deletions
51
repos/system_upgrade/common/actors/checkleftoverpackages/tests/test_checkleftoverpackages.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import pytest | ||
|
||
from leapp.libraries.actor import checkleftoverpackages | ||
from leapp.libraries.common.testutils import CurrentActorMocked, produce_mocked | ||
from leapp.libraries.stdlib import api | ||
from leapp.models import InstalledUnsignedRPM, LeftoverPackages, RPM | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('source_major_version', 'rpm_name', 'release', 'expected_to_be_removed'), | ||
( | ||
(7, 'sed', '7.el7', True), | ||
(8, 'sed', '7.el7', True), | ||
(8, 'sed', '8.el7', True), | ||
(7, 'leapp', '1.el7', False), | ||
(7, 'unsigned', '1.el7', False), | ||
(7, 'leapp-repository', '1.el8', False), | ||
(7, 'gnutls', '8.el8_9.1', False), | ||
) | ||
) | ||
def test_package_to_be_removed(monkeypatch, source_major_version, rpm_name, release, expected_to_be_removed): | ||
rpm_details = { | ||
'version': '0.1', | ||
'epoch': '0', | ||
'packager': 'packager', | ||
'arch': 'noarch', | ||
'pgpsig': 'sig' | ||
} | ||
|
||
def get_installed_rpms_mocked(): | ||
return ['{}|{}|{}|{}|{}|{}|{}'.format(rpm_name, rpm_details['version'], release, rpm_details['epoch'], | ||
rpm_details['packager'], rpm_details['arch'], rpm_details['pgpsig'])] | ||
|
||
UnsignedRPM = RPM(name='unsigned', version='0.1', release=release, epoch='0', | ||
packager='packager', arch='noarch', pgpsig='OTHER_SIG') | ||
|
||
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[InstalledUnsignedRPM(items=[UnsignedRPM])])) | ||
monkeypatch.setattr(checkleftoverpackages, 'get_installed_rpms', get_installed_rpms_mocked) | ||
monkeypatch.setattr(checkleftoverpackages, 'get_source_major_version', lambda: source_major_version) | ||
monkeypatch.setattr(api, 'produce', produce_mocked()) | ||
|
||
checkleftoverpackages.process() | ||
|
||
expected_output = LeftoverPackages() | ||
if expected_to_be_removed: | ||
expected_output.items.append(RPM(name=rpm_name, release=release, **rpm_details)) | ||
|
||
assert api.produce.called == 1 | ||
assert api.produce.model_instances[0] == expected_output |
22 changes: 22 additions & 0 deletions
22
repos/system_upgrade/common/actors/removeleftoverpackages/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import removeleftoverpackages | ||
from leapp.models import LeftoverPackages, RemovedPackages | ||
from leapp.reporting import Report | ||
from leapp.tags import ExperimentalTag, IPUWorkflowTag, RPMUpgradePhaseTag | ||
|
||
|
||
class RemoveLeftoverPackages(Actor): | ||
""" | ||
Remove packages left on the system after the upgrade to higher major version of RHEL. | ||
Removal of packages is necessary in order to keep the machine in supported state. | ||
Actor generates report telling users what packages have been removed. | ||
""" | ||
|
||
name = 'remove_leftover_packages' | ||
consumes = (LeftoverPackages, ) | ||
produces = (Report, RemovedPackages) | ||
tags = (RPMUpgradePhaseTag, IPUWorkflowTag, ExperimentalTag) | ||
|
||
def process(self): | ||
removeleftoverpackages.process() |
56 changes: 56 additions & 0 deletions
56
...s/system_upgrade/common/actors/removeleftoverpackages/libraries/removeleftoverpackages.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from leapp.libraries.common.rhsm import skip_rhsm | ||
from leapp.libraries.common.rpms import get_installed_rpms | ||
from leapp.libraries.stdlib import api, CalledProcessError, run | ||
from leapp.models import LeftoverPackages, RemovedPackages, RPM | ||
|
||
|
||
def get_leftover_packages(): | ||
leftover_packages = next(api.consume(LeftoverPackages), LeftoverPackages()) | ||
if not leftover_packages.items: | ||
api.current_logger().info('No leftover packages, skipping...') | ||
return None | ||
return leftover_packages | ||
|
||
|
||
def _get_removed_packages(installed_rpms): | ||
return list(set(installed_rpms) - set(get_installed_rpms())) | ||
|
||
|
||
def get_removed_packages(installed_rpms): | ||
removed_packages = RemovedPackages() | ||
removed = _get_removed_packages(installed_rpms) | ||
|
||
for pkg in removed: | ||
name, version, release, epoch, packager, arch, pgpsig = pkg.split('|') | ||
removed_packages.items.append(RPM( | ||
name=name, | ||
version=version, | ||
epoch=epoch, | ||
packager=packager, | ||
arch=arch, | ||
release=release, | ||
pgpsig=pgpsig | ||
)) | ||
return removed_packages | ||
|
||
|
||
def process(): | ||
leftover_packages = get_leftover_packages() | ||
if not leftover_packages: | ||
return | ||
|
||
installed_rpms = get_installed_rpms() | ||
|
||
to_remove = ['-'.join([pkg.name, pkg.version, pkg.release]) for pkg in leftover_packages.items] | ||
cmd = ['dnf', 'remove', '-y', '--noautoremove'] + to_remove | ||
if skip_rhsm(): | ||
# ensure we don't use suscription-manager when it should be skipped | ||
cmd += ['--disableplugin', 'subscription-manager'] | ||
try: | ||
run(cmd) | ||
except (CalledProcessError, OSError): | ||
error = 'Failed to remove packages: {}'.format(', '.join(to_remove)) | ||
api.current_logger().error(error) | ||
return | ||
|
||
api.produce(get_removed_packages(installed_rpms)) |
116 changes: 116 additions & 0 deletions
116
.../system_upgrade/common/actors/removeleftoverpackages/tests/test_removeleftoverpackages.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import pytest | ||
|
||
from leapp.libraries.actor import removeleftoverpackages | ||
from leapp.libraries.common.testutils import CurrentActorMocked, logger_mocked, produce_mocked | ||
from leapp.libraries.stdlib import api, CalledProcessError | ||
from leapp.models import LeftoverPackages, RemovedPackages, RPM | ||
|
||
|
||
def test_get_leftover_packages(monkeypatch): | ||
rpm = RPM(name='rpm', version='1.0', release='1.el7', epoch='0', packager='foo', arch='noarch', pgpsig='SIG') | ||
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[LeftoverPackages(items=[rpm])])) | ||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
|
||
assert removeleftoverpackages.get_leftover_packages() == LeftoverPackages(items=[rpm]) | ||
|
||
|
||
def test_no_leftover_packages(monkeypatch): | ||
monkeypatch.setattr(api, 'current_actor', CurrentActorMocked(msgs=[LeftoverPackages()])) | ||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
|
||
removeleftoverpackages.get_leftover_packages() | ||
|
||
assert api.current_logger.infomsg == ['No leftover packages, skipping...'] | ||
|
||
|
||
def test_remove_lefover_packages_error(monkeypatch): | ||
def get_leftover_pkgs(): | ||
return LeftoverPackages(items=[RPM(name='rpm', version='1.0', release='1.el7', epoch='0', | ||
packager='packager', arch='noarch', pgpsig='SIG')]) | ||
|
||
def mocked_run(cmd): | ||
raise CalledProcessError(command=cmd, | ||
message='mocked error', | ||
result={'stdout': 'out', 'stderr': 'err', 'exit_code': 1, 'signal': 0}) | ||
|
||
monkeypatch.setattr(api, 'current_logger', logger_mocked()) | ||
monkeypatch.setattr(api, 'produce', produce_mocked()) | ||
monkeypatch.setattr(removeleftoverpackages, 'get_leftover_packages', get_leftover_pkgs) | ||
monkeypatch.setattr(removeleftoverpackages, 'get_installed_rpms', lambda: []) | ||
monkeypatch.setattr(removeleftoverpackages, 'skip_rhsm', lambda: False) | ||
monkeypatch.setattr(removeleftoverpackages, 'run', mocked_run) | ||
|
||
removeleftoverpackages.process() | ||
|
||
assert api.produce.called == 0 | ||
assert api.current_logger.errmsg == ['Failed to remove packages: rpm-1.0-1.el7'] | ||
|
||
|
||
def test__get_removed_packages(monkeypatch): | ||
pkg1 = 'rpm|1.0|1.el7|0|packager|noarch|SIG' | ||
pkg2 = 'rpm2|1.0|1.el7|0|packager|noarch|SIG' | ||
installed_packages = [pkg1, pkg2] | ||
monkeypatch.setattr(removeleftoverpackages, 'get_installed_rpms', lambda: [pkg1]) | ||
|
||
assert removeleftoverpackages._get_removed_packages(installed_packages) == [pkg2] | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('installed_rpms'), | ||
( | ||
([]), | ||
(['rpm1']), | ||
(['rpm1', 'rpm2']), | ||
) | ||
) | ||
def test_get_removed_packages(monkeypatch, installed_rpms): | ||
rpm_details = { | ||
'version': '1.0', | ||
'release': '1.el7', | ||
'epoch': '0', | ||
'packager': 'packager', | ||
'arch': 'noarch', | ||
'pgpsig': 'SIG' | ||
} | ||
rpm_details_composed = '|'.join([rpm_details[key] for key in ['version', 'release', 'epoch', | ||
'packager', 'arch', 'pgpsig']]) | ||
mocked_installed_rpms = ['{}|{}'.format(rpm, rpm_details_composed) for rpm in installed_rpms] | ||
|
||
monkeypatch.setattr(removeleftoverpackages, '_get_removed_packages', lambda _: mocked_installed_rpms) | ||
|
||
removed_packages = removeleftoverpackages.get_removed_packages(mocked_installed_rpms) | ||
expected_output = [RPM(name=rpm, **rpm_details) for rpm in installed_rpms] | ||
|
||
assert removed_packages == RemovedPackages(items=expected_output) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
('removed_packages'), | ||
( | ||
([]), | ||
(['rpm1']), | ||
(['rpm1', 'rpm2']), | ||
) | ||
) | ||
def test_process(monkeypatch, removed_packages): | ||
def get_leftover_pkgs(): | ||
return LeftoverPackages() | ||
|
||
removed_pkgs = RemovedPackages(items=[RPM(name=pkg, version='1.0', release='1.el7', epoch='0', | ||
packager='packager', arch='noarch', pgpsig='SIG') | ||
for pkg in removed_packages]) | ||
|
||
def mocked_get_removed_packages(installed_rpms): | ||
return removed_pkgs | ||
|
||
monkeypatch.setattr(api, 'produce', produce_mocked()) | ||
monkeypatch.setattr(removeleftoverpackages, 'get_leftover_packages', get_leftover_pkgs) | ||
monkeypatch.setattr(removeleftoverpackages, 'get_installed_rpms', lambda: []) | ||
monkeypatch.setattr(removeleftoverpackages, 'run', lambda _: None) | ||
monkeypatch.setattr(removeleftoverpackages, 'skip_rhsm', lambda: False) | ||
monkeypatch.setattr(removeleftoverpackages, 'get_removed_packages', mocked_get_removed_packages) | ||
|
||
removeleftoverpackages.process() | ||
|
||
assert api.produce.called == 1 | ||
assert api.produce.model_instances == [removed_pkgs] |
23 changes: 23 additions & 0 deletions
23
repos/system_upgrade/common/actors/reportleftoverpackages/reportleftoverpackages/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import reportleftoverpackages | ||
from leapp.models import LeftoverPackages, RemovedPackages | ||
from leapp.reporting import Report | ||
from leapp.tags import IPUWorkflowTag, RPMUpgradePhaseTag | ||
|
||
|
||
class ReportLeftoverPackages(Actor): | ||
""" | ||
Collect messages about leftover RHEL packages from older major versions and generate report for users. | ||
Depending on execution of previous actors, | ||
generated report contains information that there are still old RHEL packages | ||
present on the system, which makes it unsupported or lists packages that have been removed. | ||
""" | ||
|
||
name = 'report_leftover_packages' | ||
consumes = (LeftoverPackages, RemovedPackages) | ||
produces = (Report,) | ||
tags = (RPMUpgradePhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
reportleftoverpackages.process() |
47 changes: 47 additions & 0 deletions
47
.../actors/reportleftoverpackages/reportleftoverpackages/libraries/reportleftoverpackages.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
from leapp import reporting | ||
from leapp.libraries.stdlib import api | ||
from leapp.models import LeftoverPackages, RemovedPackages | ||
|
||
|
||
def process(): | ||
removed_packages = next(api.consume(RemovedPackages), None) | ||
leftover_packages = next(api.consume(LeftoverPackages), LeftoverPackages()) | ||
to_remove = ['-'.join([pkg.name, pkg.version, pkg.release]) for pkg in leftover_packages.items] | ||
|
||
if removed_packages: | ||
title = 'Leftover RHEL packages have been removed' | ||
|
||
if removed_packages.items: | ||
removed = ['-'.join([pkg.name, pkg.version, pkg.release]) for pkg in removed_packages.items] | ||
reporting.create_report([ | ||
reporting.Title(title), | ||
reporting.Summary('Following packages have been removed:\n{}'.format('\n'.join(removed))), | ||
reporting.Severity(reporting.Severity.HIGH), | ||
reporting.Groups([reporting.Groups.SANITY]), | ||
] + [reporting.RelatedResource('package', pkg.name) for pkg in removed_packages.items]) | ||
else: | ||
summary = ('Following packages have been removed:\n' | ||
'{}\n' | ||
'Dependent packages may have been removed as well, please check that you are not missing ' | ||
'any packages.\n'.format('\n'.join(to_remove))) | ||
|
||
reporting.create_report([ | ||
reporting.Title(title), | ||
reporting.Summary(summary), | ||
reporting.Severity(reporting.Severity.HIGH), | ||
reporting.Groups([reporting.Groups.SANITY]), | ||
] + [reporting.RelatedResource('package', pkg.name) for pkg in leftover_packages.items]) | ||
return | ||
|
||
if not leftover_packages.items: | ||
api.current_logger().info('No leftover packages, skipping...') | ||
return | ||
|
||
summary = 'Following RHEL packages have not been upgraded:\n{}\n'.format('\n'.join(to_remove)) | ||
summary += 'Please remove these packages to keep your system in supported state.\n' | ||
reporting.create_report([ | ||
reporting.Title('Some RHEL packages have not been upgraded'), | ||
reporting.Summary(summary), | ||
reporting.Severity(reporting.Severity.HIGH), | ||
reporting.Groups([reporting.Groups.SANITY]), | ||
] + [reporting.RelatedResource('package', pkg.name) for pkg in leftover_packages.items]) |
Oops, something went wrong.