Add comprehensive PCIe device support to Sushy
Implement complete Redfish PCIeDevice v1.19.0 specification support including PCIeDevice and PCIeDeviceCollection resources embedded data support. - Add PCIeDevice resource with schema compliance - Support embedded PCIeDevices (Dell iDRAC pattern) - Add methods for device inspection - Comprehensive test coverage included onnboard devices too - Handle both standard and embedded PCIeDevices patterns Change-Id: I0326d5c2985e1b09828daa0f003b147f09628d3a Signed-off-by: Nidhi Rai <nidhi.rai94@gmail.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Adds comprehensive PCIeDevice resource support implementing the complete
|
||||||
|
Redfish PCIeDevice v1.19.0 specification. The new pcie_devices property
|
||||||
|
on System objects provides access to PCIe device collections with support
|
||||||
|
for both standard Redfish collections and embedded PCIeDevices (Dell iDRAC).
|
||||||
|
|
||||||
|
Features include full schema compliance, PCIe interface information and
|
||||||
|
slot details.
|
189
sushy/resources/system/pcie_device.py
Normal file
189
sushy/resources/system/pcie_device.py
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
# This is referred from Redfish standard schema.
|
||||||
|
# https://redfish.dmtf.org/schemas/v1/PCIeDevice.v1_19_0.json
|
||||||
|
# Per DMTF DSP0268_2025.2 Section 6.96 PCIeDevice 1.19.0
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sushy.resources import base
|
||||||
|
from sushy.resources import common
|
||||||
|
from sushy import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeInterfaceField(base.CompositeField):
|
||||||
|
"""PCIe interface information for the device."""
|
||||||
|
|
||||||
|
lanes_in_use = base.Field('LanesInUse', adapter=utils.int_or_none)
|
||||||
|
"""The number of PCIe lanes in use by this device."""
|
||||||
|
|
||||||
|
max_lanes = base.Field('MaxLanes', adapter=utils.int_or_none)
|
||||||
|
"""The number of PCIe lanes supported by this device."""
|
||||||
|
|
||||||
|
max_pcie_type = base.Field('MaxPCIeType')
|
||||||
|
"""The highest version of the PCIe specification supported by this
|
||||||
|
device."""
|
||||||
|
pcie_type = base.Field('PCIeType')
|
||||||
|
"""The version of the PCIe specification in use by this device."""
|
||||||
|
|
||||||
|
|
||||||
|
class SlotField(base.CompositeField):
|
||||||
|
"""Slot information for the PCIe device."""
|
||||||
|
|
||||||
|
lanes = base.Field('Lanes', adapter=utils.int_or_none)
|
||||||
|
"""The number of PCIe lanes supported by this slot."""
|
||||||
|
|
||||||
|
location = base.Field('Location')
|
||||||
|
"""The location of the PCIe slot."""
|
||||||
|
|
||||||
|
pcie_type = base.Field('PCIeType')
|
||||||
|
"""The PCIe specification this slot supports."""
|
||||||
|
|
||||||
|
slot_type = base.Field('SlotType')
|
||||||
|
"""The PCIe slot type."""
|
||||||
|
|
||||||
|
hot_pluggable = base.Field('HotPluggable', adapter=bool)
|
||||||
|
"""An indication of whether this PCIe slot supports hotplug."""
|
||||||
|
|
||||||
|
lane_splitting = base.Field('LaneSplitting')
|
||||||
|
"""The lane splitting strategy used in the PCIe slot."""
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeDevice(base.ResourceBase):
|
||||||
|
"""Represents a PCIe device associated with a system."""
|
||||||
|
|
||||||
|
identity = base.Field('Id', required=True)
|
||||||
|
"""The PCIe device identity string"""
|
||||||
|
|
||||||
|
name = base.Field('Name')
|
||||||
|
"""The PCIe device name"""
|
||||||
|
|
||||||
|
description = base.Field('Description')
|
||||||
|
"""The PCIe device description"""
|
||||||
|
|
||||||
|
manufacturer = base.Field('Manufacturer')
|
||||||
|
"""The manufacturer of this PCIe device."""
|
||||||
|
|
||||||
|
model = base.Field('Model')
|
||||||
|
"""The model number for the PCIe device."""
|
||||||
|
|
||||||
|
serial_number = base.Field('SerialNumber')
|
||||||
|
"""The serial number for this PCIe device."""
|
||||||
|
|
||||||
|
part_number = base.Field('PartNumber')
|
||||||
|
"""The part number for this PCIe device."""
|
||||||
|
|
||||||
|
sku = base.Field('SKU')
|
||||||
|
"""The stock-keeping unit for this PCIe device."""
|
||||||
|
|
||||||
|
device_type = base.Field('DeviceType')
|
||||||
|
"""The device type for this PCIe device."""
|
||||||
|
|
||||||
|
firmware_version = base.Field('FirmwareVersion')
|
||||||
|
"""The version of firmware for this PCIe device."""
|
||||||
|
|
||||||
|
asset_tag = base.Field('AssetTag')
|
||||||
|
"""The user-assigned asset tag for this PCIe device."""
|
||||||
|
|
||||||
|
status = common.StatusField('Status')
|
||||||
|
"""The status and health of the resource and its subordinate resources."""
|
||||||
|
|
||||||
|
pcie_interface = PCIeInterfaceField('PCIeInterface')
|
||||||
|
"""The PCIe interface details for this device."""
|
||||||
|
|
||||||
|
slot = SlotField('Slot')
|
||||||
|
"""Information about the slot for this PCIe device."""
|
||||||
|
|
||||||
|
links = base.Field('Links')
|
||||||
|
"""Links to related resources."""
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeDeviceCollection(base.ResourceCollectionBase):
|
||||||
|
@property
|
||||||
|
def _resource_type(self):
|
||||||
|
return PCIeDevice
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def device_count(self):
|
||||||
|
"""The number of PCIe devices in the collection.
|
||||||
|
|
||||||
|
Returns the cached value until it (or its parent resource)
|
||||||
|
is refreshed.
|
||||||
|
"""
|
||||||
|
return len(self.get_members())
|
||||||
|
|
||||||
|
def __init__(self, connector, path, redfish_version=None, registries=None,
|
||||||
|
root=None, embedded_data=None):
|
||||||
|
if path == "/empty":
|
||||||
|
self._conn = connector
|
||||||
|
self._path = path
|
||||||
|
self._json = {'Members': []}
|
||||||
|
self.redfish_version = redfish_version
|
||||||
|
self._registries = registries
|
||||||
|
self._root = root
|
||||||
|
self._is_stale = False
|
||||||
|
return
|
||||||
|
|
||||||
|
if embedded_data is not None:
|
||||||
|
self._conn = connector
|
||||||
|
self._path = path
|
||||||
|
self._json = {'Members': embedded_data}
|
||||||
|
self.redfish_version = redfish_version
|
||||||
|
self._registries = registries
|
||||||
|
self._root = root
|
||||||
|
self._is_stale = False
|
||||||
|
return
|
||||||
|
|
||||||
|
super().__init__(connector, path, redfish_version, registries, root)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def members_identities(self):
|
||||||
|
if self._path == "/empty":
|
||||||
|
return []
|
||||||
|
if hasattr(self, '_json') and self._json and 'Members' in self._json:
|
||||||
|
return tuple(m['@odata.id'] for m in self._json['Members']
|
||||||
|
if isinstance(m, dict) and '@odata.id' in m)
|
||||||
|
return super().members_identities
|
||||||
|
|
||||||
|
def get_members(self):
|
||||||
|
if self._path == "/empty":
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Handle embedded PCIeDevices case
|
||||||
|
if hasattr(self, '_json') and self._json and 'Members' in self._json:
|
||||||
|
device_objects = []
|
||||||
|
for member in self._json['Members']:
|
||||||
|
if isinstance(member, dict) and '@odata.id' in member:
|
||||||
|
device_path = member['@odata.id']
|
||||||
|
try:
|
||||||
|
# Fetch device data and create object
|
||||||
|
device_response = self._conn.get(device_path)
|
||||||
|
if device_response:
|
||||||
|
device_obj = PCIeDevice(
|
||||||
|
self._conn, device_path,
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
registries=self._registries, root=self._root
|
||||||
|
)
|
||||||
|
device_obj._json = device_response.json()
|
||||||
|
device_objects.append(device_obj)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.warning(
|
||||||
|
'Error fetching PCIe device at path %s: %s',
|
||||||
|
device_path, str(e))
|
||||||
|
continue # Skip failed devices but continue processing
|
||||||
|
return device_objects
|
||||||
|
|
||||||
|
# Standard collection behavior
|
||||||
|
return super().get_members()
|
@@ -32,6 +32,7 @@ from sushy.resources import settings
|
|||||||
from sushy.resources.system import bios
|
from sushy.resources.system import bios
|
||||||
from sushy.resources.system import constants as sys_cons
|
from sushy.resources.system import constants as sys_cons
|
||||||
from sushy.resources.system import ethernet_interface
|
from sushy.resources.system import ethernet_interface
|
||||||
|
from sushy.resources.system import pcie_device
|
||||||
from sushy.resources.system import processor
|
from sushy.resources.system import processor
|
||||||
from sushy.resources.system import secure_boot
|
from sushy.resources.system import secure_boot
|
||||||
from sushy.resources.system import simple_storage as sys_simple_storage
|
from sushy.resources.system import simple_storage as sys_simple_storage
|
||||||
@@ -674,6 +675,32 @@ class System(base.ResourceBase):
|
|||||||
redfish_version=self.redfish_version, registries=self.registries,
|
redfish_version=self.redfish_version, registries=self.registries,
|
||||||
root=self.root)
|
root=self.root)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@utils.cache_it
|
||||||
|
def pcie_devices(self):
|
||||||
|
"""Property to reference PCIeDeviceCollection instance"""
|
||||||
|
try:
|
||||||
|
pcie_path = utils.get_sub_resource_path_by(self, "PCIeDevices")
|
||||||
|
return pcie_device.PCIeDeviceCollection(
|
||||||
|
self._conn, pcie_path,
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
registries=self.registries, root=self.root)
|
||||||
|
except exceptions.MissingAttributeError:
|
||||||
|
# Check if PCIeDevices is embedded in System JSON
|
||||||
|
if (hasattr(self, 'json') and self.json
|
||||||
|
and 'PCIeDevices' in self.json):
|
||||||
|
pcie_devices_data = self.json['PCIeDevices']
|
||||||
|
if isinstance(pcie_devices_data, list) and pcie_devices_data:
|
||||||
|
return pcie_device.PCIeDeviceCollection(
|
||||||
|
self._conn, "/embedded",
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
registries=self.registries, root=self.root,
|
||||||
|
embedded_data=pcie_devices_data)
|
||||||
|
return pcie_device.PCIeDeviceCollection(
|
||||||
|
self._conn, "/empty",
|
||||||
|
redfish_version=self.redfish_version,
|
||||||
|
registries=self.registries, root=self.root)
|
||||||
|
|
||||||
|
|
||||||
class SystemCollection(base.ResourceCollectionBase):
|
class SystemCollection(base.ResourceCollectionBase):
|
||||||
|
|
||||||
|
71
sushy/tests/unit/json_samples/pcie_device.json
Normal file
71
sushy/tests/unit/json_samples/pcie_device.json
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#PCIeDevice.PCIeDevice",
|
||||||
|
"@odata.etag": "\"1756839817\"",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0",
|
||||||
|
"@odata.type": "#PCIeDevice.v1_11_1.PCIeDevice",
|
||||||
|
"AssetTag": null,
|
||||||
|
"Description": "BCM957414A4142CC 10Gb/25Gb Ethernet PCIe",
|
||||||
|
"DeviceType": "MultiFunction",
|
||||||
|
"FirmwareVersion": "224.1.102.0",
|
||||||
|
"Id": "196-0",
|
||||||
|
"Links": {
|
||||||
|
"Chassis": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Chassis@odata.count": 1,
|
||||||
|
"Oem": {
|
||||||
|
"Dell": {
|
||||||
|
"@odata.type": "#DellOem.v1_3_0.DellOemLinks",
|
||||||
|
"CPUAffinity": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Systems/System.Embedded.1/Processors/CPU.Socket.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"CPUAffinity@odata.count": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PCIeFunctions": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0/PCIeFunctions/196-0-1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0/PCIeFunctions/196-0-0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PCIeFunctions@odata.count": 2,
|
||||||
|
"PCIeFunctions@Redfish.Deprecated": "Please migrate to PCIeFunctions property in the root resource."
|
||||||
|
},
|
||||||
|
"Manufacturer": "Broadcom Inc. and subsidiaries",
|
||||||
|
"Model": null,
|
||||||
|
"Name": "BCM957414A4142CC 10Gb/25Gb Ethernet PCIe",
|
||||||
|
"PartNumber": null,
|
||||||
|
"SKU": null,
|
||||||
|
"SerialNumber": null,
|
||||||
|
"Slot": {
|
||||||
|
"Lanes": 8,
|
||||||
|
"Location": {
|
||||||
|
"PartLocation": {
|
||||||
|
"LocationOrdinalValue": 1,
|
||||||
|
"LocationType": "Slot"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PCIeType": "Gen5",
|
||||||
|
"SlotType": "HalfLength"
|
||||||
|
},
|
||||||
|
"PCIeInterface": {
|
||||||
|
"MaxPCIeType": "Gen5",
|
||||||
|
"PCIeType": "Gen5",
|
||||||
|
"MaxLanes": 8,
|
||||||
|
"LanesInUse": 8
|
||||||
|
},
|
||||||
|
"Status": {
|
||||||
|
"State": "Enabled",
|
||||||
|
"Health": "OK",
|
||||||
|
"HealthRollup": "OK"
|
||||||
|
},
|
||||||
|
"PCIeFunctions": {
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0/PCIeFunctions"
|
||||||
|
}
|
||||||
|
}
|
19
sushy/tests/unit/json_samples/pcie_device_collection.json
Normal file
19
sushy/tests/unit/json_samples/pcie_device_collection.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#PCIeDeviceCollection.PCIeDeviceCollection",
|
||||||
|
"@odata.etag": "\"1756839817\"",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices",
|
||||||
|
"@odata.type": "#PCIeDeviceCollection.PCIeDeviceCollection",
|
||||||
|
"Description": "Collection of PCIe Devices",
|
||||||
|
"Members": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0",
|
||||||
|
"Id": "196-0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/65-0",
|
||||||
|
"Id": "65-0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Members@odata.count": 2,
|
||||||
|
"Name": "PCIe Device Collection"
|
||||||
|
}
|
48
sushy/tests/unit/json_samples/pcie_device_onboard.json
Normal file
48
sushy/tests/unit/json_samples/pcie_device_onboard.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#PCIeDevice.PCIeDevice",
|
||||||
|
"@odata.etag": "\"1756839815\"",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/128-1",
|
||||||
|
"@odata.type": "#PCIeDevice.v1_18_0.PCIeDevice",
|
||||||
|
"AssetTag": null,
|
||||||
|
"Description": "Advanced Micro Devices, Inc. [AMD]",
|
||||||
|
"DeviceType": "MultiFunction",
|
||||||
|
"FirmwareVersion": "",
|
||||||
|
"Id": "128-1",
|
||||||
|
"Links": {
|
||||||
|
"Chassis": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Chassis@odata.count": 1,
|
||||||
|
"Oem": {
|
||||||
|
"Dell": {
|
||||||
|
"@odata.type": "#DellOem.v1_3_0.DellOemLinks",
|
||||||
|
"CPUAffinity": [],
|
||||||
|
"CPUAffinity@odata.count": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PCIeFunctions": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/128-1/PCIeFunctions/128-1-0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PCIeFunctions@odata.count": 1,
|
||||||
|
"PCIeFunctions@Redfish.Deprecated": "Please migrate to PCIeFunctions property in the root resource."
|
||||||
|
},
|
||||||
|
"Manufacturer": "Advanced Micro Devices, Inc. [AMD]",
|
||||||
|
"Model": null,
|
||||||
|
"Name": "Advanced Micro Devices, Inc. [AMD]",
|
||||||
|
"PartNumber": null,
|
||||||
|
"SKU": null,
|
||||||
|
"SerialNumber": null,
|
||||||
|
"Slot": {},
|
||||||
|
"Status": {
|
||||||
|
"State": "Enabled",
|
||||||
|
"Health": "OK",
|
||||||
|
"HealthRollup": "OK"
|
||||||
|
},
|
||||||
|
"PCIeFunctions": {
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/128-1/PCIeFunctions"
|
||||||
|
}
|
||||||
|
}
|
168
sushy/tests/unit/resources/system/test_pcie_device.py
Normal file
168
sushy/tests/unit/resources/system/test_pcie_device.py
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from sushy.resources import constants as res_cons
|
||||||
|
from sushy.resources.system import pcie_device
|
||||||
|
from sushy.tests.unit import base
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeDeviceTestCase(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
with open('sushy/tests/unit/json_samples/pcie_device.json') as f:
|
||||||
|
self.json_doc = json.load(f)
|
||||||
|
|
||||||
|
self.conn.get.return_value.json.return_value = self.json_doc
|
||||||
|
|
||||||
|
self.pcie_dev = pcie_device.PCIeDevice(
|
||||||
|
self.conn,
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0',
|
||||||
|
redfish_version='1.0.2')
|
||||||
|
|
||||||
|
def test__parse_attributes(self):
|
||||||
|
self.pcie_dev._parse_attributes(self.json_doc)
|
||||||
|
self.assertEqual('1.0.2', self.pcie_dev.redfish_version)
|
||||||
|
self.assertEqual('196-0', self.pcie_dev.identity)
|
||||||
|
self.assertEqual('BCM957414A4142CC 10Gb/25Gb Ethernet PCIe',
|
||||||
|
self.pcie_dev.name)
|
||||||
|
self.assertEqual('BCM957414A4142CC 10Gb/25Gb Ethernet PCIe',
|
||||||
|
self.pcie_dev.description)
|
||||||
|
self.assertEqual('Broadcom Inc. and subsidiaries',
|
||||||
|
self.pcie_dev.manufacturer)
|
||||||
|
self.assertEqual('MultiFunction', self.pcie_dev.device_type)
|
||||||
|
self.assertEqual('224.1.102.0', self.pcie_dev.firmware_version)
|
||||||
|
self.assertIsNone(self.pcie_dev.asset_tag)
|
||||||
|
self.assertIsNone(self.pcie_dev.serial_number)
|
||||||
|
self.assertIsNone(self.pcie_dev.model)
|
||||||
|
self.assertIsNone(self.pcie_dev.part_number)
|
||||||
|
self.assertIsNone(self.pcie_dev.sku)
|
||||||
|
|
||||||
|
def test_pcie_interface(self):
|
||||||
|
pcie_if = self.pcie_dev.pcie_interface
|
||||||
|
self.assertEqual('Gen5', pcie_if.pcie_type)
|
||||||
|
self.assertEqual('Gen5', pcie_if.max_pcie_type)
|
||||||
|
self.assertEqual(8, pcie_if.lanes_in_use)
|
||||||
|
self.assertEqual(8, pcie_if.max_lanes)
|
||||||
|
|
||||||
|
def test_slot_information(self):
|
||||||
|
slot = self.pcie_dev.slot
|
||||||
|
self.assertEqual('HalfLength', slot.slot_type)
|
||||||
|
self.assertEqual('Gen5', slot.pcie_type)
|
||||||
|
self.assertEqual(8, slot.lanes)
|
||||||
|
self.assertIsNotNone(slot.location)
|
||||||
|
self.assertIsNone(slot.lane_splitting)
|
||||||
|
self.assertIsNone(slot.hot_pluggable)
|
||||||
|
|
||||||
|
def test_status_field(self):
|
||||||
|
status = self.pcie_dev.status
|
||||||
|
self.assertEqual(res_cons.State.ENABLED, status.state)
|
||||||
|
self.assertEqual(res_cons.Health.OK, status.health)
|
||||||
|
self.assertEqual(res_cons.Health.OK, status.health_rollup)
|
||||||
|
|
||||||
|
def test_links_field(self):
|
||||||
|
links = self.pcie_dev.links
|
||||||
|
self.assertIsNotNone(links)
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeDeviceOnboardTestCase(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
with open('sushy/tests/unit/json_samples/'
|
||||||
|
'pcie_device_onboard.json') as f:
|
||||||
|
self.json_doc = json.load(f)
|
||||||
|
|
||||||
|
self.conn.get.return_value.json.return_value = self.json_doc
|
||||||
|
|
||||||
|
self.onboard_dev = pcie_device.PCIeDevice(
|
||||||
|
self.conn,
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/128-1',
|
||||||
|
redfish_version='1.0.2')
|
||||||
|
|
||||||
|
def test_onboard_device_attributes(self):
|
||||||
|
self.assertEqual('128-1', self.onboard_dev.identity)
|
||||||
|
self.assertEqual('Advanced Micro Devices, Inc. [AMD]',
|
||||||
|
self.onboard_dev.name)
|
||||||
|
self.assertEqual('Advanced Micro Devices, Inc. [AMD]',
|
||||||
|
self.onboard_dev.manufacturer)
|
||||||
|
self.assertEqual('MultiFunction', self.onboard_dev.device_type)
|
||||||
|
self.assertEqual('', self.onboard_dev.firmware_version)
|
||||||
|
|
||||||
|
def test_onboard_device_empty_slot(self):
|
||||||
|
slot = self.onboard_dev.slot
|
||||||
|
self.assertIsNotNone(slot)
|
||||||
|
# Empty slot object should have None values
|
||||||
|
self.assertIsNone(slot.slot_type)
|
||||||
|
self.assertIsNone(slot.lanes)
|
||||||
|
self.assertIsNone(slot.pcie_type)
|
||||||
|
|
||||||
|
|
||||||
|
class PCIeDeviceCollectionTestCase(base.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.conn = mock.Mock()
|
||||||
|
with open('sushy/tests/unit/json_samples/'
|
||||||
|
'pcie_device_collection.json') as f:
|
||||||
|
self.json_doc = json.load(f)
|
||||||
|
|
||||||
|
self.conn.get.return_value.json.return_value = self.json_doc
|
||||||
|
|
||||||
|
self.collection = pcie_device.PCIeDeviceCollection(
|
||||||
|
self.conn, '/redfish/v1/Chassis/System.Embedded.1/PCIeDevices',
|
||||||
|
redfish_version='1.0.2')
|
||||||
|
|
||||||
|
def test__parse_attributes(self):
|
||||||
|
self.collection._parse_attributes(self.json_doc)
|
||||||
|
self.assertEqual('1.0.2', self.collection.redfish_version)
|
||||||
|
self.assertEqual('PCIe Device Collection', self.collection.name)
|
||||||
|
self.assertEqual(
|
||||||
|
('/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/196-0',
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/PCIeDevices/65-0'),
|
||||||
|
self.collection.members_identities)
|
||||||
|
|
||||||
|
@mock.patch.object(pcie_device, 'PCIeDevice', autospec=True)
|
||||||
|
def test_get_member(self, mock_pcie_device):
|
||||||
|
self.collection.get_member(
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||||
|
'PCIeDevices/196-0')
|
||||||
|
mock_pcie_device.assert_called_once_with(
|
||||||
|
self.collection._conn,
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||||
|
'PCIeDevices/196-0',
|
||||||
|
redfish_version=self.collection.redfish_version,
|
||||||
|
registries=None, root=self.collection.root)
|
||||||
|
|
||||||
|
@mock.patch.object(pcie_device, 'PCIeDevice', autospec=True)
|
||||||
|
def test_get_members(self, mock_pcie_device):
|
||||||
|
members = self.collection.get_members()
|
||||||
|
calls = [
|
||||||
|
mock.call(self.collection._conn,
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||||
|
'PCIeDevices/196-0',
|
||||||
|
redfish_version=self.collection.redfish_version,
|
||||||
|
registries=None, root=self.collection.root),
|
||||||
|
mock.call(self.collection._conn,
|
||||||
|
'/redfish/v1/Chassis/System.Embedded.1/'
|
||||||
|
'PCIeDevices/65-0',
|
||||||
|
redfish_version=self.collection.redfish_version,
|
||||||
|
registries=None, root=self.collection.root)
|
||||||
|
]
|
||||||
|
mock_pcie_device.assert_has_calls(calls)
|
||||||
|
self.assertIsInstance(members, list)
|
||||||
|
self.assertEqual(2, len(members))
|
Reference in New Issue
Block a user