@@ -237,8 +237,9 @@ def test_session_number(aggregator, integration_check, pg_instance):
237237
238238
239239@requires_over_14
240- def test_session_idle_and_killed (aggregator , integration_check , pg_instance ):
241- # Reset idle time to 0
240+ def test_session_killed_and_abandoned (aggregator , integration_check , pg_instance ):
241+ """Test session counter metrics (killed, fatal, abandoned) - deterministic event counts."""
242+ # Reset stats to 0
242243 postgres_conn = _get_superconn (pg_instance )
243244 with postgres_conn .cursor () as cur :
244245 cur .execute ("select pg_stat_reset();" )
@@ -250,18 +251,17 @@ def test_session_idle_and_killed(aggregator, integration_check, pg_instance):
250251 check .run ()
251252 expected_tags = _get_expected_tags (check , pg_instance , db = DB_NAME )
252253
253- aggregator . assert_metric ( 'postgresql.sessions.idle_in_transaction_time' , value = 0 , count = 1 , tags = expected_tags )
254+ # Verify baseline counters are 0
254255 aggregator .assert_metric ('postgresql.sessions.killed' , value = 0 , count = 1 , tags = expected_tags )
255256 aggregator .assert_metric ('postgresql.sessions.fatal' , value = 0 , count = 1 , tags = expected_tags )
256257 aggregator .assert_metric ('postgresql.sessions.abandoned' , value = 0 , count = 1 , tags = expected_tags )
257258
258- conn = _get_conn (pg_instance )
259+ # Create a session to kill
260+ conn = _get_conn (pg_instance , autocommit = False )
259261 with conn .cursor () as cur :
260262 cur .execute ('BEGIN;' )
261263 _increase_txid (cur )
262264 cur .fetchall ()
263- # Keep transaction idle for 500ms
264- time .sleep (0.5 )
265265 cur .execute ('select pg_backend_pid();' )
266266 pid = cur .fetchall ()[0 ][0 ]
267267
@@ -270,20 +270,72 @@ def test_session_idle_and_killed(aggregator, integration_check, pg_instance):
270270 cur .execute ("SELECT pg_terminate_backend({})" .format (pid ))
271271 cur .fetchall ()
272272
273- # Abandon session
273+ # Abandon session by shutting down the socket
274274 sock = socket .fromfd (postgres_conn .fileno (), socket .AF_INET , socket .SOCK_STREAM )
275275 sock .shutdown (socket .SHUT_RDWR )
276276
277+ # Wait for stats collector to update
278+ time .sleep (0.5 )
279+
277280 aggregator .reset ()
278281 check .run ()
279282
280- assert_metric_at_least (
281- aggregator , 'postgresql.sessions.idle_in_transaction_time' , count = 1 , lower_bound = 0.5 , tags = expected_tags
282- )
283+ # Verify counter metrics incremented correctly
283284 aggregator .assert_metric ('postgresql.sessions.killed' , value = 1 , count = 1 , tags = expected_tags )
284285 aggregator .assert_metric ('postgresql.sessions.fatal' , value = 0 , count = 1 , tags = expected_tags )
285286 aggregator .assert_metric ('postgresql.sessions.abandoned' , value = 1 , count = 1 , tags = expected_tags )
286287
288+ # Clean up connection objects (connections are already in bad state from kill/abandon)
289+ try :
290+ conn .close ()
291+ except Exception :
292+ pass # Connection was killed, close may fail
293+ try :
294+ postgres_conn .close ()
295+ except Exception :
296+ pass # Socket was shut down, close may fail
297+
298+
299+ @requires_over_14
300+ @pytest .mark .flaky (max_runs = 3 )
301+ def test_session_idle_in_transaction_time (aggregator , integration_check , pg_instance ):
302+ """Test idle_in_transaction_time metric tracks time spent idle in a transaction."""
303+ postgres_conn = _get_superconn (pg_instance )
304+ with postgres_conn .cursor () as cur :
305+ cur .execute ("select pg_stat_reset();" )
306+ cur .fetchall ()
307+ time .sleep (0.5 )
308+
309+ check = integration_check (pg_instance )
310+ check .run ()
311+ expected_tags = _get_expected_tags (check , pg_instance , db = DB_NAME )
312+
313+ aggregator .assert_metric ('postgresql.sessions.idle_in_transaction_time' , value = 0 , count = 1 , tags = expected_tags )
314+
315+ # Use autocommit=False to keep the transaction open during the sleep
316+ conn = _get_conn (pg_instance , autocommit = False )
317+ with conn .cursor () as cur :
318+ cur .execute ('BEGIN' )
319+ _increase_txid (cur )
320+ cur .fetchall ()
321+ # Keep transaction idle for 5 seconds
322+ time .sleep (5.0 )
323+
324+ # Close the connection to end the transaction
325+ conn .close ()
326+
327+ # Wait for stats collector to update
328+ time .sleep (1.0 )
329+ aggregator .reset ()
330+ check .run ()
331+
332+ # Verify we now have a greater than 0 seconds of idle transaction time
333+ assert_metric_at_least (
334+ aggregator , 'postgresql.sessions.idle_in_transaction_time' , count = 1 , lower_bound = 0.1 , tags = expected_tags
335+ )
336+
337+ postgres_conn .close ()
338+
287339
288340def test_unsupported_replication (aggregator , integration_check , pg_instance ):
289341 check = integration_check (pg_instance )
0 commit comments