From 98a1057bb40a53a2200b0cfba9e4ad75b1d8f796 Mon Sep 17 00:00:00 2001 From: Petr Stodulka Date: Mon, 22 Jan 2024 18:40:07 +0100 Subject: [PATCH 68/69] device driver deprecation data: print nice error msg on malformed data In case of malformed device_driver_deprecation_data.json user could originally see raw traceback without having too much information what it actually means or how to fix it. That usually happens only when the file is manually modified on the machine. So in this case we inform user what file is problematic and how to restore the original file installed by our package. In case of upstream development, this msg could be seen also when new data is provided if: * data file is malformed * data file has a new format of data (still json expected) * etc. These issues however will be discovered prior the merge as the running tests will fail, so such a problematic file should never get part of the upstream. From that point, we will be expect that user has malformed / customized data file. So no need to handle all possible errors differently in this case. Jira: OAMG-7549 Co-authored-by: Toshio Kuratomi --- .../deviceanddriverdeprecationdataload.py | 36 ++++++++++++++----- .../tests/test_ddddload.py | 28 +++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py index f422c2c3..b12e77c9 100644 --- a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py +++ b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/libraries/deviceanddriverdeprecationdataload.py @@ -1,6 +1,9 @@ +from leapp.exceptions import StopActorExecutionError from leapp.libraries.common import fetch +from leapp.libraries.common.rpms import get_leapp_packages, LeappComponents from leapp.libraries.stdlib import api from leapp.models import DeviceDriverDeprecationData, DeviceDriverDeprecationEntry +from leapp.models.fields import ModelViolationError def process(): @@ -22,12 +25,29 @@ def process(): docs_url='', docs_title='') - api.produce( - DeviceDriverDeprecationData( - entries=[ - DeviceDriverDeprecationEntry(**entry) - for entry in deprecation_data['data'] - if entry.get('device_type') in supported_device_types - ] + try: + api.produce( + DeviceDriverDeprecationData( + entries=[ + DeviceDriverDeprecationEntry(**entry) + for entry in deprecation_data['data'] + if entry.get('device_type') in supported_device_types + ] + ) ) - ) + except (ModelViolationError, ValueError, KeyError, AttributeError, TypeError) as err: + # For the listed errors, we expect this to happen only when data is malformed + # or manually updated. Corrupted data in the upstream is discovered + # prior the merge thanks to testing. So just suggest the restoration + # of the file. + msg = 'Invalid device and driver deprecation data: {}'.format(err) + hint = ( + 'This issue is usually caused by manual update of the {lp} file.' + ' The data inside is either incorrect or old. To restore the original' + ' {lp} file, remove it and reinstall the following packages: {rpms}' + .format( + lp='/etc/leapp/file/device_driver_deprecation_data.json', + rpms=', '.join(get_leapp_packages(component=LeappComponents.REPOSITORY)) + ) + ) + raise StopActorExecutionError(msg, details={'hint': hint}) diff --git a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py index 69bcd09c..c3386745 100644 --- a/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py +++ b/repos/system_upgrade/common/actors/loaddevicedriverdeprecationdata/tests/test_ddddload.py @@ -1,5 +1,9 @@ +import pytest + +from leapp.exceptions import StopActorExecutionError from leapp.libraries.actor import deviceanddriverdeprecationdataload as ddddload from leapp.libraries.common import fetch +from leapp.libraries.common.testutils import CurrentActorMocked TEST_DATA = { 'data': [ @@ -57,3 +61,27 @@ def test_filtered_load(monkeypatch): assert produced assert len(produced[0].entries) == 3 assert not any([e.device_type == 'unsupported' for e in produced[0].entries]) + + +@pytest.mark.parametrize('data', ( + {}, + {'foo': 'bar'}, + {'data': 1, 'foo': 'bar'}, + {'data': 'string', 'foo': 'bar'}, + {'data': {'foo': 1}, 'bar': 2}, + {'data': {'foo': 1, 'device_type': None}}, + {'data': {'foo': 1, 'device_type': 'cpu'}}, + {'data': {'driver_name': ['foo'], 'device_type': 'cpu'}}, +)) +def test_invalid_dddd_data(monkeypatch, data): + produced = [] + + def load_data_asset_mock(*args, **kwargs): + return data + + monkeypatch.setattr(fetch, 'load_data_asset', load_data_asset_mock) + monkeypatch.setattr(ddddload.api, 'current_actor', CurrentActorMocked()) + monkeypatch.setattr(ddddload.api, 'produce', lambda *v: produced.extend(v)) + with pytest.raises(StopActorExecutionError): + ddddload.process() + assert not produced -- 2.42.0