diff --git a/hotsos/core/ycheck/engine/properties/checks.py b/hotsos/core/ycheck/engine/properties/checks.py index 484e56320..82826b2d0 100644 --- a/hotsos/core/ycheck/engine/properties/checks.py +++ b/hotsos/core/ycheck/engine/properties/checks.py @@ -27,15 +27,40 @@ def _search_results(self): search constraints requested. """ global_results = self.context.search_results - if global_results is not None: - tag = self.search.unique_search_tag - _results = global_results.find_by_tag(tag) - log.debug("check %s has %s search results with tag %s", - self.check_name, len(_results), tag) - return self.search.apply_extra_constraints(_results) - - raise Exception("no search results provided to check '{}'". - format(self.check_name)) + if global_results is None: + raise Exception("no search results provided to check '{}'". + format(self.check_name)) + + tag = self.search.unique_search_tag + + # first get simple search results + simple_results = global_results.find_by_tag(tag) + log.debug("check %s has %s simple search results with tag %s", + self.check_name, len(simple_results), tag) + results = self.search.apply_extra_constraints(simple_results) + + seq_def = self.search.cache.sequence_search + if not seq_def: + return results + + # Not try for sequence search results + sections = global_results.find_sequence_by_tag(tag).values() + log.debug("check %s has %s sequence search results with tag %s", + self.check_name, len(sections), tag) + if not sections: + return results + + # Use the result of the first section start as the final + # result. This is enough for now because the section is guaranteed + # to be complete i.e. a full match and the result is ultimately + # True/False based on whether or not a result was found. + for result in list(sections)[0]: + if result.tag == seq_def.start_tag: + # NOTE: we don't yet support applying extra constraints here + results.append(result) + break + + return results @classmethod def _override_keys(cls): @@ -84,6 +109,7 @@ def _result(self): return False return True + if self.requires: if self.cache.requires: result = self.cache.requires.passes diff --git a/tests/unit/test_ycheck_scenarios.py b/tests/unit/test_ycheck_scenarios.py index 75411cc36..62c48d28e 100644 --- a/tests/unit/test_ycheck_scenarios.py +++ b/tests/unit/test_ycheck_scenarios.py @@ -338,6 +338,28 @@ def init_test_scenario_inner2(*args, **kwargs): """ # 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: @@ -702,6 +724,20 @@ def test_yaml_def_expr_list(self): msg = "yay list search" self.assertEqual(issue['message'], msg) + @init_test_scenario(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")}) + def test_yaml_def_seq_search(self): + scenarios.YScenarioChecker().load_and_run() + issues = list(IssuesStore().load().values()) + self.assertEqual(len(issues[0]), 1) + i_types = [i['type'] for i in issues[0]] + self.assertEqual(i_types, ['SystemWarning',]) + for issue in issues[0]: + msg = "yay seq searches worked!" + self.assertEqual(issue['message'], msg) + @init_test_scenario(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, '