Skip to content

Commit a085b79

Browse files
Enhance conditional mark logic with use_longest for special cases (sonic-net#17317)
What is the motivation for this PR? In PR sonic-net#16930, we refined the logic of conditional marking to ensure that the longest matching entry with a True condition is prioritized. If the condition for the longest match is False, we then consider the next longest match. However, there is a special case where the longest match has a False condition, but we still want to adopt this False condition instead of falling back to shorter matches. For example, in a skip scenario: Shorter matching entries have True conditions, meaning the test should be skipped. The longest matching entry has a False condition, meaning the test should not be skipped. In this case, we actually want to respect the longest match and not skip the test. To address this, this PR introduces a new key, use_longest. When use_longest is set to True, only the conditions of the longest matching entry will be used, ensuring the intended behavior in such edge cases. How did you do it? To address this, this PR introduces a new key, use_longest. When use_longest is set to True, only the conditions of the longest matching entry will be used, ensuring the intended behavior in such edge cases. How did you verify/test it? Add unit test test cases
1 parent f32e603 commit a085b79

File tree

4 files changed

+141
-2
lines changed

4 files changed

+141
-2
lines changed

tests/common/plugins/conditional_mark/__init__.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,17 @@ def find_all_matches(nodeid, conditions, session, dynamic_update_skip_reason, ba
432432
match = re.search(condition_entry, nodeid)
433433
else:
434434
match = None
435+
436+
elif "use_longest" in condition_items.keys():
437+
assert isinstance(condition_items["use_longest"], bool), \
438+
"The value of 'use_longest' in the mark conditions yaml should be bool type."
439+
if nodeid.startswith(condition_entry) and condition_items["use_longest"] is True:
440+
all_matches = []
441+
442+
match = nodeid.startswith(condition_entry)
435443
else:
436444
match = nodeid.startswith(condition_entry)
445+
437446
if match:
438447
all_matches.append(condition)
439448

@@ -442,6 +451,9 @@ def find_all_matches(nodeid, conditions, session, dynamic_update_skip_reason, ba
442451
length = len(case_starting_substring)
443452
marks = match[case_starting_substring].keys()
444453
for mark in marks:
454+
if mark in ["regex", "use_longest"]:
455+
continue
456+
445457
condition_value = evaluate_conditions(dynamic_update_skip_reason, match[case_starting_substring][mark],
446458
match[case_starting_substring][mark].get('conditions'), basic_facts,
447459
match[case_starting_substring][mark].get(
@@ -636,7 +648,7 @@ def pytest_collection_modifyitems(session, config, items):
636648
for match in all_matches:
637649
# match is a dict which has only one item, so we use match.values()[0] to get its value.
638650
for mark_name, mark_details in list(list(match.values())[0].items()):
639-
if mark_name == "regex":
651+
if mark_name in ["regex", "use_longest"]:
640652
continue
641653
conditions_logical_operator = mark_details.get('conditions_logical_operator', 'AND').upper()
642654
add_mark = False

tests/common/plugins/conditional_mark/unit_test/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The unit tests cover the following scenarios:
2222
- Test duplicated conditions
2323
- Test contradicting conditions
2424
- Test no matches
25-
25+
- Test only use the longest match
2626

2727
### How to run tests
2828
To execute the unit tests, we can follow below command

tests/common/plugins/conditional_mark/unit_test/tests_conditions.yaml

+46
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,49 @@ test_conditional_mark.py::test_mark_7:
7777
conditions:
7878
- "topo_type in ['t0']"
7979
- "topo_type not in ['t0']"
80+
81+
test_conditional_mark.py::test_mark_8:
82+
use_longest: True
83+
skip:
84+
reason: "Skip test_conditional_mark.py::test_mark_8"
85+
conditions:
86+
- "asic_type in ['mellanox']"
87+
88+
test_conditional_mark.py::test_mark_8_1:
89+
use_longest: True
90+
skip:
91+
reason: "Skip test_conditional_mark.py::test_mark_8_1"
92+
conditions:
93+
- "asic_type in ['mellanox']"
94+
95+
test_conditional_mark.py::test_mark_8_2:
96+
use_longest: True
97+
skip:
98+
reason: "Skip test_conditional_mark.py::test_mark_8_2"
99+
conditions:
100+
- "asic_type in ['vs']"
101+
102+
test_conditional_mark.py::test_mark_9:
103+
use_longest: True
104+
skip:
105+
reason: "Skip test_conditional_mark.py::test_mark_9"
106+
conditions:
107+
- "asic_type in ['vs']"
108+
109+
test_conditional_mark.py::test_mark_9_1:
110+
use_longest: True
111+
skip:
112+
reason: "Skip test_conditional_mark.py::test_mark_9_1"
113+
conditions:
114+
- "asic_type in ['vs']"
115+
116+
test_conditional_mark.py::test_mark_9_2:
117+
use_longest: True
118+
skip:
119+
reason: "Skip test_conditional_mark.py::test_mark_9_2"
120+
conditions:
121+
- "asic_type in ['mellanox']"
122+
xfail:
123+
reason: "Xfail test_conditional_mark.py::test_mark_9_2"
124+
conditions:
125+
- "asic_type in ['vs']"

tests/common/plugins/conditional_mark/unit_test/unittest_find_all_matches.py

+81
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,87 @@ def test_no_matches(self):
211211
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
212212
self.assertFalse(matches)
213213

214+
# Test case 11: Test only use the longest match
215+
def test_only_use_the_longest_1(self):
216+
conditions, session_mock = load_test_conditions()
217+
nodeid = "test_conditional_mark.py::test_mark_8"
218+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
219+
self.assertFalse(matches)
220+
221+
def test_only_use_the_longest_2(self):
222+
conditions, session_mock = load_test_conditions()
223+
nodeid = "test_conditional_mark.py::test_mark_8_1"
224+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
225+
self.assertFalse(matches)
226+
227+
def test_only_use_the_longest_3(self):
228+
conditions, session_mock = load_test_conditions()
229+
nodeid = "test_conditional_mark.py::test_mark_8_2"
230+
231+
marks_found = []
232+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
233+
234+
for match in matches:
235+
for mark_name, mark_details in list(list(match.values())[0].items()):
236+
marks_found.append(mark_name)
237+
238+
if mark_name == "skip":
239+
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_8_2")
240+
241+
self.assertEqual(len(marks_found), 1)
242+
self.assertIn('skip', marks_found)
243+
244+
def test_only_use_the_longest_4(self):
245+
conditions, session_mock = load_test_conditions()
246+
nodeid = "test_conditional_mark.py::test_mark_9"
247+
248+
marks_found = []
249+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
250+
251+
for match in matches:
252+
for mark_name, mark_details in list(list(match.values())[0].items()):
253+
marks_found.append(mark_name)
254+
255+
if mark_name == "skip":
256+
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_9")
257+
258+
self.assertEqual(len(marks_found), 1)
259+
self.assertIn('skip', marks_found)
260+
261+
def test_only_use_the_longest_5(self):
262+
conditions, session_mock = load_test_conditions()
263+
nodeid = "test_conditional_mark.py::test_mark_9_1"
264+
265+
marks_found = []
266+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
267+
268+
for match in matches:
269+
for mark_name, mark_details in list(list(match.values())[0].items()):
270+
marks_found.append(mark_name)
271+
272+
if mark_name == "skip":
273+
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_9_1")
274+
275+
self.assertEqual(len(marks_found), 1)
276+
self.assertIn('skip', marks_found)
277+
278+
def test_only_use_the_longest_6(self):
279+
conditions, session_mock = load_test_conditions()
280+
nodeid = "test_conditional_mark.py::test_mark_9_2"
281+
282+
marks_found = []
283+
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
284+
285+
for match in matches:
286+
for mark_name, mark_details in list(list(match.values())[0].items()):
287+
marks_found.append(mark_name)
288+
289+
if mark_name == "xfail":
290+
self.assertEqual(mark_details.get("reason"), "Xfail test_conditional_mark.py::test_mark_9_2")
291+
292+
self.assertEqual(len(marks_found), 1)
293+
self.assertIn('xfail', marks_found)
294+
214295

215296
if __name__ == "__main__":
216297
unittest.main()

0 commit comments

Comments
 (0)