From de027162768b095b20c6723bd6a8b1849a0389c0 Mon Sep 17 00:00:00 2001 From: Anton Joubert <ajoubert@ska.ac.za> Date: Wed, 26 May 2021 13:28:59 +0200 Subject: [PATCH] [SAR-227] Fix intermittent DebugDevice test failures The debugger-related tests were failing sometimes with a `[Errno 98] Address already in use`. This was because debugpy was configured to listen on the same port, 5678, across multiple tests. Sometimes the OS wouldn't have released the port in time for the next test. Now use the default port for a single test, and ephemeral ports for the rest. --- src/ska_tango_base/base/base_device.py | 13 ++++++++----- tests/test_base_device.py | 11 ++++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/ska_tango_base/base/base_device.py b/src/ska_tango_base/base/base_device.py index 53b07a1b..809e1e90 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 ef16b9f2..6ea95ef6 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 @@ -616,17 +619,23 @@ class TestSKABaseDevice(object): assert tango_context.device.state def test_DebugDevice_twice_does_not_raise(self, tango_context): + patch_debugger_to_start_on_ephermal_port() tango_context.device.DebugDevice() tango_context.device.DebugDevice() assert SKABaseDevice._global_debugger_listening def test_DebugDevice_does_not_break_a_command(self, tango_context): + patch_debugger_to_start_on_ephermal_port() tango_context.device.DebugDevice() assert tango_context.device.State() == DevState.OFF tango_context.device.On() assert tango_context.device.State() == DevState.ON +def patch_debugger_to_start_on_ephermal_port(): + ska_tango_base.base.base_device._DEBUGGER_PORT = 0 + + class TestSKABaseDevice_commands: """ This class contains tests of SKABaseDevice commands -- GitLab