Skip to content

Commit 113875d

Browse files
golowanowkartben
authored andcommitted
twister: testplan: Detect duplicates on --no-detailed-test-id
Detect duplicate TestSuites on load, and raise error when it happens with `--no-detailed-test-id` option which shortens TestSuite name excluding the test project path prefix, thus increasing chances for duplicates. Without this check, only the last duplicated test configuration was selected while others silently ignored. Signed-off-by: Dmitrii Golovanov <[email protected]>
1 parent 89466f9 commit 113875d

File tree

2 files changed

+57
-11
lines changed

2 files changed

+57
-11
lines changed

scripts/pylib/twister/twisterlib/testplan.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ def discover(self):
188188
num = self.add_testsuites(testsuite_filter=self.run_individual_testsuite)
189189
if num == 0:
190190
raise TwisterRuntimeError("No test cases found at the specified location...")
191+
if self.load_errors:
192+
raise TwisterRuntimeError(f"Found {self.load_errors} errors loading {num} test configurations.")
191193

192194
self.find_subtests()
193195
# get list of scenarios we have parsed into one list
@@ -197,9 +199,6 @@ def discover(self):
197199
self.report_duplicates()
198200
self.parse_configuration(config_file=self.env.test_config)
199201

200-
if self.load_errors:
201-
raise TwisterRuntimeError("Errors while loading configurations")
202-
203202
# handle quarantine
204203
ql = self.options.quarantine_list
205204
qv = self.options.quarantine_verify
@@ -605,10 +604,18 @@ def add_testsuites(self, testsuite_filter=[]):
605604
suite.add_subcases(suite_dict, subcases, ztest_suite_names)
606605
else:
607606
suite.add_subcases(suite_dict)
607+
608608
if testsuite_filter:
609609
scenario = os.path.basename(suite.name)
610610
if suite.name and (suite.name in testsuite_filter or scenario in testsuite_filter):
611611
self.testsuites[suite.name] = suite
612+
elif suite.name in self.testsuites:
613+
msg = f"test suite '{suite.name}' in '{suite.yamlfile}' is already added"
614+
if suite.yamlfile == self.testsuites[suite.name].yamlfile:
615+
logger.debug(f"Skip - {msg}")
616+
else:
617+
msg = f"Duplicate {msg} from '{self.testsuites[suite.name].yamlfile}'"
618+
raise TwisterRuntimeError(msg)
612619
else:
613620
self.testsuites[suite.name] = suite
614621

scripts/tests/twister/test_testplan.py

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,19 +1309,35 @@ def test_testplan_get_all_tests():
13091309

13101310

13111311
TESTDATA_9 = [
1312-
([], False, 7),
1313-
([], True, 5),
1314-
(['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], False, 3),
1315-
(['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], True, 0),
1312+
([], False, True, 11, 1),
1313+
([], False, False, 7, 2),
1314+
([], True, False, 9, 1),
1315+
([], True, True, 9, 1),
1316+
([], True, False, 9, 1),
1317+
(['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], False, True, 3, 1),
1318+
(['good_test/dummy.common.1', 'good_test/dummy.common.2',
1319+
'duplicate_test/dummy.common.1', 'duplicate_test/dummy.common.2'], False, True, 4, 1),
1320+
(['dummy.common.1', 'dummy.common.2'], False, False, 2, 1),
1321+
(['good_test/dummy.common.1', 'good_test/dummy.common.2', 'good_test/dummy.common.3'], True, True, 0, 1),
13161322
]
13171323

13181324
@pytest.mark.parametrize(
1319-
'testsuite_filter, use_alt_root, expected_suite_count',
1325+
'testsuite_filter, use_alt_root, detailed_id, expected_suite_count, expected_errors',
13201326
TESTDATA_9,
1321-
ids=['no testsuite filter', 'no testsuite filter, alt root',
1322-
'testsuite filter', 'testsuite filter, alt root']
1327+
ids=[
1328+
'no testsuite filter, detailed id',
1329+
'no testsuite filter, short id',
1330+
'no testsuite filter, alt root, detailed id',
1331+
'no filter, alt root, detailed id',
1332+
'no filter, alt root, short id',
1333+
'testsuite filter',
1334+
'testsuite filter and valid duplicate',
1335+
'testsuite filter, short id and duplicate',
1336+
'testsuite filter, alt root',
1337+
]
13231338
)
1324-
def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expected_suite_count):
1339+
def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, detailed_id,
1340+
expected_errors, expected_suite_count):
13251341
# tmp_path
13261342
# ├ tests <- test root
13271343
# │ ├ good_test
@@ -1330,6 +1346,8 @@ def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expec
13301346
# │ │ └ testcase.yaml
13311347
# │ ├ good_sample
13321348
# │ │ └ sample.yaml
1349+
# │ ├ duplicate_test
1350+
# │ │ └ testcase.yaml
13331351
# │ └ others
13341352
# │ └ other.txt
13351353
# └ other_tests <- alternate test root
@@ -1381,6 +1399,25 @@ def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expec
13811399
samplefile_1 = tmp_good_sample_dir / 'sample.yaml'
13821400
samplefile_1.write_text(samplecase_yaml_1)
13831401

1402+
tmp_duplicate_test_dir = tmp_test_root_dir / 'duplicate_test'
1403+
tmp_duplicate_test_dir.mkdir()
1404+
# The duplicate needs to have the same number of tests as these configurations
1405+
# can be read either with duplicate_test first, or good_test first, so number
1406+
# of selected tests needs to be the same in both situations.
1407+
testcase_yaml_4 = """\
1408+
tests:
1409+
dummy.common.1:
1410+
build_on_all: true
1411+
dummy.common.2:
1412+
build_on_all: true
1413+
dummy.common.3:
1414+
build_on_all: true
1415+
dummy.special:
1416+
build_on_all: false
1417+
"""
1418+
testfile_4 = tmp_duplicate_test_dir / 'testcase.yaml'
1419+
testfile_4.write_text(testcase_yaml_4)
1420+
13841421
tmp_other_dir = tmp_test_root_dir / 'others'
13851422
tmp_other_dir.mkdir()
13861423
_ = tmp_other_dir / 'other.txt'
@@ -1402,6 +1439,7 @@ def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expec
14021439

14031440
env = mock.Mock(
14041441
test_roots=[tmp_test_root_dir],
1442+
options=mock.Mock(detailed_test_id=detailed_id),
14051443
alt_config_root=[tmp_alt_test_root_dir] if use_alt_root else []
14061444
)
14071445

@@ -1410,6 +1448,7 @@ def test_testplan_add_testsuites(tmp_path, testsuite_filter, use_alt_root, expec
14101448
res = testplan.add_testsuites(testsuite_filter)
14111449

14121450
assert res == expected_suite_count
1451+
assert testplan.load_errors == expected_errors
14131452

14141453

14151454
def test_testplan_str():

0 commit comments

Comments
 (0)