Add System Processor/Memory info
This patch adds 2 new attributes to System: memory_summary: <type: namedtuple> The memory of the system in general detail. It is a namedtuple containing the following: `size_gib`: The size of memory of the system in GiB `health`: The overall health state of memory. processor_summary: <type: namedtuple> The processors of the system in general detail. It is a namedtuple containing the following: `count`: The number of processors in the system. To be precise, it is number of logical CPUs (threads). `architecture`: The architecture of the processor/s. This processor and memory information will be directly consumed by ironic inspection. Change-Id: I19acd74e26a861147df747f3d3f34852decf5403
This commit is contained in:
parent
3a6e665962
commit
18febd060f
|
@ -72,6 +72,12 @@ To use sushy in a project:
|
|||
# Get a list of allowed boot source target values
|
||||
print(sys_inst.get_allowed_system_boot_source_values())
|
||||
|
||||
# Get the memory summary
|
||||
print(sys_inst.memory_summary)
|
||||
|
||||
# Get the processor summary
|
||||
print(sys_inst.processors.summary)
|
||||
|
||||
|
||||
If you do not have any real baremetal machine that supports the Redfish
|
||||
protocol you can look at the :ref:`contributing` page to learn how to
|
||||
|
|
|
@ -96,3 +96,15 @@ BOOT_SOURCE_MODE_UEFI = 'uefi'
|
|||
BOOT_SOURCE_ENABLED_ONCE = 'once'
|
||||
BOOT_SOURCE_ENABLED_CONTINUOUS = 'continuous'
|
||||
BOOT_SOURCE_ENABLED_DISABLED = 'disabled'
|
||||
|
||||
# Processor related constants
|
||||
# Values comes from the Redfish Processor json-schema 1.0.0:
|
||||
# http://redfish.dmtf.org/schemas/v1/Processor.v1_0_0.json
|
||||
|
||||
# Processor Architecture constants
|
||||
|
||||
PROCESSOR_ARCH_x86 = 'x86 or x86-64'
|
||||
PROCESSOR_ARCH_IA_64 = 'Intel Itanium'
|
||||
PROCESSOR_ARCH_ARM = 'ARM'
|
||||
PROCESSOR_ARCH_MIPS = 'MIPS'
|
||||
PROCESSOR_ARCH_OEM = 'OEM-defined'
|
||||
|
|
|
@ -71,3 +71,14 @@ BOOT_SOURCE_ENABLED_MAP = {
|
|||
}
|
||||
|
||||
BOOT_SOURCE_ENABLED_MAP_REV = utils.revert_dictionary(BOOT_SOURCE_ENABLED_MAP)
|
||||
|
||||
PROCESSOR_ARCH_VALUE_MAP = {
|
||||
'x86': sys_cons.PROCESSOR_ARCH_x86,
|
||||
'IA-64': sys_cons.PROCESSOR_ARCH_IA_64,
|
||||
'ARM': sys_cons.PROCESSOR_ARCH_ARM,
|
||||
'MIPS': sys_cons.PROCESSOR_ARCH_MIPS,
|
||||
'OEM': sys_cons.PROCESSOR_ARCH_OEM,
|
||||
}
|
||||
|
||||
PROCESSOR_ARCH_VALUE_MAP_REV = (
|
||||
utils.revert_dictionary(PROCESSOR_ARCH_VALUE_MAP))
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# 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 collections
|
||||
import logging
|
||||
|
||||
from sushy.resources import base
|
||||
from sushy.resources.system import mappings as sys_maps
|
||||
|
||||
# Representation of Summary of Processor information
|
||||
ProcessorSummary = collections.namedtuple('ProcessorSummary',
|
||||
['count', 'architecture'])
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Processor(base.ResourceBase):
|
||||
|
||||
identity = None
|
||||
"""The processor identity string"""
|
||||
|
||||
socket = None
|
||||
"""The socket or location of the processor"""
|
||||
|
||||
# TODO(deray): Create mappings for the processor_type
|
||||
processor_type = None
|
||||
"""The type of processor"""
|
||||
|
||||
processor_architecture = None
|
||||
"""The architecture of the processor"""
|
||||
|
||||
# TODO(deray): Create mappings for the instruction_set
|
||||
instruction_set = None
|
||||
"""The instruction set of the processor"""
|
||||
|
||||
manufacturer = None
|
||||
"""The processor manufacturer"""
|
||||
|
||||
model = None
|
||||
"""The product model number of this device"""
|
||||
|
||||
max_speed_mhz = None
|
||||
"""The maximum clock speed of the processor in MHz."""
|
||||
|
||||
total_cores = None
|
||||
"""The total number of cores contained in this processor"""
|
||||
|
||||
total_threads = None
|
||||
"""The total number of execution threads supported by this processor"""
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a Processor
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param identity: The identity of the processor
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(Processor, self).__init__(connector, identity, redfish_version)
|
||||
|
||||
def _parse_attributes(self):
|
||||
self.identity = self.json.get('Id')
|
||||
self.socket = self.json.get('Socket')
|
||||
self.processor_type = self.json.get('ProcessorType')
|
||||
self.processor_architecture = (
|
||||
sys_maps.PROCESSOR_ARCH_VALUE_MAP.get(
|
||||
self.json.get('ProcessorArchitecture')))
|
||||
self.instruction_set = self.json.get('InstructionSet')
|
||||
self.manufacturer = self.json.get('Manufacturer')
|
||||
self.model = self.json.get('Model')
|
||||
self.max_speed_mhz = self.json.get('MaxSpeedMHz')
|
||||
self.total_cores = self.json.get('TotalCores')
|
||||
self.total_threads = self.json.get('TotalThreads')
|
||||
|
||||
|
||||
class ProcessorCollection(base.ResourceCollectionBase):
|
||||
|
||||
@property
|
||||
def _resource_type(self):
|
||||
return Processor
|
||||
|
||||
_summary = None
|
||||
"""The summary of processors of the system in general detail
|
||||
|
||||
This has to be accessed by exposed :prop:`summary`.
|
||||
"""
|
||||
|
||||
@property
|
||||
def summary(self):
|
||||
"""Property to provide ProcessorSummary info
|
||||
|
||||
It is calculated once when the first time it is queried. On refresh,
|
||||
this property gets reset.
|
||||
:returns: A namedtuple containing the following:
|
||||
count: The number of processors in the system. To be precise,
|
||||
it returns the number of logical CPUs (threads).
|
||||
architecture: The architecture of the processor/s.
|
||||
"""
|
||||
if self._summary is None:
|
||||
count, architecture = 0, None
|
||||
for proc in self.get_members():
|
||||
# Note(deray): It attempts to detect the number of CPU cores.
|
||||
# It returns the number of logical CPUs.
|
||||
if proc.total_threads is not None:
|
||||
count += proc.total_threads
|
||||
|
||||
# Note(deray): Bail out of checking the architecture info
|
||||
# if you have already got hold of any one of the processors'
|
||||
# architecture information.
|
||||
if (architecture is None
|
||||
and proc.processor_architecture is not None):
|
||||
architecture = proc.processor_architecture
|
||||
|
||||
self._summary = ProcessorSummary(count=count,
|
||||
architecture=architecture)
|
||||
|
||||
return self._summary
|
||||
|
||||
def __init__(self, connector, path, redfish_version=None):
|
||||
"""A class representing a ProcessorCollection
|
||||
|
||||
:param connector: A Connector instance
|
||||
:param path: The canonical path to the Processor collection resource
|
||||
:param redfish_version: The version of RedFish. Used to construct
|
||||
the object according to schema of the given version.
|
||||
"""
|
||||
super(ProcessorCollection, self).__init__(connector, path,
|
||||
redfish_version)
|
||||
|
||||
def refresh(self):
|
||||
"""Refresh the resource"""
|
||||
super(ProcessorCollection, self).refresh()
|
||||
# Reset summary attribute
|
||||
self._summary = None
|
|
@ -13,13 +13,18 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import logging
|
||||
|
||||
from sushy import exceptions
|
||||
from sushy.resources import base
|
||||
from sushy.resources.system import constants as sys_cons
|
||||
from sushy.resources.system import mappings as sys_maps
|
||||
from sushy.resources.system import processor
|
||||
|
||||
# Representation of Memory information summary
|
||||
MemorySummary = collections.namedtuple('MemorySummary',
|
||||
['size_gib', 'health'])
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -72,6 +77,19 @@ class System(base.ResourceBase):
|
|||
uuid = None
|
||||
"""The system UUID"""
|
||||
|
||||
memory_summary = None
|
||||
"""The summary info of memory of the system in general detail
|
||||
|
||||
It is a namedtuple containing the following:
|
||||
size_gib: The size of memory of the system in GiB. This signifies
|
||||
the total installed, operating system-accessible memory (RAM),
|
||||
measured in GiB.
|
||||
health: The overall health state of memory. This signifies
|
||||
health state of memory along with its dependent resources.
|
||||
"""
|
||||
|
||||
_processors = None # ref to ProcessorCollection instance
|
||||
|
||||
def __init__(self, connector, identity, redfish_version=None):
|
||||
"""A class representing a ComputerSystem
|
||||
|
||||
|
@ -110,6 +128,21 @@ class System(base.ResourceBase):
|
|||
self.boot['mode'] = sys_maps.BOOT_SOURCE_MODE_MAP.get(
|
||||
boot_attr.get('BootSourceOverrideMode'))
|
||||
|
||||
# Parse memory_summary attribute
|
||||
self.memory_summary = None
|
||||
memory_summary_attr = self.json.get('MemorySummary')
|
||||
if memory_summary_attr is not None:
|
||||
memory_size_gib = memory_summary_attr.get('TotalSystemMemoryGiB')
|
||||
try:
|
||||
memory_health = memory_summary_attr['Status']['HealthRollup']
|
||||
except KeyError:
|
||||
memory_health = None
|
||||
self.memory_summary = MemorySummary(size_gib=memory_size_gib,
|
||||
health=memory_health)
|
||||
|
||||
# Reset processor related attributes
|
||||
self._processors = None
|
||||
|
||||
def _get_reset_action_element(self):
|
||||
actions = self.json.get('Actions')
|
||||
if not actions:
|
||||
|
@ -245,6 +278,28 @@ class System(base.ResourceBase):
|
|||
# include a get_manager() and get_chassis() once we have an abstraction
|
||||
# for those resources.
|
||||
|
||||
def _get_processor_collection_path(self):
|
||||
"""Helper function to find the ProcessorCollection path"""
|
||||
processor_col = self.json.get('Processors')
|
||||
if not processor_col:
|
||||
raise exceptions.MissingAttributeError(attribute='Processors',
|
||||
resource=self._path)
|
||||
return processor_col.get('@odata.id')
|
||||
|
||||
@property
|
||||
def processors(self):
|
||||
"""Property to provide reference to `ProcessorCollection` instance
|
||||
|
||||
It is calculated once when the first time it is queried. On refresh,
|
||||
this property gets reset.
|
||||
"""
|
||||
if self._processors is None:
|
||||
self._processors = processor.ProcessorCollection(
|
||||
self._conn, self._get_processor_collection_path(),
|
||||
redfish_version=self.redfish_version)
|
||||
|
||||
return self._processors
|
||||
|
||||
|
||||
class SystemCollection(base.ResourceCollectionBase):
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"@odata.type": "#Processor.v1_0_2.Processor",
|
||||
"Id": "CPU1",
|
||||
"Socket": "CPU 1",
|
||||
"ProcessorType": "CPU",
|
||||
"ProcessorArchitecture": "x86",
|
||||
"InstructionSet": "x86-64",
|
||||
"Manufacturer": "Intel(R) Corporation",
|
||||
"Model": "Multi-Core Intel(R) Xeon(R) processor 7xxx Series",
|
||||
"ProcessorID": {
|
||||
"VendorID": "GenuineIntel",
|
||||
"IdentificationRegisters": "0x34AC34DC8901274A",
|
||||
"EffectiveFamily": "0x42",
|
||||
"EffectiveModel": "0x61",
|
||||
"Step": "0x1",
|
||||
"MicrocodeInfo": "0x429943"
|
||||
},
|
||||
"MaxSpeedMHz": 3700,
|
||||
"TotalCores": 8,
|
||||
"TotalThreads": 16,
|
||||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK"
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/437XR1138R2/Processors/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Processors/CPU1",
|
||||
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"@odata.type": "#Processor.v1_0_2.Processor",
|
||||
"Id": "CPU2",
|
||||
"Socket": "CPU 2",
|
||||
"ProcessorType": "CPU",
|
||||
"Status": {
|
||||
"State": "Absent"
|
||||
},
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Members/437XR1138R2/Processors/Members/$entity",
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Processors/CPU2",
|
||||
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"@odata.type": "#ProcssorCollection.ProcessorCollection",
|
||||
"Name": "Processors Collection",
|
||||
"Members@odata.count": 2,
|
||||
"Members": [
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Processors/CPU1"
|
||||
},
|
||||
{
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Processors/CPU2"
|
||||
}
|
||||
],
|
||||
"@odata.context": "/redfish/v1/$metadata#Systems/Links/Members/437XR1138R2/Processors/#entity",
|
||||
"@odata.id": "/redfish/v1/Systems/437XR1138R2/Processors",
|
||||
"@Redfish.Copyright": "Copyright 2014-2016 Distributed Management Task Force, Inc. (DMTF). For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright."
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
"HealthRollUp": "OK"
|
||||
"HealthRollup": "OK"
|
||||
},
|
||||
"IndicatorLED": "Off",
|
||||
"PowerState": "On",
|
||||
|
@ -67,7 +67,7 @@
|
|||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
"HealthRollUp": "OK"
|
||||
"HealthRollup": "OK"
|
||||
}
|
||||
},
|
||||
"MemorySummary": {
|
||||
|
@ -75,7 +75,7 @@
|
|||
"Status": {
|
||||
"State": "Enabled",
|
||||
"Health": "OK",
|
||||
"HealthRollUp": "OK"
|
||||
"HealthRollup": "OK"
|
||||
}
|
||||
},
|
||||
"Bios": {
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
# All Rights Reserved.
|
||||
#
|
||||
# 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
|
||||
|
||||
import mock
|
||||
|
||||
import sushy
|
||||
from sushy.resources.system import processor
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
||||
class ProcessorTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ProcessorTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/processor.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
self.sys_processor = processor.Processor(
|
||||
self.conn, '/redfish/v1/Systems/437XR1138R2/Processors/CPU1',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_processor._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_processor.redfish_version)
|
||||
self.assertEqual('CPU1', self.sys_processor.identity)
|
||||
self.assertEqual('CPU 1', self.sys_processor.socket)
|
||||
self.assertEqual('CPU', self.sys_processor.processor_type)
|
||||
self.assertEqual(sushy.PROCESSOR_ARCH_x86,
|
||||
self.sys_processor.processor_architecture)
|
||||
self.assertEqual('x86-64', self.sys_processor.instruction_set)
|
||||
self.assertEqual('Intel(R) Corporation',
|
||||
self.sys_processor.manufacturer)
|
||||
self.assertEqual('Multi-Core Intel(R) Xeon(R) processor 7xxx Series',
|
||||
self.sys_processor.model)
|
||||
self.assertEqual(3700, self.sys_processor.max_speed_mhz)
|
||||
self.assertEqual(8, self.sys_processor.total_cores)
|
||||
self.assertEqual(16, self.sys_processor.total_threads)
|
||||
|
||||
|
||||
class ProcessorCollectionTestCase(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ProcessorCollectionTestCase, self).setUp()
|
||||
self.conn = mock.Mock()
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'processor_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.sys_processor_col = processor.ProcessorCollection(
|
||||
self.conn, '/redfish/v1/Systems/437XR1138R2/Processors',
|
||||
redfish_version='1.0.2')
|
||||
|
||||
def test__parse_attributes(self):
|
||||
self.sys_processor_col._parse_attributes()
|
||||
self.assertEqual('1.0.2', self.sys_processor_col.redfish_version)
|
||||
self.assertEqual('Processors Collection', self.sys_processor_col.name)
|
||||
self.assertEqual(('/redfish/v1/Systems/437XR1138R2/Processors/CPU1',
|
||||
'/redfish/v1/Systems/437XR1138R2/Processors/CPU2'),
|
||||
self.sys_processor_col.members_identities)
|
||||
|
||||
@mock.patch.object(processor, 'Processor', autospec=True)
|
||||
def test_get_member(self, mock_processor):
|
||||
self.sys_processor_col.get_member(
|
||||
'/redfish/v1/Systems/437XR1138R2/Processors/CPU1')
|
||||
mock_processor.assert_called_once_with(
|
||||
self.sys_processor_col._conn,
|
||||
'/redfish/v1/Systems/437XR1138R2/Processors/CPU1',
|
||||
redfish_version=self.sys_processor_col.redfish_version)
|
||||
|
||||
@mock.patch.object(processor, 'Processor', autospec=True)
|
||||
def test_get_members(self, mock_processor):
|
||||
members = self.sys_processor_col.get_members()
|
||||
calls = [
|
||||
mock.call(self.sys_processor_col._conn,
|
||||
'/redfish/v1/Systems/437XR1138R2/Processors/CPU1',
|
||||
redfish_version=self.sys_processor_col.redfish_version),
|
||||
mock.call(self.sys_processor_col._conn,
|
||||
'/redfish/v1/Systems/437XR1138R2/Processors/CPU2',
|
||||
redfish_version=self.sys_processor_col.redfish_version)
|
||||
]
|
||||
mock_processor.assert_has_calls(calls)
|
||||
self.assertIsInstance(members, list)
|
||||
self.assertEqual(2, len(members))
|
||||
|
||||
def _setUp_processor_summary(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
successive_return_values = []
|
||||
with open('sushy/tests/unit/json_samples/processor.json', 'r') as f:
|
||||
successive_return_values.append(json.loads(f.read()))
|
||||
with open('sushy/tests/unit/json_samples/processor2.json', 'r') as f:
|
||||
successive_return_values.append(json.loads(f.read()))
|
||||
|
||||
self.conn.get.return_value.json.side_effect = successive_return_values
|
||||
|
||||
def test_summary(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.sys_processor_col._summary)
|
||||
# | GIVEN |
|
||||
self._setUp_processor_summary()
|
||||
# | WHEN |
|
||||
actual_summary = self.sys_processor_col.summary
|
||||
# | THEN |
|
||||
self.assertEqual((16, sushy.PROCESSOR_ARCH_x86),
|
||||
actual_summary)
|
||||
self.assertEqual(16, actual_summary.count)
|
||||
self.assertEqual(sushy.PROCESSOR_ARCH_x86,
|
||||
actual_summary.architecture)
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_summary,
|
||||
self.sys_processor_col.summary)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_summary_on_refresh(self):
|
||||
# | GIVEN |
|
||||
self._setUp_processor_summary()
|
||||
# | WHEN & THEN |
|
||||
self.assertEqual((16, sushy.PROCESSOR_ARCH_x86),
|
||||
self.sys_processor_col.summary)
|
||||
|
||||
self.conn.get.return_value.json.side_effect = None
|
||||
# On refreshing the sys_processor_col instance...
|
||||
with open('sushy/tests/unit/json_samples/'
|
||||
'processor_collection.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.sys_processor_col.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.sys_processor_col._summary)
|
||||
|
||||
# | GIVEN |
|
||||
self._setUp_processor_summary()
|
||||
# | WHEN & THEN |
|
||||
self.assertEqual((16, sushy.PROCESSOR_ARCH_x86),
|
||||
self.sys_processor_col.summary)
|
|
@ -19,6 +19,7 @@ import mock
|
|||
|
||||
import sushy
|
||||
from sushy import exceptions
|
||||
from sushy.resources.system import processor
|
||||
from sushy.resources.system import system
|
||||
from sushy.tests.unit import base
|
||||
|
||||
|
@ -54,6 +55,9 @@ class SystemTestCase(base.TestCase):
|
|||
self.sys_inst.uuid)
|
||||
self.assertEqual(sushy.SYSTEM_POWER_STATE_ON,
|
||||
self.sys_inst.power_state)
|
||||
self.assertEqual((96, "OK"),
|
||||
self.sys_inst.memory_summary)
|
||||
self.assertIsNone(self.sys_inst._processors)
|
||||
|
||||
def test_get__reset_action_element(self):
|
||||
value = self.sys_inst._get_reset_action_element()
|
||||
|
@ -218,6 +222,135 @@ class SystemTestCase(base.TestCase):
|
|||
sushy.BOOT_SOURCE_TARGET_HDD,
|
||||
enabled='invalid-enabled')
|
||||
|
||||
def test__get_processor_collection_path_missing_processors_attr(self):
|
||||
self.sys_inst._json.pop('Processors')
|
||||
self.assertRaisesRegex(
|
||||
exceptions.MissingAttributeError, 'attribute Processors',
|
||||
self.sys_inst._get_processor_collection_path)
|
||||
|
||||
def test_memory_summary_missing_attr(self):
|
||||
self.assertIsInstance(self.sys_inst.memory_summary,
|
||||
system.MemorySummary)
|
||||
self.assertEqual(96, self.sys_inst.memory_summary.size_gib)
|
||||
self.assertEqual("OK", self.sys_inst.memory_summary.health)
|
||||
|
||||
# | GIVEN |
|
||||
self.sys_inst._json['MemorySummary']['Status'].pop('HealthRollup')
|
||||
# | WHEN |
|
||||
self.sys_inst._parse_attributes()
|
||||
# | THEN |
|
||||
self.assertEqual(96, self.sys_inst.memory_summary.size_gib)
|
||||
self.assertEqual(None, self.sys_inst.memory_summary.health)
|
||||
|
||||
# | GIVEN |
|
||||
self.sys_inst._json['MemorySummary'].pop('Status')
|
||||
# | WHEN |
|
||||
self.sys_inst._parse_attributes()
|
||||
# | THEN |
|
||||
self.assertEqual(96, self.sys_inst.memory_summary.size_gib)
|
||||
self.assertEqual(None, self.sys_inst.memory_summary.health)
|
||||
|
||||
# | GIVEN |
|
||||
self.sys_inst._json['MemorySummary'].pop('TotalSystemMemoryGiB')
|
||||
# | WHEN |
|
||||
self.sys_inst._parse_attributes()
|
||||
# | THEN |
|
||||
self.assertEqual(None, self.sys_inst.memory_summary.size_gib)
|
||||
self.assertEqual(None, self.sys_inst.memory_summary.health)
|
||||
|
||||
# | GIVEN |
|
||||
self.sys_inst._json.pop('MemorySummary')
|
||||
# | WHEN |
|
||||
self.sys_inst._parse_attributes()
|
||||
# | THEN |
|
||||
self.assertEqual(None, self.sys_inst.memory_summary)
|
||||
|
||||
def test_processors(self):
|
||||
# check for the underneath variable value
|
||||
self.assertIsNone(self.sys_inst._processors)
|
||||
# | GIVEN |
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/json_samples/processor_collection.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN |
|
||||
actual_processors = self.sys_inst.processors
|
||||
# | THEN |
|
||||
self.assertIsInstance(actual_processors,
|
||||
processor.ProcessorCollection)
|
||||
self.conn.get.return_value.json.assert_called_once_with()
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_processors,
|
||||
self.sys_inst.processors)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
def test_processors_on_refresh(self):
|
||||
# | GIVEN |
|
||||
with open('sushy/tests/unit/json_samples/processor_collection.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.sys_inst.processors,
|
||||
processor.ProcessorCollection)
|
||||
|
||||
# On refreshing the system instance...
|
||||
with open('sushy/tests/unit/json_samples/system.json', 'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
self.sys_inst.refresh()
|
||||
|
||||
# | WHEN & THEN |
|
||||
self.assertIsNone(self.sys_inst._processors)
|
||||
|
||||
# | GIVEN |
|
||||
with open('sushy/tests/unit/json_samples/processor_collection.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
# | WHEN & THEN |
|
||||
self.assertIsInstance(self.sys_inst.processors,
|
||||
processor.ProcessorCollection)
|
||||
|
||||
def _setUp_processor_summary(self):
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
with open('sushy/tests/unit/json_samples/processor_collection.json',
|
||||
'r') as f:
|
||||
self.conn.get.return_value.json.return_value = json.loads(f.read())
|
||||
|
||||
# fetch processors for the first time
|
||||
self.sys_inst.processors
|
||||
|
||||
successive_return_values = []
|
||||
with open('sushy/tests/unit/json_samples/processor.json', 'r') as f:
|
||||
successive_return_values.append(json.loads(f.read()))
|
||||
with open('sushy/tests/unit/json_samples/processor2.json', 'r') as f:
|
||||
successive_return_values.append(json.loads(f.read()))
|
||||
|
||||
self.conn.get.return_value.json.side_effect = successive_return_values
|
||||
|
||||
def test_processor_summary(self):
|
||||
# | GIVEN |
|
||||
self._setUp_processor_summary()
|
||||
# | WHEN |
|
||||
actual_processor_summary = self.sys_inst.processors.summary
|
||||
# | THEN |
|
||||
self.assertEqual((16, sushy.PROCESSOR_ARCH_x86),
|
||||
actual_processor_summary)
|
||||
self.assertEqual(16, actual_processor_summary.count)
|
||||
self.assertEqual(sushy.PROCESSOR_ARCH_x86,
|
||||
actual_processor_summary.architecture)
|
||||
|
||||
# reset mock
|
||||
self.conn.get.return_value.json.reset_mock()
|
||||
|
||||
# | WHEN & THEN |
|
||||
# tests for same object on invoking subsequently
|
||||
self.assertIs(actual_processor_summary,
|
||||
self.sys_inst.processors.summary)
|
||||
self.conn.get.return_value.json.assert_not_called()
|
||||
|
||||
|
||||
class SystemCollectionTestCase(base.TestCase):
|
||||
|
||||
|
|
Loading…
Reference in New Issue