#!/usr/bin/env python3 # Copyright (c) 2023 Intel Corporation # # SPDX-License-Identifier: Apache-2.0 ''' This test file contains tests for platform.py module of twister ''' import sys import os from unittest import mock import pytest from contextlib import nullcontext from pykwalify.errors import SchemaError ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) from twisterlib.platform import Platform, Simulator, generate_platforms TESTDATA_1 = [ ( """\ identifier: dummy empty arch: arc """, { 'name': 'dummy empty', 'arch': 'arc', 'twister': True, 'ram': 128, 'timeout_multiplier': 1.0, 'ignore_tags': [], 'only_tags': [], 'default': False, 'binaries': [], 'flash': 512, 'supported': set(), 'vendor': '', 'tier': -1, 'type': 'na', 'simulators': [], 'supported_toolchains': [], 'env': [], 'env_satisfied': True }, '' ), ( """\ identifier: dummy full arch: riscv twister: true ram: 1024 testing: timeout_multiplier: 2.0 ignore_tags: - tag1 - tag2 only_tags: - tag3 default: true binaries: - dummy.exe - dummy.bin flash: 4096 supported: - ble - netif:openthread - gpio vendor: vendor1 tier: 1 type: unit simulation: - name: nsim exec: nsimdrv toolchain: - zephyr - llvm env: - dummynonexistentvar """, { 'name': 'dummy full', 'arch': 'riscv', 'twister': True, 'ram': 1024, 'timeout_multiplier': 2.0, 'ignore_tags': ['tag1', 'tag2'], 'only_tags': ['tag3'], 'default': True, 'binaries': ['dummy.exe', 'dummy.bin'], 'flash': 4096, 'supported': set(['ble', 'netif', 'openthread', 'gpio']), 'vendor': 'vendor1', 'tier': 1, 'type': 'unit', 'simulators': [Simulator({'name': 'nsim', 'exec': 'nsimdrv'})], 'supported_toolchains': ['zephyr', 'llvm', 'cross-compile'], 'env': ['dummynonexistentvar'], 'env_satisfied': False }, '' ), ] # This test is disabled because the Platform loading was changed significantly. # The test should be updated to reflect the new implementation. @pytest.mark.parametrize( 'platform_text, expected_data, expected_repr', TESTDATA_1, ids=['almost empty specification', 'full specification'] ) def xtest_platform_load(platform_text, expected_data, expected_repr): platform = Platform() with mock.patch('builtins.open', mock.mock_open(read_data=platform_text)): platform.load('dummy.yaml') for k, v in expected_data.items(): if not hasattr(platform, k): assert False, f'No key {k} in platform {platform}' att = getattr(platform, k) if isinstance(v, list) and not isinstance(att, list): assert False, f'Value mismatch in key {k} in platform {platform}' if isinstance(v, list): assert sorted(att) == sorted(v) else: assert att == v assert platform.__repr__() == expected_repr TESTDATA_2 = [ ( ['m0'], None, { 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', }, ), ( ['m0', 'm1'], None, { 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', 'p1e1/s1/v1', 'p1e1/s1/v2', 'p1e2/s1/v1', 'p2/s1/v1', }, ), ( ['m0', 'm1', 'm2'], None, { 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', 'p1e1/s1/v1', 'p1e1/s1/v2', 'p1e2/s1/v1', 'p2/s1/v1', 'p3@A/s2/c2', 'p3@B/s2/c2', 'p4/s1', }, ), ( ['m0', 'm3'], Exception("Duplicate platform identifier p1e1/s1 found"), None, ), ( ['m0', 'm1', 'm4'], Exception("Duplicate platform identifier p1e2/s1/v1 found"), None, ), ( ['m0', 'm5'], SchemaError(), # Unknown message as this is raised externally None, ), ] @pytest.mark.parametrize( 'roots, expected_exception, expected_platform_names', TESTDATA_2, ids=[ 'default board root', '1 extra board root', '2 extra board roots', '1 extra board root, duplicate platform', '2 extra board roots, duplicate platform', '1 extra board root, malformed yaml', ] ) def test_generate_platforms( tmp_path, roots, expected_exception, expected_platform_names, ): tmp_files = { 'm0/boards/zephyr/p1/board.yml': """\ boards: - name: p1e1 vendor: zephyr socs: - name: s1 - name: p1e2 vendor: zephyr socs: - name: s1 """, 'm0/boards/zephyr/p1/twister.yaml': """\ type: native arch: x86 variants: p1e1: twister: False p1e2: sysbuild: True """, 'm0/boards/zephyr/p2/board.yml': """\ boards: - name: p2 vendor: zephyr socs: - name: s1 """, 'm0/boards/zephyr/p2/p2.yaml': """\ identifier: p2/s1 type: sim arch: x86 vendor: vendor2 testing: default: True """, 'm0/boards/arm/p3/board.yml': """\ board: name: p3 vendor: arm revision: format: letter default: "A" revisions: - name: "A" - name: "B" socs: - name: s2 """, 'm0/boards/arm/p3/twister.yaml': """\ type: unit arch: arm vendor: vendor3 sysbuild: True variants: p3/s2/c1: testing: timeout_multiplier: 2.71828 p3@B/s2/c1: testing: timeout_multiplier: 3.14159 """, 'm0/soc/zephyr/soc.yml': """\ family: - name: zephyr series: - name: zephyr_testing socs: - name: s1 - name: s2 cpuclusters: - name: c1 """, 'm1/boards/zephyr/p1e1/board.yml': """\ board: extend: p1e1 variants: - name: v1 qualifier: s1 - name: v2 qualifier: s1 """, 'm1/boards/zephyr/p1e1/twister.yaml': """\ variants: p1e1/s1/v1: testing: default: True """, 'm1/boards/zephyr/p1e2/board.yml': """\ board: extend: p1e2 variants: - name: v1 qualifier: s1 """, 'm1/boards/zephyr/p2/board.yml': """\ board: extend: p2 variants: - name: v1 qualifier: s1 """, 'm1/boards/zephyr/p2/p2_s1_v1.yaml': """\ identifier: p2/s1/v1 """, 'm2/boards/misc/board.yml': """\ boards: - extend: p3 - name: p4 vendor: misc socs: - name: s1 """, 'm2/boards/misc/twister.yaml': """\ type: qemu arch: riscv vendor: vendor4 simulation: - name: qemu variants: p3@A/s2/c2: sysbuild: False """, 'm2/soc/zephyr/soc.yml': """\ socs: - extend: s2 cpuclusters: - name: c2 """, 'm3/boards/zephyr/p1e1/board.yml': """\ board: extend: p1e1 """, 'm3/boards/zephyr/p1e1/twister.yaml': """\ variants: p1e1/s1: name: Duplicate Platform """, 'm4/boards/zephyr/p1e2/board.yml': """\ board: extend: p2 """, 'm4/boards/zephyr/p1e2/p1e2_s1_v1.yaml': """\ identifier: p1e2/s1/v1 """, 'm5/boards/zephyr/p2/p2-2.yaml': """\ testing: ć#@%!#!#^#@%@:1.0 identifier: p2_2 type: sim arch: x86 vendor: vendor2 """, 'm5/boards/zephyr/p2/board.yml': """\ board: extend: p2 """, } for filename, content in tmp_files.items(): (tmp_path / filename).parent.mkdir(parents=True, exist_ok=True) (tmp_path / filename).write_text(content) roots = list(map(tmp_path.joinpath, roots)) with pytest.raises(type(expected_exception)) if \ expected_exception else nullcontext() as exception: platforms = list(generate_platforms(board_roots=roots, soc_roots=roots, arch_roots=roots)) if expected_exception: if expected_exception.args: assert str(expected_exception) == str(exception.value) return platform_names = {platform.name for platform in platforms} assert len(platforms) == len(platform_names) assert platform_names == expected_platform_names expected_data = { 'p1e1/s1': { 'aliases': ['p1e1/s1', 'p1e1'], # m0/boards/zephyr/p1/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p1/twister.yaml (base + variant) 'twister': False, 'arch': 'x86', 'type': 'native', }, 'p1e2/s1': { 'aliases': ['p1e2/s1', 'p1e2'], # m0/boards/zephyr/p1/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p1/twister.yaml (base + variant) 'sysbuild': True, 'arch': 'x86', 'type': 'native', }, 'p1e1/s1/v1': { 'aliases': ['p1e1/s1/v1'], # m0/boards/zephyr/p1/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p1/twister.yaml (base) # m1/boards/zephyr/p1e1/twister.yaml (variant) 'default': True, 'arch': 'x86', 'type': 'native', }, 'p1e1/s1/v2': { 'aliases': ['p1e1/s1/v2'], # m0/boards/zephyr/p1/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p1/twister.yaml (base) 'arch': 'x86', 'type': 'native', }, 'p1e2/s1/v1': { 'aliases': ['p1e2/s1/v1'], # m0/boards/zephyr/p1/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p1/twister.yaml (base) 'arch': 'x86', 'type': 'native', }, 'p2/s1': { 'aliases': ['p2/s1', 'p2'], # m0/boards/zephyr/p2/board.yml 'vendor': 'zephyr', # m0/boards/zephyr/p2/p2.yaml 'default': True, 'arch': 'x86', 'type': 'sim', }, 'p2/s1/v1': { 'aliases': ['p2/s1/v1'], # m0/boards/zephyr/p2/board.yml 'vendor': 'zephyr', # m1/boards/zephyr/p2/p2_s1_v1.yaml }, 'p3@A/s2/c1': { 'aliases': ['p3@A/s2/c1', 'p3/s2/c1'], # m0/boards/arm/p3/board.yml 'vendor': 'arm', # m0/boards/arm/p3/twister.yaml (base + variant) 'sysbuild': True, 'timeout_multiplier': 2.71828, 'arch': 'arm', 'type': 'unit', }, 'p3@B/s2/c1': { 'aliases': ['p3@B/s2/c1'], # m0/boards/arm/p3/board.yml 'vendor': 'arm', # m0/boards/arm/p3/twister.yaml (base + variant) 'sysbuild': True, 'timeout_multiplier': 3.14159, 'arch': 'arm', 'type': 'unit', }, 'p3@A/s2/c2': { 'aliases': ['p3@A/s2/c2', 'p3/s2/c2'], # m0/boards/arm/p3/board.yml 'vendor': 'arm', # m0/boards/arm/p3/twister.yaml (base) # m2/boards/misc/twister.yaml (variant) 'sysbuild': False, 'arch': 'arm', 'type': 'unit', }, 'p3@B/s2/c2': { 'aliases': ['p3@B/s2/c2'], # m0/boards/arm/p3/board.yml 'vendor': 'arm', # m0/boards/arm/p3/twister.yaml (base) 'sysbuild': True, 'arch': 'arm', 'type': 'unit', }, 'p4/s1': { 'aliases': ['p4/s1', 'p4'], # m2/boards/misc/board.yml 'vendor': 'misc', # m2/boards/misc/twister.yaml (base) 'arch': 'riscv', 'type': 'qemu', 'simulators': [Simulator({'name': 'qemu'})], 'simulation': 'qemu', }, } init_platform = Platform() for platform in platforms: expected_platform_data = expected_data[platform.name] for attr, default in vars(init_platform).items(): if attr in {'name', 'normalized_name', 'supported_toolchains'}: continue expected = expected_platform_data.get(attr, default) actual = getattr(platform, attr, None) assert expected == actual, \ f"expected '{platform}.{attr}' to be '{expected}', was '{actual}'"