Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
test_dispatcher.py386 linesDownload Raw Back to tests
1# -*- coding: utf-8 -*-2import socket3import unittest4from unittest.mock import Mock, patch, MagicMock5import threading6import time7 8import websocket9from websocket._dispatcher import (10    Dispatcher,11    DispatcherBase,12    SSLDispatcher,13    WrappedDispatcher,14)15 16"""17test_dispatcher.py18websocket - WebSocket client library for Python19 20Copyright 2025 engn33r21 22Licensed under the Apache License, Version 2.0 (the "License");23you may not use this file except in compliance with the License.24You may obtain a copy of the License at25 26    http://www.apache.org/licenses/LICENSE-2.027 28Unless required by applicable law or agreed to in writing, software29distributed under the License is distributed on an "AS IS" BASIS,30WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.31See the License for the specific language governing permissions and32limitations under the License.33"""34 35class MockApp:36    """Mock WebSocketApp for testing"""37 38    def __init__(self):39        self.keep_running = True40        self.sock = Mock()41        self.sock.sock = Mock()42 43 44class MockSocket:45    """Mock socket for testing"""46 47    def __init__(self):48        self.pending_return = False49 50    def pending(self):51        return self.pending_return52 53 54class MockDispatcher:55    """Mock external dispatcher for WrappedDispatcher testing"""56 57    def __init__(self):58        self.signal_calls = []59        self.abort_calls = []60        self.read_calls = []61        self.buffwrite_calls = []62        self.timeout_calls = []63 64    def signal(self, sig, handler):65        self.signal_calls.append((sig, handler))66 67    def abort(self):68        self.abort_calls.append(True)69 70    def read(self, sock, callback):71        self.read_calls.append((sock, callback))72 73    def buffwrite(self, sock, data, send_func, disconnect_handler):74        self.buffwrite_calls.append((sock, data, send_func, disconnect_handler))75 76    def timeout(self, seconds, callback, *args):77        self.timeout_calls.append((seconds, callback, args))78 79 80class DispatcherTest(unittest.TestCase):81    def setUp(self):82        self.app = MockApp()83 84    def test_dispatcher_base_init(self):85        """Test DispatcherBase initialization"""86        dispatcher = DispatcherBase(self.app, 30.0)87 88        self.assertEqual(dispatcher.app, self.app)89        self.assertEqual(dispatcher.ping_timeout, 30.0)90 91    def test_dispatcher_base_timeout(self):92        """Test DispatcherBase timeout method"""93        dispatcher = DispatcherBase(self.app, 30.0)94        callback = Mock()95 96        # Test with seconds=None (should call callback immediately)97        dispatcher.timeout(None, callback)98        callback.assert_called_once()99 100        # Test with seconds > 0 (would sleep in real implementation)101        callback.reset_mock()102        start_time = time.time()103        dispatcher.timeout(0.1, callback)104        elapsed = time.time() - start_time105 106        callback.assert_called_once()107        self.assertGreaterEqual(elapsed, 0.05)  # Allow some tolerance108 109    def test_dispatcher_base_reconnect(self):110        """Test DispatcherBase reconnect method"""111        dispatcher = DispatcherBase(self.app, 30.0)112        reconnector = Mock()113 114        # Test normal reconnect115        dispatcher.reconnect(1, reconnector)116        reconnector.assert_called_once_with(reconnecting=True)117 118        # Test reconnect with KeyboardInterrupt119        reconnector.reset_mock()120        reconnector.side_effect = KeyboardInterrupt("User interrupted")121 122        with self.assertRaises(KeyboardInterrupt):123            dispatcher.reconnect(1, reconnector)124 125    def test_dispatcher_base_send(self):126        """Test DispatcherBase send method"""127        dispatcher = DispatcherBase(self.app, 30.0)128        mock_sock = Mock()129        test_data = b"test data"130 131        with patch("websocket._dispatcher.send") as mock_send:132            mock_send.return_value = len(test_data)133            result = dispatcher.send(mock_sock, test_data)134 135            mock_send.assert_called_once_with(mock_sock, test_data)136            self.assertEqual(result, len(test_data))137 138    def test_dispatcher_read(self):139        """Test Dispatcher read method"""140        dispatcher = Dispatcher(self.app, 5.0)141        read_callback = Mock(return_value=True)142        check_callback = Mock()143        mock_sock = Mock()144 145        # Mock the selector to control the loop146        with patch("selectors.DefaultSelector") as mock_selector_class:147            mock_selector = Mock()148            mock_selector_class.return_value = mock_selector149 150            # Make select return immediately (timeout)151            mock_selector.select.return_value = []152 153            # Stop after first iteration154            def side_effect(*args):155                self.app.keep_running = False156                return []157 158            mock_selector.select.side_effect = side_effect159 160            dispatcher.read(mock_sock, read_callback, check_callback)161 162            # Verify selector was used correctly163            mock_selector.register.assert_called()164            mock_selector.select.assert_called_with(5.0)165            mock_selector.close.assert_called()166            check_callback.assert_called()167 168    def test_dispatcher_read_with_data(self):169        """Test Dispatcher read method when data is available"""170        dispatcher = Dispatcher(self.app, 5.0)171        read_callback = Mock(return_value=True)172        check_callback = Mock()173        mock_sock = Mock()174 175        with patch("selectors.DefaultSelector") as mock_selector_class:176            mock_selector = Mock()177            mock_selector_class.return_value = mock_selector178 179            # First call returns data, second call stops the loop180            call_count = 0181 182            def select_side_effect(*args):183                nonlocal call_count184                call_count += 1185                if call_count == 1:186                    return [True]  # Data available187                else:188                    self.app.keep_running = False189                    return []190 191            mock_selector.select.side_effect = select_side_effect192 193            dispatcher.read(mock_sock, read_callback, check_callback)194 195            read_callback.assert_called()196            check_callback.assert_called()197 198    def test_ssl_dispatcher_read(self):199        """Test SSLDispatcher read method"""200        dispatcher = SSLDispatcher(self.app, 5.0)201        read_callback = Mock(return_value=True)202        check_callback = Mock()203 204        # Mock socket with pending data205        mock_ssl_sock = MockSocket()206        self.app.sock.sock = mock_ssl_sock207 208        with patch("selectors.DefaultSelector") as mock_selector_class:209            mock_selector = Mock()210            mock_selector_class.return_value = mock_selector211            mock_selector.select.return_value = []212 213            # Stop after first iteration214            def side_effect(*args):215                self.app.keep_running = False216                return []217 218            mock_selector.select.side_effect = side_effect219 220            dispatcher.read(None, read_callback, check_callback)221 222            mock_selector.register.assert_called()223            check_callback.assert_called()224 225    def test_ssl_dispatcher_select_with_pending(self):226        """Test SSLDispatcher select method with pending data"""227        dispatcher = SSLDispatcher(self.app, 5.0)228        mock_ssl_sock = MockSocket()229        mock_ssl_sock.pending_return = True230        self.app.sock.sock = mock_ssl_sock231        mock_selector = Mock()232 233        result = dispatcher.select(None, mock_selector)234 235        # When pending() returns True, should return [sock]236        self.assertEqual(result, [mock_ssl_sock])237 238    def test_ssl_dispatcher_select_without_pending(self):239        """Test SSLDispatcher select method without pending data"""240        dispatcher = SSLDispatcher(self.app, 5.0)241        mock_ssl_sock = MockSocket()242        mock_ssl_sock.pending_return = False243        self.app.sock.sock = mock_ssl_sock244        mock_selector = Mock()245        mock_selector.select.return_value = [(mock_ssl_sock, None)]246 247        result = dispatcher.select(None, mock_selector)248 249        # Should return the first element of first result tuple250        self.assertEqual(result, mock_ssl_sock)251        mock_selector.select.assert_called_with(5.0)252 253    def test_ssl_dispatcher_select_no_results(self):254        """Test SSLDispatcher select method with no results"""255        dispatcher = SSLDispatcher(self.app, 5.0)256        mock_ssl_sock = MockSocket()257        mock_ssl_sock.pending_return = False258        self.app.sock.sock = mock_ssl_sock259        mock_selector = Mock()260        mock_selector.select.return_value = []261 262        result = dispatcher.select(None, mock_selector)263 264        # Should return None when no results (function doesn't return anything when len(r) == 0)265        self.assertIsNone(result)266 267    def test_wrapped_dispatcher_init(self):268        """Test WrappedDispatcher initialization"""269        mock_dispatcher = MockDispatcher()270        handle_disconnect = Mock()271 272        wrapped = WrappedDispatcher(self.app, 10.0, mock_dispatcher, handle_disconnect)273 274        self.assertEqual(wrapped.app, self.app)275        self.assertEqual(wrapped.ping_timeout, 10.0)276        self.assertEqual(wrapped.dispatcher, mock_dispatcher)277        self.assertEqual(wrapped.handleDisconnect, handle_disconnect)278 279        # Should have set up signal handler280        self.assertEqual(len(mock_dispatcher.signal_calls), 1)281        sig, handler = mock_dispatcher.signal_calls[0]282        self.assertEqual(sig, 2)  # SIGINT283        self.assertEqual(handler, mock_dispatcher.abort)284 285    def test_wrapped_dispatcher_read(self):286        """Test WrappedDispatcher read method"""287        mock_dispatcher = MockDispatcher()288        handle_disconnect = Mock()289        wrapped = WrappedDispatcher(self.app, 10.0, mock_dispatcher, handle_disconnect)290 291        mock_sock = Mock()292        read_callback = Mock()293        check_callback = Mock()294 295        wrapped.read(mock_sock, read_callback, check_callback)296 297        # Should delegate to wrapped dispatcher298        self.assertEqual(len(mock_dispatcher.read_calls), 1)299        self.assertEqual(mock_dispatcher.read_calls[0], (mock_sock, read_callback))300 301        # Should call timeout for ping_timeout302        self.assertEqual(len(mock_dispatcher.timeout_calls), 1)303        timeout_call = mock_dispatcher.timeout_calls[0]304        self.assertEqual(timeout_call[0], 10.0)  # timeout seconds305        self.assertEqual(timeout_call[1], check_callback)  # callback306 307    def test_wrapped_dispatcher_read_no_ping_timeout(self):308        """Test WrappedDispatcher read method without ping timeout"""309        mock_dispatcher = MockDispatcher()310        handle_disconnect = Mock()311        wrapped = WrappedDispatcher(self.app, None, mock_dispatcher, handle_disconnect)312 313        mock_sock = Mock()314        read_callback = Mock()315        check_callback = Mock()316 317        wrapped.read(mock_sock, read_callback, check_callback)318 319        # Should delegate to wrapped dispatcher320        self.assertEqual(len(mock_dispatcher.read_calls), 1)321 322        # Should NOT call timeout when ping_timeout is None323        self.assertEqual(len(mock_dispatcher.timeout_calls), 0)324 325    def test_wrapped_dispatcher_send(self):326        """Test WrappedDispatcher send method"""327        mock_dispatcher = MockDispatcher()328        handle_disconnect = Mock()329        wrapped = WrappedDispatcher(self.app, 10.0, mock_dispatcher, handle_disconnect)330 331        mock_sock = Mock()332        test_data = b"test data"333 334        with patch("websocket._dispatcher.send") as mock_send:335            result = wrapped.send(mock_sock, test_data)336 337            # Should delegate to dispatcher.buffwrite338            self.assertEqual(len(mock_dispatcher.buffwrite_calls), 1)339            call = mock_dispatcher.buffwrite_calls[0]340            self.assertEqual(call[0], mock_sock)341            self.assertEqual(call[1], test_data)342            self.assertEqual(call[2], mock_send)343            self.assertEqual(call[3], handle_disconnect)344 345            # Should return data length346            self.assertEqual(result, len(test_data))347 348    def test_wrapped_dispatcher_timeout(self):349        """Test WrappedDispatcher timeout method"""350        mock_dispatcher = MockDispatcher()351        handle_disconnect = Mock()352        wrapped = WrappedDispatcher(self.app, 10.0, mock_dispatcher, handle_disconnect)353 354        callback = Mock()355        args = ("arg1", "arg2")356 357        wrapped.timeout(5.0, callback, *args)358 359        # Should delegate to wrapped dispatcher360        self.assertEqual(len(mock_dispatcher.timeout_calls), 1)361        call = mock_dispatcher.timeout_calls[0]362        self.assertEqual(call[0], 5.0)363        self.assertEqual(call[1], callback)364        self.assertEqual(call[2], args)365 366    def test_wrapped_dispatcher_reconnect(self):367        """Test WrappedDispatcher reconnect method"""368        mock_dispatcher = MockDispatcher()369        handle_disconnect = Mock()370        wrapped = WrappedDispatcher(self.app, 10.0, mock_dispatcher, handle_disconnect)371 372        reconnector = Mock()373 374        wrapped.reconnect(3, reconnector)375 376        # Should delegate to timeout method with reconnect=True377        self.assertEqual(len(mock_dispatcher.timeout_calls), 1)378        call = mock_dispatcher.timeout_calls[0]379        self.assertEqual(call[0], 3)380        self.assertEqual(call[1], reconnector)381        self.assertEqual(call[2], (True,))382 383 384if __name__ == "__main__":385    unittest.main()386 
codekingpro/portable-devtools · Team Ai