import sys from unittest.mock import patch, AsyncMock, MagicMock from httpx import AsyncClient from tests.conftest import auth_header def _make_aiomysql_mock(): aiomysql = MagicMock() aiomysql.connect = AsyncMock() aiomysql.DictCursor = MagicMock() return aiomysql class TestExecuteQuery: async def test_select_query(self, client: AsyncClient, test_instance, admin_token): from contextlib import asynccontextmanager mock_cursor = AsyncMock() mock_cursor.description = [("id",), ("name",)] mock_cursor.fetchall.return_value = [{"id": 1, "name": "test"}] mock_cursor.execute = AsyncMock() @asynccontextmanager async def mock_cursor_ctx(*args, **kwargs): yield mock_cursor mock_conn = AsyncMock() mock_conn.cursor = mock_cursor_ctx mock_conn.close = MagicMock() mock_aiomysql = _make_aiomysql_mock() mock_aiomysql.connect = AsyncMock(return_value=mock_conn) mock_aiomysql.DictCursor = MagicMock() with patch.dict(sys.modules, {"aiomysql": mock_aiomysql}): resp = await client.post("/api/v1/query", headers=auth_header(admin_token), json={ "instance_id": test_instance.id, "database": "test_db", "sql": "SELECT * FROM users LIMIT 10", }) assert resp.status_code == 200 data = resp.json() assert "columns" in data assert "rows" in data async def test_drop_rejected(self, client: AsyncClient, test_instance, admin_token): resp = await client.post("/api/v1/query", headers=auth_header(admin_token), json={ "instance_id": test_instance.id, "database": "test_db", "sql": "DROP TABLE users", }) assert resp.status_code == 400 async def test_delete_rejected(self, client: AsyncClient, test_instance, admin_token): resp = await client.post("/api/v1/query", headers=auth_header(admin_token), json={ "instance_id": test_instance.id, "database": "test_db", "sql": "DELETE FROM users WHERE 1=1", }) assert resp.status_code == 400 async def test_guest_cannot_query(self, client: AsyncClient, test_instance, guest_token): resp = await client.post("/api/v1/query", headers=auth_header(guest_token), json={ "instance_id": test_instance.id, "database": "test_db", "sql": "SELECT 1", }) assert resp.status_code == 403