diff --git a/rsd_lib/resources/v2_2/telemetry/telemetry.py b/rsd_lib/resources/v2_2/telemetry/telemetry.py index d0621e1..306f4b1 100644 --- a/rsd_lib/resources/v2_2/telemetry/telemetry.py +++ b/rsd_lib/resources/v2_2/telemetry/telemetry.py @@ -20,33 +20,33 @@ from rsd_lib import common as rsd_lib_common from rsd_lib.resources.v2_2.telemetry import metric_definition from rsd_lib.resources.v2_2.telemetry import metric_report from rsd_lib.resources.v2_2.telemetry import metric_report_definition -from rsd_lib.resources.v2_2.telemetry import trigger +from rsd_lib.resources.v2_2.telemetry import triggers from rsd_lib import utils as rsd_lib_utils class Telemetry(base.ResourceBase): - max_reports = base.Field('MaxReports', adapter=rsd_lib_utils.num_or_none) + max_reports = base.Field("MaxReports", adapter=rsd_lib_utils.num_or_none) """If present, the value shall specify the maximum number of metric collectors that can be supported by this service """ - min_collection_interval = base.Field('MinCollectionInterval') + min_collection_interval = base.Field("MinCollectionInterval") """If present, the value shall be an ISO 8601 duration specifying the minimum time between collections """ - supported_collection_functions = base.Field('SupportedCollectionFunctions') + supported_collection_functions = base.Field("SupportedCollectionFunctions") """If present, the value shall define the function to apply over the collection duration """ - status = rsd_lib_common.StatusField('Status') + status = rsd_lib_common.StatusField("Status") """The telemetry service status""" def _get_metric_definitions_path(self): """Helper function to find the metric definitions path""" - return utils.get_sub_resource_path_by(self, 'MetricDefinitions') + return utils.get_sub_resource_path_by(self, "MetricDefinitions") @property @utils.cache_it @@ -57,12 +57,14 @@ class Telemetry(base.ResourceBase): this property is reset. """ return metric_definition.MetricDefinitionCollection( - self._conn, self._get_metric_definitions_path(), - redfish_version=self.redfish_version) + self._conn, + self._get_metric_definitions_path(), + redfish_version=self.redfish_version, + ) def _get_metric_report_definitions_path(self): """Helper function to find the metric report definitions path""" - return utils.get_sub_resource_path_by(self, 'MetricReportDefinitions') + return utils.get_sub_resource_path_by(self, "MetricReportDefinitions") @property @utils.cache_it @@ -73,12 +75,14 @@ class Telemetry(base.ResourceBase): this property is reset. """ return metric_report_definition.MetricReportDefinitionCollection( - self._conn, self._get_metric_definitions_path(), - redfish_version=self.redfish_version) + self._conn, + self._get_metric_definitions_path(), + redfish_version=self.redfish_version, + ) def _get_metric_reports_path(self): """Helper function to find the metric reports path""" - return utils.get_sub_resource_path_by(self, 'MetricReports') + return utils.get_sub_resource_path_by(self, "MetricReports") @property @utils.cache_it @@ -89,21 +93,25 @@ class Telemetry(base.ResourceBase): this property is reset. """ return metric_report.MetricReportCollection( - self._conn, self._get_metric_reports_path(), - redfish_version=self.redfish_version) + self._conn, + self._get_metric_reports_path(), + redfish_version=self.redfish_version, + ) def _get_triggers_path(self): """Helper function to find the triggers path""" - return utils.get_sub_resource_path_by(self, 'Triggers') + return utils.get_sub_resource_path_by(self, "Triggers") @property @utils.cache_it def triggers(self): - """Property to provide reference to `TriggerCollection` + """Property to provide reference to `TriggersCollection` It is calculated once the first time it is queried. On refresh, this property is reset. """ - return trigger.TriggerCollection( - self._conn, self._get_triggers_path(), - redfish_version=self.redfish_version) + return triggers.TriggersCollection( + self._conn, + self._get_triggers_path(), + redfish_version=self.redfish_version, + ) diff --git a/rsd_lib/resources/v2_2/telemetry/trigger.py b/rsd_lib/resources/v2_2/telemetry/trigger.py deleted file mode 100644 index 3204f39..0000000 --- a/rsd_lib/resources/v2_2/telemetry/trigger.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright 2019 Intel, 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. - -from jsonschema import validate -import logging - -from sushy.resources import base - -from rsd_lib import common as rsd_lib_common -from rsd_lib.resources.v2_2.telemetry import trigger_schemas -from rsd_lib import utils as rsd_lib_utils - - -LOG = logging.getLogger(__name__) - - -class NumericTriggersField(base.ListField): - name = base.Field('Name') - """The name of trigger""" - - value = base.Field('Value', adapter=rsd_lib_utils.num_or_none) - """This property contains the value of the trigger""" - - direction_of_crossing = base.Field('DirectionOfCrossing') - """This property contains the value of the trigger""" - - dwell_tim_msec = base.Field( - 'DwellTimMsec', adapter=rsd_lib_utils.num_or_none) - """This time the excursion persists before a trigger is determined""" - - severity = base.Field('Severity') - """This property contains the value of the Severity property in the Event - message - """ - - -class DiscreteTriggersField(base.ListField): - name = base.Field('Name') - """The name of trigger""" - - value = base.Field('Value') - """This property contains the value of the trigger""" - - dwell_tim_msec = base.Field( - 'DwellTimMsec', adapter=rsd_lib_utils.num_or_none) - """This time the excursion persists before a trigger is determined""" - - severity = base.Field('Severity') - """This property contains the value of the Severity property in the Event - message - """ - - -class WildcardsField(base.ListField): - name = base.Field("Name") - """This property shall contain a name for a Wildcard for a key""" - - keys = base.Field("Keys") - """If the value is an empty string, then the server shall substitute every - current key. Each not empty key value shall be substituted for the - wildcard - """ - - -class Trigger(base.ResourceBase): - identity = base.Field("Id") - """The trigger identity""" - - name = base.Field("Name") - """The trigger name""" - - description = base.Field("Description") - """The trigger description""" - - metric_type = base.Field("MetricType") - """The type of trigger""" - - trigger_actions = base.Field("TriggerActions") - """The metric report description""" - - numeric_triggers = NumericTriggersField("NumericTriggers") - """List of numeric triggers""" - - discrete_trigger_condition = base.Field("DiscreteTriggerCondition") - """The value shall indicate how the corresponding metric""" - - discrete_triggers = DiscreteTriggersField("DiscreteTriggers") - """List of discrete triggers""" - - status = rsd_lib_common.StatusField('Status') - """The trigger status""" - - wildcards = WildcardsField("Wildcards") - """The property shall contain an array of wildcards and their replacements - strings, which are to appliced to the MetricProperties array property - """ - - metric_properties = base.Field("MetricProperties") - """The report definition metric properties""" - - def delete(self): - """Delete trigger""" - self._conn.delete(self.path) - - -class TriggerCollection(base.ResourceCollectionBase): - - @property - def _resource_type(self): - return Trigger - - def create_trigger(self, name=None, description=None, metric_type=None, - trigger_actions=None, numeric_triggers=None, - discrete_trigger_condition=None, discrete_triggers=None, - status=None, wildcards=None, metric_properties=None): - """Create a new trigger - - :param name: The trigger name - :param description: The trigger description - :param metric_type: The type of trigger - :param trigger_actions: The metric report description - :param numeric_triggers: List of numeric triggers - :param discrete_trigger_condition: The value shall indicate how the - corresponding metric - :param discrete_triggers: List of discrete triggers - :param status: The trigger status - :param wildcards: Wildcards used to replace values in MetricProperties - array property - :param metric_properties: The report definition metric properties - :returns: The uri of the new trigger - """ - target_uri = self._path - - # prepare the request data of creating new trigger - data = {} - if name is not None: - data['Name'] = name - if description is not None: - data['Description'] = description - - if metric_type is not None: - validate(metric_type, - trigger_schemas.metric_type_schema) - data['MetricType'] = metric_type - - if trigger_actions is not None: - validate(trigger_actions, - trigger_schemas.trigger_actions_schema) - data['TriggerActions'] = trigger_actions - - if numeric_triggers is not None: - validate(numeric_triggers, - trigger_schemas.numeric_triggers_schema) - data['NumericTriggers'] = numeric_triggers - - if discrete_trigger_condition is not None: - validate(discrete_trigger_condition, - trigger_schemas.discrete_trigger_condition_schema) - data['DiscreteTriggerCondition'] = discrete_trigger_condition - - if discrete_triggers is not None: - validate(discrete_triggers, - trigger_schemas.discrete_triggers_schema) - data['DiscreteTriggers'] = discrete_triggers - - if status is not None: - validate(status, - trigger_schemas.status_schema) - data['Status'] = status - - if wildcards is not None: - validate(wildcards, - trigger_schemas.wildcards_schema) - data['Wildcards'] = wildcards - - if metric_properties is not None: - validate(metric_properties, - trigger_schemas.metric_properties_schema) - data['MetricProperties'] = metric_properties - - # Issue POST request to create new trigger - resp = self._conn.post(target_uri, data=data) - LOG.info("Node created at %s", resp.headers['Location']) - node_url = resp.headers['Location'] - - return node_url[node_url.find(self._path):] diff --git a/rsd_lib/resources/v2_2/telemetry/triggers.py b/rsd_lib/resources/v2_2/telemetry/triggers.py new file mode 100644 index 0000000..bedc65a --- /dev/null +++ b/rsd_lib/resources/v2_2/telemetry/triggers.py @@ -0,0 +1,219 @@ +# Copyright 2019 Intel, 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. + +from jsonschema import validate +import logging + +from sushy.resources import base + +from rsd_lib import base as rsd_lib_base +from rsd_lib.resources.v2_2.telemetry import trigger_schemas +from rsd_lib import utils as rsd_lib_utils + + +LOG = logging.getLogger(__name__) + + +class DiscreteTriggerCollectionField(base.ListField): + """DiscreteTrigger field + + A discrete trigger. + """ + + name = base.Field("Name") + """The name of trigger.""" + + value = base.Field("Value") + """This property contains the value of the trigger.""" + + dwell_tim_msec = base.Field( + "DwellTimMsec", adapter=rsd_lib_utils.num_or_none + ) + """This time the excursion persists before a trigger is determined.""" + + severity = base.Field("Severity") + """This property contains the value of the Severity property in the Event + message. + """ + + +class WildcardCollectionField(base.ListField): + """Wildcard field + + Wildcards used to replace values in MetricProperties array property. + """ + + name = base.Field("Name") + """The name of Wildcard.""" + + values = base.Field("Values") + """An array of values to substitute for the wildcard.""" + + +class NumericTriggerCollectionField(base.ListField): + """NumericTrigger field + + A numeric trigger. + """ + + name = base.Field("Name") + """The name of trigger.""" + + value = base.Field("Value", adapter=rsd_lib_utils.num_or_none) + """This property contains the value of the trigger.""" + + direction_of_crossing = base.Field("DirectionOfCrossing") + """This property contains the value of the trigger.""" + + dwell_tim_msec = base.Field( + "DwellTimMsec", adapter=rsd_lib_utils.num_or_none + ) + """This time the excursion persists before a trigger is determined.""" + + severity = base.Field("Severity") + """This property contains the value of the Severity property in the Event + message. + """ + + +class Triggers(rsd_lib_base.ResourceBase): + """Triggers resource class + + This is the schema definition for a Triggers. + """ + + metric_type = base.Field("MetricType") + """The type of trigger.""" + + trigger_actions = base.Field("TriggerActions") + """This property specifies what action is perform when the MetricTrigger + occurs. + """ + + numeric_triggers = NumericTriggerCollectionField("NumericTriggers") + """List of numeric triggers.""" + + discrete_trigger_condition = base.Field("DiscreteTriggerCondition") + """The type of trigger.""" + + discrete_triggers = DiscreteTriggerCollectionField("DiscreteTriggers") + """List of discrete triggers.""" + + status = rsd_lib_base.StatusField("Status") + """This indicates the known state of the resource, such as if it is + enabled. + """ + + wildcards = WildcardCollectionField("Wildcards") + """Wildcards used to replace values in MetricProperties array property.""" + + metric_properties = base.Field("MetricProperties") + """A collection of URI for the properties on which this metric definition + is defined. + """ + + def delete(self): + """Delete trigger""" + self._conn.delete(self.path) + + +class TriggersCollection(rsd_lib_base.ResourceCollectionBase): + @property + def _resource_type(self): + return Triggers + + def create_trigger( + self, + name=None, + description=None, + metric_type=None, + trigger_actions=None, + numeric_triggers=None, + discrete_trigger_condition=None, + discrete_triggers=None, + status=None, + wildcards=None, + metric_properties=None, + ): + """Create a new trigger + + :param name: The trigger name + :param description: The trigger description + :param metric_type: The type of trigger + :param trigger_actions: The metric report description + :param numeric_triggers: List of numeric triggers + :param discrete_trigger_condition: The value shall indicate how the + corresponding metric + :param discrete_triggers: List of discrete triggers + :param status: The trigger status + :param wildcards: Wildcards used to replace values in MetricProperties + array property + :param metric_properties: The report definition metric properties + :returns: The uri of the new trigger + """ + target_uri = self._path + + # prepare the request data of creating new trigger + data = {} + if name is not None: + data["Name"] = name + if description is not None: + data["Description"] = description + + if metric_type is not None: + validate(metric_type, trigger_schemas.metric_type_schema) + data["MetricType"] = metric_type + + if trigger_actions is not None: + validate(trigger_actions, trigger_schemas.trigger_actions_schema) + data["TriggerActions"] = trigger_actions + + if numeric_triggers is not None: + validate(numeric_triggers, trigger_schemas.numeric_triggers_schema) + data["NumericTriggers"] = numeric_triggers + + if discrete_trigger_condition is not None: + validate( + discrete_trigger_condition, + trigger_schemas.discrete_trigger_condition_schema, + ) + data["DiscreteTriggerCondition"] = discrete_trigger_condition + + if discrete_triggers is not None: + validate( + discrete_triggers, trigger_schemas.discrete_triggers_schema + ) + data["DiscreteTriggers"] = discrete_triggers + + if status is not None: + validate(status, trigger_schemas.status_schema) + data["Status"] = status + + if wildcards is not None: + validate(wildcards, trigger_schemas.wildcards_schema) + data["Wildcards"] = wildcards + + if metric_properties is not None: + validate( + metric_properties, trigger_schemas.metric_properties_schema + ) + data["MetricProperties"] = metric_properties + + # Issue POST request to create new trigger + resp = self._conn.post(target_uri, data=data) + LOG.info("Node created at %s", resp.headers["Location"]) + node_url = resp.headers["Location"] + + return node_url[node_url.find(self._path):] diff --git a/rsd_lib/tests/unit/json_samples/v2_2/trigger_collection.json b/rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json similarity index 100% rename from rsd_lib/tests/unit/json_samples/v2_2/trigger_collection.json rename to rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json diff --git a/rsd_lib/tests/unit/resources/v2_2/telemetry/test_telemetry.py b/rsd_lib/tests/unit/resources/v2_2/telemetry/test_telemetry.py index f2bc7fe..48441a5 100644 --- a/rsd_lib/tests/unit/resources/v2_2/telemetry/test_telemetry.py +++ b/rsd_lib/tests/unit/resources/v2_2/telemetry/test_telemetry.py @@ -23,263 +23,327 @@ from rsd_lib.resources.v2_2.telemetry import metric_definition from rsd_lib.resources.v2_2.telemetry import metric_report from rsd_lib.resources.v2_2.telemetry import metric_report_definition from rsd_lib.resources.v2_2.telemetry import telemetry -from rsd_lib.resources.v2_2.telemetry import trigger +from rsd_lib.resources.v2_2.telemetry import triggers class TelemetryTestCase(testtools.TestCase): - def setUp(self): super(TelemetryTestCase, self).setUp() self.conn = mock.Mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'telemetry_service.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/telemetry_service.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.telemetry_inst = telemetry.Telemetry( - self.conn, '/redfish/v1/TelemetryService', - redfish_version='1.1.0') + self.conn, "/redfish/v1/TelemetryService", redfish_version="1.1.0" + ) def test__parse_attributes(self): self.telemetry_inst._parse_attributes() - self.assertEqual('1.1.0', self.telemetry_inst.redfish_version) - self.assertEqual('Enabled', self.telemetry_inst.status.state) - self.assertEqual('OK', self.telemetry_inst.status.health) + self.assertEqual("1.1.0", self.telemetry_inst.redfish_version) + self.assertEqual("Enabled", self.telemetry_inst.status.state) + self.assertEqual("OK", self.telemetry_inst.status.health) self.assertEqual(None, self.telemetry_inst.status.health_rollup) self.assertEqual(None, self.telemetry_inst.max_reports) self.assertEqual(None, self.telemetry_inst.min_collection_interval) self.assertEqual( - None, self.telemetry_inst.supported_collection_functions) + None, self.telemetry_inst.supported_collection_functions + ) def test__get_metric_definitions_path(self): - self.assertEqual('/redfish/v1/TelemetryService/MetricDefinitions', - self.telemetry_inst._get_metric_definitions_path()) + self.assertEqual( + "/redfish/v1/TelemetryService/MetricDefinitions", + self.telemetry_inst._get_metric_definitions_path(), + ) def test__get_metric_definitions_path_missing_attr(self): - self.telemetry_inst._json.pop('MetricDefinitions') + self.telemetry_inst._json.pop("MetricDefinitions") with self.assertRaisesRegex( - exceptions.MissingAttributeError, 'attribute MetricDefinitions'): + exceptions.MissingAttributeError, "attribute MetricDefinitions" + ): self.telemetry_inst._get_metric_definitions_path() def test_metric_definitions(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN | actual_metric_definitions = self.telemetry_inst.metric_definitions # | THEN | - self.assertIsInstance(actual_metric_definitions, - metric_definition.MetricDefinitionCollection) + self.assertIsInstance( + actual_metric_definitions, + metric_definition.MetricDefinitionCollection, + ) 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_metric_definitions, - self.telemetry_inst.metric_definitions) + self.assertIs( + actual_metric_definitions, self.telemetry_inst.metric_definitions + ) self.conn.get.return_value.json.assert_not_called() def test_metric_definitions_on_refresh(self): # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | - self.assertIsInstance(self.telemetry_inst.metric_definitions, - metric_definition.MetricDefinitionCollection) + self.assertIsInstance( + self.telemetry_inst.metric_definitions, + metric_definition.MetricDefinitionCollection, + ) # On refreshing the telemetry service instance... - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'telemetry_service.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/telemetry_service.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.telemetry_inst.invalidate() self.telemetry_inst.refresh(force=False) # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | - self.assertIsInstance(self.telemetry_inst.metric_definitions, - metric_definition.MetricDefinitionCollection) + self.assertIsInstance( + self.telemetry_inst.metric_definitions, + metric_definition.MetricDefinitionCollection, + ) def test__get_metric_report_definitions_path_path(self): self.assertEqual( - '/redfish/v1/TelemetryService/MetricReportDefinitions', - self.telemetry_inst._get_metric_report_definitions_path()) + "/redfish/v1/TelemetryService/MetricReportDefinitions", + self.telemetry_inst._get_metric_report_definitions_path(), + ) def test__get_metric_report_definitions_path_missing_attr(self): - self.telemetry_inst._json.pop('MetricReportDefinitions') + self.telemetry_inst._json.pop("MetricReportDefinitions") with self.assertRaisesRegex( exceptions.MissingAttributeError, - 'attribute MetricReportDefinitions'): + "attribute MetricReportDefinitions", + ): self.telemetry_inst._get_metric_report_definitions_path() def test_metric_report_definitions(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN | - actual_report_definitions = \ + actual_report_definitions = ( self.telemetry_inst.metric_report_definitions + ) # | THEN | self.assertIsInstance( actual_report_definitions, - metric_report_definition.MetricReportDefinitionCollection) + metric_report_definition.MetricReportDefinitionCollection, + ) 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_report_definitions, - self.telemetry_inst.metric_report_definitions) + self.assertIs( + actual_report_definitions, + self.telemetry_inst.metric_report_definitions, + ) self.conn.get.return_value.json.assert_not_called() def test_metric_report_definitions_on_refresh(self): # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( self.telemetry_inst.metric_report_definitions, - metric_report_definition.MetricReportDefinitionCollection) + metric_report_definition.MetricReportDefinitionCollection, + ) # On refreshing the telemetry service instance... - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'telemetry_service.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/telemetry_service.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.telemetry_inst.invalidate() self.telemetry_inst.refresh(force=False) # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_definition_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_definition_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( self.telemetry_inst.metric_report_definitions, - metric_report_definition.MetricReportDefinitionCollection) + metric_report_definition.MetricReportDefinitionCollection, + ) def test__get_metric_reports_path_path(self): self.assertEqual( - '/redfish/v1/TelemetryService/MetricReports', - self.telemetry_inst._get_metric_reports_path()) + "/redfish/v1/TelemetryService/MetricReports", + self.telemetry_inst._get_metric_reports_path(), + ) def test__get_metric_reports_path_missing_attr(self): - self.telemetry_inst._json.pop('MetricReports') - with self.assertRaisesRegex(exceptions.MissingAttributeError, - 'attribute MetricReports'): + self.telemetry_inst._json.pop("MetricReports") + with self.assertRaisesRegex( + exceptions.MissingAttributeError, "attribute MetricReports" + ): self.telemetry_inst._get_metric_reports_path() def test_metric_reports(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN | actual_metric_reports = self.telemetry_inst.metric_reports # | THEN | self.assertIsInstance( - actual_metric_reports, metric_report.MetricReportCollection) + actual_metric_reports, metric_report.MetricReportCollection + ) 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_metric_reports, - self.telemetry_inst.metric_reports) + self.assertIs( + actual_metric_reports, self.telemetry_inst.metric_reports + ) self.conn.get.return_value.json.assert_not_called() def test_metric_reports_on_refresh(self): # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( self.telemetry_inst.metric_reports, - metric_report.MetricReportCollection) + metric_report.MetricReportCollection, + ) # On refreshing the telemetry service instance... - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'telemetry_service.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/telemetry_service.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.telemetry_inst.invalidate() self.telemetry_inst.refresh(force=False) # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'metric_report_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/" + "metric_report_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( self.telemetry_inst.metric_reports, - metric_report.MetricReportCollection) + metric_report.MetricReportCollection, + ) def test__get_triggers_path_path(self): self.assertEqual( - '/redfish/v1/TelemetryService/Triggers', - self.telemetry_inst._get_triggers_path()) + "/redfish/v1/TelemetryService/Triggers", + self.telemetry_inst._get_triggers_path(), + ) def test__get_triggers_path_missing_attr(self): - self.telemetry_inst._json.pop('Triggers') - with self.assertRaisesRegex(exceptions.MissingAttributeError, - 'attribute Triggers'): + self.telemetry_inst._json.pop("Triggers") + with self.assertRaisesRegex( + exceptions.MissingAttributeError, "attribute Triggers" + ): self.telemetry_inst._get_triggers_path() def test_triggers(self): # | GIVEN | self.conn.get.return_value.json.reset_mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'trigger_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN | actual_triggers = self.telemetry_inst.triggers # | THEN | - self.assertIsInstance( - actual_triggers, trigger.TriggerCollection) + self.assertIsInstance(actual_triggers, triggers.TriggersCollection) 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_triggers, - self.telemetry_inst.triggers) + self.assertIs(actual_triggers, self.telemetry_inst.triggers) self.conn.get.return_value.json.assert_not_called() def test_triggers_on_refresh(self): # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'trigger_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( - self.telemetry_inst.triggers, trigger.TriggerCollection) + self.telemetry_inst.triggers, triggers.TriggersCollection + ) # On refreshing the telemetry service instance... - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'telemetry_service.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/telemetry_service.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.telemetry_inst.invalidate() self.telemetry_inst.refresh(force=False) # | GIVEN | - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'trigger_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) # | WHEN & THEN | self.assertIsInstance( - self.telemetry_inst.triggers, trigger.TriggerCollection) + self.telemetry_inst.triggers, triggers.TriggersCollection + ) diff --git a/rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py b/rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py index ec67b4f..47a8e4d 100644 --- a/rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py +++ b/rsd_lib/tests/unit/resources/v2_2/telemetry/test_trigger.py @@ -17,188 +17,223 @@ import json import mock import testtools -from rsd_lib.resources.v2_2.telemetry import trigger +from rsd_lib.resources.v2_2.telemetry import triggers from rsd_lib.tests.unit.fakes import request_fakes -class TriggerTestCase(testtools.TestCase): - +class TriggersTestCase(testtools.TestCase): def setUp(self): - super(TriggerTestCase, self).setUp() + super(TriggersTestCase, self).setUp() self.conn = mock.Mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/numeric_trigger.json', - 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/numeric_trigger.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) - self.trigger_inst = trigger.Trigger( + self.triggers_inst = triggers.Triggers( self.conn, - '/redfish/v1/TelemetryService/Triggers/ProcessorTemperature', - redfish_version='1.1.0') + "/redfish/v1/TelemetryService/Triggers/ProcessorTemperature", + redfish_version="1.1.0", + ) def test__parse_attributes(self): - self.trigger_inst._parse_attributes() - self.assertEqual("ProcessorTemperature", self.trigger_inst.identity) - self.assertEqual("Triggers for Processor Temperature Malfunction", - self.trigger_inst.name) - self.assertEqual(None, self.trigger_inst.description) + self.triggers_inst._parse_attributes() + self.assertEqual("ProcessorTemperature", self.triggers_inst.identity) + self.assertEqual( + "Triggers for Processor Temperature Malfunction", + self.triggers_inst.name, + ) + self.assertEqual(None, self.triggers_inst.description) - self.assertEqual('Enabled', self.trigger_inst.status.state) - self.assertEqual('OK', self.trigger_inst.status.health) - self.assertEqual(None, self.trigger_inst.status.health_rollup) + self.assertEqual("Enabled", self.triggers_inst.status.state) + self.assertEqual("OK", self.triggers_inst.status.health) + self.assertEqual(None, self.triggers_inst.status.health_rollup) - self.assertEqual('Numeric', self.trigger_inst.metric_type) - self.assertEqual(["Transmit"], self.trigger_inst.trigger_actions) - self.assertEqual(None, self.trigger_inst.discrete_trigger_condition) - self.assertEqual(None, self.trigger_inst.discrete_triggers) - self.assertEqual(None, self.trigger_inst.wildcards) + self.assertEqual("Numeric", self.triggers_inst.metric_type) + self.assertEqual(["Transmit"], self.triggers_inst.trigger_actions) + self.assertEqual(None, self.triggers_inst.discrete_trigger_condition) + self.assertEqual(None, self.triggers_inst.discrete_triggers) + self.assertEqual(None, self.triggers_inst.wildcards) self.assertEqual( [ "/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/" "TemperatureCelsius", "/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/" - "TemperatureCelsius" + "TemperatureCelsius", ], - self.trigger_inst.metric_properties) + self.triggers_inst.metric_properties, + ) self.assertEqual( - 'UpperThresholdCritical', - self.trigger_inst.numeric_triggers[0].name) - self.assertEqual(90, self.trigger_inst.numeric_triggers[0].value) + "UpperThresholdCritical", + self.triggers_inst.numeric_triggers[0].name, + ) + self.assertEqual(90, self.triggers_inst.numeric_triggers[0].value) self.assertEqual( - 'Increasing', - self.trigger_inst.numeric_triggers[0].direction_of_crossing) + "Increasing", + self.triggers_inst.numeric_triggers[0].direction_of_crossing, + ) self.assertEqual( - 1, self.trigger_inst.numeric_triggers[0].dwell_tim_msec) + 1, self.triggers_inst.numeric_triggers[0].dwell_tim_msec + ) self.assertEqual( - 'Critical', self.trigger_inst.numeric_triggers[0].severity) + "Critical", self.triggers_inst.numeric_triggers[0].severity + ) self.assertEqual( - 'UpperThresholdNonCritical', - self.trigger_inst.numeric_triggers[1].name) - self.assertEqual(75, self.trigger_inst.numeric_triggers[1].value) + "UpperThresholdNonCritical", + self.triggers_inst.numeric_triggers[1].name, + ) + self.assertEqual(75, self.triggers_inst.numeric_triggers[1].value) self.assertEqual( - 'Increasing', - self.trigger_inst.numeric_triggers[1].direction_of_crossing) + "Increasing", + self.triggers_inst.numeric_triggers[1].direction_of_crossing, + ) self.assertEqual( - 4, self.trigger_inst.numeric_triggers[1].dwell_tim_msec) + 4, self.triggers_inst.numeric_triggers[1].dwell_tim_msec + ) self.assertEqual( - 'Warning', self.trigger_inst.numeric_triggers[1].severity) + "Warning", self.triggers_inst.numeric_triggers[1].severity + ) - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'discrete_trigger.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/discrete_trigger.json", "r" + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) - self.trigger_inst.refresh() + self.triggers_inst.refresh() self.assertEqual( - "ProcessorMachineCheckError", self.trigger_inst.identity) - self.assertEqual("Trigger for Processor Machine Check Error", - self.trigger_inst.name) + "ProcessorMachineCheckError", self.triggers_inst.identity + ) + self.assertEqual( + "Trigger for Processor Machine Check Error", + self.triggers_inst.name, + ) self.assertEqual( "Triggers for System1 Processor Machine Check Error", - self.trigger_inst.description) + self.triggers_inst.description, + ) - self.assertEqual('Enabled', self.trigger_inst.status.state) - self.assertEqual('OK', self.trigger_inst.status.health) - self.assertEqual(None, self.trigger_inst.status.health_rollup) + self.assertEqual("Enabled", self.triggers_inst.status.state) + self.assertEqual("OK", self.triggers_inst.status.health) + self.assertEqual(None, self.triggers_inst.status.health_rollup) - self.assertEqual('Discrete', self.trigger_inst.metric_type) - self.assertEqual(["Transmit"], self.trigger_inst.trigger_actions) + self.assertEqual("Discrete", self.triggers_inst.metric_type) + self.assertEqual(["Transmit"], self.triggers_inst.trigger_actions) self.assertEqual( - 'Specified', self.trigger_inst.discrete_trigger_condition) - self.assertEqual( - None, self.trigger_inst.numeric_triggers) - self.assertEqual(None, self.trigger_inst.wildcards) + "Specified", self.triggers_inst.discrete_trigger_condition + ) + self.assertEqual(None, self.triggers_inst.numeric_triggers) + self.assertEqual(None, self.triggers_inst.wildcards) self.assertEqual( [ "/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/" "CPUHealth", "/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/" - "CPUHealth" + "CPUHealth", ], - self.trigger_inst.metric_properties) + self.triggers_inst.metric_properties, + ) - self.assertEqual(None, self.trigger_inst.discrete_triggers[0].name) + self.assertEqual(None, self.triggers_inst.discrete_triggers[0].name) self.assertEqual( "Machine Check Exception", - self.trigger_inst.discrete_triggers[0].value) + self.triggers_inst.discrete_triggers[0].value, + ) self.assertEqual( - 1, self.trigger_inst.discrete_triggers[0].dwell_tim_msec) + 1, self.triggers_inst.discrete_triggers[0].dwell_tim_msec + ) self.assertEqual( - 'Critical', self.trigger_inst.discrete_triggers[0].severity) + "Critical", self.triggers_inst.discrete_triggers[0].severity + ) def test_delete(self): - self.trigger_inst.delete() - self.trigger_inst._conn.delete.assert_called_once_with( - self.trigger_inst.path) + self.triggers_inst.delete() + self.triggers_inst._conn.delete.assert_called_once_with( + self.triggers_inst.path + ) -class TriggerCollectionTestCase(testtools.TestCase): - +class TriggersCollectionTestCase(testtools.TestCase): def setUp(self): - super(TriggerCollectionTestCase, self).setUp() + super(TriggersCollectionTestCase, self).setUp() self.conn = mock.Mock() - with open('rsd_lib/tests/unit/json_samples/v2_2/' - 'trigger_collection.json', 'r') as f: + with open( + "rsd_lib/tests/unit/json_samples/v2_2/triggers_collection.json", + "r", + ) as f: self.conn.get.return_value.json.return_value = json.loads(f.read()) self.conn.post.return_value = request_fakes.fake_request_post( - None, headers={ + None, + headers={ "Location": "https://localhost:8443/redfish/v1/" - "TelemetryService/Triggers/2"}) - - self.trigger_col = trigger.TriggerCollection( - self.conn, '/redfish/v1/TelemetryService/Triggers', - redfish_version='1.1.0') - - def test_parse_attributes(self): - self.trigger_col._parse_attributes() - self.assertEqual("Triggers Collection", self.trigger_col.name) - - @mock.patch.object(trigger, 'Trigger', autospec=True) - def test_get_member(self, mock_trigger): - self.trigger_col.get_member( - '/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError') - - mock_trigger.assert_called_once_with( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError', - redfish_version=self.trigger_col.redfish_version + "TelemetryService/Triggers/2" + }, ) - @mock.patch.object(trigger, 'Trigger', autospec=True) + self.triggers_col = triggers.TriggersCollection( + self.conn, + "/redfish/v1/TelemetryService/Triggers", + redfish_version="1.1.0", + ) + + def test_parse_attributes(self): + self.triggers_col._parse_attributes() + self.assertEqual("Triggers Collection", self.triggers_col.name) + + @mock.patch.object(triggers, "Triggers", autospec=True) + def test_get_member(self, mock_trigger): + self.triggers_col.get_member( + "/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError" + ) + + mock_trigger.assert_called_once_with( + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/ProcessorCatastrophicError", + redfish_version=self.triggers_col.redfish_version, + ) + + @mock.patch.object(triggers, "Triggers", autospec=True) def test_get_members(self, mock_trigger): - members = self.trigger_col.get_members() + members = self.triggers_col.get_members() calls = [ mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/' - 'ProcessorCatastrophicError', - redfish_version=self.trigger_col.redfish_version), + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/" + "ProcessorCatastrophicError", + redfish_version=self.triggers_col.redfish_version, + ), mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/' - 'ProcessorInitializationError', - redfish_version=self.trigger_col.redfish_version), + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/" + "ProcessorInitializationError", + redfish_version=self.triggers_col.redfish_version, + ), mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/' - 'ProcessorMachineCheckError', - redfish_version=self.trigger_col.redfish_version), + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/" + "ProcessorMachineCheckError", + redfish_version=self.triggers_col.redfish_version, + ), mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/ProcessorPOSTFailure', - redfish_version=self.trigger_col.redfish_version), + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/ProcessorPOSTFailure", + redfish_version=self.triggers_col.redfish_version, + ), mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/ProcessorTemperature', - redfish_version=self.trigger_col.redfish_version), + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/ProcessorTemperature", + redfish_version=self.triggers_col.redfish_version, + ), mock.call( - self.trigger_col._conn, - '/redfish/v1/TelemetryService/Triggers/ProcessorThermalTrip', - redfish_version=self.trigger_col.redfish_version) + self.triggers_col._conn, + "/redfish/v1/TelemetryService/Triggers/ProcessorThermalTrip", + redfish_version=self.triggers_col.redfish_version, + ), ] mock_trigger.assert_has_calls(calls) self.assertEqual(mock_trigger.call_count, 6) @@ -209,40 +244,37 @@ class TriggerCollectionTestCase(testtools.TestCase): reqs = { "Name": "Trigger for Processor Machine Check Error", "Description": "Triggers for System1 Processor Machine Check " - "Error", + "Error", "MetricType": "Discrete", - "TriggerActions": [ - "Transmit" - ], + "TriggerActions": ["Transmit"], "DiscreteTriggerCondition": "Specified", "DiscreteTriggers": [ { "Value": "Machine Check Exception", "DwellTimMsec": 1, - "Severity": "Critical" + "Severity": "Critical", } ], - "Status": { - "State": "Enabled", - "Health": "OK" - }, + "Status": {"State": "Enabled", "Health": "OK"}, "MetricProperties": [ "/redfish/v1/Systems/System1/Processors/CPU0/Metrics#/" "CPUHealth", "/redfish/v1/Systems/System1/Processors/CPU1/Metrics#/" - "CPUHealth" - ] + "CPUHealth", + ], } - result = self.trigger_col.create_trigger( - name=reqs['Name'], description=reqs['Description'], - metric_type=reqs['MetricType'], - trigger_actions=reqs['TriggerActions'], - discrete_trigger_condition=reqs['DiscreteTriggerCondition'], - discrete_triggers=reqs['DiscreteTriggers'], status=reqs['Status'], - metric_properties=reqs['MetricProperties'],) - self.trigger_col._conn.post.assert_called_once_with( - '/redfish/v1/TelemetryService/Triggers', - data=reqs) - self.assertEqual( - result, '/redfish/v1/TelemetryService/Triggers/2') + result = self.triggers_col.create_trigger( + name=reqs["Name"], + description=reqs["Description"], + metric_type=reqs["MetricType"], + trigger_actions=reqs["TriggerActions"], + discrete_trigger_condition=reqs["DiscreteTriggerCondition"], + discrete_triggers=reqs["DiscreteTriggers"], + status=reqs["Status"], + metric_properties=reqs["MetricProperties"], + ) + self.triggers_col._conn.post.assert_called_once_with( + "/redfish/v1/TelemetryService/Triggers", data=reqs + ) + self.assertEqual(result, "/redfish/v1/TelemetryService/Triggers/2")