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

261 lines
9.4 KiB
Python

"""MySQL E2E tests verifying integration with investigation pipeline.
Tests:
- MySQL config resolution from store and env
- MySQL verification (connection, server info)
- MySQL source detection in investigation state
- MySQL tools availability for query execution
"""
from __future__ import annotations
import json
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from integrations.catalog import classify_integrations as _classify_integrations
from integrations.verify import verify_integrations
from tests.e2e.source_helpers import resolve_available_tool_sources
class TestMySQLIntegrationResolution:
"""Test MySQL config resolution from multiple sources."""
def test_mysql_resolution_from_store(self):
"""MySQL integration correctly resolved from local store."""
integrations = [
{
"id": "mysql-prod",
"service": "mysql",
"status": "active",
"credentials": {
"host": "prod-primary.mysql.net",
"port": 3306,
"database": "application_db",
"username": "app_user",
"password": "secure_password",
"ssl_mode": "required",
},
}
]
resolved = _classify_integrations(integrations)
assert "mysql" in resolved
assert resolved["mysql"]["host"] == "prod-primary.mysql.net"
assert resolved["mysql"]["port"] == 3306
assert resolved["mysql"]["database"] == "application_db"
assert resolved["mysql"]["username"] == "app_user"
assert resolved["mysql"]["password"] == "secure_password"
assert resolved["mysql"]["ssl_mode"] == "required"
def test_mysql_invalid_config_skipped(self):
"""Invalid MySQL integration config is safely skipped."""
integrations = [
{
"id": "bad-mysql",
"service": "mysql",
"status": "active",
"credentials": {
"host": "",
"database": "",
},
}
]
resolved = _classify_integrations(integrations)
assert resolved.get("mysql") is None
def test_mysql_missing_database_skipped(self):
"""MySQL integration without database is safely skipped."""
integrations = [
{
"id": "no-db-mysql",
"service": "mysql",
"status": "active",
"credentials": {
"host": "localhost",
"database": "",
},
}
]
resolved = _classify_integrations(integrations)
assert resolved.get("mysql") is None
class TestMySQLToolSourceAvailability:
"""Test MySQL source availability in the tool-registry investigation path."""
def test_mysql_tool_source_available_from_resolved_integration(self):
"""MySQL source is available when a configured integration exists."""
resolved_integrations = {
"mysql": {
"host": "localhost",
"port": 3306,
"database": "application_db",
"username": "root",
"password": "test123",
"ssl_mode": "preferred",
}
}
sources = resolve_available_tool_sources(resolved_integrations)
assert "mysql" in sources
assert sources["mysql"]["host"] == "localhost"
assert sources["mysql"]["database"] == "application_db"
def test_mysql_tool_source_uses_configured_database(self):
"""MySQL tool params come from the resolved integration config."""
resolved_integrations = {
"mysql": {
"host": "localhost",
"port": 3306,
"database": "default_db",
"username": "root",
"password": "test123",
"ssl_mode": "preferred",
}
}
sources = resolve_available_tool_sources(resolved_integrations)
assert "mysql" in sources
assert sources["mysql"]["database"] == "default_db"
def test_mysql_tool_source_unavailable_if_unconfigured(self):
"""MySQL source is not included if not configured."""
resolved_integrations = {}
sources = resolve_available_tool_sources(resolved_integrations)
assert "mysql" not in sources
class TestMySQLVerification:
"""Test MySQL integration verification flow."""
@patch("integrations.mysql._get_connection")
def test_verify_mysql_success(self, mock_get_connection, monkeypatch):
"""MySQL verification succeeds with valid config."""
monkeypatch.setenv("MYSQL_HOST", "localhost")
monkeypatch.setenv("MYSQL_DATABASE", "testdb")
mock_conn = MagicMock()
mock_cursor = MagicMock()
mock_cursor.__enter__ = MagicMock(return_value=mock_cursor)
mock_cursor.__exit__ = MagicMock(return_value=False)
mock_conn.cursor.return_value = mock_cursor
mock_cursor.fetchone.return_value = {"VERSION()": "8.0.32"}
mock_get_connection.return_value = mock_conn
results = verify_integrations(service="mysql")
assert len(results) >= 1
mysql_result = next((r for r in results if r["service"] == "mysql"), None)
assert mysql_result is not None
assert mysql_result["status"] == "passed"
mock_get_connection.assert_called_once()
@patch("integrations.mysql._get_connection")
def test_verify_integrations_structure(self, mock_get_connection, monkeypatch):
"""Verify integrations returns a list with expected result fields."""
monkeypatch.setenv("MYSQL_HOST", "localhost")
monkeypatch.setenv("MYSQL_DATABASE", "testdb")
mock_conn = MagicMock()
mock_cursor = MagicMock()
mock_cursor.__enter__ = MagicMock(return_value=mock_cursor)
mock_cursor.__exit__ = MagicMock(return_value=False)
mock_conn.cursor.return_value = mock_cursor
mock_cursor.fetchone.return_value = {"VERSION()": "8.0.32"}
mock_get_connection.return_value = mock_conn
results = verify_integrations(service="mysql")
assert isinstance(results, list)
for result in results:
if result["service"] == "mysql":
assert "status" in result
assert "detail" in result
assert result["status"] in ("passed", "missing", "failed")
class TestMySQLToolsAvailability:
"""Test MySQL tools are available and configured."""
def test_mysql_tools_exist_as_modules(self):
"""MySQL tools modules exist and are properly structured."""
try:
import integrations.mysql.tools.mysql_current_processes_tool as MySQLCurrentProcessesTool
import integrations.mysql.tools.mysql_replication_status_tool as MySQLReplicationStatusTool
import integrations.mysql.tools.mysql_server_status_tool as MySQLServerStatusTool
import integrations.mysql.tools.mysql_slow_queries_tool as MySQLSlowQueriesTool
import integrations.mysql.tools.mysql_table_stats_tool as MySQLTableStatsTool
assert MySQLServerStatusTool is not None
assert MySQLCurrentProcessesTool is not None
assert MySQLReplicationStatusTool is not None
assert MySQLSlowQueriesTool is not None
assert MySQLTableStatsTool is not None
except ImportError as e:
pytest.fail(f"Failed to import MySQL tool modules: {e}")
class TestMySQLAlertFixture:
"""Test the MySQL alert fixture is valid and parseable."""
def test_mysql_alert_fixture_is_valid_json(self):
"""MySQL alert fixture is valid JSON."""
fixture_path = Path(__file__).parent / "mysql_alert.json"
assert fixture_path.exists(), f"Alert fixture not found at {fixture_path}"
with fixture_path.open() as f:
alert = json.load(f)
assert isinstance(alert, dict)
assert "state" in alert
assert "commonLabels" in alert
assert "commonAnnotations" in alert
def test_mysql_alert_fixture_has_mysql_context(self):
"""MySQL alert fixture contains MySQL-specific context."""
fixture_path = Path(__file__).parent / "mysql_alert.json"
with fixture_path.open() as f:
alert = json.load(f)
labels = alert.get("commonLabels", {})
annotations = alert.get("commonAnnotations", {})
assert "mysql_instance" in labels
assert "mysql_database" in annotations
assert "mysql_table" in annotations
class TestMySQLIntegrationConfig:
"""Test MySQLIntegrationConfig model from integrations.config_models."""
def test_mysql_integration_config_has_required_fields(self):
"""MySQL integration provides required fields in resolved config."""
from integrations.config_models import MySQLIntegrationConfig
config = MySQLIntegrationConfig(
host="localhost",
port=3306,
database="test_db",
username="root",
password="test123",
ssl_mode="preferred",
integration_id="test-id",
)
assert config.host == "localhost"
assert config.port == 3306
assert config.database == "test_db"
assert config.username == "root"
assert config.password == "test123"
assert config.ssl_mode == "preferred"
assert config.integration_id == "test-id"