CHORE: Exclude diagnostic LOG statements from coverage metrics #556
Azure Pipelines / MSSQL-Python-PR-Validation
succeeded
May 19, 2026 in 48m 59s
Build #pr-validation-pipeline had test failures
Details
- Failed: 1 (0.00%)
- Passed: 29,717 (96.68%)
- Other: 1,018 (3.31%)
- Total: 30,736
- 6629 of 8235 lines covered (80.50%)
Annotations
Check failure on line 1 in test_query_does_not_block_other_python_threads
azure-pipelines / MSSQL-Python-PR-Validation
test_query_does_not_block_other_python_threads
AssertionError: Heartbeat thread was starved during cursor.execute(WAITFOR). Got 17 ticks, expected >= 20. This indicates the GIL was not released around the blocking ODBC call.
assert 17 >= 20
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
def test_query_does_not_block_other_python_threads(conn_str):
"""
While one thread executes a 2-second ``WAITFOR DELAY``, a second pure-Python
thread must continue to run. If the GIL were held across SQLExecDirect, the
heartbeat would not advance until the WAITFOR returned.
"""
mssql_python.pooling(enabled=False)
heartbeat_interval = 0.05 # 50ms ticks
expected_min_ticks = int(WAITFOR_SECONDS / heartbeat_interval * 0.5) # 50% of theoretical max
stop_event = threading.Event()
tick_count = [0]
query_error = []
def heartbeat():
while not stop_event.is_set():
tick_count[0] += 1
time.sleep(heartbeat_interval)
def run_query():
try:
_run_waitfor(conn_str)
except Exception as exc:
query_error.append(str(exc))
hb = threading.Thread(target=heartbeat, daemon=True)
qt = threading.Thread(target=run_query, daemon=True)
# Snapshot ticks just before/after the query so we measure ticks that
# happened *during* the blocking ODBC call, not before/after.
hb.start()
time.sleep(0.1) # let heartbeat warm up
ticks_before = tick_count[0]
qt.start()
qt.join(timeout=WAITFOR_SECONDS + 30)
ticks_after = tick_count[0]
stop_event.set()
hb.join(timeout=5)
assert not qt.is_alive(), "Query thread did not finish in time"
assert not query_error, f"Query thread error: {query_error}"
ticks_during = ticks_after - ticks_before
print(
f"\n[HEARTBEAT] ticks during {WAITFOR_SECONDS}s WAITFOR: {ticks_during} "
f"(expected >= {expected_min_ticks})"
)
> assert ticks_during >= expected_min_ticks, (
f"Heartbeat thread was starved during cursor.execute(WAITFOR). "
f"Got {ticks_during} ticks, expected >= {expected_min_ticks}. "
f"This indicates the GIL was not released around the blocking ODBC call."
)
E AssertionError: Heartbeat thread was starved during cursor.execute(WAITFOR). Got 17 ticks, expected >= 20. This indicates the GIL was not released around the blocking ODBC call.
E assert 17 >= 20
tests/test_022_concurrent_query_gil_release.py:123: AssertionError
Loading