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