@@ -75,6 +75,12 @@ def test_threads(dbapi):
7575 result_queue .append (Queue (1 ))
7676
7777 def run_queries (idx ):
78+ """Answer the queries sent to this thread until it gets None.
79+
80+ Every answer is prefixed with the thread number and the usage
81+ count of the connection, so that the main thread can check that
82+ the thread kept using its own connection.
83+ """
7884 this_db = persist .connection ()
7985 db = None
8086 while True :
@@ -107,17 +113,21 @@ def run_queries(idx):
107113 thread = Thread (target = run_queries , args = (i ,))
108114 threads .append (thread )
109115 thread .start ()
116+ # all threads are alive and have an unused connection of their own
110117 for i in range (num_threads ):
111118 query_queue [i ].put ('ping' , timeout = 1 )
112119 for i in range (num_threads ):
113120 r = result_queue [i ].get (timeout = 1 )
114121 assert r == f'{ i } (0): ok - thread alive'
115122 assert threads [i ].is_alive ()
123+ # let thread number i run i + 1 queries on its own connection
116124 for i in range (num_threads ):
117125 for j in range (i + 1 ):
118126 query_queue [i ].put (f'select test{ j } ' , timeout = 1 )
119127 r = result_queue [i ].get (timeout = 1 )
120128 assert r == f'{ i } ({ j + 1 } ): test{ j } '
129+ # closing the connection of the second thread restarts its usage count,
130+ # but does not affect the connections of the other threads
121131 query_queue [1 ].put ('select test4' , timeout = 1 )
122132 r = result_queue [1 ].get (timeout = 1 )
123133 assert r == '1(3): test4'
@@ -128,13 +138,15 @@ def run_queries(idx):
128138 query_queue [1 ].put (f'select test{ j } ' , timeout = 1 )
129139 r = result_queue [1 ].get (timeout = 1 )
130140 assert r == f'1({ j + 1 } ): test{ j } '
141+ # every thread still has its own connection with its own usage count
131142 for i in range (num_threads ):
132143 assert threads [i ].is_alive ()
133144 query_queue [i ].put ('ping' , timeout = 1 )
134145 for i in range (num_threads ):
135146 r = result_queue [i ].get (timeout = 1 )
136147 assert r == f'{ i } ({ i + 1 } ): ok - thread alive'
137148 assert threads [i ].is_alive ()
149+ # send the sentinel that makes the threads finish
138150 for i in range (num_threads ):
139151 query_queue [i ].put (None , timeout = 1 )
140152
@@ -189,58 +201,74 @@ class Threadlocal:
189201 assert isinstance (persist .thread , Threadlocal )
190202
191203
192- def test_ping_check (dbapi ):
193- """Check that connections are pinged as configured."""
194- con_cls = dbapi .Connection
195- con_cls .has_ping = True
196- con_cls .num_pings = 0
204+ def test_ping_check_never (dbapi , ping_con_cls ):
205+ """Check that connections are not pinged when ping is 0."""
197206 persist = PersistentDB (dbapi , 0 , None , None , 0 , True )
198207 db = persist .connection ()
199208 assert db ._con .valid is True
200- assert con_cls .num_pings == 0
209+ assert ping_con_cls .num_pings == 0
210+ # the closed connection is handed out again without being pinged,
211+ # so the fact that it is broken goes unnoticed
201212 db .close ()
202213 db = persist .connection ()
203214 assert db ._con .valid is False
204- assert con_cls .num_pings == 0
215+ assert ping_con_cls .num_pings == 0
216+
217+
218+ def test_ping_check_when_fetched (dbapi , ping_con_cls ):
219+ """Check that connections are pinged when ping is 1."""
205220 persist = PersistentDB (dbapi , 0 , None , None , 1 , True )
206221 db = persist .connection ()
207222 assert db ._con .valid is True
208- assert con_cls .num_pings == 1
223+ assert ping_con_cls .num_pings == 1
224+ # the closed connection is pinged when it is requested again,
225+ # so it is transparently reopened
209226 db .close ()
210227 db = persist .connection ()
211228 assert db ._con .valid is True
212- assert con_cls .num_pings == 2
229+ assert ping_con_cls .num_pings == 2
230+
231+
232+ def test_ping_check_when_cursor_created (dbapi , ping_con_cls ):
233+ """Check that connections are pinged when ping is 2."""
213234 persist = PersistentDB (dbapi , 0 , None , None , 2 , True )
214235 db = persist .connection ()
215236 assert db ._con .valid is True
216- assert con_cls .num_pings == 2
237+ assert ping_con_cls .num_pings == 0
238+ # requesting the closed connection does not ping it yet
217239 db .close ()
218240 db = persist .connection ()
219241 assert db ._con .valid is False
220- assert con_cls .num_pings == 2
242+ assert ping_con_cls .num_pings == 0
243+ # but creating a cursor does, which reopens the connection
221244 cursor = db .cursor ()
222245 assert db ._con .valid is True
223- assert con_cls .num_pings == 3
246+ assert ping_con_cls .num_pings == 1
247+ # executing a query does not ping again
224248 cursor .execute ('select test' )
225249 assert db ._con .valid is True
226- assert con_cls .num_pings == 3
250+ assert ping_con_cls .num_pings == 1
251+
252+
253+ def test_ping_check_when_query_executed (dbapi , ping_con_cls ):
254+ """Check that connections are pinged when ping is 4."""
227255 persist = PersistentDB (dbapi , 0 , None , None , 4 , True )
228256 db = persist .connection ()
229257 assert db ._con .valid is True
230- assert con_cls .num_pings == 3
258+ assert ping_con_cls .num_pings == 0
259+ # neither requesting the connection nor creating a cursor pings it
231260 db .close ()
232261 db = persist .connection ()
233262 assert db ._con .valid is False
234- assert con_cls .num_pings == 3
263+ assert ping_con_cls .num_pings == 0
235264 cursor = db .cursor ()
236265 db ._con .close ()
237266 assert db ._con .valid is False
238- assert con_cls .num_pings == 3
267+ assert ping_con_cls .num_pings == 0
268+ # only executing a query does, which reopens the connection
239269 cursor .execute ('select test' )
240270 assert db ._con .valid is True
241- assert con_cls .num_pings == 4
242- con_cls .has_ping = False
243- con_cls .num_pings = 0
271+ assert ping_con_cls .num_pings == 1
244272
245273
246274def test_failed_transaction (dbapi ):
0 commit comments