Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-sushy for openSUSE:Factory checked in at 2026-08-22 21:36:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-sushy (Old) and /work/SRC/openSUSE:Factory/.python-sushy.new.1258 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-sushy" Sat Aug 22 21:36:38 2026 rev:25 rq:1373088 version:5.13.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-sushy/python-sushy.changes 2026-08-09 21:37:15.078148215 +0200 +++ /work/SRC/openSUSE:Factory/.python-sushy.new.1258/python-sushy.changes 2026-08-22 21:38:45.056816164 +0200 @@ -1,0 +2,7 @@ +Sat Aug 22 14:13:41 UTC 2026 - Dirk Müller <[email protected]> + +- update to 5.13.0: + * system: guard HttpBootUri writes against iDRAC 10 removal + * Handle incomplete TaskMonitor responses + +------------------------------------------------------------------- Old: ---- sushy-5.12.0.tar.gz New: ---- sushy-5.13.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-sushy.spec ++++++ --- /var/tmp/diff_new_pack.EIMz2k/_old 2026-08-22 21:38:46.397864198 +0200 +++ /var/tmp/diff_new_pack.EIMz2k/_new 2026-08-22 21:38:46.399864269 +0200 @@ -17,7 +17,7 @@ Name: python-sushy -Version: 5.12.0 +Version: 5.13.0 Release: 0 Summary: Python library to communicate with Redfish based systems License: Apache-2.0 ++++++ sushy-5.12.0.tar.gz -> sushy-5.13.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/AUTHORS new/sushy-5.13.0/AUTHORS --- old/sushy-5.12.0/AUTHORS 2026-08-03 14:37:45.000000000 +0200 +++ new/sushy-5.13.0/AUTHORS 2026-08-20 17:16:13.154013400 +0200 @@ -48,6 +48,7 @@ Marcus Furlong <[email protected]> Mark Goddard <[email protected]> Milan Fencik <[email protected]> +Mohammed Naser <[email protected]> Nahian Pathan <[email protected]> Nate Potter <[email protected]> Nguyen Van Trung <[email protected]> @@ -74,6 +75,7 @@ Varsha <[email protected]> Vu Cong Tuan <[email protected]> Winicius Silva <[email protected]> +Yorick <[email protected]> Youngjun <[email protected]> Yusef Shaban <[email protected]> ajya <[email protected]> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/ChangeLog new/sushy-5.13.0/ChangeLog --- old/sushy-5.12.0/ChangeLog 2026-08-03 14:37:45.000000000 +0200 +++ new/sushy-5.13.0/ChangeLog 2026-08-20 17:16:13.098004600 +0200 @@ -1,6 +1,12 @@ CHANGES ======= +5.13.0 +------ + +* system: guard HttpBootUri writes against iDRAC 10 removal +* Handle incomplete TaskMonitor responses + 5.12.0 ------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/PKG-INFO new/sushy-5.13.0/PKG-INFO --- old/sushy-5.12.0/PKG-INFO 2026-08-03 14:37:45.465364700 +0200 +++ new/sushy-5.13.0/PKG-INFO 2026-08-20 17:16:13.455060700 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: sushy -Version: 5.12.0 +Version: 5.13.0 Summary: Sushy is a small Python library to communicate with Redfish based systems Home-page: https://docs.openstack.org/sushy/latest/ Author: OpenStack diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/releasenotes/notes/idrac10-httpbooturi-59d970aaf3fe86c2.yaml new/sushy-5.13.0/releasenotes/notes/idrac10-httpbooturi-59d970aaf3fe86c2.yaml --- old/sushy-5.12.0/releasenotes/notes/idrac10-httpbooturi-59d970aaf3fe86c2.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/sushy-5.13.0/releasenotes/notes/idrac10-httpbooturi-59d970aaf3fe86c2.yaml 2026-08-20 17:15:26.821323200 +0200 @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed ``set_system_boot_source`` to handle BMCs that do not advertise + ``HttpBootUri`` in the Boot section, such as iDRAC 10 which removed + this property entirely. The property is now only written when the BMC + explicitly advertises it, preventing spurious 400 errors on UefiHTTP + boot requests. An explicit URI passed by the caller will still raise + ``MissingAttributeError`` when the BMC does not support the property. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy/resources/system/system.py new/sushy-5.13.0/sushy/resources/system/system.py --- old/sushy-5.12.0/sushy/resources/system/system.py 2026-08-03 14:36:58.000000000 +0200 +++ new/sushy-5.13.0/sushy/resources/system/system.py 2026-08-20 17:15:26.882451300 +0200 @@ -349,15 +349,18 @@ a :py:class:`sushy.BootSourceOverrideMode` value. Optional. :param http_boot_uri: The requested HTTP Boot URI to transmit to the BMC. Only valid when BootSourceOverrideTarget is set to UefiHTTP, - when utilizing the ``target`` parameter. If no value is supplied, - and the target is set to UefiHTTP, then an empty value will be - sent to the BMC to remove any prior setting, allowing the host - to load configuration from DHCP. + when utilizing the ``target`` parameter. If no value is supplied + and the target is set to UefiHTTP, an existing value is cleared + only when the BMC advertises the HttpBootUri property. Otherwise + the property is omitted, allowing the host to load configuration + from DHCP. If not explicitly set, any value will be removed from a BMC when UefiHttp boot is not engaged. :raises: InvalidParameterValueError, if any information passed is invalid. + :raises: MissingAttributeError, if an explicit HTTP boot URI is + requested but the BMC does not advertise HttpBootUri. """ data = collections.defaultdict(dict) settings_data = collections.defaultdict(dict) @@ -369,6 +372,37 @@ settings_resp = None settings_boot_section = {} + main_boot_section = self.json.get('Boot') or {} + + def _set_boot_property(name, value, require_advertised=False, + only_if_set=False): + """Add a Boot property to the correct Redfish resource. + + Prefer the Settings resource when it advertises the property, + otherwise use the main ComputerSystem resource. For standard boot + properties, preserve the existing fallback to ComputerSystem even + when the property is not present in the response. Properties such + as HttpBootUri can require explicit advertisement instead. + + :returns: ``True`` when the property is supported or queued, + otherwise ``False``. + """ + if settings_resp and name in settings_boot_section: + boot_data = settings_data + current_value = settings_boot_section.get(name) + elif name in main_boot_section: + boot_data = data + current_value = main_boot_section.get(name) + elif require_advertised: + return False + else: + boot_data = data + current_value = None + + if not only_if_set or current_value is not None: + boot_data['Boot'][name] = value + return True + if target is not None: valid_targets = self.get_allowed_system_boot_source_values() if target not in valid_targets: @@ -394,12 +428,32 @@ 'machine. Overriding boot device from %s to %s.', target, sys_cons.BootSource.USB_CD) target = sys_cons.BootSource.USB_CD - if (settings_resp and "BootSourceOverrideTarget" in - settings_boot_section): - settings_data['Boot']['BootSourceOverrideTarget'] = \ - target.value - else: - data['Boot']['BootSourceOverrideTarget'] = target.value + _set_boot_property('BootSourceOverrideTarget', target.value) + + if target == sys_cons.BootSource.UEFI_HTTP: + # The http_boot_uri value *can* be set independently of the + # target, but the BMC will just ignore it unless the target + # is set. So we should only, and explicitly set it when we've + # been requested to boot from UefiHTTP. + if http_boot_uri: + if not _set_boot_property( + 'HttpBootUri', http_boot_uri, + require_advertised=True): + raise exceptions.MissingAttributeError( + attribute='HttpBootUri', resource=self.path) + else: + # DHCP-based UEFI HTTP boot. Clear a prior explicit URI + # only when the BMC advertises the property; otherwise + # omit it. + _set_boot_property( + 'HttpBootUri', None, require_advertised=True, + only_if_set=True) + elif not http_boot_uri: + # We're switching to a non-HTTP target. Clear a previous URI + # only on the Redfish resource that actually advertises it. + _set_boot_property( + 'HttpBootUri', None, require_advertised=True, + only_if_set=True) if enabled is not None: try: @@ -408,11 +462,7 @@ raise exceptions.InvalidParameterValueError( parameter='enabled', value=enabled, valid_values=list(sys_cons.BootSourceOverrideEnabled)) - if (settings_resp and "BootSourceOverrideEnabled" in - settings_boot_section): - settings_data['Boot']['BootSourceOverrideEnabled'] = fishy_freq - else: - data['Boot']['BootSourceOverrideEnabled'] = fishy_freq + _set_boot_property('BootSourceOverrideEnabled', fishy_freq) if mode is not None: try: @@ -421,32 +471,7 @@ raise exceptions.InvalidParameterValueError( parameter='mode', value=mode, valid_values=list(sys_cons.BootSourceOverrideMode)) - if (settings_resp and "BootSourceOverrideMode" in - settings_boot_section): - settings_data['Boot']['BootSourceOverrideMode'] = fishy_mode - else: - data['Boot']['BootSourceOverrideMode'] = fishy_mode - - if target == sys_cons.BootSource.UEFI_HTTP: - # The http_boot_uri value *can* be set independently of the - # target, but the BMC will just ignore it unless the target - # is set. So we should only, and explicitly set it when we've - # been requested to boot from UefiHTTP. - if not http_boot_uri: - # This should clear out any old entries, as no URI translates - # to the intent of "use whatever the dhcp server says". - http_boot_uri = None - - if (settings_resp and "HttpBootUri" in settings_boot_section): - settings_data['Boot']['HttpBootUri'] = http_boot_uri - else: - data['Boot']['HttpBootUri'] = http_boot_uri - elif not http_boot_uri: - # We're not doing boot from URL, we should cleanup any setting - # which may be from a prior step/call. - if settings_boot_section.get('HttpBootUri'): - # If the setting is present, and has any value, unset it. - data['Boot']['HttpBootUri'] = None + _set_boot_property('BootSourceOverrideMode', fishy_mode) # TODO(lucasagomes): Check the return code and response body ? # Probably we should call refresh() as well. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy/taskmonitor.py new/sushy-5.13.0/sushy/taskmonitor.py --- old/sushy-5.12.0/sushy/taskmonitor.py 2026-08-03 14:36:58.000000000 +0200 +++ new/sushy-5.13.0/sushy/taskmonitor.py 2026-08-20 17:15:26.884455700 +0200 @@ -51,15 +51,30 @@ self._task = None self._response = response - if (self._response and self._response.content + if (self._response and self._response.status_code == http_client.ACCEPTED): - self._task = task.Task(self._connector, self._task_monitor_uri, - redfish_version=self._redfish_version, - registries=self._registries, - json_doc=self._response.json()) + json_doc = self._get_task_json_doc(self._response) + if json_doc: + self._task = task.Task( + self._connector, self._task_monitor_uri, + redfish_version=self._redfish_version, + registries=self._registries, json_doc=json_doc) else: self.refresh() + @staticmethod + def _get_task_json_doc(response): + """Return a complete Task representation from a monitor response.""" + if not response.content: + return None + + json_doc = response.json() + # Some BMCs return partial Task payloads while the monitor remains 202. + if not json_doc.get('Id'): + return None + + return json_doc + def refresh(self): """Refresh the Task @@ -71,19 +86,19 @@ self._response = self._connector.get(path=self.task_monitor_uri) if self._response.status_code == http_client.ACCEPTED: - # A Task should have been returned, but wasn't - if not self._response.content: + json_doc = self._get_task_json_doc(self._response) + # A complete Task should have been returned, but wasn't. + if not json_doc: self._task = None return - # Assume that the body contains a Task since we got a 202 if not self._task: self._task = task.Task(self._connector, self._task_monitor_uri, redfish_version=self._redfish_version, registries=self._registries, - json_doc=self._response.json()) + json_doc=json_doc) else: - self._task.refresh(json_doc=self._response.json()) + self._task.refresh(json_doc=json_doc) else: self._task = None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy/tests/unit/resources/system/test_system.py new/sushy-5.13.0/sushy/tests/unit/resources/system/test_system.py --- old/sushy-5.12.0/sushy/tests/unit/resources/system/test_system.py 2026-08-03 14:36:58.000000000 +0200 +++ new/sushy-5.13.0/sushy/tests/unit/resources/system/test_system.py 2026-08-20 17:15:26.953600600 +0200 @@ -282,7 +282,8 @@ '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Continuous', 'BootSourceOverrideTarget': 'Pxe', - 'BootSourceOverrideMode': 'UEFI'}}, + 'BootSourceOverrideMode': 'UEFI', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_options_no_mode_specified(self): @@ -292,7 +293,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'Hdd'}}, + 'BootSourceOverrideTarget': 'Hdd', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_options_no_target_specified(self): @@ -312,7 +314,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideTarget': 'Pxe', - 'BootSourceOverrideMode': 'UEFI'}}, + 'BootSourceOverrideMode': 'UEFI', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_options_nothing_specified(self): @@ -346,7 +349,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'UsbCd'}}, + 'BootSourceOverrideTarget': 'UsbCd', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_options_supermicro_no_usb_cd_boot(self): @@ -359,7 +363,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'Cd'}}, + 'BootSourceOverrideTarget': 'Cd', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_options_settings_resource_nokia(self): @@ -444,7 +449,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/1', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'Cd'}}, + 'BootSourceOverrideTarget': 'Cd', + 'HttpBootUri': None}}, etag='"222"') def test_set_system_boot_options_settings_resource_bootmode_only(self): @@ -491,6 +497,18 @@ 'HttpBootUri': 'http://test.lan/test_image.iso'}}, etag=mock.ANY) + def test_set_system_boot_options_httpbooturi_not_advertised(self): + self.json_doc['Boot'].pop('HttpBootUri') + self.sys_inst._parse_attributes(self.json_doc) + + self.assertRaisesRegex( + exceptions.MissingAttributeError, + 'attribute HttpBootUri', + self.sys_inst.set_system_boot_options, + sushy.BootSource.UEFI_HTTP, + enabled=sushy.BootSourceOverrideEnabled.ONCE, + http_boot_uri='http://test.lan/test_image.iso') + def test_set_system_boot_options_httpboot_settings(self): with open('sushy/tests/unit/json_samples/settings-nokia.json') as f: @@ -535,25 +553,32 @@ etag=mock.ANY) def test_set_system_boot_options_httpboot_unset(self): + # When settings advertises HttpBootUri with a value, switching to a + # non-HTTP target should clear it on the settings resource, while + # writing target/mode to the main system resource. self.sys_inst._settings = mock.Mock() - self.sys_inst._settings.resource_uri = 'meow' - settings_body = json.dumps( - {'Boot': {'HttpBootUri': 'http://foo.bar'}} + self.sys_inst._settings.resource_uri = ( + '/redfish/v1/Systems/437XR1138R2/SD' ) - get_settings = mock.MagicMock() - get_settings.json.return_value = settings_body - self.conn.get.side_effect = get_settings + get_settings = mock.MagicMock(headers={'ETag': '"abc"'}) + get_settings.json.return_value = { + 'Boot': {'HttpBootUri': 'http://foo.bar'} + } + self.conn.get.return_value = get_settings self.sys_inst.set_system_boot_options( sushy.BootSource.HDD, mode=sushy.BootSourceOverrideMode.UEFI ) - self.sys_inst._conn.patch.assert_called_once_with( + self.sys_inst._conn.patch.assert_any_call( + '/redfish/v1/Systems/437XR1138R2/SD', + data={'Boot': {'HttpBootUri': None}}, + etag='"abc"') + self.sys_inst._conn.patch.assert_any_call( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideTarget': 'Hdd', - 'BootSourceOverrideMode': 'UEFI', - 'HttpBootUri': None}}, + 'BootSourceOverrideMode': 'UEFI'}}, etag=mock.ANY) def test_set_system_boot_source(self): @@ -565,7 +590,8 @@ '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Continuous', 'BootSourceOverrideTarget': 'Pxe', - 'BootSourceOverrideMode': 'UEFI'}}, + 'BootSourceOverrideMode': 'UEFI', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_source_with_etag(self): @@ -578,7 +604,8 @@ '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Continuous', 'BootSourceOverrideTarget': 'Pxe', - 'BootSourceOverrideMode': 'UEFI'}}, + 'BootSourceOverrideMode': 'UEFI', + 'HttpBootUri': None}}, etag="81802dbf61beb0bd") def test_set_system_boot_source_no_mode_specified(self): @@ -588,7 +615,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'Hdd'}}, + 'BootSourceOverrideTarget': 'Hdd', + 'HttpBootUri': None}}, etag='81802dbf61beb0bd') def test_set_system_boot_unsets_http_boot_uri(self): @@ -598,7 +626,8 @@ self.sys_inst._conn.patch.assert_called_once_with( '/redfish/v1/Systems/437XR1138R2', data={'Boot': {'BootSourceOverrideEnabled': 'Once', - 'BootSourceOverrideTarget': 'Hdd'}}, + 'BootSourceOverrideTarget': 'Hdd', + 'HttpBootUri': None}}, etag=mock.ANY) def test_set_system_boot_source_invalid_target(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy/tests/unit/resources/taskservice/test_task.py new/sushy-5.13.0/sushy/tests/unit/resources/taskservice/test_task.py --- old/sushy-5.12.0/sushy/tests/unit/resources/taskservice/test_task.py 2026-08-03 14:36:58.000000000 +0200 +++ new/sushy-5.13.0/sushy/tests/unit/resources/taskservice/test_task.py 2026-08-20 17:15:26.954602700 +0200 @@ -15,6 +15,7 @@ import json from unittest import mock +from sushy import exceptions from sushy.resources import constants as res_cons from sushy.resources.taskservice import constants as ts_cons from sushy.resources.taskservice import task @@ -61,6 +62,12 @@ self.assertEqual(res_cons.Severity.WARNING, self.task.messages[0].severity) + def test_init_missing_identity_raises(self): + self.assertRaises( + exceptions.MissingAttributeError, + task.Task, self.conn, '/redfish/v1/TaskService/Tasks/545', + json_doc={'Name': 'Task without identity'}) + def test_is_processing_true(self): self.task.status_code = http_client.ACCEPTED self.assertTrue(self.task.is_processing) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy/tests/unit/test_taskmonitor.py new/sushy-5.13.0/sushy/tests/unit/test_taskmonitor.py --- old/sushy-5.12.0/sushy/tests/unit/test_taskmonitor.py 2026-08-03 14:36:58.000000000 +0200 +++ new/sushy-5.13.0/sushy/tests/unit/test_taskmonitor.py 2026-08-20 17:15:26.955604800 +0200 @@ -74,6 +74,20 @@ def test_init_accepted_content(self): self.assertIsNotNone(self.task_monitor.task) + def test_init_accepted_content_no_task_id(self): + response = mock.Mock() + response.status_code = http_client.ACCEPTED + response.headers = {'Location': '/Task/545'} + response.content = b'{"Name": "Test"}' + response.json.return_value = {'Name': 'Test'} + + task_monitor = taskmonitor.TaskMonitor( + self.conn, '/Task/545', response=response) + + self.assertIsNone(task_monitor.task) + self.assertTrue(task_monitor.is_processing) + self.assertEqual('/Task/545', task_monitor.task_monitor_uri) + def test_init_no_response(self): self.conn.reset_mock() self.conn.get.return_value.status_code = 202 @@ -120,6 +134,63 @@ self.assertEqual(1, self.conn.get.call_count) self.assertIsNotNone(self.task_monitor.task) + def test_refresh_content_no_task_id_no_task(self): + self.conn.reset_mock() + self.conn.get.return_value.status_code = http_client.ACCEPTED + self.conn.get.return_value.headers = {'Content-Length': 42} + self.conn.get.return_value.content = b'{"Name": "Test"}' + self.conn.get.return_value.json.return_value = {'Name': 'Test'} + self.task_monitor._task = None + + self.task_monitor.refresh() + + self.conn.get.assert_called_once_with(path='/Task/545') + self.assertIsNone(self.task_monitor.task) + self.assertTrue(self.task_monitor.is_processing) + + def test_refresh_content_no_task_id_existing_task(self): + self.conn.reset_mock() + self.conn.get.return_value.status_code = http_client.ACCEPTED + self.conn.get.return_value.headers = {'Content-Length': 42} + self.conn.get.return_value.content = b'{"Name": "Test"}' + self.conn.get.return_value.json.return_value = {'Name': 'Test'} + existing_task = self.task_monitor.task + + with mock.patch.object(existing_task, 'refresh', + autospec=True) as mock_refresh: + self.task_monitor.refresh() + + mock_refresh.assert_not_called() + self.assertIsNone(self.task_monitor.task) + + def test_refresh_recovers_from_incomplete_task_response(self): + response = mock.Mock() + response.status_code = http_client.ACCEPTED + response.headers = {'Location': '/Task/545'} + response.content = b'{"Name": "Test"}' + response.json.return_value = {'Name': 'Test'} + task_monitor = taskmonitor.TaskMonitor( + self.conn, '/Task/545', response=response) + + complete_response = mock.Mock() + complete_response.status_code = http_client.ACCEPTED + complete_response.headers = {'Content-Length': 42} + complete_response.content = json.dumps(self.json_doc).encode('utf-8') + complete_response.json.return_value = self.json_doc + done_response = mock.Mock() + done_response.status_code = http_client.OK + self.conn.get.side_effect = [complete_response, done_response] + + task_monitor.refresh() + + self.assertIsNotNone(task_monitor.task) + self.assertTrue(task_monitor.is_processing) + + task_monitor.refresh() + + self.assertIsNone(task_monitor.task) + self.assertFalse(task_monitor.is_processing) + def test_refresh_done(self): self.conn.reset_mock() self.conn.get.return_value.status_code = 200 @@ -275,8 +346,8 @@ self.assertIsInstance(tm, taskmonitor.TaskMonitor) self.assertEqual('/Task/545', tm.task_monitor_uri) - self.assertIsNotNone(tm.task) - self.assertEqual('545', tm.task.identity) + self.assertIsNone(tm.task) + self.assertTrue(tm.is_processing) def test_from_response_odata_id(self): response = mock.Mock() @@ -295,6 +366,22 @@ self.assertIsNotNone(tm.task) self.assertEqual('545', tm.task.identity) + def test_from_response_content_no_task_id(self): + response = mock.Mock() + response.content = b'{"Name": "Test"}' + response.json.return_value = {'Name': 'Test'} + response.headers = {'Location': '/TaskMonitor/'} + response.status_code = http_client.ACCEPTED + + tm = taskmonitor.TaskMonitor.from_response( + self.conn, response, + '/redfish/v1/UpdateService/Actions/SimpleUpdate') + + self.assertIsInstance(tm, taskmonitor.TaskMonitor) + self.assertEqual('/TaskMonitor/', tm.task_monitor_uri) + self.assertIsNone(tm.task) + self.assertTrue(tm.is_processing) + def test_from_response_location_header_missing(self): response = mock.Mock() response.content = "something" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy.egg-info/PKG-INFO new/sushy-5.13.0/sushy.egg-info/PKG-INFO --- old/sushy-5.12.0/sushy.egg-info/PKG-INFO 2026-08-03 14:37:45.000000000 +0200 +++ new/sushy-5.13.0/sushy.egg-info/PKG-INFO 2026-08-20 17:16:13.159014200 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.4 Name: sushy -Version: 5.12.0 +Version: 5.13.0 Summary: Sushy is a small Python library to communicate with Redfish based systems Home-page: https://docs.openstack.org/sushy/latest/ Author: OpenStack diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy.egg-info/SOURCES.txt new/sushy-5.13.0/sushy.egg-info/SOURCES.txt --- old/sushy-5.12.0/sushy.egg-info/SOURCES.txt 2026-08-03 14:37:45.000000000 +0200 +++ new/sushy-5.13.0/sushy.egg-info/SOURCES.txt 2026-08-20 17:16:13.291035000 +0200 @@ -132,6 +132,7 @@ releasenotes/notes/handle_transfer_method-a51d5a17e381ebee.yaml releasenotes/notes/health_literals_change-0e3fc0c439b765e3.yaml releasenotes/notes/idrac-reset-http-reachability-0998606718098c21.yaml +releasenotes/notes/idrac10-httpbooturi-59d970aaf3fe86c2.yaml releasenotes/notes/idrac10-settings-resource-c18e754c661a7056.yaml releasenotes/notes/ignore-empty-string-etags-ee44617d7b0f72ce.yaml releasenotes/notes/increase-server-retries-5f11edde8ee0b461.yaml diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sushy-5.12.0/sushy.egg-info/pbr.json new/sushy-5.13.0/sushy.egg-info/pbr.json --- old/sushy-5.12.0/sushy.egg-info/pbr.json 2026-08-03 14:37:45.000000000 +0200 +++ new/sushy-5.13.0/sushy.egg-info/pbr.json 2026-08-20 17:16:13.173016300 +0200 @@ -1 +1 @@ -{"git_version": "ebc9454", "is_release": true} \ No newline at end of file +{"git_version": "f13efd9", "is_release": true} \ No newline at end of file
