|
| 1 | +# Copyright (c) Microsoft Corporation. |
| 2 | +# Licensed under the MIT license. |
| 3 | +from pathlib import Path |
| 4 | +from typing import Any, Dict, cast |
| 5 | + |
| 6 | +from lisa import ( |
| 7 | + Environment, |
| 8 | + Logger, |
| 9 | + Node, |
| 10 | + TestCaseMetadata, |
| 11 | + TestSuite, |
| 12 | + TestSuiteMetadata, |
| 13 | +) |
| 14 | +from lisa.sut_orchestrator import CLOUD_HYPERVISOR |
| 15 | +from lisa.sut_orchestrator.libvirt.ch_platform import CloudHypervisorPlatform |
| 16 | +from lisa.sut_orchestrator.libvirt.context import get_node_context as get_ch_context |
| 17 | +from lisa.sut_orchestrator.libvirt.schema import BaseLibvirtNodeSchema |
| 18 | +from lisa.testsuite import TestResult, simple_requirement |
| 19 | +from lisa.tools import Lspci |
| 20 | +from lisa.util import LisaException, SkippedException |
| 21 | + |
| 22 | + |
| 23 | +@TestSuiteMetadata( |
| 24 | + area="device_passthrough", |
| 25 | + category="functional", |
| 26 | + description=""" |
| 27 | + This test suite is for testing device passthrough functional tests. |
| 28 | + """, |
| 29 | +) |
| 30 | +class DevicePassthroughFunctionalTests(TestSuite): |
| 31 | + @TestCaseMetadata( |
| 32 | + description=""" |
| 33 | + Check if passthrough device is visible to guest. |
| 34 | + This testcase support only on CLOUD_HYPERVISOR |
| 35 | + platform of LISA. |
| 36 | + """, |
| 37 | + priority=4, |
| 38 | + requirement=simple_requirement( |
| 39 | + supported_platform_type=[CLOUD_HYPERVISOR], |
| 40 | + ), |
| 41 | + ) |
| 42 | + def verify_device_passthrough_on_guest( |
| 43 | + self, |
| 44 | + log: Logger, |
| 45 | + node: Node, |
| 46 | + environment: Environment, |
| 47 | + log_path: Path, |
| 48 | + result: TestResult, |
| 49 | + variables: Dict[str, Any], |
| 50 | + ) -> None: |
| 51 | + ctx = get_ch_context(node) |
| 52 | + if not ctx.passthrough_devices: |
| 53 | + raise SkippedException("No device-passthrough is set for node") |
| 54 | + |
| 55 | + lspci = node.tools[Lspci] |
| 56 | + platform = cast(CloudHypervisorPlatform, environment.platform) |
| 57 | + pool_vendor_device_map = {} |
| 58 | + assert platform.platform_runbook.device_pools, "Device pool cant be empty" |
| 59 | + for pool in platform.platform_runbook.device_pools: |
| 60 | + pool_type = str(pool.type.value) |
| 61 | + vendor_device_id = { |
| 62 | + "vendor_id": pool.devices[0].vendor_id, |
| 63 | + "device_id": pool.devices[0].device_id, |
| 64 | + } |
| 65 | + pool_vendor_device_map[pool_type] = vendor_device_id |
| 66 | + |
| 67 | + assert environment.runbook.nodes_requirement, "requirement cant be empty" |
| 68 | + for node_space in environment.runbook.nodes_requirement: |
| 69 | + node_runbook: BaseLibvirtNodeSchema = node_space.get_extended_runbook( |
| 70 | + BaseLibvirtNodeSchema, CLOUD_HYPERVISOR |
| 71 | + ) |
| 72 | + assert node_runbook.device_passthrough, "device_passthrough cant be empty" |
| 73 | + for req in node_runbook.device_passthrough: |
| 74 | + pool_type = str(req.pool_type.value) |
| 75 | + ven_dev_id_of_pool = pool_vendor_device_map[pool_type] |
| 76 | + ven_id = ven_dev_id_of_pool["vendor_id"] |
| 77 | + dev_id = ven_dev_id_of_pool["device_id"] |
| 78 | + devices = lspci.get_devices_by_vendor_device_id( |
| 79 | + vendor_id=ven_id, |
| 80 | + device_id=dev_id, |
| 81 | + force_run=True, |
| 82 | + ) |
| 83 | + if len(devices) != req.count: |
| 84 | + raise LisaException( |
| 85 | + f"Device count don't match, got total: {len(devices)} " |
| 86 | + f"As per runbook, Required device count: {req.count}, " |
| 87 | + f"for pool_type: {pool_type} having Vendor/Device ID as " |
| 88 | + f"vendor_id = {ven_id}, device_id={dev_id}" |
| 89 | + ) |
0 commit comments