33import sys
44import unittest
55import unittest .mock
6+ from ast import literal_eval
7+ from threading import Thread
68from test import support
79from test .support import import_helper
810from test .support import os_helper
@@ -304,11 +306,19 @@ def test_wrap_socket(sock, *,
304306 return context .wrap_socket (sock , ** kwargs )
305307
306308
309+ USE_SAME_TEST_CONTEXT = False
310+ _TEST_CONTEXT = None
311+
307312def testing_context (server_cert = SIGNED_CERTFILE , * , server_chain = True ):
308313 """Create context
309314
310315 client_context, server_context, hostname = testing_context()
311316 """
317+ global _TEST_CONTEXT
318+ if USE_SAME_TEST_CONTEXT :
319+ if _TEST_CONTEXT is not None :
320+ return _TEST_CONTEXT
321+
312322 if server_cert == SIGNED_CERTFILE :
313323 hostname = SIGNED_CERTFILE_HOSTNAME
314324 elif server_cert == SIGNED_CERTFILE2 :
@@ -326,6 +336,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
326336 if server_chain :
327337 server_context .load_verify_locations (SIGNING_CA )
328338
339+ if USE_SAME_TEST_CONTEXT :
340+ if _TEST_CONTEXT is not None :
341+ _TEST_CONTEXT = client_context , server_context , hostname
342+
329343 return client_context , server_context , hostname
330344
331345
@@ -2834,6 +2848,44 @@ def test_echo(self):
28342848 'Cannot create a client socket with a PROTOCOL_TLS_SERVER context' ,
28352849 str (e .exception ))
28362850
2851+ @unittest .skipUnless (support .Py_GIL_DISABLED , "test is only useful if the GIL is disabled" )
2852+ def test_ssl_in_multiple_threads (self ):
2853+ # See GH-124984: OpenSSL is not thread safe.
2854+ threads = []
2855+
2856+ global USE_SAME_TEST_CONTEXT
2857+ USE_SAME_TEST_CONTEXT = True
2858+ try :
2859+ for func in (
2860+ self .test_echo ,
2861+ self .test_alpn_protocols ,
2862+ self .test_getpeercert ,
2863+ self .test_crl_check ,
2864+ self .test_check_hostname_idn ,
2865+ self .test_wrong_cert_tls12 ,
2866+ self .test_wrong_cert_tls13 ,
2867+ ):
2868+ # Be careful with the number of threads here.
2869+ # Too many can result in failing tests.
2870+ for num in range (5 ):
2871+ with self .subTest (func = func , num = num ):
2872+ threads .append (Thread (target = func ))
2873+
2874+ with threading_helper .catch_threading_exception () as cm :
2875+ for thread in threads :
2876+ with self .subTest (thread = thread ):
2877+ thread .start ()
2878+
2879+ for thread in threads :
2880+ with self .subTest (thread = thread ):
2881+ thread .join ()
2882+ if cm .exc_value is not None :
2883+ # Some threads can skip their test
2884+ if not isinstance (cm .exc_value , unittest .SkipTest ):
2885+ raise cm .exc_value
2886+ finally :
2887+ USE_SAME_TEST_CONTEXT = False
2888+
28372889 def test_getpeercert (self ):
28382890 if support .verbose :
28392891 sys .stdout .write ("\n " )
0 commit comments