#!/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 ''' from contextlib import nullcontext from unittest import mock import pytest from pykwalify.errors import SchemaError 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}'"