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