1+ import socket
12import typing
23from collections import deque
34from decimal import Decimal
4- from unittest .mock import patch
5- import socket
65from unittest import mock
6+ from unittest .mock import patch
77
88import pytest # type: ignore
99
1313 Error ,
1414 IntegrityError ,
1515 InterfaceError ,
16+ OperationalError ,
1617 ProgrammingError ,
17- OperationalError
1818)
1919from redshift_connector .config import (
2020 ClientProtocolVersion ,
2828from redshift_connector .utils .type_utils import py_types as PY_TYPES
2929from redshift_connector .utils .type_utils import redshift_types as REDSHIFT_TYPES
3030
31- test_error_responses_data : typing .List [typing .Tuple [bytes , typing .Dict , typing .Type [Error ]]] = [
31+ test_error_responses_data : typing .List [
32+ typing .Tuple [bytes , typing .Dict , typing .Type [Error ]]
33+ ] = [
3234 (
3335 (
3436 b"SERROR\x00 "
@@ -332,8 +334,141 @@ def test_client_os_version_is_not_present():
332334 with patch ("platform.platform" , side_effect = Exception ("not for you" )):
333335 assert mock_connection .client_os_version == "unknown"
334336
337+
335338def test_socket_timeout_error ():
336339 with mock .patch ('socket.socket.connect' ) as mock_socket :
337340 mock_socket .side_effect = (socket .timeout )
338341 with pytest .raises (OperationalError ):
339342 Connection (user = 'mock_user' , password = 'mock_password' , host = 'localhost' , port = 8080 , database = 'mocked' )
343+
344+
345+ def mock_read (* args , ** kwargs ):
346+ return b""
347+
348+
349+ def test_handle_messages_broken_pipe_blocking ():
350+ # mock the connection and mock the read attribute
351+ mock_connection : Connection = Connection .__new__ (Connection )
352+ mock_connection ._read = mock_read
353+
354+ # we only need to mock the raw socket
355+ mock_usock = mock .Mock ()
356+ mock_usock .timeout = None
357+ mock_connection ._usock = mock_usock
358+
359+ mock_cursor : Cursor = Cursor .__new__ (Cursor )
360+ mock_cursor .ps = None
361+
362+ with pytest .raises (
363+ InterfaceError ,
364+ match = "BrokenPipe: server socket closed. Please check that client side networking configurations such "
365+ "as Proxies, firewalls, VPN, etc. are not affecting your network connection." ,
366+ ):
367+ mock_connection .handle_messages (mock_cursor )
368+
369+
370+ def test_handle_messages_broken_pipe_timeout ():
371+ # mock the connection and mock the read attribute
372+ mock_connection : Connection = Connection .__new__ (Connection )
373+ mock_connection ._read = mock_read
374+
375+ # we only need to mock the raw socket
376+ mock_usock = mock .Mock ()
377+ mock_usock .timeout = 47
378+ mock_connection ._usock = mock_usock
379+
380+ mock_cursor : Cursor = Cursor .__new__ (Cursor )
381+ mock_cursor .ps = None
382+
383+ with pytest .raises (
384+ InterfaceError ,
385+ match = "BrokenPipe: server socket closed. We noticed a timeout is set for this connection. Consider "
386+ "raising the timeout or defaulting timeout to none." ,
387+ ):
388+ mock_connection .handle_messages (mock_cursor )
389+
390+
391+ def test_handle_messages_merge_socket_read_broken_pipe_blocking ():
392+ # mock the connection and mock the read attribute
393+ mock_connection : Connection = Connection .__new__ (Connection )
394+ mock_connection ._read = mock_read
395+
396+ # we only need to mock the raw socket
397+ mock_usock = mock .Mock ()
398+ mock_usock .timeout = None
399+ mock_connection ._usock = mock_usock
400+
401+ mock_cursor : Cursor = Cursor .__new__ (Cursor )
402+ mock_cursor .ps = None
403+
404+ with pytest .raises (
405+ InterfaceError ,
406+ match = "BrokenPipe: server socket closed. Please check that client side networking configurations such "
407+ "as Proxies, firewalls, VPN, etc. are not affecting your network connection." ,
408+ ):
409+ mock_connection .handle_messages_merge_socket_read (mock_cursor )
410+
411+
412+ def test_handle_messages_merge_socket_read_broken_pipe_timeout ():
413+ # mock the connection and mock the read attribute
414+ mock_connection : Connection = Connection .__new__ (Connection )
415+ mock_connection ._read = mock_read
416+
417+ # we only need to mock the raw socket
418+ mock_usock = mock .Mock ()
419+ mock_usock .timeout = 47
420+ mock_connection ._usock = mock_usock
421+
422+ mock_cursor : Cursor = Cursor .__new__ (Cursor )
423+ mock_cursor .ps = None
424+
425+ with pytest .raises (
426+ InterfaceError ,
427+ match = "BrokenPipe: server socket closed. We noticed a timeout is set for this connection. Consider "
428+ "raising the timeout or defaulting timeout to none." ,
429+ ):
430+ mock_connection .handle_messages_merge_socket_read (mock_cursor )
431+
432+
433+ def test_broken_pipe_on_connect (db_kwargs ):
434+ db_kwargs ["ssl" ] = False
435+
436+ with mock .patch ("socket.getaddrinfo" ) as mock_getaddrinfo :
437+ addr_tuple = [(0 , 1 , 2 , "" , ('3.226.18.73' , 5439 )), (2 , 1 , 6 , '' , ('3.226.18.73' , 5439 ))]
438+ mock_getaddrinfo .return_value = addr_tuple
439+ with mock .patch ('socket.socket.connect' ) as mock_usock :
440+ mock_usock .side_effect = lambda * args , ** kwargs : None
441+ with mock .patch ("socket.socket.makefile" ) as mock_sock :
442+ mock_file = mock_sock .return_value
443+ mock_file ._read .return_value = b""
444+ with pytest .raises (
445+ InterfaceError ,
446+ match = "BrokenPipe: server socket closed. Please check that client side networking configurations such "
447+ "as Proxies, firewalls, VPN, etc. are not affecting your network connection." ,
448+ ):
449+ db_kwargs .pop ("region" )
450+ db_kwargs .pop ("cluster_identifier" )
451+ Connection (** db_kwargs )
452+
453+ def test_broken_pipe_timeout_on_connect (db_kwargs ):
454+ db_kwargs ["ssl" ] = False
455+ db_kwargs ["timeout" ] = 60
456+
457+
458+ with mock .patch ("socket.getaddrinfo" ) as mock_getaddrinfo :
459+ addr_tuple = [(0 , 1 , 2 , "" , ('3.226.18.73' , 5439 )), (2 , 1 , 6 , '' , ('3.226.18.73' , 5439 ))]
460+ mock_getaddrinfo .return_value = addr_tuple
461+ with mock .patch ('socket.socket.connect' ) as mock_usock :
462+ mock_usock .side_effect = lambda * args , ** kwargs : None
463+
464+ with mock .patch ("socket.socket.makefile" ) as mock_sock :
465+ mock_file = mock_sock .return_value
466+ mock_file ._read .return_value = b""
467+ with pytest .raises (
468+ InterfaceError ,
469+ match = "BrokenPipe: server socket closed. We noticed a timeout is set for this connection. Consider "
470+ "raising the timeout or defaulting timeout to none." ,
471+ ):
472+ db_kwargs .pop ("region" )
473+ db_kwargs .pop ("cluster_identifier" )
474+ Connection (** db_kwargs )
0 commit comments