feat(infra): conexion y consulta directa a SQL Server (Navision) via pymssql
Grupo de capacidad nuevo 'sql-connect' (3 funciones) para conectar a un
Microsoft SQL Server (donde corre Navision) y consultar directamente, en
lugar del ida y vuelta manual de pegar CSVs.
- mssql_connect_py_infra: abre conexion pymssql (login_timeout acotado,
credenciales por argumento, RuntimeError claro si falla).
- mssql_query_py_infra: SELECT parametrizada con binding seguro (sin
inyeccion) sobre conexion abierta; devuelve {columns, rows, row_count};
0 filas -> lista vacia; max_rows con fetchmany; read-only.
- run_mssql_query_py_pipelines: one-shot que compone connect+query y cierra
siempre; CLI imprime JSON o CSV; contrasena desde env var (pass).
Pagina madre docs/capabilities/sql-connect.md + fila en INDEX.md.
Dependencia pymssql>=2.3.13 anadida a python/pyproject.toml + uv.lock.
Tests mock-based (11) verdes; error path verificado end-to-end contra el
driver real (host inalcanzable -> RuntimeError, acotado por login_timeout).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
"""Tests for mssql_connect (mock-based, no real SQL Server)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
|
||||
from mssql_connect import mssql_connect
|
||||
|
||||
|
||||
def test_golden_connect_passes_string_port_and_kwargs(monkeypatch):
|
||||
"""Golden path: returns the driver connection and forwards the right kwargs.
|
||||
|
||||
The TCP port must reach pymssql as a STRING, and login_timeout must default
|
||||
to 15 when not supplied.
|
||||
"""
|
||||
captured: dict = {}
|
||||
sentinel = object()
|
||||
|
||||
def fake_connect(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return sentinel
|
||||
|
||||
monkeypatch.setattr("pymssql.connect", fake_connect)
|
||||
|
||||
result = mssql_connect("10.0.0.5", "navdb", "sa", "pw", port=1433)
|
||||
|
||||
assert result is sentinel
|
||||
assert captured["server"] == "10.0.0.5"
|
||||
assert captured["database"] == "navdb"
|
||||
assert captured["user"] == "sa"
|
||||
assert captured["password"] == "pw"
|
||||
assert captured["port"] == "1433"
|
||||
assert isinstance(captured["port"], str)
|
||||
assert captured["login_timeout"] == 15
|
||||
assert captured["timeout"] == 30
|
||||
|
||||
|
||||
def test_error_path_wraps_failure_with_host(monkeypatch):
|
||||
"""Error path: a driver failure becomes a clear RuntimeError, not a hang.
|
||||
|
||||
The wrapped message must include the host and the phrase 'failed connecting'
|
||||
so callers can diagnose connectivity problems.
|
||||
"""
|
||||
def fake_connect(**kwargs):
|
||||
raise Exception("login timeout")
|
||||
|
||||
monkeypatch.setattr("pymssql.connect", fake_connect)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
mssql_connect("10.0.0.5", "navdb", "sa", "pw", port=1433)
|
||||
|
||||
message = str(excinfo.value)
|
||||
assert "10.0.0.5" in message
|
||||
assert "failed connecting" in message
|
||||
Reference in New Issue
Block a user