Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions tests/common/plugins/conditional_mark/unit_test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Unit Test for conditional marks
We have unit tests to verify the correct selection of marks for each test case. The core logic resides in the `find_all_matches` function within `tests/common/plugins/conditional_mark/__init__.py`.
Therefore, our unit tests are primarily focused on testing this function.

### Code sturcture
To test the `find_all_matches` function, we primarily need two key parameters: nodeid and conditions.
- nodeid represents the test case name and serves as the lookup key in `tests_conditions.yaml`.
- conditions are read from `tests_conditions.yaml`, which contains the predefined marks and conditions for test scripts.

For the session parameter, we will use MagicMock to create a mock session.
As for the other parameters, they are not the primary focus of our unit tests, so we will assign them default values.

### Test coverage
The unit tests cover the following scenarios:
- The condition in the longest matching entry is fully satisfied.
- The condition in the longest matching entry is partially unsatisfied.
- All conditions along the matching path are unsatisfied.
- The condition in the longest matching entry is empty
- Test logic operation `or`
- Test default logic operation
- Test logic operation `and`
- Test duplicated conditions
- Test contradicting conditions
- Test no matches


### How to run tests
To execute the unit tests, we can follow below command
```buildoutcfg
yutongzhang@sonic_mgmt:/data/sonic-mgmt$ python -m pytest --noconftest --capture=no tests/common/plugins/conditional_mark/unit_test/unittest_find_all_matches.py -v -s
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
test_conditional_mark.py:
xfail:
reason: "Xfail test_conditional_mark.py"
conditions:
- "asic_type in ['mellanox']"
skip:
reason: "Skip test_conditional_mark.py"
conditions:
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_false_mark_1:
skip:
reason: "Skip test_conditional_mark.py::test_false_mark"
conditions:
- "topo_type not in ['t0']"

test_conditional_mark.py::test_false_mark_2:
skip:
reason: "Skip test_conditional_mark.py::test_false_mark"
conditions_logical_operator: or
conditions:
- "topo_type not in ['t0']"
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_mark:
skip:
reason: "Skip test_conditional_mark.py::test_mark"
conditions:
- "topo_type in ['t0']"

test_conditional_mark.py::test_mark_1:
xfail:
reason: "Xfail test_conditional_mark.py::test_mark_1"
conditions:
- "asic_type in ['vs']"
skip:
reason: "Skip test_conditional_mark.py::test_mark_1"
conditions:
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_mark_2:
skip:
reason: "Skip test_conditional_mark.py::test_mark_2"

test_conditional_mark.py::test_mark_3:
skip:
reason: "Skip test_conditional_mark.py::test_mark_3"
conditions_logical_operator: or
conditions:
- "topo_type in ['t0']"
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_mark_4:
skip:
reason: "Skip test_conditional_mark.py::test_mark_4"
conditions:
- "topo_type in ['t0']"
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_mark_5:
skip:
reason: "Skip test_conditional_mark.py::test_mark_5"
conditions:
- "topo_type in ['t0']"
- "asic_type in ['mellanox']"

test_conditional_mark.py::test_mark_6:
skip:
reason: "Skip test_conditional_mark.py::test_mark_6"
conditions:
- "topo_type in ['t0']"
- "topo_type in ['t0']"

test_conditional_mark.py::test_mark_7:
skip:
reason: "Skip test_conditional_mark.py::test_mark_7"
conditions:
- "topo_type in ['t0']"
- "topo_type not in ['t0']"
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import logging
import unittest
from unittest.mock import MagicMock
from tests.common.plugins.conditional_mark import find_all_matches, load_conditions

logger = logging.getLogger(__name__)

DYNAMIC_UPDATE_SKIP_REASON = False
CUSTOM_BASIC_FACTS = {"asic_type": "vs", "topo_type": "t0"}


def load_test_conditions():
session_mock = MagicMock()
session_mock.config.option.mark_conditions_files = \
["tests/common/plugins/conditional_mark/unit_test/tests_conditions.yaml"]
return load_conditions(session_mock), session_mock


class TestFindAllMatches(unittest.TestCase):
"""Test cases for find_all_matches function."""

# Test case 1: The condition in the longest matching entry is True
# Use the conditions in the longest matching entry.
def test_true_conditions_in_longest_entry(self):
conditions, session_mock = load_test_conditions()

marks_found = []
nodeid = "test_conditional_mark.py::test_mark"

matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 2: The condition in the longest matching entry is partly false
# Use the conditions in second longest matching entry.
def test_partly_false_conditions_in_longest_entry(self):
conditions, session_mock = load_test_conditions()

marks_found = []
nodeid = "test_conditional_mark.py::test_mark_1"

matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "xfail":
self.assertEqual(mark_details.get("reason"), "Xfail test_conditional_mark.py::test_mark_1")
elif mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark")

self.assertEqual(len(marks_found), 2)
self.assertIn('skip', marks_found)
self.assertIn('xfail', marks_found)

# Test case 3: All conditions in the matching path are false
def test_all_false_conditions_in_matching_path_1(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py"

matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

self.assertFalse(matches)

def test_all_false_conditions_in_matching_path_2(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_false_mark_1"

matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

self.assertFalse(matches)

def test_all_false_conditions_in_matching_path_3(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_false_mark_2"

matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

self.assertFalse(matches)

# Test case 4: The condition in the longest matching entry is empty
def test_empty_conditions(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_2"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_2")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 5: Test logic operation `or`
def test_logic_operation_or(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_3"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_3")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 6: Test default logic operation
def test_defalut_logic_operation(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_4"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 7: Test logic operation `and`
def test_logic_operation_and(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_4"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 8: Test duplicated conditions
def test_duplicated_conditions(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_6"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark_6")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 9: Test contradicting conditions
def test_contradicting_conditions(self):
conditions, session_mock = load_test_conditions()

nodeid = "test_conditional_mark.py::test_mark_7"

marks_found = []
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)

for match in matches:
for mark_name, mark_details in list(list(match.values())[0].items()):
marks_found.append(mark_name)

if mark_name == "skip":
self.assertEqual(mark_details.get("reason"), "Skip test_conditional_mark.py::test_mark")

self.assertEqual(len(marks_found), 1)
self.assertIn('skip', marks_found)

# Test case 10: Test no matches
def test_no_matches(self):
conditions, session_mock = load_test_conditions()
nodeid = "test_conditional_mark_no_matches.py"
matches = find_all_matches(nodeid, conditions, session_mock, DYNAMIC_UPDATE_SKIP_REASON, CUSTOM_BASIC_FACTS)
self.assertFalse(matches)


if __name__ == "__main__":
unittest.main()
Loading