FEAT: [WIP] Add ActiveDirectoryServicePrincipal support for bulk copy #576
Build #pr-validation-pipeline had test failures
Details
- Failed: 1,104 (3.73%)
- Passed: 27,546 (93.06%)
- Other: 950 (3.21%)
- Total: 29,600
- 7084 of 27204 line covered (26.04%)
Annotations
Check failure on line 2226 in Build log
azure-pipelines / MSSQL-Python-PR-Validation
Build log #L2226
Bash exited with code '1'.
Check failure on line 78643 in Build log
azure-pipelines / MSSQL-Python-PR-Validation
Build log #L78643
Job cancelled due to worker timeout.
Check failure on line 109 in Build log
azure-pipelines / MSSQL-Python-PR-Validation
Build log #L109
Step cancelled due to worker timeout
Check failure on line 110 in Build log
azure-pipelines / MSSQL-Python-PR-Validation
Build log #L110
The operation was canceled.
Check failure on line 1 in test_commit_does_not_block_other_python_threads
azure-pipelines / MSSQL-Python-PR-Validation
test_commit_does_not_block_other_python_threads
AssertionError: Heartbeat thread was starved across cursor.execute+commit. Got 15 ticks, expected >= 16.
assert 15 >= 16
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
def test_commit_does_not_block_other_python_threads(conn_str):
"""
Smoke test for the SQLEndTran GIL-release added to ``Connection::commit``
and ``Connection::rollback``. A heartbeat must keep ticking across an
explicit commit on a connection that just executed a (short) WAITFOR.
SQLEndTran on a localhost connection is typically sub-millisecond, so we
can't reliably measure starvation from it alone. Instead we just assert
that the commit completes and the heartbeat made meaningful progress
over the whole transaction, including the WAITFOR.
"""
mssql_python.pooling(enabled=False)
heartbeat_interval = 0.05
stop_event = threading.Event()
tick_count = [0]
txn_error = []
def heartbeat():
while not stop_event.is_set():
tick_count[0] += 1
time.sleep(heartbeat_interval)
# Open the connection on the main thread *before* starting the heartbeat
# measurement window. The Python-side wrapper around connect() (connstr
# parsing, handle alloc, attr setup, etc.) legitimately holds the GIL,
# and including it in the window would give false starvation signals —
# especially on macOS CI where scheduler jitter is larger. We want to
# measure ticks across cursor.execute(WAITFOR) + commit only.
conn = connect(conn_str)
def run_txn():
try:
try:
cursor = conn.cursor()
try:
cursor.execute(WAITFOR_SQL)
finally:
cursor.close()
conn.commit()
finally:
conn.close()
except Exception as exc:
txn_error.append(str(exc))
hb = threading.Thread(target=heartbeat, daemon=True)
tt = threading.Thread(target=run_txn, daemon=True)
hb.start()
time.sleep(0.1)
ticks_before = tick_count[0]
tt.start()
tt.join(timeout=WAITFOR_SECONDS + 30)
ticks_after = tick_count[0]
stop_event.set()
hb.join(timeout=5)
assert not tt.is_alive(), "Transaction thread did not finish in time"
assert not txn_error, f"Transaction thread error: {txn_error}"
ticks_during = ticks_after - ticks_before
# 40% of theoretical max gives margin against macOS CI scheduler noise
# (sleep(0.05) overshoot + GIL re-acquisition latency) while still
# catching real GIL starvation, which would yield <= ~2 ticks.
expected_min_ticks = int(WAITFOR_SECONDS / heartbeat_interval * 0.4)
print(
f"\n[HEARTBEAT] ticks during WAITFOR+commit: {ticks_during} "
f"(expected >= {expected_min_ticks})"
)
> assert ticks_during >= expected_min_ticks, (
f"Heartbeat thread was starved across cursor.execute+commit. "
f"Got {ticks_during} ticks, expected >= {expected_min_ticks}."
)
E AssertionError: Heartbeat thread was starved across cursor.execute+commit. Got 15 ticks, expected >= 16.
E assert 15 >= 16
tests/test_022_concurrent_query_gil_release.py:207: AssertionError
Check failure on line 1 in test_lowercase_concurrent_access_with_db
azure-pipelines / MSSQL-Python-PR-Validation
test_lowercase_concurrent_access_with_db
failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
> conn = connect(conn_str)
^^^^^^^^^^^^^^^^^
tests/conftest.py:43:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
mssql_python/db_connection.py:55: in connect
conn = Connection(
mssql_python/connection.py:385: in __init__
_raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')
def _raise_connection_error(e: RuntimeError) -> None:
"""Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
"""
error_msg = str(e)
match = _SQLSTATE_RE.match(error_msg)
if match:
sqlstate, ddbc_error = match.group(1), match.group(2)
# Handle malformed SQLSTATE prefix (empty or invalid code)
if not sqlstate or len(sqlstate) != 5:
logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
raise OperationalError(
driver_error="Connection operation failed",
ddbc_error=ddbc_error,
) from None
exc = sqlstate_to_exception(sqlstate, ddbc_error)
if exc is None:
logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
raise DatabaseError(
driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
ddbc_error=ddbc_error,
) from None
logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
> raise exc from None
E mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
mssql_python/connection.py:89: OperationalError
During handling of the above exception, another exception occurred:
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
conn = connect(conn_str)
except Exception as e:
if "Timeout error" in str(e):
print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
time.sleep(60)
conn = connect(conn_str)
else:
> pytest.fail(f"Database connection failed: {e}")
E Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
tests/conftest.py:50: Failed
Check failure on line 1 in test_decimal_separator_with_db_operations
azure-pipelines / MSSQL-Python-PR-Validation
test_decimal_separator_with_db_operations
failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
> conn = connect(conn_str)
^^^^^^^^^^^^^^^^^
tests/conftest.py:43:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
mssql_python/db_connection.py:55: in connect
conn = Connection(
mssql_python/connection.py:385: in __init__
_raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')
def _raise_connection_error(e: RuntimeError) -> None:
"""Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
"""
error_msg = str(e)
match = _SQLSTATE_RE.match(error_msg)
if match:
sqlstate, ddbc_error = match.group(1), match.group(2)
# Handle malformed SQLSTATE prefix (empty or invalid code)
if not sqlstate or len(sqlstate) != 5:
logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
raise OperationalError(
driver_error="Connection operation failed",
ddbc_error=ddbc_error,
) from None
exc = sqlstate_to_exception(sqlstate, ddbc_error)
if exc is None:
logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
raise DatabaseError(
driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
ddbc_error=ddbc_error,
) from None
logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
> raise exc from None
E mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
mssql_python/connection.py:89: OperationalError
During handling of the above exception, another exception occurred:
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
conn = connect(conn_str)
except Exception as e:
if "Timeout error" in str(e):
print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
time.sleep(60)
conn = connect(conn_str)
else:
> pytest.fail(f"Database connection failed: {e}")
E Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
tests/conftest.py:50: Failed
Check failure on line 1 in test_decimal_separator_batch_operations
azure-pipelines / MSSQL-Python-PR-Validation
test_decimal_separator_batch_operations
failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
> conn = connect(conn_str)
^^^^^^^^^^^^^^^^^
tests/conftest.py:43:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
mssql_python/db_connection.py:55: in connect
conn = Connection(
mssql_python/connection.py:385: in __init__
_raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')
def _raise_connection_error(e: RuntimeError) -> None:
"""Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
"""
error_msg = str(e)
match = _SQLSTATE_RE.match(error_msg)
if match:
sqlstate, ddbc_error = match.group(1), match.group(2)
# Handle malformed SQLSTATE prefix (empty or invalid code)
if not sqlstate or len(sqlstate) != 5:
logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
raise OperationalError(
driver_error="Connection operation failed",
ddbc_error=ddbc_error,
) from None
exc = sqlstate_to_exception(sqlstate, ddbc_error)
if exc is None:
logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
raise DatabaseError(
driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
ddbc_error=ddbc_error,
) from None
logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
> raise exc from None
E mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
mssql_python/connection.py:89: OperationalError
During handling of the above exception, another exception occurred:
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'
@pytest.fixture(scope="module")
def db_connection(conn_str):
try:
conn = connect(conn_str)
except Exception as e:
if "Timeout error" in str(e):
print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
time.sleep(60)
conn = connect(conn_str)
else:
> pytest.fail(f"Database connection failed: {e}")
E Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726
tests/conftest.py:50: Failed