@@ -75,3 +75,175 @@ def _timers(self):
7575
7676 # There is no unpatching because there is not a clear way
7777 # of doing it reliably
78+
79+
80+ try :
81+ from eventlet .green .OpenSSL import SSL as EventletSSL
82+ _HAS_EVENTLET_PYOPENSSL = True
83+ except ImportError :
84+ _HAS_EVENTLET_PYOPENSSL = False
85+
86+
87+ @notpypy
88+ @unittest .skipIf (skip_condition , "Skipping the eventlet tests because it's not installed" )
89+ @unittest .skipIf (not _HAS_EVENTLET_PYOPENSSL , "PyOpenSSL not available for eventlet" )
90+ class EventletTLSSessionCacheTest (unittest .TestCase ):
91+ """Test TLS session caching for EventletConnection with PyOpenSSL."""
92+
93+ @classmethod
94+ def setUpClass (cls ):
95+ if skip_condition :
96+ return
97+ import eventlet
98+ eventlet .sleep ()
99+ monkey_patch ()
100+ EventletConnection .initialize_reactor ()
101+
102+ def test_wrap_socket_applies_cached_session (self ):
103+ """Test that _wrap_socket_from_context applies cached TLS session."""
104+ from unittest .mock import Mock , MagicMock
105+ from cassandra .connection import DefaultEndPoint
106+
107+ # Create mock objects
108+ mock_cache = Mock ()
109+ mock_session = Mock ()
110+ mock_cache .get_session .return_value = mock_session
111+
112+ mock_ssl_context = MagicMock ()
113+ mock_ssl_connection = MagicMock ()
114+
115+ endpoint = DefaultEndPoint ('127.0.0.1' , 9042 )
116+
117+ with patch ('eventlet.green.socket.socket' ):
118+ with patch .object (EventletConnection , '_connect_socket' ):
119+ with patch .object (EventletConnection , '_send_options_message' ):
120+ conn = EventletConnection (
121+ endpoint ,
122+ cql_version = '3.0.1' ,
123+ connect_timeout = 5
124+ )
125+ conn .ssl_context = mock_ssl_context
126+ conn .ssl_options = {}
127+ conn .tls_session_cache = mock_cache
128+ conn ._socket = Mock ()
129+
130+ # Patch SSL.Connection to return our mock
131+ with patch ('cassandra.io.eventletreactor.SSL.Connection' , return_value = mock_ssl_connection ):
132+ conn ._wrap_socket_from_context ()
133+
134+ # Verify get_session was called with endpoint
135+ mock_cache .get_session .assert_called_once_with (endpoint )
136+
137+ # Verify set_session was called on the SSL connection
138+ mock_ssl_connection .set_session .assert_called_once_with (mock_session )
139+
140+ def test_wrap_socket_no_session_when_cache_empty (self ):
141+ """Test that _wrap_socket_from_context handles empty cache."""
142+ from unittest .mock import Mock , MagicMock
143+ from cassandra .connection import DefaultEndPoint
144+
145+ mock_cache = Mock ()
146+ mock_cache .get_session .return_value = None # No cached session
147+
148+ mock_ssl_context = MagicMock ()
149+ mock_ssl_connection = MagicMock ()
150+
151+ endpoint = DefaultEndPoint ('127.0.0.1' , 9042 )
152+
153+ with patch ('eventlet.green.socket.socket' ):
154+ with patch .object (EventletConnection , '_connect_socket' ):
155+ with patch .object (EventletConnection , '_send_options_message' ):
156+ conn = EventletConnection (
157+ endpoint ,
158+ cql_version = '3.0.1' ,
159+ connect_timeout = 5
160+ )
161+ conn .ssl_context = mock_ssl_context
162+ conn .ssl_options = {}
163+ conn .tls_session_cache = mock_cache
164+ conn ._socket = Mock ()
165+
166+ with patch ('cassandra.io.eventletreactor.SSL.Connection' , return_value = mock_ssl_connection ):
167+ conn ._wrap_socket_from_context ()
168+
169+ # Verify get_session was called
170+ mock_cache .get_session .assert_called_once_with (endpoint )
171+
172+ # Verify set_session was NOT called on SSL connection (no cached session)
173+ mock_ssl_connection .set_session .assert_not_called ()
174+
175+ def test_initiate_connection_stores_session_after_handshake (self ):
176+ """Test that _initiate_connection stores session after successful handshake."""
177+ from unittest .mock import Mock , MagicMock
178+ from cassandra .connection import DefaultEndPoint
179+
180+ mock_cache = Mock ()
181+ mock_session = Mock ()
182+
183+ mock_ssl_socket = MagicMock ()
184+ mock_ssl_socket .get_session .return_value = mock_session
185+ mock_ssl_socket .session_reused .return_value = False
186+
187+ endpoint = DefaultEndPoint ('127.0.0.1' , 9042 )
188+
189+ with patch ('eventlet.green.socket.socket' ):
190+ with patch .object (EventletConnection , '_connect_socket' ):
191+ with patch .object (EventletConnection , '_send_options_message' ):
192+ conn = EventletConnection (
193+ endpoint ,
194+ cql_version = '3.0.1' ,
195+ connect_timeout = 5
196+ )
197+ conn .ssl_context = Mock ()
198+ conn .ssl_options = {}
199+ conn .tls_session_cache = mock_cache
200+ conn ._socket = mock_ssl_socket
201+ conn .uses_legacy_ssl_options = False
202+
203+ sockaddr = ('127.0.0.1' , 9042 )
204+ conn ._initiate_connection (sockaddr )
205+
206+ # Verify handshake was called
207+ mock_ssl_socket .do_handshake .assert_called_once ()
208+
209+ # Verify session was retrieved and stored
210+ mock_ssl_socket .get_session .assert_called_once ()
211+ mock_cache .set_session .assert_called_once_with (endpoint , mock_session )
212+
213+ def test_initiate_connection_logs_session_reuse (self ):
214+ """Test that _initiate_connection logs when session is reused."""
215+ from unittest .mock import Mock , MagicMock
216+ from cassandra .connection import DefaultEndPoint
217+
218+ mock_cache = Mock ()
219+ mock_session = Mock ()
220+
221+ mock_ssl_socket = MagicMock ()
222+ mock_ssl_socket .get_session .return_value = mock_session
223+ mock_ssl_socket .session_reused .return_value = True # Session was reused
224+
225+ endpoint = DefaultEndPoint ('127.0.0.1' , 9042 )
226+
227+ with patch ('eventlet.green.socket.socket' ):
228+ with patch .object (EventletConnection , '_connect_socket' ):
229+ with patch .object (EventletConnection , '_send_options_message' ):
230+ conn = EventletConnection (
231+ endpoint ,
232+ cql_version = '3.0.1' ,
233+ connect_timeout = 5
234+ )
235+ conn .ssl_context = Mock ()
236+ conn .ssl_options = {}
237+ conn .tls_session_cache = mock_cache
238+ conn ._socket = mock_ssl_socket
239+ conn .uses_legacy_ssl_options = False
240+
241+ with patch ('cassandra.io.eventletreactor.log' ) as mock_log :
242+ sockaddr = ('127.0.0.1' , 9042 )
243+ conn ._initiate_connection (sockaddr )
244+
245+ # Verify session_reused was checked
246+ mock_ssl_socket .session_reused .assert_called_once ()
247+
248+ # Verify debug log was called for session reuse
249+ mock_log .debug .assert_called ()
0 commit comments