1
+ import socket
1
2
import typing
2
3
from collections import deque
3
4
from decimal import Decimal
4
- from unittest .mock import patch
5
- import socket
6
5
from unittest import mock
6
+ from unittest .mock import patch
7
7
8
8
import pytest # type: ignore
9
9
13
13
Error ,
14
14
IntegrityError ,
15
15
InterfaceError ,
16
+ OperationalError ,
16
17
ProgrammingError ,
17
- OperationalError
18
18
)
19
19
from redshift_connector .config import (
20
20
ClientProtocolVersion ,
28
28
from redshift_connector .utils .type_utils import py_types as PY_TYPES
29
29
from redshift_connector .utils .type_utils import redshift_types as REDSHIFT_TYPES
30
30
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
+ ] = [
32
34
(
33
35
(
34
36
b"SERROR\x00 "
@@ -332,8 +334,141 @@ def test_client_os_version_is_not_present():
332
334
with patch ("platform.platform" , side_effect = Exception ("not for you" )):
333
335
assert mock_connection .client_os_version == "unknown"
334
336
337
+
335
338
def test_socket_timeout_error ():
336
339
with mock .patch ('socket.socket.connect' ) as mock_socket :
337
340
mock_socket .side_effect = (socket .timeout )
338
341
with pytest .raises (OperationalError ):
339
342
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