Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

285 lines
11 KiB
Python

"""Unit tests for the Azure SQL integration module."""
from integrations.azure_sql import (
DEFAULT_AZURE_SQL_PORT,
AzureSQLConfig,
AzureSQLValidationResult,
azure_sql_config_from_env,
azure_sql_extract_params,
azure_sql_is_available,
build_azure_sql_config,
)
class TestAzureSQLConfig:
"""Tests for AzureSQLConfig model."""
def test_defaults(self) -> None:
config = AzureSQLConfig(server="myserver.database.windows.net", database="testdb")
assert config.server == "myserver.database.windows.net"
assert config.port == 1433
assert config.database == "testdb"
assert config.username == ""
assert config.password == ""
assert config.driver == "ODBC Driver 18 for SQL Server"
assert config.encrypt is True
assert config.timeout_seconds == 15.0
assert config.max_results == 50
def test_is_configured_with_server_and_database(self) -> None:
config = AzureSQLConfig(server="myserver.database.windows.net", database="mydb")
assert config.is_configured is True
def test_is_configured_without_server(self) -> None:
config = AzureSQLConfig(database="mydb")
assert config.is_configured is False
def test_is_configured_without_database(self) -> None:
config = AzureSQLConfig(server="myserver.database.windows.net")
assert config.is_configured is False
def test_is_configured_without_server_and_database(self) -> None:
config = AzureSQLConfig()
assert config.is_configured is False
def test_normalize_server_strips_whitespace(self) -> None:
config = AzureSQLConfig(server=" myserver.database.windows.net ", database="mydb")
assert config.server == "myserver.database.windows.net"
def test_normalize_empty_server(self) -> None:
config = AzureSQLConfig(server="", database="mydb")
assert config.server == ""
assert config.is_configured is False
def test_normalize_database_strips_whitespace(self) -> None:
config = AzureSQLConfig(server="myserver.database.windows.net", database=" mydb ")
assert config.database == "mydb"
def test_normalize_empty_database(self) -> None:
config = AzureSQLConfig(server="myserver.database.windows.net", database="")
assert config.database == ""
assert config.is_configured is False
def test_normalize_driver_default(self) -> None:
config = AzureSQLConfig(server="s", database="d", driver="")
assert config.driver == "ODBC Driver 18 for SQL Server"
def test_normalize_driver_custom(self) -> None:
config = AzureSQLConfig(server="s", database="d", driver="ODBC Driver 17 for SQL Server")
assert config.driver == "ODBC Driver 17 for SQL Server"
def test_custom_values(self) -> None:
config = AzureSQLConfig(
server="prod.database.windows.net",
port=1434,
database="analytics",
username="reader",
password="secret",
driver="ODBC Driver 17 for SQL Server",
encrypt=False,
timeout_seconds=30.0,
max_results=100,
)
assert config.server == "prod.database.windows.net"
assert config.port == 1434
assert config.database == "analytics"
assert config.username == "reader"
assert config.password == "secret"
assert config.driver == "ODBC Driver 17 for SQL Server"
assert config.encrypt is False
assert config.timeout_seconds == 30.0
assert config.max_results == 100
def test_validation_result_ok(self) -> None:
result = AzureSQLValidationResult(ok=True, detail="Connected.")
assert result.ok is True
assert result.detail == "Connected."
def test_validation_result_failed(self) -> None:
result = AzureSQLValidationResult(ok=False, detail="Connection refused.")
assert result.ok is False
assert result.detail == "Connection refused."
class TestBuildAzureSQLConfig:
"""Tests for build_azure_sql_config helper."""
def test_from_dict(self) -> None:
config = build_azure_sql_config(
{
"server": "myserver.database.windows.net",
"database": "mydb",
"port": 1434,
}
)
assert config.server == "myserver.database.windows.net"
assert config.database == "mydb"
assert config.port == 1434
def test_from_none(self) -> None:
config = build_azure_sql_config(None)
assert config.server == ""
assert config.database == ""
assert config.is_configured is False
def test_from_empty_dict(self) -> None:
config = build_azure_sql_config({})
assert config.server == ""
assert config.database == ""
assert config.is_configured is False
class TestAzureSQLConfigFromEnv:
"""Tests for azure_sql_config_from_env helper."""
def test_returns_none_without_server(self) -> None:
import os
old_server = os.environ.get("AZURE_SQL_SERVER")
old_database = os.environ.get("AZURE_SQL_DATABASE")
os.environ.pop("AZURE_SQL_SERVER", None)
os.environ.pop("AZURE_SQL_DATABASE", None)
try:
result = azure_sql_config_from_env()
assert result is None
finally:
if old_server is not None:
os.environ["AZURE_SQL_SERVER"] = old_server
if old_database is not None:
os.environ["AZURE_SQL_DATABASE"] = old_database
def test_returns_config_with_server_and_database(self) -> None:
import os
old = {
k: os.environ.get(k)
for k in (
"AZURE_SQL_SERVER",
"AZURE_SQL_DATABASE",
"AZURE_SQL_PORT",
"AZURE_SQL_USERNAME",
"AZURE_SQL_PASSWORD",
)
}
os.environ["AZURE_SQL_SERVER"] = "myserver.database.windows.net"
os.environ["AZURE_SQL_DATABASE"] = "mydb"
os.environ["AZURE_SQL_PORT"] = "1434"
os.environ["AZURE_SQL_USERNAME"] = "admin"
os.environ["AZURE_SQL_PASSWORD"] = "secret"
try:
result = azure_sql_config_from_env()
assert result is not None
assert result.server == "myserver.database.windows.net"
assert result.database == "mydb"
assert result.port == 1434
assert result.username == "admin"
assert result.password == "secret"
finally:
for k, v in old.items():
if v is not None:
os.environ[k] = v
else:
os.environ.pop(k, None)
class TestAzureSQLIsAvailable:
def test_true_with_server_and_database(self) -> None:
sources = {"azure_sql": {"server": "myserver.database.windows.net", "database": "mydb"}}
assert azure_sql_is_available(sources) is True
def test_false_when_missing_server(self) -> None:
assert azure_sql_is_available({"azure_sql": {"server": "", "database": "mydb"}}) is False
def test_false_when_missing_database(self) -> None:
assert azure_sql_is_available({"azure_sql": {"server": "s", "database": ""}}) is False
def test_false_when_azure_sql_key_absent(self) -> None:
assert azure_sql_is_available({}) is False
def test_false_when_azure_sql_is_empty_dict(self) -> None:
assert azure_sql_is_available({"azure_sql": {}}) is False
def test_false_when_server_is_none(self) -> None:
assert azure_sql_is_available({"azure_sql": {"server": None, "database": "mydb"}}) is False
class TestAzureSQLExtractParams:
def test_all_identifying_fields_returned(self) -> None:
sources = {
"azure_sql": {
"server": "myserver.database.windows.net",
"database": "mydb",
"port": 1434,
}
}
params = azure_sql_extract_params(sources)
assert params == {
"server": "myserver.database.windows.net",
"database": "mydb",
"port": 1434,
}
def test_credentials_are_never_surfaced(self) -> None:
# Even if the source dict contains credentials, extract_params must only
# expose identifying params. Credentials belong in resolve_azure_sql_config,
# not on the LLM-visible tool signature.
sources = {
"azure_sql": {
"server": "s",
"database": "d",
"port": 1433,
"username": "admin",
"password": "secret",
"driver": "ODBC Driver 18 for SQL Server",
}
}
params = azure_sql_extract_params(sources)
assert set(params) == {"server", "database", "port"}
assert "username" not in params
assert "password" not in params
assert "driver" not in params
def test_defaults_when_keys_missing(self) -> None:
params = azure_sql_extract_params({"azure_sql": {}})
assert params["server"] == ""
assert params["database"] == ""
assert params["port"] == DEFAULT_AZURE_SQL_PORT
def test_empty_sources_dict(self) -> None:
params = azure_sql_extract_params({})
assert params["server"] == ""
assert params["database"] == ""
assert params["port"] == DEFAULT_AZURE_SQL_PORT
def test_server_whitespace_stripped(self) -> None:
sources = {"azure_sql": {"server": " myserver.database.windows.net ", "database": "d"}}
assert azure_sql_extract_params(sources)["server"] == "myserver.database.windows.net"
def test_port_none_collapses_to_default(self) -> None:
# A stored integration persisting {"port": null} must not crash
# extract_params with TypeError from int(None). The `or` fallback
# collapses both missing and explicit-None ports to the default.
sources = {"azure_sql": {"server": "s", "database": "d", "port": None}}
assert azure_sql_extract_params(sources)["port"] == DEFAULT_AZURE_SQL_PORT
def test_port_zero_also_collapses_to_default(self) -> None:
# Port 0 is a sentinel for "unconfigured" in this context; treat
# the same as None to match the `or` idiom.
sources = {"azure_sql": {"server": "s", "database": "d", "port": 0}}
assert azure_sql_extract_params(sources)["port"] == DEFAULT_AZURE_SQL_PORT
def test_port_as_numeric_string(self) -> None:
sources = {"azure_sql": {"server": "s", "database": "d", "port": "1434"}}
assert azure_sql_extract_params(sources)["port"] == 1434
def test_server_none_returns_empty_string(self) -> None:
# A stored integration persisting {"server": null} must not yield the
# literal string "None" through str(None). The `or ""` fallback keeps
# the result empty, matching the AzureSQLConfig._normalize_server validator.
sources = {"azure_sql": {"server": None, "database": "d"}}
assert azure_sql_extract_params(sources)["server"] == ""
def test_database_none_returns_empty_string(self) -> None:
sources = {"azure_sql": {"server": "s", "database": None}}
assert azure_sql_extract_params(sources)["database"] == ""