Skip to content

Commit c04fe30

Browse files
feat: Add tests for MSSQL connection configuration and parameter validation
1 parent 4a4c0b1 commit c04fe30

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed

tests/core/test_connection_config.py

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,3 +1180,238 @@ def test_mssql_engine_import_validator():
11801180
mock_import.return_value = None
11811181
config = MSSQLConnectionConfig(host="localhost", driver="pyodbc")
11821182
assert config.driver == "pyodbc"
1183+
1184+
1185+
def test_mssql_connection_config_parameter_validation(make_config):
1186+
"""Test MSSQL connection config parameter validation."""
1187+
# Test default driver is pymssql
1188+
config = make_config(type="mssql", host="localhost", check_import=False)
1189+
assert isinstance(config, MSSQLConnectionConfig)
1190+
assert config.driver == "pymssql"
1191+
1192+
# Test explicit pyodbc driver
1193+
config = make_config(type="mssql", host="localhost", driver="pyodbc", check_import=False)
1194+
assert isinstance(config, MSSQLConnectionConfig)
1195+
assert config.driver == "pyodbc"
1196+
1197+
# Test explicit pymssql driver
1198+
config = make_config(type="mssql", host="localhost", driver="pymssql", check_import=False)
1199+
assert isinstance(config, MSSQLConnectionConfig)
1200+
assert config.driver == "pymssql"
1201+
1202+
# Test pyodbc specific parameters
1203+
config = make_config(
1204+
type="mssql",
1205+
host="localhost",
1206+
driver="pyodbc",
1207+
driver_name="ODBC Driver 18 for SQL Server",
1208+
trust_server_certificate=True,
1209+
encrypt=False,
1210+
odbc_properties={"Authentication": "ActiveDirectoryServicePrincipal"},
1211+
check_import=False,
1212+
)
1213+
assert isinstance(config, MSSQLConnectionConfig)
1214+
assert config.driver_name == "ODBC Driver 18 for SQL Server"
1215+
assert config.trust_server_certificate is True
1216+
assert config.encrypt is False
1217+
assert config.odbc_properties == {"Authentication": "ActiveDirectoryServicePrincipal"}
1218+
1219+
# Test pymssql specific parameters
1220+
config = make_config(
1221+
type="mssql",
1222+
host="localhost",
1223+
driver="pymssql",
1224+
tds_version="7.4",
1225+
conn_properties=["SET ANSI_NULLS ON"],
1226+
check_import=False,
1227+
)
1228+
assert isinstance(config, MSSQLConnectionConfig)
1229+
assert config.tds_version == "7.4"
1230+
assert config.conn_properties == ["SET ANSI_NULLS ON"]
1231+
1232+
1233+
def test_mssql_connection_kwargs_keys():
1234+
"""Test _connection_kwargs_keys returns correct keys for each driver variant."""
1235+
# Test pymssql driver keys
1236+
config = MSSQLConnectionConfig(host="localhost", driver="pymssql", check_import=False)
1237+
pymssql_keys = config._connection_kwargs_keys
1238+
expected_pymssql_keys = {
1239+
"password",
1240+
"user",
1241+
"database",
1242+
"host",
1243+
"timeout",
1244+
"login_timeout",
1245+
"charset",
1246+
"appname",
1247+
"port",
1248+
"tds_version",
1249+
"conn_properties",
1250+
"autocommit",
1251+
}
1252+
assert pymssql_keys == expected_pymssql_keys
1253+
1254+
# Test pyodbc driver keys
1255+
config = MSSQLConnectionConfig(host="localhost", driver="pyodbc", check_import=False)
1256+
pyodbc_keys = config._connection_kwargs_keys
1257+
expected_pyodbc_keys = {
1258+
"password",
1259+
"user",
1260+
"database",
1261+
"host",
1262+
"timeout",
1263+
"login_timeout",
1264+
"charset",
1265+
"appname",
1266+
"port",
1267+
"autocommit",
1268+
"driver_name",
1269+
"trust_server_certificate",
1270+
"encrypt",
1271+
"odbc_properties",
1272+
}
1273+
assert pyodbc_keys == expected_pyodbc_keys
1274+
1275+
# Verify pyodbc keys don't include pymssql-specific parameters
1276+
assert "tds_version" not in pyodbc_keys
1277+
assert "conn_properties" not in pyodbc_keys
1278+
1279+
1280+
def test_mssql_pyodbc_connection_string_generation():
1281+
"""Test pyodbc.connect gets invoked with the correct ODBC connection string."""
1282+
with patch("pyodbc.connect") as mock_pyodbc_connect:
1283+
# Mock the return value to have the methods we need
1284+
mock_connection = mock_pyodbc_connect.return_value
1285+
1286+
# Create a pyodbc config
1287+
config = MSSQLConnectionConfig(
1288+
host="testserver.database.windows.net",
1289+
port=1433,
1290+
database="testdb",
1291+
user="testuser",
1292+
password="testpass",
1293+
driver="pyodbc",
1294+
driver_name="ODBC Driver 18 for SQL Server",
1295+
trust_server_certificate=True,
1296+
encrypt=True,
1297+
login_timeout=30,
1298+
check_import=False,
1299+
)
1300+
1301+
# Get the connection factory with kwargs and call it
1302+
factory_with_kwargs = config._connection_factory_with_kwargs
1303+
connection = factory_with_kwargs()
1304+
1305+
# Verify pyodbc.connect was called with the correct connection string
1306+
mock_pyodbc_connect.assert_called_once()
1307+
call_args = mock_pyodbc_connect.call_args
1308+
1309+
# Check the connection string (first argument)
1310+
conn_str = call_args[0][0]
1311+
expected_parts = [
1312+
"DRIVER={ODBC Driver 18 for SQL Server}",
1313+
"SERVER=testserver.database.windows.net,1433",
1314+
"DATABASE=testdb",
1315+
"Encrypt=YES",
1316+
"TrustServerCertificate=YES",
1317+
"Connection Timeout=30",
1318+
"UID=testuser",
1319+
"PWD=testpass",
1320+
]
1321+
1322+
for part in expected_parts:
1323+
assert part in conn_str
1324+
1325+
# Check autocommit parameter
1326+
assert call_args[1]["autocommit"] is False
1327+
1328+
1329+
def test_mssql_pyodbc_connection_string_with_odbc_properties():
1330+
"""Test pyodbc connection string includes custom ODBC properties."""
1331+
with patch("pyodbc.connect") as mock_pyodbc_connect:
1332+
# Create a pyodbc config with custom ODBC properties
1333+
config = MSSQLConnectionConfig(
1334+
host="testserver.database.windows.net",
1335+
database="testdb",
1336+
user="client-id",
1337+
password="client-secret",
1338+
driver="pyodbc",
1339+
odbc_properties={
1340+
"Authentication": "ActiveDirectoryServicePrincipal",
1341+
"ClientCertificate": "/path/to/cert.pem",
1342+
"TrustServerCertificate": "NO", # This should be ignored since we set it explicitly
1343+
},
1344+
trust_server_certificate=True, # This should take precedence
1345+
check_import=False,
1346+
)
1347+
1348+
# Get the connection factory with kwargs and call it
1349+
factory_with_kwargs = config._connection_factory_with_kwargs
1350+
connection = factory_with_kwargs()
1351+
1352+
# Verify pyodbc.connect was called
1353+
mock_pyodbc_connect.assert_called_once()
1354+
conn_str = mock_pyodbc_connect.call_args[0][0]
1355+
1356+
# Check that custom ODBC properties are included
1357+
assert "Authentication=ActiveDirectoryServicePrincipal" in conn_str
1358+
assert "ClientCertificate=/path/to/cert.pem" in conn_str
1359+
1360+
# Verify that explicit trust_server_certificate takes precedence
1361+
assert "TrustServerCertificate=YES" in conn_str
1362+
1363+
# Should not have the conflicting property from odbc_properties
1364+
assert conn_str.count("TrustServerCertificate") == 1
1365+
1366+
1367+
def test_mssql_pyodbc_connection_string_minimal():
1368+
"""Test pyodbc connection string with minimal configuration."""
1369+
with patch("pyodbc.connect") as mock_pyodbc_connect:
1370+
config = MSSQLConnectionConfig(
1371+
host="localhost",
1372+
driver="pyodbc",
1373+
autocommit=True,
1374+
check_import=False,
1375+
)
1376+
1377+
factory_with_kwargs = config._connection_factory_with_kwargs
1378+
connection = factory_with_kwargs()
1379+
1380+
mock_pyodbc_connect.assert_called_once()
1381+
conn_str = mock_pyodbc_connect.call_args[0][0]
1382+
1383+
# Check basic required parts
1384+
assert "DRIVER={ODBC Driver 18 for SQL Server}" in conn_str
1385+
assert "SERVER=localhost,1433" in conn_str
1386+
assert "Encrypt=YES" in conn_str # Default encrypt=True
1387+
assert "Connection Timeout=60" in conn_str # Default timeout
1388+
1389+
# Check autocommit parameter
1390+
assert mock_pyodbc_connect.call_args[1]["autocommit"] is True
1391+
1392+
1393+
def test_mssql_pymssql_connection_factory():
1394+
"""Test pymssql connection factory returns correct function."""
1395+
# Mock the import of pymssql at the module level
1396+
import sys
1397+
from unittest.mock import MagicMock
1398+
1399+
# Create a mock pymssql module
1400+
mock_pymssql = MagicMock()
1401+
sys.modules["pymssql"] = mock_pymssql
1402+
1403+
try:
1404+
config = MSSQLConnectionConfig(
1405+
host="localhost",
1406+
driver="pymssql",
1407+
check_import=False,
1408+
)
1409+
1410+
factory = config._connection_factory
1411+
1412+
# Verify the factory returns pymssql.connect
1413+
assert factory is mock_pymssql.connect
1414+
finally:
1415+
# Clean up the mock module
1416+
if "pymssql" in sys.modules:
1417+
del sys.modules["pymssql"]

0 commit comments

Comments
 (0)