@@ -49,6 +49,67 @@ def test_exchangews_cleanup_error(mocker, caplog):
4949 exchange_ws .cleanup ()
5050
5151
52+ def test_exchangews_reset_connections_timeout_and_exception (mocker , caplog ):
53+ config = MagicMock ()
54+ ccxt_object = MagicMock ()
55+ mocker .patch ("freqtrade.exchange.exchange_ws.ExchangeWS._start_forever" , MagicMock ())
56+
57+ exchange_ws = ExchangeWS (config , ccxt_object )
58+ exchange_ws ._loop = MagicMock ()
59+ exchange_ws ._loop .is_closed .return_value = False
60+
61+ timeout_future = MagicMock ()
62+ timeout_future .result .side_effect = TimeoutError ("timed out" )
63+
64+ error_future = MagicMock ()
65+ error_future .result .side_effect = RuntimeError ("broken future" )
66+
67+ def fake_run_coroutine_threadsafe (coro , loop ):
68+ # Avoid coroutine warnings since we don't execute it in this unit test.
69+ coro .close ()
70+ fake_run_coroutine_threadsafe .calls += 1
71+ return timeout_future if fake_run_coroutine_threadsafe .calls == 1 else error_future
72+
73+ fake_run_coroutine_threadsafe .calls = 0
74+
75+ mock_run = mocker .patch (
76+ "freqtrade.exchange.exchange_ws.asyncio.run_coroutine_threadsafe" ,
77+ side_effect = fake_run_coroutine_threadsafe ,
78+ )
79+
80+ exchange_ws .reset_connections ()
81+ assert log_has_re ("Timed out while resetting websocket connections" , caplog )
82+ assert log_has_re ("Resetting exchange WS connections" , caplog )
83+ assert mock_run .call_count == 1
84+
85+ exchange_ws .reset_connections (cleanup = True )
86+
87+ assert mock_run .call_count == 2
88+ assert log_has_re ("Exception while resetting websocket connections" , caplog )
89+ assert log_has_re ("Cleaning up exchange WS connections" , caplog )
90+
91+ exchange_ws .cleanup ()
92+
93+
94+ def test_exchangews_cleanup_thread_timeout_warning (mocker , caplog ):
95+ config = MagicMock ()
96+ ccxt_object = MagicMock ()
97+ mocker .patch ("freqtrade.exchange.exchange_ws.ExchangeWS._start_forever" , MagicMock ())
98+
99+ exchange_ws = ExchangeWS (config , ccxt_object )
100+ exchange_ws ._loop = MagicMock ()
101+ exchange_ws ._loop .is_closed .return_value = True
102+
103+ thread_mock = MagicMock ()
104+ thread_mock .is_alive .return_value = True
105+ exchange_ws ._thread = thread_mock
106+
107+ exchange_ws .cleanup ()
108+
109+ thread_mock .join .assert_called_once_with (timeout = 5 )
110+ assert log_has_re ("Websocket loop thread did not stop within timeout" , caplog )
111+
112+
52113def patch_eventloop_threading (exchange ):
53114 init_event = threading .Event ()
54115
0 commit comments