diff --git a/src/ska_tango_base/base/base_device.py b/src/ska_tango_base/base/base_device.py index 53b07a1b148701d3d9366f978c4956f7de02a7ce..809e1e9094a73f82ae3d24fcebde20c1a833a889 100644 --- a/src/ska_tango_base/base/base_device.py +++ b/src/ska_tango_base/base/base_device.py @@ -326,6 +326,7 @@ class SKABaseDevice(Device): """ _global_debugger_listening = False + _global_debugger_allocated_port = 0 class InitCommand(ResponseCommand, CompletionCommand): """ @@ -1330,8 +1331,9 @@ class SKABaseDevice(Device): :rtype: DevUShort """ if not SKABaseDevice._global_debugger_listening: - self.start_debugger(_DEBUGGER_PORT) + allocated_port = self.start_debugger_and_get_port(_DEBUGGER_PORT) SKABaseDevice._global_debugger_listening = True + SKABaseDevice._global_debugger_allocated_port = allocated_port device = self.target if not device._methods_patched_for_debugger: self.monkey_patch_all_methods_for_debugger() @@ -1339,14 +1341,15 @@ class SKABaseDevice(Device): else: self.logger.warning("Triggering debugger breakpoint...") debugpy.breakpoint() - return _DEBUGGER_PORT + return SKABaseDevice._global_debugger_allocated_port - def start_debugger(self, port): + def start_debugger_and_get_port(self, port): self.logger.warning("Starting debugger...") - debugpy.listen(("0.0.0.0", port)) + interface, allocated_port = debugpy.listen(("0.0.0.0", port)) self.logger.warning( - f"Debugger listening on port {port}. Performance may be degraded." + f"Debugger listening on {interface}:{allocated_port}. Performance may be degraded." ) + return allocated_port def monkey_patch_all_methods_for_debugger(self): all_methods = self.get_all_methods() diff --git a/tests/test_base_device.py b/tests/test_base_device.py index ef16b9f2ce59cc2b82c25aaf8a2f2fb2525eeafa..c98de2672f3e26ad81ab312659a5a3361eadb48c 100644 --- a/tests/test_base_device.py +++ b/tests/test_base_device.py @@ -19,6 +19,9 @@ import tango from unittest import mock from tango import DevFailed, DevState + +import ska_tango_base.base.base_device + from ska_tango_base import SKABaseDevice from ska_tango_base.base import OpStateModel, ReferenceBaseComponentManager from ska_tango_base.base.base_device import ( @@ -607,7 +610,7 @@ class TestSKABaseDevice(object): with pytest.raises(ConnectionRefusedError): s.connect(("localhost", _DEBUGGER_PORT)) - def test_DebugDevice_starts_listening(self, tango_context): + def test_DebugDevice_starts_listening_on_default_port(self, tango_context): port = tango_context.device.DebugDevice() assert port == _DEBUGGER_PORT assert SKABaseDevice._global_debugger_listening @@ -615,11 +618,13 @@ class TestSKABaseDevice(object): s.connect(("localhost", _DEBUGGER_PORT)) assert tango_context.device.state + @pytest.mark.usefixtures("patch_debugger_to_start_on_ephemeral_port") def test_DebugDevice_twice_does_not_raise(self, tango_context): tango_context.device.DebugDevice() tango_context.device.DebugDevice() assert SKABaseDevice._global_debugger_listening + @pytest.mark.usefixtures("patch_debugger_to_start_on_ephemeral_port") def test_DebugDevice_does_not_break_a_command(self, tango_context): tango_context.device.DebugDevice() assert tango_context.device.State() == DevState.OFF @@ -627,6 +632,11 @@ class TestSKABaseDevice(object): assert tango_context.device.State() == DevState.ON +@pytest.fixture() +def patch_debugger_to_start_on_ephemeral_port(): + ska_tango_base.base.base_device._DEBUGGER_PORT = 0 + + class TestSKABaseDevice_commands: """ This class contains tests of SKABaseDevice commands