diff --git a/scripts/tests/twister_blackbox/conftest.py b/scripts/tests/twister_blackbox/conftest.py index b0b41219f8a..d856261f276 100644 --- a/scripts/tests/twister_blackbox/conftest.py +++ b/scripts/tests/twister_blackbox/conftest.py @@ -21,6 +21,7 @@ sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts")) +sample_filename_mock = mock.PropertyMock(return_value='test_sample.yaml') testsuite_filename_mock = mock.PropertyMock(return_value='test_data.yaml') sample_filename_mock = mock.PropertyMock(return_value='test_sample.yaml') diff --git a/scripts/tests/twister_blackbox/pytest.ini b/scripts/tests/twister_blackbox/pytest.ini new file mode 100644 index 00000000000..d97cd121c92 --- /dev/null +++ b/scripts/tests/twister_blackbox/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +norecursedirs = test_data *.egg .* _darcs build CVS dist node_modules venv {arch} \ No newline at end of file diff --git a/scripts/tests/twister_blackbox/test_addon.py b/scripts/tests/twister_blackbox/test_addon.py new file mode 100644 index 00000000000..9bc0d50b952 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_addon.py @@ -0,0 +1,339 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +""" +Blackbox tests for twister's command line functions concerning addons to normal functions +""" + +import importlib +import mock +import os +import pkg_resources +import pytest +import re +import shutil +import subprocess +import sys + +from conftest import ZEPHYR_BASE, TEST_DATA, sample_filename_mock, testsuite_filename_mock +from twisterlib.testplan import TestPlan + + +class TestAddon: + @classmethod + def setup_class(cls): + apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') + cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) + cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) + cls.twister_module = importlib.util.module_from_spec(cls.spec) + + @classmethod + def teardown_class(cls): + pass + + @pytest.mark.parametrize( + 'ubsan_flags, expected_exit_value', + [ + # No sanitiser, no problem + ([], '0'), + # Sanitiser catches a mistake, error is raised + (['--enable-ubsan'], '1') + ], + ids=['no sanitiser', 'ubsan'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_enable_ubsan(self, out_path, ubsan_flags, expected_exit_value): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'san', 'ubsan') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + ubsan_flags + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + assert str(sys_exit.value) == expected_exit_value + + @pytest.mark.parametrize( + 'lsan_flags, expected_exit_value', + [ + # No sanitiser, no problem + ([], '0'), + # Sanitiser catches a mistake, error is raised + (['--enable-asan', '--enable-lsan'], '1') + ], + ids=['no sanitiser', 'lsan'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_enable_lsan(self, out_path, lsan_flags, expected_exit_value): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'san', 'lsan') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + lsan_flags + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + assert str(sys_exit.value) == expected_exit_value + + @pytest.mark.parametrize( + 'asan_flags, expected_exit_value, expect_asan', + [ + # No sanitiser, no problem + # Note that on some runs it may fail, + # as the process is killed instead of ending normally. + # This is not 100% repeatable, so this test is removed for now. + # ([], '0', False), + # Sanitiser catches a mistake, error is raised + (['--enable-asan'], '1', True) + ], + ids=[ + #'no sanitiser', + 'asan' + ] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_enable_asan(self, capfd, out_path, asan_flags, expected_exit_value, expect_asan): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'san', 'asan') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + asan_flags + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + assert str(sys_exit.value) == expected_exit_value + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + asan_template = r'^==\d+==ERROR:\s+AddressSanitizer:' + assert expect_asan == bool(re.search(asan_template, err, re.MULTILINE)) + + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_extra_test_args(self, capfd, out_path): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'params', 'dummy') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + [] + \ + ['-vvv'] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + \ + ['--', '-list'] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + # Use of -list makes tests not run. + # Thus, the tests 'failed'. + assert str(sys_exit.value) == '1' + + out, err = capfd.readouterr() + sys.stdout.write(out) + sys.stderr.write(err) + + expected_test_names = [ + 'param_tests::test_assert1', + 'param_tests::test_assert2', + 'param_tests::test_assert3', + ] + assert all([testname in err for testname in expected_test_names]) + + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_extra_args(self, caplog, out_path): + test_platforms = ['qemu_x86', 'frdm_k64f'] + path = os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic', 'group2') + args = ['--outdir', out_path, '-T', path] + \ + ['--extra-args', 'USE_CCACHE=0', '--extra-args', 'DUMMY=1'] + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + assert str(sys_exit.value) == '0' + + with open(os.path.join(out_path, 'twister.log')) as f: + twister_log = f.read() + + pattern_cache = r'Calling cmake: [^\n]+ -DUSE_CCACHE=0 [^\n]+\n' + pattern_dummy = r'Calling cmake: [^\n]+ -DDUMMY=1 [^\n]+\n' + + assert ' -DUSE_CCACHE=0 ' in twister_log + res = re.search(pattern_cache, twister_log) + assert res + + assert ' -DDUMMY=1 ' in twister_log + res = re.search(pattern_dummy, twister_log) + assert res + + # This test is not side-effect free. + # It installs and uninstalls pytest-twister-harness using pip + # It uses pip to check whether that plugin is previously installed + # and reinstalls it if detected at the start of its run. + # However, it does NOT restore the original plugin, ONLY reinstalls it. + @pytest.mark.parametrize( + 'allow_flags, do_install, expected_exit_value, expected_logs', + [ + ([], True, '1', ['By default Twister should work without pytest-twister-harness' + ' plugin being installed, so please, uninstall it by' + ' `pip uninstall pytest-twister-harness` and' + ' `git clean -dxf scripts/pylib/pytest-twister-harness`.']), + (['--allow-installed-plugin'], True, '0', ['You work with installed version' + ' of pytest-twister-harness plugin.']), + ([], False, '0', []), + (['--allow-installed-plugin'], False, '0', []), + ], + ids=['installed, but not allowed', 'installed, allowed', + 'not installed, not allowed', 'not installed, but allowed'] + ) + @mock.patch.object(TestPlan, 'SAMPLE_FILENAME', sample_filename_mock) + def test_allow_installed_plugin(self, caplog, out_path, allow_flags, do_install, + expected_exit_value, expected_logs): + environment_twister_module = importlib.import_module('twisterlib.environment') + harness_twister_module = importlib.import_module('twisterlib.harness') + runner_twister_module = importlib.import_module('twisterlib.runner') + + pth_path = os.path.join(ZEPHYR_BASE, 'scripts', 'pylib', 'pytest-twister-harness') + check_installed_command = [sys.executable, '-m', 'pip', 'list'] + install_command = [sys.executable, '-m', 'pip', 'install', '--no-input', pth_path] + uninstall_command = [sys.executable, '-m', 'pip', 'uninstall', '--yes', + 'pytest-twister-harness'] + + def big_uninstall(): + pth_path = os.path.join(ZEPHYR_BASE, 'scripts', 'pylib', 'pytest-twister-harness') + + subprocess.run(uninstall_command, check=True,) + + # For our registration to work, we have to delete the installation cache + additional_cache_paths = [ + # Plugin cache + os.path.join(pth_path, 'src', 'pytest_twister_harness.egg-info'), + # Additional caches + os.path.join(pth_path, 'src', 'pytest_twister_harness', '__pycache__'), + os.path.join(pth_path, 'src', 'pytest_twister_harness', 'device', '__pycache__'), + os.path.join(pth_path, 'src', 'pytest_twister_harness', 'helpers', '__pycache__'), + os.path.join(pth_path, 'src', 'pytest_twister_harness', 'build'), + ] + + for additional_cache_path in additional_cache_paths: + if os.path.exists(additional_cache_path): + if os.path.isfile(additional_cache_path): + os.unlink(additional_cache_path) + else: + shutil.rmtree(additional_cache_path) + + # To refresh the PYTEST_PLUGIN_INSTALLED global variable + def refresh_plugin_installed_variable(): + pkg_resources._initialize_master_working_set() + importlib.reload(environment_twister_module) + importlib.reload(harness_twister_module) + importlib.reload(runner_twister_module) + + check_installed_result = subprocess.run(check_installed_command, check=True, + capture_output=True, text=True) + previously_installed = 'pytest-twister-harness' in check_installed_result.stdout + + # To ensure consistent test start + big_uninstall() + + if do_install: + subprocess.run(install_command, check=True) + + # Refresh before the test, no matter the testcase + refresh_plugin_installed_variable() + + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'samples', 'pytest', 'shell') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + allow_flags + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + # To ensure consistent test exit, prevent dehermetisation + if do_install: + big_uninstall() + + # To restore previously-installed plugin as well as we can + if previously_installed: + subprocess.run(install_command, check=True) + + if previously_installed or do_install: + refresh_plugin_installed_variable() + + assert str(sys_exit.value) == expected_exit_value + + assert all([log in caplog.text for log in expected_logs]) + + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_pytest_args(self, out_path): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'pytest') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + ['--pytest-args=--custom-pytest-arg', '--pytest-args=foo', + '--pytest-args=--cmdopt', '--pytest-args=.'] + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + # YAML was modified so that the test will fail without command line override. + assert str(sys_exit.value) == '0' + + @pytest.mark.parametrize( + 'valgrind_flags, expected_exit_value', + [ + # No sanitiser, leak is ignored + ([], '0'), + # Sanitiser catches a mistake, error is raised + (['--enable-valgrind'], '1') + ], + ids=['no valgrind', 'valgrind'] + ) + @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) + def test_enable_valgrind(self, capfd, out_path, valgrind_flags, expected_exit_value): + test_platforms = ['native_sim'] + test_path = os.path.join(TEST_DATA, 'tests', 'san', 'val') + args = ['-i', '--outdir', out_path, '-T', test_path] + \ + valgrind_flags + \ + [] + \ + [val for pair in zip( + ['-p'] * len(test_platforms), test_platforms + ) for val in pair] + + with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ + pytest.raises(SystemExit) as sys_exit: + self.loader.exec_module(self.twister_module) + + assert str(sys_exit.value) == expected_exit_value diff --git a/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/CMakeLists.txt new file mode 100644 index 00000000000..a8fae2b9931 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(shell) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/prj.conf b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/prj.conf new file mode 100644 index 00000000000..37788381065 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/prj.conf @@ -0,0 +1,5 @@ +CONFIG_PRINTK=y +CONFIG_SHELL=y +CONFIG_LOG=y +CONFIG_SHELL_BACKEND_SERIAL=y +CONFIG_KERNEL_SHELL=y diff --git a/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/pytest/test_shell.py b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/pytest/test_shell.py new file mode 100755 index 00000000000..84d16ec1e5a --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/pytest/test_shell.py @@ -0,0 +1,23 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +import logging + +from twister_harness import Shell + +logger = logging.getLogger(__name__) + + +def test_shell_print_help(shell: Shell): + logger.info('send "help" command') + lines = shell.exec_command('help') + assert 'Available commands:' in lines, 'expected response not found' + logger.info('response is valid') + + +def test_shell_print_version(shell: Shell): + logger.info('send "kernel version" command') + lines = shell.exec_command('kernel version') + assert any(['Zephyr version' in line for line in lines]), 'expected response not found' + logger.info('response is valid') diff --git a/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/src/main.c b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/src/main.c new file mode 100644 index 00000000000..98394897582 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/src/main.c @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +int main(void) +{ + /* Shell application source code is injected by applied Kconfg SHELL + * options, no more "extra" functionalities are required for exemplary + * pytest test. + */ + return 0; +} diff --git a/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/test_sample.yaml b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/test_sample.yaml new file mode 100644 index 00000000000..86b9314f444 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/samples/pytest/shell/test_sample.yaml @@ -0,0 +1,14 @@ +tests: + sample.pytest.shell: + filter: CONFIG_SERIAL and dt_chosen_enabled("zephyr,shell-uart") + min_ram: 40 + harness: pytest + extra_configs: + - arch:posix:CONFIG_NATIVE_UART_0_ON_STDINOUT=y + integration_platforms: + - native_sim + - qemu_cortex_m3 + tags: + - test_framework + - pytest + - shell diff --git a/scripts/tests/twister_blackbox/test_data/tests/params/dummy/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/params/dummy/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/params/dummy/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/src/main.c new file mode 100644 index 00000000000..84bff77a989 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/src/main.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + + +ZTEST_SUITE(param_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(param_tests, test_assert1) +{ + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} +ZTEST(param_tests, test_assert2) +{ + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} +ZTEST(param_tests, test_assert3) +{ + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/params/dummy/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/test_data.yaml new file mode 100644 index 00000000000..cc12db26ab3 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/params/dummy/test_data.yaml @@ -0,0 +1,9 @@ +tests: + params.dummy: + platform_allow: + - native_sim + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_sim + tags: params diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/pytest/CMakeLists.txt new file mode 100644 index 00000000000..b5ff04dd824 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(pytest_sample) + +target_sources(app PRIVATE src/main.c) diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/pytest/prj.conf new file mode 100644 index 00000000000..c3e81438ced --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/prj.conf @@ -0,0 +1,2 @@ +CONFIG_ZTEST=y +CONFIG_IDLE_STACK_SIZE=4096 diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/conftest.py b/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/conftest.py new file mode 100644 index 00000000000..75b5c585273 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/conftest.py @@ -0,0 +1,27 @@ +# Copyright (c) 2020 Intel Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +import pytest + +# add option "--cmdopt" to pytest, or it will report "unknown option" +# this option is passed from twister. +def pytest_addoption(parser): + parser.addoption( + '--cmdopt' + ) + parser.addoption( + '--custom-pytest-arg' + ) + +# define fixture to return value of option "--cmdopt", this fixture +# will be requested by other fixture of tests. +@pytest.fixture() +def cmdopt(request): + return request.config.getoption('--cmdopt') + +# define fixture to return value of option "--custom-pytest-arg", this fixture +# will be requested by other fixture of tests. +@pytest.fixture() +def custom_pytest_arg(request): + return request.config.getoption('--custom-pytest-arg') diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/test_sample.py b/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/test_sample.py new file mode 100755 index 00000000000..33b6b8d6a6d --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/pytest/test_sample.py @@ -0,0 +1,42 @@ +# Copyright (c) 2020 Intel Corporation. +# +# SPDX-License-Identifier: Apache-2.0 + +import os +import pytest + +# fixture cmdopt defined in conftest.py, it can be requested either in +# tests or in other fixtures + +@pytest.fixture(autouse=True) +def pytest_cmdopt_handle(cmdopt): + ''' An auto fixture, all tests automatically request this fixture. + Argument "cmdopt" is a fixture defined in conftest.py, it returns + the value of an option passed by twister, this fixture export + that value to environment. + ''' + print("handle cmdopt:") + print(cmdopt) + data_path = cmdopt + os.environ['data_path'] = str(data_path) + +def test_case(cmdopt): + ''' Test cases make use of fixture cmdopt to get the value of "--cmdopt" option + passed by twister. Actually, fixture cmdopt returns a path of the directory + which holds the artifacts generated by ztest. The main work of test cases + in this file is to check those stuff in that directory. + This test case simply compare the return value of cmdopt with the + environment variable exported by fixture pytest_cmdopt_handle. + ''' + assert os.path.exists(cmdopt) + + print("run test cases in:") + print(cmdopt) + +def test_custom_arg(custom_pytest_arg): + ''' Test passing of custom command line arguments to pytest. + ''' + assert custom_pytest_arg == "foo" + +if __name__ == "__main__": + pytest.main() diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/pytest/src/main.c new file mode 100644 index 00000000000..49fae9559a3 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/src/main.c @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2020 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + +ZTEST_SUITE(test_pytest, NULL, NULL, NULL, NULL, NULL); + +ZTEST(test_pytest, test_pytest) +{ + TC_PRINT("Hello world\n"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/pytest/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/pytest/test_data.yaml new file mode 100644 index 00000000000..6dc504cd64c --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/pytest/test_data.yaml @@ -0,0 +1,13 @@ +tests: + sample.twister.pytest: + platform_allow: + - native_posix + - native_sim + harness: pytest + harness_config: + pytest_args: ["--custom-pytest-arg", "foo", "--cmdopt", "."] + tags: + - test_framework + - pytest + integration_platforms: + - native_sim diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/asan/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/san/asan/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/asan/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/asan/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/san/asan/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/asan/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/asan/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/san/asan/src/main.c new file mode 100644 index 00000000000..aa69e1f9710 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/asan/src/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +int *ptr; + +int helper(void) +{ + char *s = malloc(10); + + strcpy(s, "123456789"); + s[9] = '0'; + free(s); + strcpy(s, "Hello"); + printf("string is: %s\n", s); + + return 0; +} + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + helper(); + + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/asan/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/san/asan/test_data.yaml new file mode 100644 index 00000000000..47d2d4b2387 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/asan/test_data.yaml @@ -0,0 +1,11 @@ +tests: + san.asan: + platform_allow: + - native_sim + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_sim + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/lsan/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/lsan/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/lsan/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/src/main.c new file mode 100644 index 00000000000..a3f63d309a2 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/src/main.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +int helper(void) +{ + char *s = malloc(100); + + s[0] = '!'; + s[1] = '\0'; + printf("string is: %s\n", s); + return 0; +} + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + helper(); + + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/lsan/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/test_data.yaml new file mode 100644 index 00000000000..01d6978a5ce --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/lsan/test_data.yaml @@ -0,0 +1,11 @@ +tests: + san.lsan: + platform_allow: + - native_sim + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_sim + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/src/main.c new file mode 100644 index 00000000000..b81e0799750 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/src/main.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + int k = INT_MAX; + + k += 256; + printf("num is: %d\n", k); + + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/test_data.yaml new file mode 100644 index 00000000000..f4efff55c4b --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/ubsan/test_data.yaml @@ -0,0 +1,11 @@ +tests: + san.ubsan: + platform_allow: + - native_sim + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_sim + tags: + - agnostic + - subgrouped diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/val/CMakeLists.txt b/scripts/tests/twister_blackbox/test_data/tests/san/val/CMakeLists.txt new file mode 100644 index 00000000000..635c696edf9 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/val/CMakeLists.txt @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(integration) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/val/prj.conf b/scripts/tests/twister_blackbox/test_data/tests/san/val/prj.conf new file mode 100644 index 00000000000..9467c292689 --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/val/prj.conf @@ -0,0 +1 @@ +CONFIG_ZTEST=y diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/val/src/main.c b/scripts/tests/twister_blackbox/test_data/tests/san/val/src/main.c new file mode 100644 index 00000000000..38ee6f7c1bf --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/val/src/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include + +#include + + +ZTEST_SUITE(a1_1_tests, NULL, NULL, NULL, NULL, NULL); + +/** + * @brief Test Asserts + * + * This test verifies various assert macros provided by ztest. + * + */ +ZTEST(a1_1_tests, test_assert) +{ + char *s = malloc(10); + + strcpy(s, "123456789"); + printf("string is: %s\n", s); + + zassert_true(1, "1 was false"); + zassert_false(0, "0 was true"); + zassert_is_null(NULL, "NULL was not NULL"); + zassert_not_null("foo", "\"foo\" was NULL"); + zassert_equal(1, 1, "1 was not equal to 1"); + zassert_equal_ptr(NULL, NULL, "NULL was not equal to NULL"); +} diff --git a/scripts/tests/twister_blackbox/test_data/tests/san/val/test_data.yaml b/scripts/tests/twister_blackbox/test_data/tests/san/val/test_data.yaml new file mode 100644 index 00000000000..0c2027624cc --- /dev/null +++ b/scripts/tests/twister_blackbox/test_data/tests/san/val/test_data.yaml @@ -0,0 +1,11 @@ +tests: + san.valgrind: + platform_allow: + - native_sim + - qemu_x86 + - qemu_x86_64 + integration_platforms: + - native_sim + tags: + - agnostic + - subgrouped