# Copyright 2017 Red Hat, Inc. # 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 import exceptions from sushy.resources.chassis import chassis from sushy.resources import constants as res_cons from sushy.resources.manager import manager from sushy.resources.oem import fake from sushy.resources.system import bios from sushy.resources.system import mappings as sys_map from sushy.resources.system import processor from sushy.resources.system import simple_storage from sushy.resources.system.storage import storage from sushy.resources.system import system from sushy.tests.unit import base class SystemTestCase(base.TestCase): def setUp(self): super(SystemTestCase, self).setUp() self.conn = mock.Mock() with open('sushy/tests/unit/json_samples/system.json') as f: self.conn.get.return_value.json.return_value = json.load(f) self.sys_inst = system.System( self.conn, '/redfish/v1/Systems/437XR1138R2', redfish_version='1.0.2') def test__parse_attributes(self): self.sys_inst._parse_attributes() self.assertEqual('1.0.2', self.sys_inst.redfish_version) self.assertEqual('Chicago-45Z-2381', self.sys_inst.asset_tag) self.assertEqual('P79 v1.33 (02/28/2015)', self.sys_inst.bios_version) self.assertEqual('Web Front End node', self.sys_inst.description) self.assertEqual('web483', self.sys_inst.hostname) self.assertEqual('437XR1138R2', self.sys_inst.identity) self.assertEqual(sushy.SYSTEM_INDICATOR_LED_OFF, self.sys_inst.indicator_led) self.assertEqual('Contoso', self.sys_inst.manufacturer) self.assertEqual('WebFrontEnd483', self.sys_inst.name) self.assertEqual('224071-J23', self.sys_inst.part_number) self.assertEqual('437XR1138R2', self.sys_inst.serial_number) self.assertEqual('8675309', self.sys_inst.sku) self.assertEqual(sushy.SYSTEM_TYPE_PHYSICAL, self.sys_inst.system_type) self.assertEqual('38947555-7742-3448-3784-823347823834', self.sys_inst.uuid) self.assertEqual(res_cons.STATE_ENABLED, self.sys_inst.status.state) self.assertEqual(res_cons.HEALTH_OK, self.sys_inst.status.health) self.assertEqual(res_cons.HEALTH_OK, self.sys_inst.status.health_rollup) self.assertEqual(sushy.SYSTEM_POWER_STATE_ON, self.sys_inst.power_state) self.assertEqual(96, self.sys_inst.memory_summary.size_gib) self.assertEqual("OK", self.sys_inst.memory_summary.health) for oem_vendor in self.sys_inst.oem_vendors: self.assertIn(oem_vendor, ('Contoso', 'Chipwise')) def test__parse_attributes_missing_actions(self): self.sys_inst.json.pop('Actions') self.assertRaisesRegex( exceptions.MissingAttributeError, 'attribute Actions', self.sys_inst._parse_attributes) def test__parse_attributes_missing_boot(self): self.sys_inst.json.pop('Boot') self.assertRaisesRegex( exceptions.MissingAttributeError, 'attribute Boot', self.sys_inst._parse_attributes) def test__parse_attributes_missing_reset_target(self): self.sys_inst.json['Actions']['#ComputerSystem.Reset'].pop( 'target') self.assertRaisesRegex( exceptions.MissingAttributeError, 'attribute Actions/#ComputerSystem.Reset/target', self.sys_inst._parse_attributes) def test__parse_attributes_null_memory_capacity(self): self.sys_inst.json['MemorySummary']['TotalSystemMemoryGiB'] = None self.sys_inst._parse_attributes() self.assertIsNone(self.sys_inst.memory_summary.size_gib) def test_get__reset_action_element(self): value = self.sys_inst._get_reset_action_element() self.assertEqual("/redfish/v1/Systems/437XR1138R2/Actions/" "ComputerSystem.Reset", value.target_uri) self.assertEqual(["On", "ForceOff", "GracefulShutdown", "GracefulRestart", "ForceRestart", "Nmi", "ForceOn" ], value.allowed_values) def test_get__reset_action_element_missing_reset_action(self): self.sys_inst._actions.reset = None self.assertRaisesRegex( exceptions.MissingActionError, 'action #ComputerSystem.Reset', self.sys_inst._get_reset_action_element) def test_get_allowed_reset_system_values(self): values = self.sys_inst.get_allowed_reset_system_values() expected = set([sushy.RESET_GRACEFUL_SHUTDOWN, sushy.RESET_GRACEFUL_RESTART, sushy.RESET_FORCE_RESTART, sushy.RESET_FORCE_OFF, sushy.RESET_FORCE_ON, sushy.RESET_ON, sushy.RESET_NMI]) self.assertEqual(expected, values) self.assertIsInstance(values, set) @mock.patch.object(system.LOG, 'warning', autospec=True) def test_get_allowed_reset_system_values_no_values_specified( self, mock_log): self.sys_inst._actions.reset.allowed_values = {} values = self.sys_inst.get_allowed_reset_system_values() # Assert it returns all values if it can't get the specific ones expected = set([sushy.RESET_GRACEFUL_SHUTDOWN, sushy.RESET_GRACEFUL_RESTART, sushy.RESET_FORCE_RESTART, sushy.RESET_FORCE_OFF, sushy.RESET_FORCE_ON, sushy.RESET_ON, sushy.RESET_NMI, sushy.RESET_PUSH_POWER_BUTTON]) self.assertEqual(expected, values) self.assertIsInstance(values, set) self.assertEqual(1, mock_log.call_count) def test_reset_system(self): self.sys_inst.reset_system(sushy.RESET_FORCE_OFF) self.sys_inst._conn.post.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2/Actions/ComputerSystem.Reset', data={'ResetType': 'ForceOff'}) def test_reset_system_invalid_value(self): self.assertRaises(exceptions.InvalidParameterValueError, self.sys_inst.reset_system, 'invalid-value') def test_get_allowed_system_boot_source_values(self): values = self.sys_inst.get_allowed_system_boot_source_values() expected = set([sushy.BOOT_SOURCE_TARGET_NONE, sushy.BOOT_SOURCE_TARGET_PXE, sushy.BOOT_SOURCE_TARGET_CD, sushy.BOOT_SOURCE_TARGET_USB, sushy.BOOT_SOURCE_TARGET_HDD, sushy.BOOT_SOURCE_TARGET_BIOS_SETUP, sushy.BOOT_SOURCE_TARGET_UTILITIES, sushy.BOOT_SOURCE_TARGET_DIAGS, sushy.BOOT_SOURCE_TARGET_SD_CARD, sushy.BOOT_SOURCE_TARGET_UEFI_TARGET]) self.assertEqual(expected, values) self.assertIsInstance(values, set) @mock.patch.object(system.LOG, 'warning', autospec=True) def test_get_allowed_system_boot_source_values_no_values_specified( self, mock_log): self.sys_inst.boot.allowed_values = None values = self.sys_inst.get_allowed_system_boot_source_values() # Assert it returns all values if it can't get the specific ones expected = set([sushy.BOOT_SOURCE_TARGET_NONE, sushy.BOOT_SOURCE_TARGET_PXE, sushy.BOOT_SOURCE_TARGET_CD, sushy.BOOT_SOURCE_TARGET_USB, sushy.BOOT_SOURCE_TARGET_HDD, sushy.BOOT_SOURCE_TARGET_BIOS_SETUP, sushy.BOOT_SOURCE_TARGET_UTILITIES, sushy.BOOT_SOURCE_TARGET_DIAGS, sushy.BOOT_SOURCE_TARGET_SD_CARD, sushy.BOOT_SOURCE_TARGET_FLOPPY, sushy.BOOT_SOURCE_TARGET_UEFI_TARGET, sushy.BOOT_SOURCE_TARGET_UEFI_SHELL, sushy.BOOT_SOURCE_TARGET_UEFI_HTTP]) self.assertEqual(expected, values) self.assertIsInstance(values, set) self.assertEqual(1, mock_log.call_count) def test_set_system_boot_source(self): self.sys_inst.set_system_boot_source( sushy.BOOT_SOURCE_TARGET_PXE, enabled=sushy.BOOT_SOURCE_ENABLED_CONTINUOUS, mode=sushy.BOOT_SOURCE_MODE_UEFI) self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Continuous', 'BootSourceOverrideTarget': 'Pxe', 'BootSourceOverrideMode': 'UEFI'}}) def test_set_system_boot_source_no_mode_specified(self): self.sys_inst.set_system_boot_source( sushy.BOOT_SOURCE_TARGET_HDD, enabled=sushy.BOOT_SOURCE_ENABLED_ONCE) self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', 'BootSourceOverrideTarget': 'Hdd'}}) def test_set_system_boot_source_invalid_target(self): self.assertRaises(exceptions.InvalidParameterValueError, self.sys_inst.set_system_boot_source, 'invalid-target') def test_set_system_boot_source_invalid_enabled(self): with self.assertRaisesRegex( exceptions.InvalidParameterValueError, '"enabled" value.*{0}'.format( list(sys_map.BOOT_SOURCE_ENABLED_MAP_REV))): self.sys_inst.set_system_boot_source( sushy.BOOT_SOURCE_TARGET_HDD, enabled='invalid-enabled') def test_set_indicator_led(self): with mock.patch.object( self.sys_inst, 'invalidate', autospec=True) as invalidate_mock: self.sys_inst.set_indicator_led(sushy.INDICATOR_LED_BLINKING) self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'IndicatorLED': 'Blinking'}) invalidate_mock.assert_called_once_with() def test_set_indicator_led_invalid_state(self): self.assertRaises(exceptions.InvalidParameterValueError, self.sys_inst.set_indicator_led, 'spooky-glowing') 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): # | 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.assertIsNone(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.assertIsNone(self.sys_inst.memory_summary.health) # | GIVEN | self.sys_inst._json['MemorySummary'].pop('TotalSystemMemoryGiB') # | WHEN | self.sys_inst._parse_attributes() # | THEN | self.assertIsNone(self.sys_inst.memory_summary.size_gib) self.assertIsNone(self.sys_inst.memory_summary.health) # | GIVEN | self.sys_inst._json.pop('MemorySummary') # | WHEN | self.sys_inst._parse_attributes() # | THEN | self.assertIsNone(self.sys_inst.memory_summary) def test_processors(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() with open('sushy/tests/unit/json_samples/' 'processor_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | 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') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | self.assertIsInstance(self.sys_inst.processors, processor.ProcessorCollection) # On refreshing the system instance... with open('sushy/tests/unit/json_samples/system.json') as f: self.conn.get.return_value.json.return_value = json.load(f) self.sys_inst.invalidate() self.sys_inst.refresh(force=False) # | GIVEN | with open('sushy/tests/unit/json_samples/' 'processor_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | 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') as f: self.conn.get.return_value.json.return_value = json.load(f) # fetch processors for the first time self.sys_inst.processors successive_return_values = [] file_names = ['sushy/tests/unit/json_samples/processor.json', 'sushy/tests/unit/json_samples/processor2.json'] for file_name in file_names: with open(file_name) as f: successive_return_values.append(json.load(f)) 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() def test_ethernet_interfaces(self): self.conn.get.return_value.json.reset_mock() eth_coll_return_value = None eth_return_value = None with open('sushy/tests/unit/json_samples/' 'ethernet_interfaces_collection.json') as f: eth_coll_return_value = json.load(f) with open('sushy/tests/unit/json_samples/' 'ethernet_interfaces.json') as f: eth_return_value = json.load(f) self.conn.get.return_value.json.side_effect = [eth_coll_return_value, eth_return_value] actual_macs = self.sys_inst.ethernet_interfaces.summary expected_macs = ( {'12:44:6A:3B:04:11': res_cons.STATE_ENABLED}) self.assertEqual(expected_macs, actual_macs) def test_bios(self): self.conn.get.return_value.json.reset_mock() bios_return_value = None with open('sushy/tests/unit/json_samples/bios.json') as f: bios_return_value = json.load(f) self.conn.get.return_value.json.side_effect = [bios_return_value] self.assertIsInstance(self.sys_inst.bios, bios.Bios) self.assertEqual('BIOS Configuration Current Settings', self.sys_inst.bios.name) def test_simple_storage_for_missing_attr(self): self.sys_inst.json.pop('SimpleStorage') with self.assertRaisesRegex( exceptions.MissingAttributeError, 'attribute SimpleStorage'): self.sys_inst.simple_storage def test_simple_storage(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() with open('sushy/tests/unit/json_samples/' 'simple_storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN | actual_simple_storage = self.sys_inst.simple_storage # | THEN | self.assertIsInstance(actual_simple_storage, simple_storage.SimpleStorageCollection) 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_simple_storage, self.sys_inst.simple_storage) self.conn.get.return_value.json.assert_not_called() def test_simple_storage_on_refresh(self): # | GIVEN | with open('sushy/tests/unit/json_samples/' 'simple_storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | self.assertIsInstance(self.sys_inst.simple_storage, simple_storage.SimpleStorageCollection) # On refreshing the system instance... with open('sushy/tests/unit/json_samples/system.json') as f: self.conn.get.return_value.json.return_value = json.load(f) self.sys_inst.invalidate() self.sys_inst.refresh(force=False) # | GIVEN | with open('sushy/tests/unit/json_samples/' 'simple_storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | self.assertIsInstance(self.sys_inst.simple_storage, simple_storage.SimpleStorageCollection) def test_storage_for_missing_attr(self): self.sys_inst.json.pop('Storage') with self.assertRaisesRegex( exceptions.MissingAttributeError, 'attribute Storage'): self.sys_inst.storage def test_storage(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() with open('sushy/tests/unit/json_samples/' 'storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN | actual_storage = self.sys_inst.storage # | THEN | self.assertIsInstance(actual_storage, storage.StorageCollection) 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_storage, self.sys_inst.storage) self.conn.get.return_value.json.assert_not_called() def test_storage_on_refresh(self): # | GIVEN | with open('sushy/tests/unit/json_samples/' 'storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | self.assertIsInstance(self.sys_inst.storage, storage.StorageCollection) # On refreshing the system instance... with open('sushy/tests/unit/json_samples/system.json') as f: self.conn.get.return_value.json.return_value = json.load(f) self.sys_inst.invalidate() self.sys_inst.refresh(force=False) # | GIVEN | with open('sushy/tests/unit/json_samples/' 'storage_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | self.assertIsInstance(self.sys_inst.storage, storage.StorageCollection) def test_managers(self): # | GIVEN | with open('sushy/tests/unit/json_samples/' 'manager.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | actual_managers = self.sys_inst.managers self.assertIsInstance(actual_managers[0], manager.Manager) self.assertEqual( '/redfish/v1/Managers/BMC', actual_managers[0].path) def test_chassis(self): # | GIVEN | with open('sushy/tests/unit/json_samples/' 'chassis.json') as f: self.conn.get.return_value.json.return_value = json.load(f) # | WHEN & THEN | actual_chassis = self.sys_inst.chassis self.assertIsInstance(actual_chassis[0], chassis.Chassis) self.assertEqual( '/redfish/v1/Chassis/1U', actual_chassis[0].path) def test_get_oem_extension(self): # | WHEN | contoso_system_extn_inst = self.sys_inst.get_oem_extension('Contoso') # | THEN | self.assertIsInstance(contoso_system_extn_inst, fake.FakeOEMSystemExtension) self.assertIs(self.sys_inst, contoso_system_extn_inst.core_resource) self.assertEqual('Contoso', contoso_system_extn_inst.oem_property_name) class SystemCollectionTestCase(base.TestCase): def setUp(self): super(SystemCollectionTestCase, self).setUp() self.conn = mock.Mock() with open('sushy/tests/unit/json_samples/' 'system_collection.json') as f: self.conn.get.return_value.json.return_value = json.load(f) self.sys_col = system.SystemCollection( self.conn, '/redfish/v1/Systems', redfish_version='1.0.2') def test__parse_attributes(self): self.sys_col._parse_attributes() self.assertEqual('1.0.2', self.sys_col.redfish_version) self.assertEqual('Computer System Collection', self.sys_col.name) self.assertEqual(('/redfish/v1/Systems/437XR1138R2',), self.sys_col.members_identities) @mock.patch.object(system, 'System', autospec=True) def test_get_member(self, mock_system): self.sys_col.get_member('/redfish/v1/Systems/437XR1138R2') mock_system.assert_called_once_with( self.sys_col._conn, '/redfish/v1/Systems/437XR1138R2', redfish_version=self.sys_col.redfish_version) @mock.patch.object(system, 'System', autospec=True) def test_get_members(self, mock_system): members = self.sys_col.get_members() mock_system.assert_called_once_with( self.sys_col._conn, '/redfish/v1/Systems/437XR1138R2', redfish_version=self.sys_col.redfish_version) self.assertIsInstance(members, list) self.assertEqual(1, len(members))