1#!/usr/bin/env python3 2# Copyright (c) 2024 Intel Corporation 3# 4# SPDX-License-Identifier: Apache-2.0 5""" 6Blackbox tests for twister's command line functions related to Twister's tooling. 7""" 8# pylint: disable=duplicate-code 9 10import importlib 11import mock 12import os 13import pytest 14import sys 15import json 16 17from conftest import ZEPHYR_BASE, TEST_DATA, sample_filename_mock, testsuite_filename_mock 18from twisterlib.statuses import TwisterStatus 19from twisterlib.testplan import TestPlan 20 21 22class TestTooling: 23 @classmethod 24 def setup_class(cls): 25 apath = os.path.join(ZEPHYR_BASE, 'scripts', 'twister') 26 cls.loader = importlib.machinery.SourceFileLoader('__main__', apath) 27 cls.spec = importlib.util.spec_from_loader(cls.loader.name, cls.loader) 28 cls.twister_module = importlib.util.module_from_spec(cls.spec) 29 30 @classmethod 31 def teardown_class(cls): 32 pass 33 34 @pytest.mark.parametrize( 35 'jobs', 36 ['1', '2'], 37 ids=['single job', 'two jobs'] 38 ) 39 @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) 40 def test_jobs(self, out_path, jobs): 41 test_platforms = ['qemu_x86', 'intel_adl_crb'] 42 path = os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic', 'group2') 43 args = ['-i', '--outdir', out_path, '-T', path] + \ 44 ['--jobs', jobs] + \ 45 [val for pair in zip( 46 ['-p'] * len(test_platforms), test_platforms 47 ) for val in pair] 48 49 with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ 50 pytest.raises(SystemExit) as sys_exit: 51 self.loader.exec_module(self.twister_module) 52 53 with open(os.path.join(out_path, 'twister.log')) as f: 54 log = f.read() 55 assert f'JOBS: {jobs}' in log 56 57 assert str(sys_exit.value) == '0' 58 59 @mock.patch.object(TestPlan, 'SAMPLE_FILENAME', sample_filename_mock) 60 def test_force_toolchain(self, out_path): 61 # nsim_vpx5 is one of the rare platforms that do not support the zephyr toolchain 62 test_platforms = ['nsim/nsim_vpx5'] 63 path = os.path.join(TEST_DATA, 'samples', 'hello_world') 64 args = ['-i', '--outdir', out_path, '-T', path, '-y'] + \ 65 ['--force-toolchain'] + \ 66 [] + \ 67 [val for pair in zip( 68 ['-p'] * len(test_platforms), test_platforms 69 ) for val in pair] 70 71 with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ 72 pytest.raises(SystemExit) as sys_exit: 73 self.loader.exec_module(self.twister_module) 74 75 assert str(sys_exit.value) == '0' 76 77 with open(os.path.join(out_path, 'testplan.json')) as f: 78 j = json.load(f) 79 filtered_j = [ 80 (ts['platform'], ts['name'], tc['identifier'], tc['status']) \ 81 for ts in j['testsuites'] \ 82 for tc in ts['testcases'] 83 ] 84 85 # Normally, board not supporting our toolchain would be filtered, so we check against that 86 assert len(filtered_j) == 1 87 assert filtered_j[0][3] != TwisterStatus.FILTER 88 89 @pytest.mark.parametrize( 90 'test_path, test_platforms', 91 [ 92 ( 93 os.path.join(TEST_DATA, 'tests', 'dummy', 'agnostic'), 94 ['qemu_x86'], 95 ) 96 ], 97 ids=[ 98 'ninja', 99 ] 100 ) 101 @pytest.mark.parametrize( 102 'flag', 103 ['--ninja', '-N'] 104 ) 105 @mock.patch.object(TestPlan, 'TESTSUITE_FILENAME', testsuite_filename_mock) 106 def test_ninja(self, capfd, out_path, test_path, test_platforms, flag): 107 args = ['--outdir', out_path, '-T', test_path, flag] + \ 108 [val for pair in zip( 109 ['-p'] * len(test_platforms), test_platforms 110 ) for val in pair] 111 112 with mock.patch.object(sys, 'argv', [sys.argv[0]] + args), \ 113 pytest.raises(SystemExit) as sys_exit: 114 self.loader.exec_module(self.twister_module) 115 116 out, err = capfd.readouterr() 117 sys.stdout.write(out) 118 sys.stderr.write(err) 119 120 assert str(sys_exit.value) == '0' 121