44import pytest
55
66from ydb ._grpc .common .protos import ydb_query_pb2
7+ from ydb ._grpc .grpcwrapper import common_utils
78from ydb .aio .pool import ConnectionPool as AsyncConnectionPool
8- from ydb .pool import ConnectionPool
9+ from ydb .pool import ConnectionPool , ConnectionsCache
910from ydb .query .session import QuerySession
1011
1112
@@ -85,8 +86,52 @@ def test_no_hint_does_not_invalidate(self):
8586 assert not session ._invalidated
8687 assert not session ._closed
8788
89+ def test_none_response_does_not_invalidate (self ):
90+ session , driver = _make_session ()
91+
92+ session ._handle_attach_session_state (None )
93+
94+ driver ._pessimize_node .assert_not_called ()
95+ assert not session ._invalidated
96+ assert not session ._closed
97+
98+ def test_attach_stream_wrapper_handles_hint_and_returns_status (self ):
99+ session , driver = _make_session (node_id = 42 )
100+ response = ydb_query_pb2 .SessionState (
101+ status = 0 ,
102+ session_shutdown = ydb_query_pb2 .SessionShutdownHint (),
103+ )
104+
105+ status = session ._attach_stream_wrapper (response )
106+
107+ driver ._pessimize_node .assert_not_called ()
108+ assert session ._invalidated
109+ assert isinstance (status , common_utils .ServerStatus )
110+
111+ def test_attach_stream_wrapper_returns_status_without_hint (self ):
112+ session , driver = _make_session ()
113+ response = ydb_query_pb2 .SessionState (status = 0 )
114+
115+ status = session ._attach_stream_wrapper (response )
116+
117+ driver ._pessimize_node .assert_not_called ()
118+ assert not session ._invalidated
119+ assert isinstance (status , common_utils .ServerStatus )
120+
88121
89122class TestConnectionPoolAttachHintPessimization :
123+ def test_connections_cache_get_connection_by_node_id (self ):
124+ cache = ConnectionsCache ()
125+ connection = mock .Mock ()
126+ connection .endpoint = "grpc://localhost:2135"
127+ connection .node_id = 42
128+ connection .add_cleanup_callback = mock .Mock ()
129+
130+ cache .add (connection )
131+
132+ assert cache .get_connection_by_node_id (42 ) is connection
133+ assert cache .get_connection_by_node_id (99 ) is None
134+
90135 def test_sync_pool_pessimizes_node_connection (self ):
91136 pool = ConnectionPool .__new__ (ConnectionPool )
92137 connection = mock .Mock ()
@@ -107,7 +152,34 @@ def test_sync_pool_ignores_missing_node_connection(self):
107152
108153 pool ._pessimize_node (42 )
109154 pool ._pessimize_node (0 )
155+ pool ._pessimize_node (- 1 )
156+
157+ pool ._store .get_connection_by_node_id .assert_called_once_with (42 )
158+ pool ._on_disconnected .assert_not_called ()
159+
160+ @pytest .mark .asyncio
161+ async def test_async_pool_ignores_non_positive_node_id (self ):
162+ pool = AsyncConnectionPool .__new__ (AsyncConnectionPool )
163+ pool ._store = mock .Mock ()
164+ pool ._on_disconnected = mock .Mock ()
165+
166+ pool ._pessimize_node (0 )
167+ pool ._pessimize_node (- 1 )
110168
169+ pool ._store .get_connection_by_node_id .assert_not_called ()
170+ pool ._on_disconnected .assert_not_called ()
171+
172+ @pytest .mark .asyncio
173+ async def test_async_pool_ignores_missing_node_connection (self ):
174+ pool = AsyncConnectionPool .__new__ (AsyncConnectionPool )
175+ pool ._store = mock .Mock ()
176+ pool ._store .get_connection_by_node_id .return_value = None
177+ pool ._on_disconnected = mock .Mock ()
178+
179+ pool ._pessimize_node (42 )
180+ await asyncio .sleep (0 )
181+
182+ pool ._store .get_connection_by_node_id .assert_called_once_with (42 )
111183 pool ._on_disconnected .assert_not_called ()
112184
113185 @pytest .mark .asyncio
0 commit comments