Skip to content

Commit abcfa2b

Browse files
committed
Fix patterns filter for empty multitest
1 parent 925a159 commit abcfa2b

5 files changed

Lines changed: 86 additions & 2 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The ``--patterns`` filter will run a Multitest as long as the test name matches even if the Multitest is empty.

testplan/testing/filtering.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ class BaseFilter:
4848
def map(self, f):
4949
raise NotImplementedError
5050

51+
def filter_test(self, test) -> bool:
52+
raise NotImplementedError
53+
5154
def filter(self, test, suite, case) -> bool:
5255
raise NotImplementedError
5356

@@ -169,6 +172,9 @@ class Or(MetaFilter):
169172

170173
operator_str = "|"
171174

175+
def filter_test(self, test):
176+
return any(f.filter_test(test) for f in self.filters)
177+
172178
def composed_filter(self, test, suite, case):
173179
return any(f.filter(test, suite, case) for f in self.filters)
174180

@@ -180,6 +186,9 @@ class And(MetaFilter):
180186

181187
operator_str = "&"
182188

189+
def filter_test(self, test):
190+
return all(f.filter_test(test) for f in self.filters)
191+
183192
def composed_filter(self, test, suite, case):
184193
return all(f.filter(test, suite, case) for f in self.filters)
185194

@@ -204,6 +213,9 @@ def map(self, f):
204213
self.filter_obj = f(self.filter_obj)
205214
return self
206215

216+
def filter_test(self, test):
217+
return not self.filter_obj.filter_test(test)
218+
207219
def filter(self, test, suite, case):
208220
return not self.filter_obj.filter(test, suite, case)
209221

testplan/testing/multitest/base.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,8 +626,14 @@ def add_main_batch_steps(self):
626626
def should_run(self):
627627
"""
628628
MultiTest filters are applied in `get_test_context`
629-
so we just check if `test_context` is not empty."""
630-
return bool(self.test_context)
629+
so we check if `test_context` is not empty.
630+
If there's no parts, MultiTest should still be ran even if it is empty, add a filter just for the test
631+
"""
632+
if self.cfg.part:
633+
return bool(self.test_context)
634+
return bool(self.test_context) or self.cfg.test_filter.filter_test(
635+
self
636+
)
631637

632638
def aborting(self):
633639
"""Suppressing not implemented debug log from parent class."""

tests/functional/testplan/testing/test_filtering.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,30 @@ def test_programmatic_filtering(filter_obj, report_ctx):
195195
check_report_context(test_report, report_ctx)
196196

197197

198+
def test_programmatic_filtering_empty_multitest():
199+
"""MultiTest with no suites should still run if pattern matches test name."""
200+
multitest_x = MultiTest(name="XXX", suites=[])
201+
202+
plan = TestplanMock(name="plan", test_filter=filtering.Pattern("XXX"))
203+
plan.add(multitest_x)
204+
plan.run()
205+
206+
test_report = plan.report
207+
check_report_context(test_report, [("XXX", [])])
208+
209+
210+
def test_programmatic_filtering_empty_multitest_no_match():
211+
"""MultiTest with no suites should not run if pattern doesn't match."""
212+
multitest_x = MultiTest(name="XXX", suites=[])
213+
214+
plan = TestplanMock(name="plan", test_filter=filtering.Pattern("YYY"))
215+
plan.add(multitest_x)
216+
plan.run()
217+
218+
test_report = plan.report
219+
check_report_context(test_report, [])
220+
221+
198222
@pytest.mark.parametrize(
199223
"filter_obj, report_ctx",
200224
(

tests/unit/testplan/testing/multitest/test_multitest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,3 +664,44 @@ def test_skip_steps():
664664
)
665665
)
666666
assert "_start_resource" not in mt.result.step_results
667+
668+
669+
@pytest.mark.parametrize(
670+
"pattern, name, expected",
671+
(
672+
("Test", "Test", True),
673+
("T*", "Test", True),
674+
("Test1", "Test", False),
675+
("*", "Test", True),
676+
("*:*:*", "Test", True),
677+
("Test:Suite:case", "Test", True),
678+
("Test1:Suite:case", "Test", False),
679+
),
680+
)
681+
def test_should_run_with_pattern_filter(pattern, name, expected):
682+
mt = multitest.MultiTest(
683+
name=name,
684+
suites=[Suite()],
685+
**{**MTEST_DEFAULT_PARAMS, "test_filter": filtering.Pattern(pattern)},
686+
)
687+
assert mt.should_run() == expected
688+
689+
690+
def test_should_run_with_no_suites():
691+
"""should_run returns True if filter matches even with no suites."""
692+
mt = multitest.MultiTest(
693+
name="Test",
694+
suites=[],
695+
**{**MTEST_DEFAULT_PARAMS, "test_filter": filtering.Pattern("Test")},
696+
)
697+
assert mt.should_run() is True
698+
699+
700+
def test_should_run_with_no_suites_no_match():
701+
"""should_run returns False if filter doesn't match and no suites."""
702+
mt = multitest.MultiTest(
703+
name="Test",
704+
suites=[],
705+
**{**MTEST_DEFAULT_PARAMS, "test_filter": filtering.Pattern("Test1")},
706+
)
707+
assert mt.should_run() is False

0 commit comments

Comments
 (0)