From 55936d27d51ef7bbdc2d045f11a4661f334105aa Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Wed, 17 Jul 2024 12:52:20 -0400 Subject: [PATCH] pylintrc: re-enable too-many-lines, final patch To get under the 1000 line limit, move ycheck unit tests into their own directory, and split-up into sub-files as necessary. Finally, enable the too-many-lines check in pylintrc. --- pylintrc | 1 - tests/unit/ycheck/__init__.py | 0 .../test_events.py} | 2 +- .../test_properties.py} | 332 +--------- tests/unit/ycheck/test_properties_apt.py | 178 ++++++ tests/unit/ycheck/test_properties_binary.py | 43 ++ tests/unit/ycheck/test_properties_snap.py | 123 ++++ .../test_scenarios.py} | 594 +----------------- tests/unit/ycheck/test_scenarios_data.py | 542 ++++++++++++++++ 9 files changed, 915 insertions(+), 900 deletions(-) create mode 100644 tests/unit/ycheck/__init__.py rename tests/unit/{test_ycheck_events.py => ycheck/test_events.py} (99%) rename tests/unit/{test_ycheck_properties.py => ycheck/test_properties.py} (70%) create mode 100644 tests/unit/ycheck/test_properties_apt.py create mode 100644 tests/unit/ycheck/test_properties_binary.py create mode 100644 tests/unit/ycheck/test_properties_snap.py rename tests/unit/{test_ycheck_scenarios.py => ycheck/test_scenarios.py} (58%) create mode 100644 tests/unit/ycheck/test_scenarios_data.py diff --git a/pylintrc b/pylintrc index ac1b17bbc..85a654448 100644 --- a/pylintrc +++ b/pylintrc @@ -30,5 +30,4 @@ disable= too-many-arguments, too-many-branches, too-many-instance-attributes, - too-many-lines, too-many-locals, diff --git a/tests/unit/ycheck/__init__.py b/tests/unit/ycheck/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/test_ycheck_events.py b/tests/unit/ycheck/test_events.py similarity index 99% rename from tests/unit/test_ycheck_events.py rename to tests/unit/ycheck/test_events.py index f27c7a750..e48e78901 100644 --- a/tests/unit/test_ycheck_events.py +++ b/tests/unit/ycheck/test_events.py @@ -11,7 +11,7 @@ EventProcessingUtils, ) -from . import utils +from .. import utils EVENT_DEF_INPUT = """ pluginX: diff --git a/tests/unit/test_ycheck_properties.py b/tests/unit/ycheck/test_properties.py similarity index 70% rename from tests/unit/test_ycheck_properties.py rename to tests/unit/ycheck/test_properties.py index 2a6d3d4b0..c347260c7 100644 --- a/tests/unit/test_ycheck_properties.py +++ b/tests/unit/ycheck/test_properties.py @@ -7,9 +7,6 @@ import yaml from hotsos.core.config import HotSOSConfig -from hotsos.core.host_helpers import ( - DPKGVersion -) from hotsos.core.host_helpers.config import IniConfigBase from hotsos.core.issues.utils import IssuesStore from hotsos.core.search import ExtraSearchConstraints @@ -23,14 +20,8 @@ PropertyCacheRefResolver, ) from hotsos.core.ycheck.common import GlobalSearcher -from hotsos.core.ycheck.engine.properties.requires.types import ( - apt, - binary, - snap, -) -from hotsos.core.plugins import juju -from . import utils +from .. import utils class TestProperty(YPropertyBase): @@ -225,10 +216,6 @@ def __init__(self, name, state, has_instances, start_time): - apt: python1.0 """ -DPKG_L = """ -ii openssh-server 1:8.2p1-4ubuntu0.4 amd64 secure shell (SSH) server, for secure access from remote machines -""" # noqa - class TempScenarioDefs(): """ Context manager to load copies of scenario definitions into a temporary @@ -444,323 +431,6 @@ def test_grouped_items_all_true_mixed_types_snap_first(self): self.assertEqual(issues[0]['message'], 'snapd') -class TestYamlRequiresTypeBinary(utils.BaseTestCase): - """ Tests requires type binary property. """ - - def test_binary_check_comparison(self): - items = binary.BinCheckItems({'juju': [{'min': '3.0', 'max': '3.2'}]}, - bin_handler=juju.JujuBinaryInterface) - self.assertEqual(items.installed, ['juju']) - self.assertEqual(items.not_installed, set()) - _bin, versions = list(items)[0] - version = items.packaging_helper.get_version(_bin) - self.assertFalse(DPKGVersion.is_version_within_ranges(version, - versions)) - - items = binary.BinCheckItems({'juju': [{'min': '2.9', 'max': '3.2'}]}, - bin_handler=juju.JujuBinaryInterface) - self.assertEqual(items.installed, ['juju']) - self.assertEqual(items.not_installed, set()) - _bin, versions = list(items)[0] - version = items.packaging_helper.get_version(_bin) - self.assertTrue(DPKGVersion.is_version_within_ranges(version, - versions)) - - items = binary.BinCheckItems({'juju': [{'min': '2.9.2', - 'max': '2.9.22'}]}, - bin_handler=juju.JujuBinaryInterface) - self.assertEqual(items.installed, ['juju']) - self.assertEqual(items.not_installed, set()) - _bin, versions = list(items)[0] - version = items.packaging_helper.get_version(_bin) - self.assertTrue(DPKGVersion.is_version_within_ranges(version, - versions)) - - -class TestYamlRequiresTypeAPT(utils.BaseTestCase): - """ Tests requires type apt property. """ - - @staticmethod - def load_apt_requires(yaml_content): - return apt.YRequirementTypeAPT( - "requires", - "apt", - yaml.safe_load(yaml_content), - "requires.apt") - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_no_criteria(self): - content = r""" - openssh-server: - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_no_criteria_alt_form(self): - content = r""" - - openssh-server - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_no_criteria_name_mismatch(self): - # We expect test to fail because no such package exist. - content = r""" - openssh-serverx: - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_name_mismatch(self): - content = r""" - openssh-serverx: - - eq: '1:8.2p1-4ubuntu0.4' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_gt_single_true(self): - content = r""" - openssh-server: - - gt: '1:8.2' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_gt_single_false(self): - content = r""" - openssh-server: - - gt: '1:8.2p1-4ubuntu0.4' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_ge_single_true(self): - content = r""" - openssh-server: - - ge: '1:8.2' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_ge_single_false(self): - content = r""" - openssh-server: - - ge: '1:8.2p1-4ubuntu0.5' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_lt_single_true(self): - content = r""" - openssh-server: - - lt: '1:8.2p1-4ubuntu0.5' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_lt_single_false(self): - content = r""" - openssh-server: - - lt: '1:8.2p1-4ubuntu0.3' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_le_single_true(self): - content = r""" - openssh-server: - - le: '1:8.2p1-4ubuntu0.4' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_le_single_false(self): - content = r""" - openssh-server: - - le: '1:8.2p1-4ubuntu0.3' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_eq_single_true(self): - content = r""" - openssh-server: - - eq: '1:8.2p1-4ubuntu0.4' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_eq_single_false(self): - content = r""" - openssh-server: - - eq: '1:8.2p1-4ubuntu0.4.4' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_eq_multiple_true(self): - content = r""" - openssh-server: - - eq: '1:8.2p1-4ubuntu0.1' - - eq: '1:8.2p1-4ubuntu0.2' - - eq: '1:8.2p1-4ubuntu0.3' - - eq: '1:8.2p1-4ubuntu0.4' # <-- should match this - - eq: '1:8.2p1-4ubuntu0.5' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_eq_multiple_false(self): - content = r""" - openssh-server: - - eq: '1:8.2p1-4ubuntu0.1' - - eq: '1:8.2p1-4ubuntu0.2' - - eq: '1:8.2p1-4ubuntu0.3' - - eq: '1:8.2p1-4ubuntu0.5' - - eq: '1:8.2p1-4ubuntu0.6' - """ - self.assertFalse(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_ge_multiple(self): - content = r""" - openssh-server: - - ge: '1:8.9' - - gt: '1:8.1' # <-- should match - lt: '1:8.3' - """ - self.assertTrue(self.load_apt_requires(content).result) - - @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) - def test_apt_mixed(self): - content = r""" - openssh-server: - - ge: '1:8.9 ' - - lt: '1:4' - - ge: '1:6.3' - lt: '1:7.2' - """ - self.assertFalse(self.load_apt_requires(content).result) - - -class TestYamlRequiresTypeSnap(utils.BaseTestCase): - """ Tests requires type snap property. """ - - def test_snap_revision_within_ranges_no_channel_true(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'revision': {'min': '1327', - 'max': '1328'} - } - ]) - self.assertTrue(result) - - def test_snap_revision_within_ranges_no_channel_false(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'revision': {'min': '1326', - 'max': '1327'} - } - ]) - self.assertFalse(result) - - def test_snap_revision_within_ranges_channel_true(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'revision': {'min': '1327', - 'max': '1328'}, - 'channel': 'latest/stable' - } - ]) - self.assertTrue(result) - - def test_snap_revision_within_ranges_channel_false(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'revision': {'min': '1327', - 'max': '1328'}, - 'channel': 'foo' - } - ]) - self.assertFalse(result) - - def test_snap_revision_within_multi_ranges_channel_true(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'revision': {'min': '1326', - 'max': '1327'}, - 'channel': 'foo' - }, - { - 'revision': {'min': '1327', - 'max': '1328'}, - 'channel': 'latest/stable' - }, - { - 'revision': {'min': '1329', - 'max': '1330'}, - 'channel': 'bar' - } - ]) - self.assertTrue(result) - - def test_snap_revision_with_invalid_range(self): - with self.assertRaises(Exception): - snap.SnapCheckItems('core20').package_info_matches('core20', [ - { - 'revision': {'mix': '1327'} - } - ]) - - def test_snap_version_check_min_max(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'version': {'min': '20220114', - 'max': '20220114'} - } - ]) - self.assertTrue(result) - - def test_snap_version_check_lt(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'version': {'lt': '20220115'} - } - ]) - self.assertTrue(result) - - def test_snap_version_check_gt_lt(self): - ci = snap.SnapCheckItems('core20') - result = ci.package_info_matches('core20', [ - { - 'version': {'gt': '20220113', - 'lt': '20220115'} - } - ]) - self.assertTrue(result) - - def test_snap_version_check_everything(self): - ci = snap.SnapCheckItems('core20') - print(ci.installed_revisions) - result = ci.package_info_matches('core20', [ - { - 'version': {'gt': '20220113', - 'lt': '20220115'}, - 'channel': 'latest/stable', - 'revision': {'eq': '1328'} - } - ]) - self.assertTrue(result) - - class TestYamlProperties(utils.BaseTestCase): """ Miscellaneous tests for YAML properties. """ diff --git a/tests/unit/ycheck/test_properties_apt.py b/tests/unit/ycheck/test_properties_apt.py new file mode 100644 index 000000000..aa71b26fb --- /dev/null +++ b/tests/unit/ycheck/test_properties_apt.py @@ -0,0 +1,178 @@ + +import yaml +from hotsos.core.ycheck.engine.properties.requires.types import ( + apt, +) + +from .. import utils + +DPKG_L = """ +ii openssh-server 1:8.2p1-4ubuntu0.4 amd64 secure shell (SSH) server, for secure access from remote machines +""" # noqa + + +class TestYamlRequiresTypeAPT(utils.BaseTestCase): + """ Tests requires type apt property. """ + + @staticmethod + def load_apt_requires(yaml_content): + return apt.YRequirementTypeAPT( + "requires", + "apt", + yaml.safe_load(yaml_content), + "requires.apt") + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_no_criteria(self): + content = r""" + openssh-server: + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_no_criteria_alt_form(self): + content = r""" + - openssh-server + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_no_criteria_name_mismatch(self): + # We expect test to fail because no such package exist. + content = r""" + openssh-serverx: + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_name_mismatch(self): + content = r""" + openssh-serverx: + - eq: '1:8.2p1-4ubuntu0.4' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_gt_single_true(self): + content = r""" + openssh-server: + - gt: '1:8.2' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_gt_single_false(self): + content = r""" + openssh-server: + - gt: '1:8.2p1-4ubuntu0.4' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_ge_single_true(self): + content = r""" + openssh-server: + - ge: '1:8.2' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_ge_single_false(self): + content = r""" + openssh-server: + - ge: '1:8.2p1-4ubuntu0.5' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_lt_single_true(self): + content = r""" + openssh-server: + - lt: '1:8.2p1-4ubuntu0.5' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_lt_single_false(self): + content = r""" + openssh-server: + - lt: '1:8.2p1-4ubuntu0.3' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_le_single_true(self): + content = r""" + openssh-server: + - le: '1:8.2p1-4ubuntu0.4' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_le_single_false(self): + content = r""" + openssh-server: + - le: '1:8.2p1-4ubuntu0.3' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_eq_single_true(self): + content = r""" + openssh-server: + - eq: '1:8.2p1-4ubuntu0.4' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_eq_single_false(self): + content = r""" + openssh-server: + - eq: '1:8.2p1-4ubuntu0.4.4' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_eq_multiple_true(self): + content = r""" + openssh-server: + - eq: '1:8.2p1-4ubuntu0.1' + - eq: '1:8.2p1-4ubuntu0.2' + - eq: '1:8.2p1-4ubuntu0.3' + - eq: '1:8.2p1-4ubuntu0.4' # <-- should match this + - eq: '1:8.2p1-4ubuntu0.5' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_eq_multiple_false(self): + content = r""" + openssh-server: + - eq: '1:8.2p1-4ubuntu0.1' + - eq: '1:8.2p1-4ubuntu0.2' + - eq: '1:8.2p1-4ubuntu0.3' + - eq: '1:8.2p1-4ubuntu0.5' + - eq: '1:8.2p1-4ubuntu0.6' + """ + self.assertFalse(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_ge_multiple(self): + content = r""" + openssh-server: + - ge: '1:8.9' + - gt: '1:8.1' # <-- should match + lt: '1:8.3' + """ + self.assertTrue(self.load_apt_requires(content).result) + + @utils.create_data_root({'sos_commands/dpkg/dpkg_-l': DPKG_L}) + def test_apt_mixed(self): + content = r""" + openssh-server: + - ge: '1:8.9 ' + - lt: '1:4' + - ge: '1:6.3' + lt: '1:7.2' + """ + self.assertFalse(self.load_apt_requires(content).result) diff --git a/tests/unit/ycheck/test_properties_binary.py b/tests/unit/ycheck/test_properties_binary.py new file mode 100644 index 000000000..db6f4a717 --- /dev/null +++ b/tests/unit/ycheck/test_properties_binary.py @@ -0,0 +1,43 @@ + +from hotsos.core.host_helpers import ( + DPKGVersion +) +from hotsos.core.ycheck.engine.properties.requires.types import ( + binary, +) +from hotsos.core.plugins import juju + +from .. import utils + + +class TestYamlRequiresTypeBinary(utils.BaseTestCase): + """ Tests requires type binary property. """ + + def test_binary_check_comparison(self): + items = binary.BinCheckItems({'juju': [{'min': '3.0', 'max': '3.2'}]}, + bin_handler=juju.JujuBinaryInterface) + self.assertEqual(items.installed, ['juju']) + self.assertEqual(items.not_installed, set()) + _bin, versions = list(items)[0] + version = items.packaging_helper.get_version(_bin) + self.assertFalse(DPKGVersion.is_version_within_ranges(version, + versions)) + + items = binary.BinCheckItems({'juju': [{'min': '2.9', 'max': '3.2'}]}, + bin_handler=juju.JujuBinaryInterface) + self.assertEqual(items.installed, ['juju']) + self.assertEqual(items.not_installed, set()) + _bin, versions = list(items)[0] + version = items.packaging_helper.get_version(_bin) + self.assertTrue(DPKGVersion.is_version_within_ranges(version, + versions)) + + items = binary.BinCheckItems({'juju': [{'min': '2.9.2', + 'max': '2.9.22'}]}, + bin_handler=juju.JujuBinaryInterface) + self.assertEqual(items.installed, ['juju']) + self.assertEqual(items.not_installed, set()) + _bin, versions = list(items)[0] + version = items.packaging_helper.get_version(_bin) + self.assertTrue(DPKGVersion.is_version_within_ranges(version, + versions)) diff --git a/tests/unit/ycheck/test_properties_snap.py b/tests/unit/ycheck/test_properties_snap.py new file mode 100644 index 000000000..9dff71ff8 --- /dev/null +++ b/tests/unit/ycheck/test_properties_snap.py @@ -0,0 +1,123 @@ + +from hotsos.core.ycheck.engine.properties.requires.types import ( + snap, +) + +from .. import utils + + +class TestYamlRequiresTypeSnap(utils.BaseTestCase): + """ Tests requires type snap property. """ + + def test_snap_revision_within_ranges_no_channel_true(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'revision': {'min': '1327', + 'max': '1328'} + } + ]) + self.assertTrue(result) + + def test_snap_revision_within_ranges_no_channel_false(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'revision': {'min': '1326', + 'max': '1327'} + } + ]) + self.assertFalse(result) + + def test_snap_revision_within_ranges_channel_true(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'revision': {'min': '1327', + 'max': '1328'}, + 'channel': 'latest/stable' + } + ]) + self.assertTrue(result) + + def test_snap_revision_within_ranges_channel_false(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'revision': {'min': '1327', + 'max': '1328'}, + 'channel': 'foo' + } + ]) + self.assertFalse(result) + + def test_snap_revision_within_multi_ranges_channel_true(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'revision': {'min': '1326', + 'max': '1327'}, + 'channel': 'foo' + }, + { + 'revision': {'min': '1327', + 'max': '1328'}, + 'channel': 'latest/stable' + }, + { + 'revision': {'min': '1329', + 'max': '1330'}, + 'channel': 'bar' + } + ]) + self.assertTrue(result) + + def test_snap_revision_with_invalid_range(self): + with self.assertRaises(Exception): + snap.SnapCheckItems('core20').package_info_matches('core20', [ + { + 'revision': {'mix': '1327'} + } + ]) + + def test_snap_version_check_min_max(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'version': {'min': '20220114', + 'max': '20220114'} + } + ]) + self.assertTrue(result) + + def test_snap_version_check_lt(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'version': {'lt': '20220115'} + } + ]) + self.assertTrue(result) + + def test_snap_version_check_gt_lt(self): + ci = snap.SnapCheckItems('core20') + result = ci.package_info_matches('core20', [ + { + 'version': {'gt': '20220113', + 'lt': '20220115'} + } + ]) + self.assertTrue(result) + + def test_snap_version_check_everything(self): + ci = snap.SnapCheckItems('core20') + print(ci.installed_revisions) + result = ci.package_info_matches('core20', [ + { + 'version': {'gt': '20220113', + 'lt': '20220115'}, + 'channel': 'latest/stable', + 'revision': {'eq': '1328'} + } + ]) + self.assertTrue(result) diff --git a/tests/unit/test_ycheck_scenarios.py b/tests/unit/ycheck/test_scenarios.py similarity index 58% rename from tests/unit/test_ycheck_scenarios.py rename to tests/unit/ycheck/test_scenarios.py index 86ef2e96d..584e1c3ba 100644 --- a/tests/unit/test_ycheck_scenarios.py +++ b/tests/unit/ycheck/test_scenarios.py @@ -13,7 +13,8 @@ YPropertyConclusion, ) -from . import utils +from .. import utils +from . import test_scenarios_data as test_data class TestProperty(): @@ -39,555 +40,11 @@ class TestConfig(IniConfigBase): """ Test config """ -YDEF_NESTED_LOGIC = """ -checks: - isTrue: - requires: - and: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - - property: - path: tests.unit.test_ycheck_scenarios.TestProperty.always_false - ops: [[not_]] - isalsoTrue: - requires: - or: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_false - isstillTrue: - requires: - and: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - or: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_false - isnotTrue: - requires: - and: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - or: - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_false - - property: tests.unit.test_ycheck_scenarios.TestProperty.always_false -conclusions: - conc1: - decision: - and: - - isTrue - - isalsoTrue - or: - - isstillTrue - raises: - type: IssueTypeBase - message: conc1 - conc2: - decision: - and: - - isTrue - - isnotTrue - or: - - isalsoTrue - raises: - type: IssueTypeBase - message: conc2 - conc3: - decision: - not: - - isnotTrue - or: - - isalsoTrue - raises: - type: IssueTypeBase - message: conc3 -""" - - -CONCLUSION_PRIORITY_1 = """ -checks: - testcheck: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true -conclusions: - conc1: - priority: 1 - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc1 - conc2: - priority: 2 - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc2 - conc3: - priority: 3 - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc3 -""" - -CONCLUSION_PRIORITY_2 = """ -checks: - testcheck: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true -conclusions: - conc1: - priority: 1 - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc1 - conc2: - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc2 - conc3: - decision: - - testcheck - raises: - type: IssueTypeBase - message: conc3 -""" - - -YAML_DEF_REQUIRES_MAPPED = """ -checks: - is_exists_mapped: - systemd: nova-compute - is_exists_unmapped: - requires: - systemd: nova-compute -conclusions: -""" - -SCENARIO_W_EXPR_LIST = r""" -input: - path: {path} -checks: - listsearch1: - expr: ['hello y', 'hello x'] - listsearch2: - search: ['hello y', 'hello x'] - listsearch3: - search: - expr: ['hello y', 'hello x'] -conclusions: - listsearch1worked: - decision: listsearch1 - raises: - type: SystemWarning - message: yay list search - listsearch2worked: - decision: listsearch2 - raises: - type: SystemWarning - message: yay list search - listsearch3worked: - decision: listsearch3 - raises: - type: SystemWarning - message: yay list search -""" # noqa - - -SCENARIO_W_SEQ_SEARCH = r""" -input: - path: {path} -checks: - seqsearch1: - start: "it's the start" - body: ".+" - end: "it's the end" - seqsearch2: - start: "it's the start" - end: "it's the end" -conclusions: - seqsearchworked: - decision: - - seqsearch1 - - seqsearch2 - raises: - type: SystemWarning - message: yay seq searches worked! -""" # noqa - - -SCENARIO_W_ERROR = r""" -scenarioA: - checks: - property_no_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - conclusions: - c1: - decision: property_no_error - raises: - type: SystemWarning - message: foo -scenarioB: - checks: - property_w_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.i_dont_exist - conclusions: - c1: - decision: property_w_error - raises: - type: SystemWarning - message: foo -""" # noqa - - -CONCLUSION_W_INVALID_BUG_RAISES = r""" -scenarioA: - checks: - property_no_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - conclusions: - c1: - decision: property_no_error - raises: - type: SystemWarning - bug-id: 1234 - message: foo -scenarioB: - checks: - property_w_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - conclusions: - c1: - decision: property_no_error - raises: - type: LaunchpadBug - message: foo -scenarioC: - checks: - property_w_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - conclusions: - c1: - decision: property_no_error - raises: - type: UbuntuCVE - message: foo -scenarioD: - checks: - property_w_error: - property: tests.unit.test_ycheck_scenarios.TestProperty.always_true - conclusions: - c1: - decision: property_no_error - raises: - cve-id: 123 -""" # noqa - - -SCENARIO_CHECKS = r""" -checks: - logmatch: - input: - path: foo.log - expr: '(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}\.\d{3}) (\S+) \S+' - constraints: - min-results: 3 - search-period-hours: 24 - search-result-age-hours: 48 - property_true_shortform: - requires: - property: - path: hotsos.core.plugins.system.system.SystemBase.virtualisation_type - property_has_value_longform: - requires: - property: - path: hotsos.core.plugins.system.system.SystemBase.virtualisation_type - ops: [[eq, kvm], [truth], [not_], [not_]] - apt_pkg_exists: - requires: - apt: nova-compute - snap_pkg_exists: - requires: - snap: core20 - service_exists_short: - requires: - systemd: nova-compute - service_exists_and_enabled: - requires: - systemd: - nova-compute: enabled - service_exists_not_enabled: - requires: - systemd: - nova-compute: - state: enabled - op: ne -conclusions: - justlog: - priority: 1 - decision: logmatch - raises: - type: SystemWarning - message: log matched {num} times ({group}) - format-dict: - num: '@checks.logmatch.search.num_results' - group: '@checks.logmatch.search.results_group_2:comma_join' - logandsnap: - priority: 2 - decision: - and: - - logmatch - - snap_pkg_exists - raises: - type: SystemWarning - message: log matched {num} times and snap exists - format-dict: - num: '@checks.logmatch.search.num_results' - logandsnapandservice: - priority: 3 - decision: - and: - - logmatch - - snap_pkg_exists - - service_exists_short - - service_exists_and_enabled - - property_true_shortform - - property_has_value_longform - raises: - type: SystemWarning - message: log matched {num} times, snap and service exists - format-dict: - num: '@checks.logmatch.search.num_results' -""" # noqa - - -CONFIG_SCENARIO = """ -checks: - cfg_is_bad: - config: - handler: tests.unit.test_ycheck_scenarios.TestConfig - path: test.conf - assertions: - - key: key1 - section: DEFAULT - ops: [[lt, 102]] - - key: key1 - section: DEFAULT - ops: [[gt, 100]] - cfg_is_bad2: - config: - handler: tests.unit.test_ycheck_scenarios.TestConfig - path: test.conf - assertions: - not: - - key: key1 - section: DEFAULT - ops: [[lt, 103]] - - key: key1 - section: DEFAULT - ops: [[gt, 101]] -conclusions: - cfg_is_bad: - decision: cfg_is_bad - raises: - type: SystemWarning - message: cfg is bad - cfg_is_bad2: - decision: cfg_is_bad2 - raises: - type: SystemWarning - message: cfg is bad2 -""" - - -VARS = """ -vars: - foo: 1000 - limit: 10 - bar: "two" - frombadprop: '@tests.unit.idontexist' # add to ensure lazy-loaded - fromprop: '@tests.unit.test_ycheck_scenarios.TestProperty.myattr' - fromfact: '@hotsos.core.host_helpers.systemd.ServiceFactory.start_time_secs:snapd' - fromfact2: '@hotsos.core.host_helpers.filestat.FileFactory.mtime:myfile.txt' - fromsysctl: '@hotsos.core.host_helpers.sysctl.SYSCtlFactory:net.core.somaxconn' - boolvar: false -checks: - aptcheck: - apt: nova-compute - is_foo_lt: - varops: [[$foo], [lt, $limit]] - is_foo_gt: - varops: [[$foo], [gt, $limit]] - isbar: - varops: [[$bar], [ne, ""]] - fromprop: - varops: [[$fromprop], [eq, "123"]] - fromfact: - varops: [[$fromfact], [gt, 1644446300]] - fromfact2: - varops: [[$fromfact2], [eq, 0]] - fromsysctl: - varops: [[$fromsysctl], [eq, '4096']] - boolvar: - varops: [[$boolvar], [truth], [not_]] -conclusions: - aptcheck: - decision: aptcheck - raises: - type: SystemWarning - message: "{name}={version}" - format-dict: - name: '@checks.aptcheck.requires.package' - version: '@checks.aptcheck.requires.version' - is_foo_gt: - decision: is_foo_gt - raises: - type: SystemWarning - message: it's foo gt! ({varname}={varval}) - format-dict: - varname: '@checks.is_foo_gt.requires.input_ref' - varval: '@checks.is_foo_gt.requires.input_value' - is_foo_lt: - decision: is_foo_lt - raises: - type: SystemWarning - message: it's foo lt! ({varname}={varval}) - format-dict: - varname: '@checks.is_foo_lt.requires.input_ref' - varval: '@checks.is_foo_lt.requires.input_value' - isbar: - decision: isbar - raises: - type: SystemWarning - message: it's bar! ({varname}={varval}) - format-dict: - varname: '@checks.isbar.requires.input_ref' - varval: '@checks.isbar.requires.input_value' - fromprop: - decision: - and: [fromprop, boolvar, fromfact, fromfact2, fromsysctl] - raises: - type: SystemWarning - message: fromprop! ({varname}={varval}) - format-dict: - varname: '@checks.fromprop.requires.input_ref' - varval: '@checks.fromprop.requires.input_value' -""" # noqa - - -# this set of checks should cover the variations of logical op groupings that -# will not process items beyond the first that returns False which is the -# default for any AND operation since a single False makes the group result the -# same. -LOGIC_TEST = """ -vars: - # this one will resolve as False - v1: '@tests.unit.test_ycheck_scenarios.TestProperty.always_false' - # this one will raise an ImportError - v2: '@tests.unit.test_ycheck_scenarios.TestProperty.doesntexist' -checks: - # the second item in each group must be one that if evaluated will raise an - # error. - chk_and: - and: - - varops: [[$v1], [truth]] - - varops: [[$v2], [not_]] - chk_nand: - nand: - - varops: [[$v1], [not_]] - - varops: [[$v2], [not_]] - chk_not: - not: - - varops: [[$v1], [not_]] - - varops: [[$v2], [not_]] - chk_default_and: - - varops: [[$v2], [not_]] - - varops: [[$v1], [truth]] -conclusions: - conc1: - decision: - or: - - chk_and - - chk_nand - - chk_not - - chk_default_and - raises: - type: SystemWarning - message: >- - This should never get raised since all checks should be - returning False and the first false result in each check's logical - group should result in further items not being executed. -""" - -NESTED_LOGIC_TEST_W_ISSUE = """ -vars: - bool_true: true -checks: - chk_pass1: - and: - - varops: [[$bool_true], [truth]] - - not: - varops: [[$bool_true], [not_]] - chk_pass2: - or: - - and: - - varops: [[$bool_true], [truth]] - - varops: [[$bool_true], [not_]] - - and: - - varops: [[$bool_true], [truth]] - - varops: [[$bool_true], [truth]] - - varops: [[$bool_true], [truth]] - chk_pass3: - or: - - varops: [[$bool_true], [truth]] - - varops: [[$bool_true], [truth]] -conclusions: - conc1: - decision: [chk_pass1, chk_pass2, chk_pass3] - raises: - type: SystemWarning - message: -""" - - -NESTED_LOGIC_TEST_NO_ISSUE = """ -vars: - bool_true: true -checks: - chk_fail1: - and: - - varops: [[$bool_true], [truth]] - - not: - varops: [[$bool_true], [truth]] - chk_fail2: - or: - - and: - - varops: [[$bool_true], [not_]] - - varops: [[$bool_true], [not_]] - - and: - - varops: [[$bool_true], [not_]] - - varops: [[$bool_true], [not_]] - - varops: [[$bool_true], [not_]] -conclusions: - conc1: - decision: - or: [chk_fail1, chk_fail2] - raises: - type: SystemWarning - message: -""" - -DPKG_L = """ -ii openssh-server 1:8.2p1-4ubuntu0.4 amd64 secure shell (SSH) server, for secure access from remote machines -""" # noqa - - class TestYamlScenarios(utils.BaseTestCase): # noqa, pylint: disable=too-many-public-methods """ Tests scenarios functionality. """ - @utils.init_test_scenario(SCENARIO_W_EXPR_LIST. + @utils.init_test_scenario(test_data.SCENARIO_W_EXPR_LIST. format(path=os.path.basename('data.txt'))) @utils.create_data_root({'data.txt': 'hello x\n'}) @utils.global_search_context @@ -603,7 +60,7 @@ def test_yaml_def_expr_list(self, global_searcher): msg = "yay list search" self.assertEqual(issue['message'], msg) - @utils.init_test_scenario(SCENARIO_W_SEQ_SEARCH. + @utils.init_test_scenario(test_data.SCENARIO_W_SEQ_SEARCH. format(path=os.path.basename('data.txt'))) @utils.create_data_root({'data.txt': ("blah blah\nit's the start\nblah " "blah\nit's the end")}) @@ -618,7 +75,7 @@ def test_yaml_def_seq_search(self, global_searcher): msg = "yay seq searches worked!" self.assertEqual(issue['message'], msg) - @utils.init_test_scenario(SCENARIO_CHECKS) + @utils.init_test_scenario(test_data.SCENARIO_CHECKS) @utils.create_data_root({'foo.log': '2021-04-01 00:31:00.000 an event\n', 'uptime': (' 16:19:19 up 17:41, 2 users, ' ' load average: 3.58, 3.27, 2.58'), @@ -638,7 +95,7 @@ def test_yaml_def_scenario_checks_false(self, global_searcher): self.assertEqual(IssuesManager().load_issues(), {}) - @utils.init_test_scenario(SCENARIO_CHECKS) + @utils.init_test_scenario(test_data.SCENARIO_CHECKS) @utils.global_search_context def test_yaml_def_scenario_checks_requires(self, global_searcher): checker = scenarios.YScenarioChecker(global_searcher) @@ -667,7 +124,7 @@ def test_yaml_def_scenario_checks_requires(self, global_searcher): self.assertEqual(IssuesManager().load_issues(), {}) - @utils.init_test_scenario(SCENARIO_CHECKS) + @utils.init_test_scenario(test_data.SCENARIO_CHECKS) @utils.create_data_root({'foo.log': ('2021-03-29 00:31:00.000 an event\n' '2021-03-30 00:32:00.000 an event\n' @@ -757,7 +214,7 @@ def test_yaml_def_scenario_result_filters_by_period(self): result = ExtraSearchConstraints.filter_by_period(results, 24) self.assertEqual(len(result), 2) - @utils.init_test_scenario(YDEF_NESTED_LOGIC) + @utils.init_test_scenario(test_data.YDEF_NESTED_LOGIC) @utils.global_search_context def test_yaml_def_nested_logic(self, global_searcher): scenarios.YScenarioChecker(global_searcher).run() @@ -765,7 +222,7 @@ def test_yaml_def_nested_logic(self, global_searcher): self.assertEqual(sorted([issue['message'] for issue in issues]), sorted(['conc1', 'conc3'])) - @utils.init_test_scenario(YAML_DEF_REQUIRES_MAPPED) + @utils.init_test_scenario(test_data.YAML_DEF_REQUIRES_MAPPED) @utils.global_search_context def test_yaml_def_mapped_overrides(self, global_searcher): checker = scenarios.YScenarioChecker(global_searcher) @@ -782,7 +239,7 @@ def test_yaml_def_mapped_overrides(self, global_searcher): @mock.patch('hotsos.core.ycheck.engine.properties.requires.requires.log') @mock.patch('hotsos.core.ycheck.engine.properties.requires.common.log') @mock.patch('hotsos.core.ycheck.engine.properties.common.log') - @utils.init_test_scenario(SCENARIO_W_ERROR) + @utils.init_test_scenario(test_data.SCENARIO_W_ERROR) @utils.global_search_context def test_failed_scenario_caught(self, global_searcher, mock_log1, mock_log2, _mock_log3, @@ -791,7 +248,7 @@ def test_failed_scenario_caught(self, global_searcher, mock_log1, # Check caught exception logs args = ('failed to import and call property %s', - 'tests.unit.test_ycheck_scenarios.TestProperty.i_dont_exist') + 'tests.unit.ycheck.test_scenarios.TestProperty.i_dont_exist') mock_log1.exception.assert_called_with(*args) args = ('requires.%s.result raised the following', @@ -821,7 +278,7 @@ def test_failed_scenario_caught(self, global_searcher, mock_log1, "detail") self.assertEqual(issue['message'], msg) - @utils.init_test_scenario(CONFIG_SCENARIO) + @utils.init_test_scenario(test_data.CONFIG_SCENARIO) @utils.create_data_root({'test.conf': '[DEFAULT]\nkey1 = 101\n'}) @utils.global_search_context def test_config_scenario_fail(self, global_searcher): @@ -830,7 +287,7 @@ def test_config_scenario_fail(self, global_searcher): self.assertEqual([issue['message'] for issue in issues], ['cfg is bad', 'cfg is bad2']) - @utils.init_test_scenario(CONFIG_SCENARIO) + @utils.init_test_scenario(test_data.CONFIG_SCENARIO) @utils.create_data_root({'test.conf': '[DEFAULT]\nkey1 = 102\n'}) @utils.global_search_context def test_config_scenario_pass(self, global_searcher): @@ -842,7 +299,7 @@ def test_config_scenario_pass(self, global_searcher): @mock.patch('hotsos.core.ycheck.scenarios.log') @mock.patch('hotsos.core.ycheck.engine.properties.conclusions.' 'ScenarioException') - @utils.init_test_scenario(CONCLUSION_W_INVALID_BUG_RAISES) + @utils.init_test_scenario(test_data.CONCLUSION_W_INVALID_BUG_RAISES) @utils.global_search_context def test_raises_w_invalid_types(self, global_searcher, mock_exc, mock_log, mock_log2): @@ -871,7 +328,7 @@ def test_raises_w_invalid_types(self, global_searcher, mock_exc, mock_log, "debug mode (--debug) to get more detail") self.assertEqual(issue['message'], msg) - @utils.init_test_scenario(VARS) + @utils.init_test_scenario(test_data.VARS) @utils.global_search_context def test_vars(self, global_searcher): scenarios.YScenarioChecker(global_searcher).run() @@ -894,7 +351,7 @@ def test_vars(self, global_searcher): @mock.patch('hotsos.core.ycheck.engine.properties.requires.requires.log') @mock.patch('hotsos.core.ycheck.engine.properties.requires.common.log') @mock.patch('hotsos.core.ycheck.engine.properties.common.log') - @utils.init_test_scenario(LOGIC_TEST) + @utils.init_test_scenario(test_data.LOGIC_TEST) @utils.global_search_context def test_logical_collection_and_with_fail(self, global_searcher, mock_log1, mock_log2, _mock_log3, mock_log4, @@ -904,7 +361,7 @@ def test_logical_collection_and_with_fail(self, global_searcher, mock_log1, expected = [ (mock_log1, ('failed to import and call property %s', - 'tests.unit.test_ycheck_scenarios.TestProperty.doesntexist'), + 'tests.unit.ycheck.test_scenarios.TestProperty.doesntexist'), 'exception'), (mock_log2, ('requires.%s.result raised the following', 'YPropertyVarOps'), @@ -934,28 +391,30 @@ def test_logical_collection_and_with_fail(self, global_searcher, mock_log1, "detail") self.assertEqual(issue['message'], msg) - @utils.init_test_scenario(NESTED_LOGIC_TEST_NO_ISSUE) + @utils.init_test_scenario(test_data.NESTED_LOGIC_TEST_NO_ISSUE) @utils.global_search_context def test_logical_collection_nested_no_issue(self, global_searcher): scenarios.YScenarioChecker(global_searcher).run() issues = list(IssuesStore().load().values()) self.assertEqual(len(issues), 0) - @utils.init_test_scenario(NESTED_LOGIC_TEST_W_ISSUE) + @utils.init_test_scenario(test_data.NESTED_LOGIC_TEST_W_ISSUE) @utils.global_search_context def test_logical_collection_nested_w_issue(self, global_searcher): scenarios.YScenarioChecker(global_searcher).run() issues = list(IssuesStore().load().values()) self.assertEqual(len(issues), 1) - @utils.init_test_scenario(NESTED_LOGIC_TEST_W_ISSUE, 'myscenario') + @utils.init_test_scenario(test_data.NESTED_LOGIC_TEST_W_ISSUE, + 'myscenario') @utils.global_search_context def test_scenarios_filter_none(self, global_searcher): sc = scenarios.YScenarioChecker(global_searcher) sc.load() self.assertEqual([s.name for s in sc.scenarios], ['myscenario']) - @utils.init_test_scenario(NESTED_LOGIC_TEST_W_ISSUE, 'myscenario') + @utils.init_test_scenario(test_data.NESTED_LOGIC_TEST_W_ISSUE, + 'myscenario') @utils.global_search_context def test_scenarios_filter_myscenario(self, global_searcher): HotSOSConfig.scenario_filter = 'myplugin.scenariogroup.myscenario' @@ -963,7 +422,8 @@ def test_scenarios_filter_myscenario(self, global_searcher): sc.load() self.assertEqual([s.name for s in sc.scenarios], ['myscenario']) - @utils.init_test_scenario(NESTED_LOGIC_TEST_W_ISSUE, 'myscenario') + @utils.init_test_scenario(test_data.NESTED_LOGIC_TEST_W_ISSUE, + 'myscenario') @utils.global_search_context def test_scenarios_filter_nonexistent(self, global_searcher): HotSOSConfig.scenario_filter = 'blahblah' @@ -971,7 +431,7 @@ def test_scenarios_filter_nonexistent(self, global_searcher): sc.load() self.assertEqual([s.name for s in sc.scenarios], []) - @utils.init_test_scenario(CONCLUSION_PRIORITY_1, 'myscenario') + @utils.init_test_scenario(test_data.CONCLUSION_PRIORITY_1, 'myscenario') @utils.global_search_context def test_conclusion_priority_exec_highest(self, global_searcher): called = [] @@ -994,7 +454,7 @@ def reached(self, *args, **kwargs): self.assertEqual(called, ['conc3']) - @utils.init_test_scenario(CONCLUSION_PRIORITY_2, 'myscenario') + @utils.init_test_scenario(test_data.CONCLUSION_PRIORITY_2, 'myscenario') @utils.global_search_context def test_conclusion_priority_exec_all_same(self, global_searcher): called = [] diff --git a/tests/unit/ycheck/test_scenarios_data.py b/tests/unit/ycheck/test_scenarios_data.py new file mode 100644 index 000000000..156a86306 --- /dev/null +++ b/tests/unit/ycheck/test_scenarios_data.py @@ -0,0 +1,542 @@ + +# Definitions for ycheck_scenarios tests, put here to address the +# too-many-lines (1000 lines) per file pylint limit. + +YDEF_NESTED_LOGIC = """ +checks: + isTrue: + requires: + and: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + - property: + path: tests.unit.ycheck.test_scenarios.TestProperty.always_false + ops: [[not_]] + isalsoTrue: + requires: + or: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_false + isstillTrue: + requires: + and: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + or: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_false + isnotTrue: + requires: + and: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + or: + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_false + - property: tests.unit.ycheck.test_scenarios.TestProperty.always_false +conclusions: + conc1: + decision: + and: + - isTrue + - isalsoTrue + or: + - isstillTrue + raises: + type: IssueTypeBase + message: conc1 + conc2: + decision: + and: + - isTrue + - isnotTrue + or: + - isalsoTrue + raises: + type: IssueTypeBase + message: conc2 + conc3: + decision: + not: + - isnotTrue + or: + - isalsoTrue + raises: + type: IssueTypeBase + message: conc3 +""" + + +CONCLUSION_PRIORITY_1 = """ +checks: + testcheck: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true +conclusions: + conc1: + priority: 1 + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc1 + conc2: + priority: 2 + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc2 + conc3: + priority: 3 + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc3 +""" + +CONCLUSION_PRIORITY_2 = """ +checks: + testcheck: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true +conclusions: + conc1: + priority: 1 + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc1 + conc2: + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc2 + conc3: + decision: + - testcheck + raises: + type: IssueTypeBase + message: conc3 +""" + + +YAML_DEF_REQUIRES_MAPPED = """ +checks: + is_exists_mapped: + systemd: nova-compute + is_exists_unmapped: + requires: + systemd: nova-compute +conclusions: +""" + +SCENARIO_W_EXPR_LIST = r""" +input: + path: {path} +checks: + listsearch1: + expr: ['hello y', 'hello x'] + listsearch2: + search: ['hello y', 'hello x'] + listsearch3: + search: + expr: ['hello y', 'hello x'] +conclusions: + listsearch1worked: + decision: listsearch1 + raises: + type: SystemWarning + message: yay list search + listsearch2worked: + decision: listsearch2 + raises: + type: SystemWarning + message: yay list search + listsearch3worked: + decision: listsearch3 + raises: + type: SystemWarning + message: yay list search +""" # noqa + + +SCENARIO_W_SEQ_SEARCH = r""" +input: + path: {path} +checks: + seqsearch1: + start: "it's the start" + body: ".+" + end: "it's the end" + seqsearch2: + start: "it's the start" + end: "it's the end" +conclusions: + seqsearchworked: + decision: + - seqsearch1 + - seqsearch2 + raises: + type: SystemWarning + message: yay seq searches worked! +""" # noqa + + +SCENARIO_W_ERROR = r""" +scenarioA: + checks: + property_no_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + conclusions: + c1: + decision: property_no_error + raises: + type: SystemWarning + message: foo +scenarioB: + checks: + property_w_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.i_dont_exist + conclusions: + c1: + decision: property_w_error + raises: + type: SystemWarning + message: foo +""" # noqa + + +CONCLUSION_W_INVALID_BUG_RAISES = r""" +scenarioA: + checks: + property_no_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + conclusions: + c1: + decision: property_no_error + raises: + type: SystemWarning + bug-id: 1234 + message: foo +scenarioB: + checks: + property_w_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + conclusions: + c1: + decision: property_no_error + raises: + type: LaunchpadBug + message: foo +scenarioC: + checks: + property_w_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + conclusions: + c1: + decision: property_no_error + raises: + type: UbuntuCVE + message: foo +scenarioD: + checks: + property_w_error: + property: tests.unit.ycheck.test_scenarios.TestProperty.always_true + conclusions: + c1: + decision: property_no_error + raises: + cve-id: 123 +""" # noqa + + +SCENARIO_CHECKS = r""" +checks: + logmatch: + input: + path: foo.log + expr: '(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}\.\d{3}) (\S+) \S+' + constraints: + min-results: 3 + search-period-hours: 24 + search-result-age-hours: 48 + property_true_shortform: + requires: + property: + path: hotsos.core.plugins.system.system.SystemBase.virtualisation_type + property_has_value_longform: + requires: + property: + path: hotsos.core.plugins.system.system.SystemBase.virtualisation_type + ops: [[eq, kvm], [truth], [not_], [not_]] + apt_pkg_exists: + requires: + apt: nova-compute + snap_pkg_exists: + requires: + snap: core20 + service_exists_short: + requires: + systemd: nova-compute + service_exists_and_enabled: + requires: + systemd: + nova-compute: enabled + service_exists_not_enabled: + requires: + systemd: + nova-compute: + state: enabled + op: ne +conclusions: + justlog: + priority: 1 + decision: logmatch + raises: + type: SystemWarning + message: log matched {num} times ({group}) + format-dict: + num: '@checks.logmatch.search.num_results' + group: '@checks.logmatch.search.results_group_2:comma_join' + logandsnap: + priority: 2 + decision: + and: + - logmatch + - snap_pkg_exists + raises: + type: SystemWarning + message: log matched {num} times and snap exists + format-dict: + num: '@checks.logmatch.search.num_results' + logandsnapandservice: + priority: 3 + decision: + and: + - logmatch + - snap_pkg_exists + - service_exists_short + - service_exists_and_enabled + - property_true_shortform + - property_has_value_longform + raises: + type: SystemWarning + message: log matched {num} times, snap and service exists + format-dict: + num: '@checks.logmatch.search.num_results' +""" # noqa + + +CONFIG_SCENARIO = """ +checks: + cfg_is_bad: + config: + handler: tests.unit.ycheck.test_scenarios.TestConfig + path: test.conf + assertions: + - key: key1 + section: DEFAULT + ops: [[lt, 102]] + - key: key1 + section: DEFAULT + ops: [[gt, 100]] + cfg_is_bad2: + config: + handler: tests.unit.ycheck.test_scenarios.TestConfig + path: test.conf + assertions: + not: + - key: key1 + section: DEFAULT + ops: [[lt, 103]] + - key: key1 + section: DEFAULT + ops: [[gt, 101]] +conclusions: + cfg_is_bad: + decision: cfg_is_bad + raises: + type: SystemWarning + message: cfg is bad + cfg_is_bad2: + decision: cfg_is_bad2 + raises: + type: SystemWarning + message: cfg is bad2 +""" + + +VARS = """ +vars: + foo: 1000 + limit: 10 + bar: "two" + frombadprop: '@tests.unit.idontexist' # add to ensure lazy-loaded + fromprop: '@tests.unit.ycheck.test_scenarios.TestProperty.myattr' + fromfact: '@hotsos.core.host_helpers.systemd.ServiceFactory.start_time_secs:snapd' + fromfact2: '@hotsos.core.host_helpers.filestat.FileFactory.mtime:myfile.txt' + fromsysctl: '@hotsos.core.host_helpers.sysctl.SYSCtlFactory:net.core.somaxconn' + boolvar: false +checks: + aptcheck: + apt: nova-compute + is_foo_lt: + varops: [[$foo], [lt, $limit]] + is_foo_gt: + varops: [[$foo], [gt, $limit]] + isbar: + varops: [[$bar], [ne, ""]] + fromprop: + varops: [[$fromprop], [eq, "123"]] + fromfact: + varops: [[$fromfact], [gt, 1644446300]] + fromfact2: + varops: [[$fromfact2], [eq, 0]] + fromsysctl: + varops: [[$fromsysctl], [eq, '4096']] + boolvar: + varops: [[$boolvar], [truth], [not_]] +conclusions: + aptcheck: + decision: aptcheck + raises: + type: SystemWarning + message: "{name}={version}" + format-dict: + name: '@checks.aptcheck.requires.package' + version: '@checks.aptcheck.requires.version' + is_foo_gt: + decision: is_foo_gt + raises: + type: SystemWarning + message: it's foo gt! ({varname}={varval}) + format-dict: + varname: '@checks.is_foo_gt.requires.input_ref' + varval: '@checks.is_foo_gt.requires.input_value' + is_foo_lt: + decision: is_foo_lt + raises: + type: SystemWarning + message: it's foo lt! ({varname}={varval}) + format-dict: + varname: '@checks.is_foo_lt.requires.input_ref' + varval: '@checks.is_foo_lt.requires.input_value' + isbar: + decision: isbar + raises: + type: SystemWarning + message: it's bar! ({varname}={varval}) + format-dict: + varname: '@checks.isbar.requires.input_ref' + varval: '@checks.isbar.requires.input_value' + fromprop: + decision: + and: [fromprop, boolvar, fromfact, fromfact2, fromsysctl] + raises: + type: SystemWarning + message: fromprop! ({varname}={varval}) + format-dict: + varname: '@checks.fromprop.requires.input_ref' + varval: '@checks.fromprop.requires.input_value' +""" # noqa + + +# this set of checks should cover the variations of logical op groupings that +# will not process items beyond the first that returns False which is the +# default for any AND operation since a single False makes the group result the +# same. +LOGIC_TEST = """ +vars: + # this one will resolve as False + v1: '@tests.unit.ycheck.test_scenarios.TestProperty.always_false' + # this one will raise an ImportError + v2: '@tests.unit.ycheck.test_scenarios.TestProperty.doesntexist' +checks: + # the second item in each group must be one that if evaluated will raise an + # error. + chk_and: + and: + - varops: [[$v1], [truth]] + - varops: [[$v2], [not_]] + chk_nand: + nand: + - varops: [[$v1], [not_]] + - varops: [[$v2], [not_]] + chk_not: + not: + - varops: [[$v1], [not_]] + - varops: [[$v2], [not_]] + chk_default_and: + - varops: [[$v2], [not_]] + - varops: [[$v1], [truth]] +conclusions: + conc1: + decision: + or: + - chk_and + - chk_nand + - chk_not + - chk_default_and + raises: + type: SystemWarning + message: >- + This should never get raised since all checks should be + returning False and the first false result in each check's logical + group should result in further items not being executed. +""" + +NESTED_LOGIC_TEST_W_ISSUE = """ +vars: + bool_true: true +checks: + chk_pass1: + and: + - varops: [[$bool_true], [truth]] + - not: + varops: [[$bool_true], [not_]] + chk_pass2: + or: + - and: + - varops: [[$bool_true], [truth]] + - varops: [[$bool_true], [not_]] + - and: + - varops: [[$bool_true], [truth]] + - varops: [[$bool_true], [truth]] + - varops: [[$bool_true], [truth]] + chk_pass3: + or: + - varops: [[$bool_true], [truth]] + - varops: [[$bool_true], [truth]] +conclusions: + conc1: + decision: [chk_pass1, chk_pass2, chk_pass3] + raises: + type: SystemWarning + message: +""" + + +NESTED_LOGIC_TEST_NO_ISSUE = """ +vars: + bool_true: true +checks: + chk_fail1: + and: + - varops: [[$bool_true], [truth]] + - not: + varops: [[$bool_true], [truth]] + chk_fail2: + or: + - and: + - varops: [[$bool_true], [not_]] + - varops: [[$bool_true], [not_]] + - and: + - varops: [[$bool_true], [not_]] + - varops: [[$bool_true], [not_]] + - varops: [[$bool_true], [not_]] +conclusions: + conc1: + decision: + or: [chk_fail1, chk_fail2] + raises: + type: SystemWarning + message: +"""