Add 3 new Coolify plugin handlers (37 new tools, 67 total): - projects.py: 8 tools (CRUD projects + environments) - databases.py: 16 tools (CRUD, lifecycle, 6 DB types, backups) - services.py: 13 tools (CRUD, lifecycle, env vars) 734 tests passing. Total platform tools: 633. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
238 lines
8.4 KiB
Python
238 lines
8.4 KiB
Python
"""
|
|
Tests for Coolify Databases Handler
|
|
|
|
Unit tests with mocked HTTP responses.
|
|
"""
|
|
|
|
import json
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from plugins.coolify.client import CoolifyClient
|
|
from plugins.coolify.handlers import databases
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
"""Create a CoolifyClient instance for testing."""
|
|
return CoolifyClient(site_url="https://coolify.test.com", token="test-token-123")
|
|
|
|
|
|
class TestDatabaseToolSpecs:
|
|
"""Tests for database tool specifications."""
|
|
|
|
def test_database_tool_count(self):
|
|
"""Test database tool specification count."""
|
|
specs = databases.get_tool_specifications()
|
|
assert len(specs) == 16
|
|
|
|
def test_tool_specs_have_required_fields(self):
|
|
"""Test all specs have required fields."""
|
|
for spec in databases.get_tool_specifications():
|
|
assert "name" in spec
|
|
assert "method_name" in spec
|
|
assert "description" in spec
|
|
assert "schema" in spec
|
|
assert "scope" in spec
|
|
assert spec["scope"] in ("read", "write", "admin")
|
|
|
|
def test_tool_names_unique(self):
|
|
"""Test that all tool names are unique."""
|
|
specs = databases.get_tool_specifications()
|
|
names = [s["name"] for s in specs]
|
|
assert len(names) == len(set(names))
|
|
|
|
def test_all_db_types_present(self):
|
|
"""Test all 6 database creation tools exist."""
|
|
specs = databases.get_tool_specifications()
|
|
names = [s["name"] for s in specs]
|
|
for db_type in ["postgresql", "mysql", "mariadb", "mongodb", "redis", "clickhouse"]:
|
|
assert f"create_{db_type}" in names
|
|
|
|
def test_scope_distribution(self):
|
|
"""Test correct scope assignments."""
|
|
specs = databases.get_tool_specifications()
|
|
by_scope = {}
|
|
for s in specs:
|
|
by_scope.setdefault(s["scope"], []).append(s["name"])
|
|
assert "list_databases" in by_scope["read"]
|
|
assert "delete_database" in by_scope["admin"]
|
|
assert "start_database" in by_scope["write"]
|
|
|
|
|
|
class TestDatabaseHandlers:
|
|
"""Tests for database handler functions."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_databases(self, client):
|
|
"""Test list_databases handler."""
|
|
mock_dbs = [
|
|
{"uuid": "db-1", "name": "postgres-main", "type": "postgresql", "status": "running"},
|
|
{"uuid": "db-2", "name": "redis-cache", "type": "redis", "status": "running"},
|
|
]
|
|
client.list_databases = AsyncMock(return_value=mock_dbs)
|
|
|
|
result = await databases.list_databases(client)
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert data["count"] == 2
|
|
client.list_databases.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_database(self, client):
|
|
"""Test get_database handler."""
|
|
mock_db = {"uuid": "db-1", "name": "postgres-main", "type": "postgresql"}
|
|
client.get_database = AsyncMock(return_value=mock_db)
|
|
|
|
result = await databases.get_database(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert data["database"]["name"] == "postgres-main"
|
|
client.get_database.assert_called_once_with("db-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_database(self, client):
|
|
"""Test update_database handler."""
|
|
mock_response = {"uuid": "db-1"}
|
|
client.update_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.update_database(client, uuid="db-1", name="renamed-db")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert "updated" in data["message"].lower()
|
|
client.update_database.assert_called_once_with("db-1", {"name": "renamed-db"})
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_database(self, client):
|
|
"""Test delete_database handler."""
|
|
mock_response = {"message": "Database deleted."}
|
|
client.delete_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.delete_database(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert "deleted" in data["message"].lower()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_start_database(self, client):
|
|
"""Test start_database handler."""
|
|
mock_response = {"message": "Starting."}
|
|
client.start_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.start_database(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
client.start_database.assert_called_once_with("db-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_stop_database(self, client):
|
|
"""Test stop_database handler."""
|
|
mock_response = {"message": "Stopping."}
|
|
client.stop_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.stop_database(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
client.stop_database.assert_called_once_with("db-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_restart_database(self, client):
|
|
"""Test restart_database handler."""
|
|
mock_response = {"message": "Restarting."}
|
|
client.restart_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.restart_database(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
client.restart_database.assert_called_once_with("db-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_postgresql(self, client):
|
|
"""Test create_postgresql handler."""
|
|
mock_response = {"uuid": "db-new", "type": "postgresql"}
|
|
client.create_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.create_postgresql(
|
|
client,
|
|
project_uuid="proj-1",
|
|
server_uuid="srv-1",
|
|
environment_name="production",
|
|
)
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert "postgresql" in data["message"].lower()
|
|
client.create_database.assert_called_once_with(
|
|
"postgresql",
|
|
{
|
|
"project_uuid": "proj-1",
|
|
"server_uuid": "srv-1",
|
|
"environment_name": "production",
|
|
},
|
|
)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_redis(self, client):
|
|
"""Test create_redis handler."""
|
|
mock_response = {"uuid": "db-new", "type": "redis"}
|
|
client.create_database = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.create_redis(
|
|
client,
|
|
project_uuid="proj-1",
|
|
server_uuid="srv-1",
|
|
environment_name="production",
|
|
name="my-cache",
|
|
)
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert "redis" in data["message"].lower()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_database_backups(self, client):
|
|
"""Test get_database_backups handler."""
|
|
mock_backups = {"enabled": True, "frequency": "0 0 * * *", "backups": []}
|
|
client.get_database_backups = AsyncMock(return_value=mock_backups)
|
|
|
|
result = await databases.get_database_backups(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
client.get_database_backups.assert_called_once_with("db-1")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_database_backup(self, client):
|
|
"""Test create_database_backup handler."""
|
|
mock_response = {"message": "Backup started."}
|
|
client.create_database_backup = AsyncMock(return_value=mock_response)
|
|
|
|
result = await databases.create_database_backup(client, uuid="db-1")
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert "backup" in data["message"].lower()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_backup_executions(self, client):
|
|
"""Test list_backup_executions handler."""
|
|
mock_executions = [
|
|
{"id": 1, "database_uuid": "db-1", "status": "success"},
|
|
{"id": 2, "database_uuid": "db-1", "status": "failed"},
|
|
]
|
|
client.list_backup_executions = AsyncMock(return_value=mock_executions)
|
|
|
|
result = await databases.list_backup_executions(client)
|
|
data = json.loads(result)
|
|
|
|
assert data["success"] is True
|
|
assert data["count"] == 2
|