letsbe-hub/tests/test_admin.py

234 lines
6.6 KiB
Python

"""Tests for admin endpoints."""
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_create_client(client: AsyncClient, admin_headers: dict):
"""Test creating a new client."""
response = await client.post(
"/api/v1/admin/clients",
json={
"name": "Acme Corp",
"contact_email": "admin@acme.com",
"billing_plan": "pro",
},
headers=admin_headers,
)
assert response.status_code == 201
data = response.json()
assert data["name"] == "Acme Corp"
assert data["contact_email"] == "admin@acme.com"
assert data["billing_plan"] == "pro"
assert data["status"] == "active"
assert "id" in data
@pytest.mark.asyncio
async def test_create_client_unauthorized(client: AsyncClient):
"""Test creating client without auth fails."""
response = await client.post(
"/api/v1/admin/clients",
json={"name": "Test Corp"},
)
assert response.status_code == 422 # Missing header
@pytest.mark.asyncio
async def test_create_client_invalid_key(client: AsyncClient):
"""Test creating client with invalid key fails."""
response = await client.post(
"/api/v1/admin/clients",
json={"name": "Test Corp"},
headers={"X-Admin-Api-Key": "invalid-key"},
)
assert response.status_code == 401
@pytest.mark.asyncio
async def test_list_clients(client: AsyncClient, admin_headers: dict):
"""Test listing clients."""
# Create a client first
await client.post(
"/api/v1/admin/clients",
json={"name": "Test Corp 1"},
headers=admin_headers,
)
await client.post(
"/api/v1/admin/clients",
json={"name": "Test Corp 2"},
headers=admin_headers,
)
response = await client.get(
"/api/v1/admin/clients",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert len(data) >= 2
@pytest.mark.asyncio
async def test_create_instance(client: AsyncClient, admin_headers: dict):
"""Test creating an instance for a client."""
# Create client first
client_response = await client.post(
"/api/v1/admin/clients",
json={"name": "Instance Test Corp"},
headers=admin_headers,
)
client_id = client_response.json()["id"]
# Create instance
response = await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={
"instance_id": "test-orchestrator",
"region": "eu-west-1",
},
headers=admin_headers,
)
assert response.status_code == 201
data = response.json()
assert data["instance_id"] == "test-orchestrator"
assert data["region"] == "eu-west-1"
assert data["license_status"] == "active"
assert data["status"] == "pending"
# Keys should be returned on creation
assert "license_key" in data
assert data["license_key"].startswith("lb_inst_")
assert "hub_api_key" in data
assert data["hub_api_key"].startswith("hk_")
@pytest.mark.asyncio
async def test_create_duplicate_instance(client: AsyncClient, admin_headers: dict):
"""Test that duplicate instance_id fails."""
# Create client
client_response = await client.post(
"/api/v1/admin/clients",
json={"name": "Duplicate Test Corp"},
headers=admin_headers,
)
client_id = client_response.json()["id"]
# Create first instance
await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={"instance_id": "duplicate-test"},
headers=admin_headers,
)
# Try to create duplicate
response = await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={"instance_id": "duplicate-test"},
headers=admin_headers,
)
assert response.status_code == 409
@pytest.mark.asyncio
async def test_rotate_license_key(client: AsyncClient, admin_headers: dict):
"""Test rotating a license key."""
# Create client and instance
client_response = await client.post(
"/api/v1/admin/clients",
json={"name": "Rotate Test Corp"},
headers=admin_headers,
)
client_id = client_response.json()["id"]
instance_response = await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={"instance_id": "rotate-test"},
headers=admin_headers,
)
original_key = instance_response.json()["license_key"]
# Rotate license
response = await client.post(
"/api/v1/admin/instances/rotate-test/rotate-license",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert data["license_key"].startswith("lb_inst_")
assert data["license_key"] != original_key
@pytest.mark.asyncio
async def test_suspend_instance(client: AsyncClient, admin_headers: dict):
"""Test suspending an instance."""
# Create client and instance
client_response = await client.post(
"/api/v1/admin/clients",
json={"name": "Suspend Test Corp"},
headers=admin_headers,
)
client_id = client_response.json()["id"]
await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={"instance_id": "suspend-test"},
headers=admin_headers,
)
# Suspend
response = await client.post(
"/api/v1/admin/instances/suspend-test/suspend",
headers=admin_headers,
)
assert response.status_code == 200
assert response.json()["status"] == "suspended"
# Verify status
get_response = await client.get(
"/api/v1/admin/instances/suspend-test",
headers=admin_headers,
)
assert get_response.json()["license_status"] == "suspended"
@pytest.mark.asyncio
async def test_reactivate_instance(client: AsyncClient, admin_headers: dict):
"""Test reactivating a suspended instance."""
# Create client and instance
client_response = await client.post(
"/api/v1/admin/clients",
json={"name": "Reactivate Test Corp"},
headers=admin_headers,
)
client_id = client_response.json()["id"]
await client.post(
f"/api/v1/admin/clients/{client_id}/instances",
json={"instance_id": "reactivate-test"},
headers=admin_headers,
)
# Suspend
await client.post(
"/api/v1/admin/instances/reactivate-test/suspend",
headers=admin_headers,
)
# Reactivate
response = await client.post(
"/api/v1/admin/instances/reactivate-test/reactivate",
headers=admin_headers,
)
assert response.status_code == 200
assert response.json()["status"] == "pending" # Not activated yet