1#!/usr/bin/env python3 2# Copyright (c) 2023 Intel Corporation 3# 4# SPDX-License-Identifier: Apache-2.0 5 6''' 7This test file contains tests for platform.py module of twister 8''' 9import sys 10import os 11from unittest import mock 12import pytest 13 14from contextlib import nullcontext 15from pykwalify.errors import SchemaError 16 17ZEPHYR_BASE = os.getenv("ZEPHYR_BASE") 18sys.path.insert(0, os.path.join(ZEPHYR_BASE, "scripts/pylib/twister")) 19 20from twisterlib.platform import Platform, Simulator, generate_platforms 21 22 23TESTDATA_1 = [ 24 ( 25"""\ 26identifier: dummy empty 27arch: arc 28""", 29 { 30 'name': 'dummy empty', 31 'arch': 'arc', 32 'twister': True, 33 'ram': 128, 34 'timeout_multiplier': 1.0, 35 'ignore_tags': [], 36 'only_tags': [], 37 'default': False, 38 'binaries': [], 39 'flash': 512, 40 'supported': set(), 41 'vendor': '', 42 'tier': -1, 43 'type': 'na', 44 'simulators': [], 45 'supported_toolchains': [], 46 'env': [], 47 'env_satisfied': True 48 }, 49 '<dummy empty on arc>' 50 ), 51 ( 52"""\ 53identifier: dummy full 54arch: riscv 55twister: true 56ram: 1024 57testing: 58 timeout_multiplier: 2.0 59 ignore_tags: 60 - tag1 61 - tag2 62 only_tags: 63 - tag3 64 default: true 65 binaries: 66 - dummy.exe 67 - dummy.bin 68flash: 4096 69supported: 70 - ble 71 - netif:openthread 72 - gpio 73vendor: vendor1 74tier: 1 75type: unit 76simulation: 77- name: nsim 78 exec: nsimdrv 79toolchain: 80 - zephyr 81 - llvm 82env: 83 - dummynonexistentvar 84""", 85 { 86 'name': 'dummy full', 87 'arch': 'riscv', 88 'twister': True, 89 'ram': 1024, 90 'timeout_multiplier': 2.0, 91 'ignore_tags': ['tag1', 'tag2'], 92 'only_tags': ['tag3'], 93 'default': True, 94 'binaries': ['dummy.exe', 'dummy.bin'], 95 'flash': 4096, 96 'supported': set(['ble', 'netif', 'openthread', 'gpio']), 97 'vendor': 'vendor1', 98 'tier': 1, 99 'type': 'unit', 100 'simulators': [Simulator({'name': 'nsim', 'exec': 'nsimdrv'})], 101 'supported_toolchains': ['zephyr', 'llvm', 'cross-compile'], 102 'env': ['dummynonexistentvar'], 103 'env_satisfied': False 104 }, 105 '<dummy full on riscv>' 106 ), 107] 108 109# This test is disabled because the Platform loading was changed significantly. 110# The test should be updated to reflect the new implementation. 111 112@pytest.mark.parametrize( 113 'platform_text, expected_data, expected_repr', 114 TESTDATA_1, 115 ids=['almost empty specification', 'full specification'] 116) 117def xtest_platform_load(platform_text, expected_data, expected_repr): 118 platform = Platform() 119 120 with mock.patch('builtins.open', mock.mock_open(read_data=platform_text)): 121 platform.load('dummy.yaml') 122 123 for k, v in expected_data.items(): 124 if not hasattr(platform, k): 125 assert False, f'No key {k} in platform {platform}' 126 att = getattr(platform, k) 127 if isinstance(v, list) and not isinstance(att, list): 128 assert False, f'Value mismatch in key {k} in platform {platform}' 129 if isinstance(v, list): 130 assert sorted(att) == sorted(v) 131 else: 132 assert att == v 133 134 assert platform.__repr__() == expected_repr 135 136 137TESTDATA_2 = [ 138 ( 139 ['m0'], 140 None, 141 { 142 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', 143 }, 144 ), 145 ( 146 ['m0', 'm1'], 147 None, 148 { 149 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', 150 'p1e1/s1/v1', 'p1e1/s1/v2', 'p1e2/s1/v1', 'p2/s1/v1', 151 }, 152 ), 153 ( 154 ['m0', 'm1', 'm2'], 155 None, 156 { 157 'p1e1/s1', 'p1e2/s1', 'p2/s1', 'p3@A/s2/c1', 'p3@B/s2/c1', 158 'p1e1/s1/v1', 'p1e1/s1/v2', 'p1e2/s1/v1', 'p2/s1/v1', 159 'p3@A/s2/c2', 'p3@B/s2/c2', 'p4/s1', 160 }, 161 ), 162 ( 163 ['m0', 'm3'], 164 Exception("Duplicate platform identifier p1e1/s1 found"), 165 None, 166 ), 167 ( 168 ['m0', 'm1', 'm4'], 169 Exception("Duplicate platform identifier p1e2/s1/v1 found"), 170 None, 171 ), 172 ( 173 ['m0', 'm5'], 174 SchemaError(), # Unknown message as this is raised externally 175 None, 176 ), 177] 178 179@pytest.mark.parametrize( 180 'roots, expected_exception, expected_platform_names', 181 TESTDATA_2, 182 ids=[ 183 'default board root', 184 '1 extra board root', 185 '2 extra board roots', 186 '1 extra board root, duplicate platform', 187 '2 extra board roots, duplicate platform', 188 '1 extra board root, malformed yaml', 189 ] 190) 191def test_generate_platforms( 192 tmp_path, 193 roots, 194 expected_exception, 195 expected_platform_names, 196): 197 tmp_files = { 198 'm0/boards/zephyr/p1/board.yml': """\ 199boards: 200 - name: p1e1 201 vendor: zephyr 202 socs: 203 - name: s1 204 - name: p1e2 205 vendor: zephyr 206 socs: 207 - name: s1 208""", 209 'm0/boards/zephyr/p1/twister.yaml': """\ 210type: native 211arch: x86 212variants: 213 p1e1: 214 twister: False 215 p1e2: 216 sysbuild: True 217""", 218 'm0/boards/zephyr/p2/board.yml': """\ 219boards: 220 - name: p2 221 vendor: zephyr 222 socs: 223 - name: s1 224""", 225 'm0/boards/zephyr/p2/p2.yaml': """\ 226identifier: p2/s1 227type: sim 228arch: x86 229vendor: vendor2 230testing: 231 default: True 232""", 233 'm0/boards/arm/p3/board.yml': """\ 234board: 235 name: p3 236 vendor: arm 237 revision: 238 format: letter 239 default: "A" 240 revisions: 241 - name: "A" 242 - name: "B" 243 socs: 244 - name: s2 245""", 246 'm0/boards/arm/p3/twister.yaml': """\ 247type: unit 248arch: arm 249vendor: vendor3 250sysbuild: True 251variants: 252 p3/s2/c1: 253 testing: 254 timeout_multiplier: 2.71828 255 p3@B/s2/c1: 256 testing: 257 timeout_multiplier: 3.14159 258""", 259 'm0/soc/zephyr/soc.yml': """\ 260family: 261 - name: zephyr 262 series: 263 - name: zephyr_testing 264 socs: 265 - name: s1 266 - name: s2 267 cpuclusters: 268 - name: c1 269""", 270 'm1/boards/zephyr/p1e1/board.yml': """\ 271board: 272 extend: p1e1 273 variants: 274 - name: v1 275 qualifier: s1 276 - name: v2 277 qualifier: s1 278""", 279 'm1/boards/zephyr/p1e1/twister.yaml': """\ 280variants: 281 p1e1/s1/v1: 282 testing: 283 default: True 284""", 285 'm1/boards/zephyr/p1e2/board.yml': """\ 286board: 287 extend: p1e2 288 variants: 289 - name: v1 290 qualifier: s1 291""", 292 'm1/boards/zephyr/p2/board.yml': """\ 293board: 294 extend: p2 295 variants: 296 - name: v1 297 qualifier: s1 298""", 299 'm1/boards/zephyr/p2/p2_s1_v1.yaml': """\ 300identifier: p2/s1/v1 301""", 302 'm2/boards/misc/board.yml': """\ 303boards: 304 - extend: p3 305 - name: p4 306 vendor: misc 307 socs: 308 - name: s1 309""", 310 'm2/boards/misc/twister.yaml': """\ 311type: qemu 312arch: riscv 313vendor: vendor4 314simulation: 315 - name: qemu 316variants: 317 p3@A/s2/c2: 318 sysbuild: False 319""", 320 'm2/soc/zephyr/soc.yml': """\ 321socs: 322 - extend: s2 323 cpuclusters: 324 - name: c2 325""", 326 'm3/boards/zephyr/p1e1/board.yml': """\ 327board: 328 extend: p1e1 329""", 330 'm3/boards/zephyr/p1e1/twister.yaml': """\ 331variants: 332 p1e1/s1: 333 name: Duplicate Platform 334""", 335 'm4/boards/zephyr/p1e2/board.yml': """\ 336board: 337 extend: p2 338""", 339 'm4/boards/zephyr/p1e2/p1e2_s1_v1.yaml': """\ 340identifier: p1e2/s1/v1 341""", 342 'm5/boards/zephyr/p2/p2-2.yaml': """\ 343testing: 344 ć#@%!#!#^#@%@:1.0 345identifier: p2_2 346type: sim 347arch: x86 348vendor: vendor2 349""", 350 'm5/boards/zephyr/p2/board.yml': """\ 351board: 352 extend: p2 353""", 354 } 355 356 for filename, content in tmp_files.items(): 357 (tmp_path / filename).parent.mkdir(parents=True, exist_ok=True) 358 (tmp_path / filename).write_text(content) 359 360 roots = list(map(tmp_path.joinpath, roots)) 361 with pytest.raises(type(expected_exception)) if \ 362 expected_exception else nullcontext() as exception: 363 platforms = list(generate_platforms(board_roots=roots, soc_roots=roots, arch_roots=roots)) 364 365 if expected_exception: 366 if expected_exception.args: 367 assert str(expected_exception) == str(exception.value) 368 return 369 370 platform_names = {platform.name for platform in platforms} 371 assert len(platforms) == len(platform_names) 372 assert platform_names == expected_platform_names 373 374 expected_data = { 375 'p1e1/s1': { 376 'aliases': ['p1e1/s1', 'p1e1'], 377 # m0/boards/zephyr/p1/board.yml 378 'vendor': 'zephyr', 379 # m0/boards/zephyr/p1/twister.yaml (base + variant) 380 'twister': False, 381 'arch': 'x86', 382 'type': 'native', 383 }, 384 'p1e2/s1': { 385 'aliases': ['p1e2/s1', 'p1e2'], 386 # m0/boards/zephyr/p1/board.yml 387 'vendor': 'zephyr', 388 # m0/boards/zephyr/p1/twister.yaml (base + variant) 389 'sysbuild': True, 390 'arch': 'x86', 391 'type': 'native', 392 }, 393 'p1e1/s1/v1': { 394 'aliases': ['p1e1/s1/v1'], 395 # m0/boards/zephyr/p1/board.yml 396 'vendor': 'zephyr', 397 # m0/boards/zephyr/p1/twister.yaml (base) 398 # m1/boards/zephyr/p1e1/twister.yaml (variant) 399 'default': True, 400 'arch': 'x86', 401 'type': 'native', 402 }, 403 'p1e1/s1/v2': { 404 'aliases': ['p1e1/s1/v2'], 405 # m0/boards/zephyr/p1/board.yml 406 'vendor': 'zephyr', 407 # m0/boards/zephyr/p1/twister.yaml (base) 408 'arch': 'x86', 409 'type': 'native', 410 }, 411 'p1e2/s1/v1': { 412 'aliases': ['p1e2/s1/v1'], 413 # m0/boards/zephyr/p1/board.yml 414 'vendor': 'zephyr', 415 # m0/boards/zephyr/p1/twister.yaml (base) 416 'arch': 'x86', 417 'type': 'native', 418 }, 419 'p2/s1': { 420 'aliases': ['p2/s1', 'p2'], 421 # m0/boards/zephyr/p2/board.yml 422 'vendor': 'zephyr', 423 # m0/boards/zephyr/p2/p2.yaml 424 'default': True, 425 'arch': 'x86', 426 'type': 'sim', 427 }, 428 'p2/s1/v1': { 429 'aliases': ['p2/s1/v1'], 430 # m0/boards/zephyr/p2/board.yml 431 'vendor': 'zephyr', 432 # m1/boards/zephyr/p2/p2_s1_v1.yaml 433 }, 434 'p3@A/s2/c1': { 435 'aliases': ['p3@A/s2/c1', 'p3/s2/c1'], 436 # m0/boards/arm/p3/board.yml 437 'vendor': 'arm', 438 # m0/boards/arm/p3/twister.yaml (base + variant) 439 'sysbuild': True, 440 'timeout_multiplier': 2.71828, 441 'arch': 'arm', 442 'type': 'unit', 443 }, 444 'p3@B/s2/c1': { 445 'aliases': ['p3@B/s2/c1'], 446 # m0/boards/arm/p3/board.yml 447 'vendor': 'arm', 448 # m0/boards/arm/p3/twister.yaml (base + variant) 449 'sysbuild': True, 450 'timeout_multiplier': 3.14159, 451 'arch': 'arm', 452 'type': 'unit', 453 }, 454 'p3@A/s2/c2': { 455 'aliases': ['p3@A/s2/c2', 'p3/s2/c2'], 456 # m0/boards/arm/p3/board.yml 457 'vendor': 'arm', 458 # m0/boards/arm/p3/twister.yaml (base) 459 # m2/boards/misc/twister.yaml (variant) 460 'sysbuild': False, 461 'arch': 'arm', 462 'type': 'unit', 463 }, 464 'p3@B/s2/c2': { 465 'aliases': ['p3@B/s2/c2'], 466 # m0/boards/arm/p3/board.yml 467 'vendor': 'arm', 468 # m0/boards/arm/p3/twister.yaml (base) 469 'sysbuild': True, 470 'arch': 'arm', 471 'type': 'unit', 472 }, 473 'p4/s1': { 474 'aliases': ['p4/s1', 'p4'], 475 # m2/boards/misc/board.yml 476 'vendor': 'misc', 477 # m2/boards/misc/twister.yaml (base) 478 'arch': 'riscv', 479 'type': 'qemu', 480 'simulators': [Simulator({'name': 'qemu'})], 481 'simulation': 'qemu', 482 }, 483 } 484 485 init_platform = Platform() 486 for platform in platforms: 487 expected_platform_data = expected_data[platform.name] 488 for attr, default in vars(init_platform).items(): 489 if attr in {'name', 'normalized_name', 'supported_toolchains'}: 490 continue 491 expected = expected_platform_data.get(attr, default) 492 actual = getattr(platform, attr, None) 493 assert expected == actual, \ 494 f"expected '{platform}.{attr}' to be '{expected}', was '{actual}'" 495