From 1544e1f0722677ff5b5b50cb4c64ab883b721121 Mon Sep 17 00:00:00 2001 From: rherrell Date: Thu, 12 Feb 2026 15:44:11 -0700 Subject: [PATCH 1/7] in progress: add ResourceChanged event handling Signed-off-by: rherrell --- .../redfish/redfish_event_handler.py | 105 +++++++++++++++++- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py index 2a62045..2404005 100644 --- a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py +++ b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py @@ -83,7 +83,7 @@ def ResourceCreated(cls, event_handler: EventHandlerInterface, event: dict, cont # sunfishAliasDB contains renaming data, the alias xref array, the boundaryLink # data, and assorted flags that are used during upload renaming and final merge of # boundary components based on boundary links. - # + # logger.info("New resource created") @@ -111,7 +111,7 @@ def ResourceCreated(cls, event_handler: EventHandlerInterface, event: dict, cont if "@odata.id" not in response: # should never hit this! logger.warning(f"Resource {id} did not have @odata.id set when retrieved from Agent. Initializing its value with {id}") - response["odata.id"] = id + response["@odata.id"] = id # New resource should not exist in Sunfish inventory length = len(event_handler.core.conf["redfish_root"]) @@ -133,6 +133,76 @@ def ResourceCreated(cls, event_handler: EventHandlerInterface, event: dict, cont logger.debug(f"\n{json.dumps(aggregation_source, indent=4)}") return 200 + @classmethod + def ResourceChanged(cls, event_handler: EventHandlerInterface, event: dict, context: str): + """ + Handles a ResourceChanged event from an agent. + This handler fetches the updated resource from the agent, translates its + URI to the corresponding Sunfish URI, and patches the existing object in + the database with the new properties. + """ + pdb.set_trace() + try: + if "OriginOfCondition" not in event or not event["OriginOfCondition"].get("@odata.id"): + logger.error("ResourceChanged event is missing OriginOfCondition.") + return + + if not context: + logger.error("No context (AggregationSource ID) in ResourceChanged event.") + return + + aggregation_source_id = context + aggregation_source = event_handler.core.storage_backend.read(f"/redfish/v1/AggregationService/AggregationSources/{aggregation_source_id}") + host = aggregation_source["HostName"] + origin_of_condition = event["OriginOfCondition"]["@odata.id"] + + # Fetch the updated resource from the agent + logger.info(f"Fetching updated resource {origin_of_condition} from agent {aggregation_source_id} at {host}") + resource_endpoint = host + origin_of_condition + response = requests.get(resource_endpoint) + if response.status_code != 200: + logger.error(f"Could not fetch resource {origin_of_condition} from agent {aggregation_source_id}. Status: {response.status_code}") + return + updated_resource = response.json() + + # URI Aliasing to find the object in Sunfish + sunfish_uri = RedfishEventHandler.xlateToSunfishPath(event_handler.core, origin_of_condition, aggregation_source) + + # Check if object exists before attempting to patch + try: + event_handler.core.storage_backend.read(sunfish_uri) + except NotFound: + logger.error(f"ResourceChanged event for a non-existent object. Agent URI: {origin_of_condition}, Sunfish URI: {sunfish_uri}") + return + + # Get aliases for this agent to update links in the payload + uri_alias_file = os.path.join(os.getcwd(), event_handler.core.conf["backend_conf"]["fs_private"], 'URI_aliases.json') + agent_aliases = {} + if os.path.exists(uri_alias_file): + with open(uri_alias_file, 'r') as data_json: + uri_aliasDB = json.load(data_json) + owning_agent_id = aggregation_source["@odata.id"].split("/")[-1] + if owning_agent_id in uri_aliasDB.get('Agents_xref_URIs', {}) and 'aliases' in uri_aliasDB['Agents_xref_URIs'][owning_agent_id]: + agent_aliases = uri_aliasDB['Agents_xref_URIs'][owning_agent_id]['aliases'] + + # Update any internal @odata.id links in the fetched payload + updated_resource = RedfishEventHandler.update_aliased_links_in_object(event_handler.core, updated_resource, agent_aliases) + + # Boundary Link Processing - check if this update establishes a new boundary link + if "Oem" in updated_resource and "Sunfish_RM" in updated_resource["Oem"] and updated_resource["Oem"]["Sunfish_RM"].get("BoundaryComponent") == "BoundaryPort": + RedfishEventHandler.track_boundary_port(event_handler.core, updated_resource, aggregation_source) + + # Patch the existing object with the new data + logger.info(f"Patching resource at {sunfish_uri}") + event_handler.core.storage_backend.patch(sunfish_uri, updated_resource) + + # After patching, check if any cross-agent links need to be updated + RedfishEventHandler.updateAllAgentsRedirectedLinks(event_handler.core) + + except Exception: + logger.error("Exception in ResourceChanged handler", exc_info=True) + + @classmethod def TriggerEvent(cls, event_handler: EventHandlerInterface, event: dict, context: str): ### @@ -199,6 +269,7 @@ class RedfishEventHandler(EventHandlerInterface): dispatch_table = { "AggregationSourceDiscovered": RedfishEventHandlersTable.AggregationSourceDiscovered, "ResourceCreated": RedfishEventHandlersTable.ResourceCreated, + "ResourceChanged": RedfishEventHandlersTable.ResourceChanged, "TriggerEvent": RedfishEventHandlersTable.TriggerEvent } @@ -524,7 +595,7 @@ def createInspectedObject(self,redfish_obj, aggregation_source): redfish_obj['Id'] = sunfish_aliased_URI.split("/")[-1] logger.debug(f"xlated agent_redfish_URI is {sunfish_aliased_URI}") if 'Collection' in redfish_obj['@odata.type']: - logger.debug("This is a collection, ignore it until we need it") + logger.info("This is a collection, ignore it until we need it") pass else: # use Sunfish (aliased) paths for conflict testing if it exists @@ -631,6 +702,34 @@ def xlateToSunfishPath(self,agent_path, aggregation_source): agent_path = agentFinal_obj_path return agent_path + def update_aliased_links_in_object(self, obj, agent_aliases): + """ + Recursively traverses a dictionary/list object and updates any '@odata.id' + links based on the provided agent_aliases mapping. + """ + def findNestedURIs(obj, aliases): + if isinstance(obj, list): + for item in obj: + findNestedURIs(item, aliases) + elif isinstance(obj, dict): + for key, value in obj.items(): + if key == '@odata.id' and value in aliases: + logger.info(f"Translating internal link {value} to {aliases[value]}") + obj[key] = aliases[value] + # Do not recurse into Sunfish_RM as its paths are not meant to be translated. + elif key != "Sunfish_RM" and isinstance(value, (dict, list)): + findNestedURIs(value, aliases) + + if not isinstance(obj, dict) or "@odata.type" not in obj: + return obj + + obj_type = obj["@odata.type"].split('.')[0].replace("#", "") + # Do not perform aliasing on the Members array of a Collection, as the Members array + # should contain both original and aliased URIs. + if "Collection" not in obj_type: + findNestedURIs(obj, agent_aliases) + return obj + def updateAllAliasedLinks(self,aggregation_source): try: uri_alias_file = os.path.join(os.getcwd(), self.conf["backend_conf"]["fs_private"], 'URI_aliases.json') From f5a3ebdd703512abe2b6a38fe13e1ea49421629d Mon Sep 17 00:00:00 2001 From: rherrell Date: Mon, 9 Mar 2026 16:05:26 -0600 Subject: [PATCH 2/7] fixed a bug and added 1 new test for core Signed-off-by: rherrell --- .../index.json | 14 ++++++++ .../AggregationSources/index.json | 11 ++++++ .../ConnectionMethods/index.json | 9 ----- tests/Resources/AggregationService/index.json | 6 +++- tests/test_sunfishcore_library.py | 11 ++++++ tests/tests_template.py | 35 ++++++++++++++++++- 6 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json create mode 100755 tests/Resources/AggregationService/AggregationSources/index.json delete mode 100644 tests/Resources/AggregationService/ConnectionMethods/index.json diff --git a/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json b/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json new file mode 100644 index 0000000..2fb1485 --- /dev/null +++ b/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json @@ -0,0 +1,14 @@ +{ + "@odata.id": "/redfish/v1/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955", + "@odata.type": "#AggregationSource.v1_2_.AggregationSource", + "HostName": "http://127.0.0.1:8080", + "Id": "feb7bb58-83f2-4945-a798-7c0811a29955", + "Links": { + "ConnectionMethod": { + "@odata.id": "/redfish/v1/AggregationService/ConnectionMethods/Pytest1" + }, + "ResourcesAccessed": [ + "/redfish/v1/Fabrics/Pytest1Fabric" + ] + } +} diff --git a/tests/Resources/AggregationService/AggregationSources/index.json b/tests/Resources/AggregationService/AggregationSources/index.json new file mode 100755 index 0000000..fbb2a81 --- /dev/null +++ b/tests/Resources/AggregationService/AggregationSources/index.json @@ -0,0 +1,11 @@ +{ + "@odata.id": "/redfish/v1/AggregationService/AggregationSources", + "@odata.type": "#AggregationService/AggregationSourcesCollection.AggregationService/AggregationSourcesCollection", + "Members": [ + { + "@odata.id": "/redfish/v1/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955" + } + ], + "Members@odata.count": 1, + "Name": "AggregationService/AggregationSources Collection" +} diff --git a/tests/Resources/AggregationService/ConnectionMethods/index.json b/tests/Resources/AggregationService/ConnectionMethods/index.json deleted file mode 100644 index 1e97d55..0000000 --- a/tests/Resources/AggregationService/ConnectionMethods/index.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "@odata.type": "#ConnectionMethodCollection.ConnectionMethodCollection", - "Name": "ConnectionMethod Collection", - "Members@odata.count": 0, - "Members": [ - ], - "@odata.id": "/redfish/v1/ConnectionMethods", - "@Redfish.Copyright": "Copyright 2015-2022 SNIA. All rights reserved." -} diff --git a/tests/Resources/AggregationService/index.json b/tests/Resources/AggregationService/index.json index 14f4caa..37f011d 100644 --- a/tests/Resources/AggregationService/index.json +++ b/tests/Resources/AggregationService/index.json @@ -7,8 +7,12 @@ "State": "Enabled", "Health": "OK" }, + "AgregationSources": { + "@odata.id": "/redfish/v1/AggregationService/AggregationSources" + }, + "ServiceEnabled": true, "@odata.id": "/redfish/v1/AggregationService", "@Redfish.Copyright": "Copyright 2023 OpenFabrics Alliance. All rights reserved." -} \ No newline at end of file +} diff --git a/tests/test_sunfishcore_library.py b/tests/test_sunfishcore_library.py index ae2b453..56b7d6a 100644 --- a/tests/test_sunfishcore_library.py +++ b/tests/test_sunfishcore_library.py @@ -8,6 +8,7 @@ import os import logging import pytest +import pdb from pytest_httpserver import HTTPServer from sunfish.lib.core import Core from sunfish.lib.exceptions import * @@ -188,6 +189,16 @@ def test_agent_delete_forwarding(self, httpserver: HTTPServer): assert resp == f"Object {connection_path} deleted" + # test agent register and agent upload event handlers + def test_agent_register(self, httpserver: HTTPServer): + pdb.set_trace() + connection_path = os.path.join(self.conf['redfish_root'], "AggregationService/ConnectionMethods/Pytest2") + httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.connection_method_pytest2) + connection_path = os.path.join(self.conf['redfish_root'], "EventService/Subscriptions/SunfishServer") + httpserver.expect_ordered_request(connection_path, method="PATCH").respond_with_data("OK") + resp = self.core.handle_event(tests_template.reg_event) + + assert len(resp) == 0 # deletes all the subscriptions @pytest.mark.order("last") def test_clean_up(self): diff --git a/tests/tests_template.py b/tests/tests_template.py index 34c00bc..0dc27c5 100644 --- a/tests/tests_template.py +++ b/tests/tests_template.py @@ -489,4 +489,37 @@ "@odata.id": "/redfish/v1/Fabrics/CXL" } }] -} \ No newline at end of file +} + +reg_event = { + "@odata.type": "#Event.v1_7_0.Event", + "Name": "AggregationSourceDiscovered", + "Context": "", + "Events": [ { + "Severity": "Ok", + "Message": "A aggregation source of connection method", + "MessageId": "ResourceEvent.1.x.AggregationSourceDiscovered", + "MessageArgs": [ "Redfish", "http://127.0.0.1:8080" ], + "OriginOfCondition": { + "@odata.id": "/redfish/v1/AggregationService/ConnectionMethods/Pytest2" + } + } ] +} + +connection_method_pytest2 = { + "@odata.id": "/redfish/v1/AggregationService/ConnectionMethods/Pytest2", + "@odata.type": "#ConnectionMethod.v1_1_0.ConnectionMethod", + "ConnectionMethodType": "Redfish", + "ConnectionMethodVariant": "Contoso", + "Id": "Pytest2", + "Links": { + "AggregationSources": [] + }, + "Name": "ConnectionMethod for Agent Pytest2", + "Oem": { + "Sunfish_RM": { + "@odata.type": "#SunfishExtensions.v1_0_0.ResourceExtensions" + } + } +} + From 0de4f7c442c06e59dfa81d4cf2af197b1e8ed772 Mon Sep 17 00:00:00 2001 From: rherrell Date: Fri, 13 Mar 2026 00:01:11 -0600 Subject: [PATCH 3/7] more fixes to agent_upload tests, and Sunfish renaming routings Signed-off-by: rherrell --- .../Resources/SunfishPrivate/URI_aliases.json | 30 +++++++++ tests/conf.json | 2 +- tests/test_sunfishcore_library.py | 22 ++++++- tests/tests_template.py | 62 +++++++++++++++++++ 4 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 tests/Resources/SunfishPrivate/URI_aliases.json diff --git a/tests/Resources/SunfishPrivate/URI_aliases.json b/tests/Resources/SunfishPrivate/URI_aliases.json new file mode 100644 index 0000000..75d4b23 --- /dev/null +++ b/tests/Resources/SunfishPrivate/URI_aliases.json @@ -0,0 +1,30 @@ +{ + "Sunfish_xref_URIs" : { + "aliases": { + "/example/Sunfish/URI": [ + "/example/Agent1/URI", + "/example/Agent2/URI" + ], + "/another/Sunfish/URI": [ + "/different/Agent1/URI" + ] + }, + "missing": [] + }, + + "Agents_xref_URIs" : { + "exampleAgentContex": { + "aliases": { + "/example/Agent/URI": "/exampleRenamed/Sunfish/URI", + "/another/Agent/URI": "/anotherRenamed/Sunfish/URI" + }, + "foreignBoundaryComponents": { + "/example/Agent/boundary/URI": "/exampleRenamed/Sunfish/boundary/URI", + "/another/Agent/boundary/URI": "/anotherRenamed/Sunfish/boundary/URI" + + } + + } + + } +} diff --git a/tests/conf.json b/tests/conf.json index 57f09e8..31f9512 100644 --- a/tests/conf.json +++ b/tests/conf.json @@ -6,7 +6,7 @@ }, "backend_conf" : { "fs_root": "Resources", - "fs_private": "SunfishPrivate", + "fs_private": "Resources/SunfishPrivate", "subscribers_root": "EventService/Subscriptions" }, "events_handler": { diff --git a/tests/test_sunfishcore_library.py b/tests/test_sunfishcore_library.py index 56b7d6a..c3c03ff 100644 --- a/tests/test_sunfishcore_library.py +++ b/tests/test_sunfishcore_library.py @@ -191,14 +191,34 @@ def test_agent_delete_forwarding(self, httpserver: HTTPServer): # test agent register and agent upload event handlers def test_agent_register(self, httpserver: HTTPServer): - pdb.set_trace() connection_path = os.path.join(self.conf['redfish_root'], "AggregationService/ConnectionMethods/Pytest2") httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.connection_method_pytest2) connection_path = os.path.join(self.conf['redfish_root'], "EventService/Subscriptions/SunfishServer") httpserver.expect_ordered_request(connection_path, method="PATCH").respond_with_data("OK") resp = self.core.handle_event(tests_template.reg_event) + httpserver.check() + + assert len(resp) == 0 + + def test_agent_upload(self, httpserver: HTTPServer): + pdb.set_trace() + # arm the httpserver with agent's response to GET on OriginOfCondition + connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1") + httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_pytest1) + # the above is actually retrieved again at start up recursive fetch (upload) + connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1") + httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_pytest1) + # arm the httpserver with agent's response to GET on subordinate Switches collection + connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1/Switches") + httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_switch_collection) + # arm the httpserver with agent's response to GET on Switch object + connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1/Switches/Pytest1") + httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_switch_pytest1) + resp = self.core.handle_event(tests_template.upload_event) + httpserver.check() assert len(resp) == 0 + # deletes all the subscriptions @pytest.mark.order("last") def test_clean_up(self): diff --git a/tests/tests_template.py b/tests/tests_template.py index 0dc27c5..19e775e 100644 --- a/tests/tests_template.py +++ b/tests/tests_template.py @@ -506,6 +506,21 @@ } ] } +upload_event = { + "@odata.type": "#Event.v1_7_0.Event", + "Name": "ResourceCreated", + "Context": "feb7bb58-83f2-4945-a798-7c0811a29955", + "Events": [ { + "Severity": "Ok", + "Message": "A new Fabric resource created", + "MessageId": "ResourceEvent.1.x.ResourceCreated", + "MessageArgs": [ "Redfish", "http://127.0.0.1:8080" ], + "OriginOfCondition": { + "@odata.id": "/redfish/v1/Fabrics/Pytest1" + } + } ] +} + connection_method_pytest2 = { "@odata.id": "/redfish/v1/AggregationService/ConnectionMethods/Pytest2", "@odata.type": "#ConnectionMethod.v1_1_0.ConnectionMethod", @@ -523,3 +538,50 @@ } } +fabrics_pytest1 = { + "@odata.id": "/redfish/v1/Fabrics/Pytest1", + "@odata.type": "#Fabric.v1_3_0.Fabric", + "Description": "Pytest CXL Fabric", + "FabricType": "CXL", + "Id": "CXL", + "Name": "CXL Fabric", + "Status": { + "Health": "OK", + "State": "Enabled" + }, + "Switches": { + "@odata.id": "/redfish/v1/Fabrics/Pytest1/Switches" + }, + "UUID": "1af883ee-d4b7-400d-afb2-536d2c2aea31" +} + +fabrics_switch_collection = { + "@odata.id": "/redfish/v1/Fabrics/Pytest1/Switches", + "@odata.type": "#SwitchesCollection.SwitchesCollection", + "Members": [ + ], + "Members@odata.count": 0, + "Name": "Switches Collection" +} + +fabrics_switch_pytest1 = { + "@odata.id": "/redfish/v1/Fabrics/CXL/Switches/Pytest1", + "@odata.type": "#Switch.v1_9_1.Switch", + "CXL": { + "MaxVCSsSupported": 4, + "TotalNumbervPPBs": 4, + "VCS": { + "HDMDecoders": 12 + } + }, + "Id": "CXL1", + "Name": "CXL Fabric Switch", + "Status": { + "Health": "OK", + "HealthRollup": "OK", + "State": "Enabled" + }, + "SwitchType": "CXL", + "UUID": "bfd8ca1e-b5b5-4c0f-a3cf-4d741b85b1fb" +} + From b23a9bea835b208f059d273cbdd1e7e984f6340d Mon Sep 17 00:00:00 2001 From: rherrell Date: Fri, 13 Mar 2026 00:07:26 -0600 Subject: [PATCH 4/7] more fixes for agent_upload tests, and Sunfish renaming Signed-off-by: rherrell --- .../events_handlers/redfish/redfish_event_handler.py | 3 ++- .../objects_managers/sunfish_agent/sunfish_agent_manager.py | 6 ++++++ .../feb7bb58-83f2-4945-a798-7c0811a29955/index.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py index 2404005..d915978 100644 --- a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py +++ b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py @@ -40,7 +40,8 @@ def AggregationSourceDiscovered(cls, event_handler: EventHandlerInterface, event connectionMethodId = event['OriginOfCondition']['@odata.id'] hostname = event['MessageArgs'][1] # Agent address - response = requests.get(f"{hostname}/{connectionMethodId}") + #response = requests.get(f"{hostname}/{connectionMethodId}") + response = requests.get(f"{hostname}{connectionMethodId}") if response.status_code != 200: raise Exception("Cannot find ConnectionMethod") response = response.json() diff --git a/sunfish_plugins/objects_managers/sunfish_agent/sunfish_agent_manager.py b/sunfish_plugins/objects_managers/sunfish_agent/sunfish_agent_manager.py index 070f353..784ac6a 100644 --- a/sunfish_plugins/objects_managers/sunfish_agent/sunfish_agent_manager.py +++ b/sunfish_plugins/objects_managers/sunfish_agent/sunfish_agent_manager.py @@ -221,7 +221,13 @@ def findNestedURIs(self, URI_to_match, URI_to_sub, obj, path_to_nested_URI): try: #pdb.set_trace() owning_agent_id = agent_obj["Oem"]["Sunfish_RM"]["ManagingAgent"]["@odata.id"].split("/")[-1] + # must also have agent_aliases in the database agent_aliases = uri_aliasDB["Agents_xref_URIs"][owning_agent_id]["aliases"] + except (KeyError, TypeError): + # can't rename links without all the above keys in the uri_aliasDB + return False + + try: object_URI = agent_obj["@odata.id"] aliasedNestedPaths=[] obj_modified = False diff --git a/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json b/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json index 2fb1485..f400ead 100644 --- a/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json +++ b/tests/Resources/AggregationService/AggregationSources/feb7bb58-83f2-4945-a798-7c0811a29955/index.json @@ -8,7 +8,7 @@ "@odata.id": "/redfish/v1/AggregationService/ConnectionMethods/Pytest1" }, "ResourcesAccessed": [ - "/redfish/v1/Fabrics/Pytest1Fabric" + "/redfish/v1/Fabrics/Pytest1" ] } } From a12f1a17d5dc1afab334e14619217d4fe42b5938 Mon Sep 17 00:00:00 2001 From: rherrell Date: Mon, 16 Mar 2026 07:23:18 -0600 Subject: [PATCH 5/7] made minor test suite changes, config changes Signed-off-by: rherrell --- tests/conf_broken_module.json | 2 +- tests/test_sunfishcore_library.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/conf_broken_module.json b/tests/conf_broken_module.json index 222d9f2..740db2e 100644 --- a/tests/conf_broken_module.json +++ b/tests/conf_broken_module.json @@ -6,7 +6,7 @@ }, "backend_conf" : { "fs_root": "Resources", - "fs_private": "SunfishPrivate", + "fs_private": "Resources/SunfishPrivate", "subscribers_root": "EventService/Subscriptions" }, "event_handler": { diff --git a/tests/test_sunfishcore_library.py b/tests/test_sunfishcore_library.py index c3c03ff..793c057 100644 --- a/tests/test_sunfishcore_library.py +++ b/tests/test_sunfishcore_library.py @@ -201,11 +201,11 @@ def test_agent_register(self, httpserver: HTTPServer): assert len(resp) == 0 def test_agent_upload(self, httpserver: HTTPServer): - pdb.set_trace() + #pdb.set_trace() # arm the httpserver with agent's response to GET on OriginOfCondition connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1") httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_pytest1) - # the above is actually retrieved again at start up recursive fetch (upload) + # the above is actually retrieved again at start of recursive fetch (upload) connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1") httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_pytest1) # arm the httpserver with agent's response to GET on subordinate Switches collection @@ -216,6 +216,8 @@ def test_agent_upload(self, httpserver: HTTPServer): httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_switch_pytest1) resp = self.core.handle_event(tests_template.upload_event) httpserver.check() + # TODO + # should verify the two objects got uploaded and written to the Sunfish DB assert len(resp) == 0 From ba8ad5a345108cb3536b49790aecb5435884d4c7 Mon Sep 17 00:00:00 2001 From: rherrell Date: Mon, 16 Mar 2026 07:34:26 -0600 Subject: [PATCH 6/7] had to remove a pdb.set_trace() Signed-off-by: rherrell --- .../events_handlers/redfish/redfish_event_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py index d915978..c8b9e39 100644 --- a/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py +++ b/sunfish_plugins/events_handlers/redfish/redfish_event_handler.py @@ -142,7 +142,7 @@ def ResourceChanged(cls, event_handler: EventHandlerInterface, event: dict, cont URI to the corresponding Sunfish URI, and patches the existing object in the database with the new properties. """ - pdb.set_trace() + #pdb.set_trace() try: if "OriginOfCondition" not in event or not event["OriginOfCondition"].get("@odata.id"): logger.error("ResourceChanged event is missing OriginOfCondition.") From 8469a8d6c76f462b5657626988a519c28bda4033 Mon Sep 17 00:00:00 2001 From: rherrell Date: Fri, 20 Mar 2026 16:37:19 -0600 Subject: [PATCH 7/7] fixed the test directory initialization problem, and another bug in the agent upload test Signed-off-by: rherrell --- Makefile | 2 -- tests/test_sunfishcore_library.py | 15 +++++++++++++-- tests/tests_template.py | 9 ++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 20223a2..fcd8158 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,6 @@ build: poetry build test: - rm -rf ./Resources - cp -rp ./tests/Resources . python3 -m pytest tests/test_sunfishcore_library.py -vvvv clean: diff --git a/tests/test_sunfishcore_library.py b/tests/test_sunfishcore_library.py index 793c057..5870bc2 100644 --- a/tests/test_sunfishcore_library.py +++ b/tests/test_sunfishcore_library.py @@ -8,7 +8,9 @@ import os import logging import pytest +import shutil import pdb +from pathlib import Path from pytest_httpserver import HTTPServer from sunfish.lib.core import Core from sunfish.lib.exceptions import * @@ -59,6 +61,15 @@ def test_delete(self): self.core.delete_object(system_url) assert test_utils.check_delete(system_url) == True + # reset the test directory + def test_reset_directories(self): + base_path = Path(__file__).parent.parent + src = base_path / "tests/Resources" + dst = base_path / "Resources" + # Copy the test tree over the existing Resources tree + shutil.rmtree(dst, ignore_errors=True) + shutil.copytree(src, dst, dirs_exist_ok=True) + def test_delete_exception(self): system_url = os.path.join(self.conf["redfish_root"], 'Systems', '-1') # raise exception if element doesnt exist @@ -196,7 +207,7 @@ def test_agent_register(self, httpserver: HTTPServer): connection_path = os.path.join(self.conf['redfish_root'], "EventService/Subscriptions/SunfishServer") httpserver.expect_ordered_request(connection_path, method="PATCH").respond_with_data("OK") resp = self.core.handle_event(tests_template.reg_event) - httpserver.check() + assert len(httpserver.log) == 2 assert len(resp) == 0 @@ -215,7 +226,7 @@ def test_agent_upload(self, httpserver: HTTPServer): connection_path = os.path.join(self.conf['redfish_root'], "Fabrics/Pytest1/Switches/Pytest1") httpserver.expect_ordered_request(connection_path, method="GET").respond_with_json(tests_template.fabrics_switch_pytest1) resp = self.core.handle_event(tests_template.upload_event) - httpserver.check() + assert len(httpserver.log) == 4 # TODO # should verify the two objects got uploaded and written to the Sunfish DB diff --git a/tests/tests_template.py b/tests/tests_template.py index 19e775e..7418120 100644 --- a/tests/tests_template.py +++ b/tests/tests_template.py @@ -559,13 +559,16 @@ "@odata.id": "/redfish/v1/Fabrics/Pytest1/Switches", "@odata.type": "#SwitchesCollection.SwitchesCollection", "Members": [ + { + "@odata.id" : "/redfish/v1/Fabrics/Pytest1/Switches/Pytest1" + } ], - "Members@odata.count": 0, + "Members@odata.count": 1, "Name": "Switches Collection" } fabrics_switch_pytest1 = { - "@odata.id": "/redfish/v1/Fabrics/CXL/Switches/Pytest1", + "@odata.id": "/redfish/v1/Fabrics/Pytest1/Switches/Pytest1", "@odata.type": "#Switch.v1_9_1.Switch", "CXL": { "MaxVCSsSupported": 4, @@ -574,7 +577,7 @@ "HDMDecoders": 12 } }, - "Id": "CXL1", + "Id": "Pytest1", "Name": "CXL Fabric Switch", "Status": { "Health": "OK",