Backend (Phase 1-6): - Pydantic schemas for request/response validation - Service layer (SSH Key, Server, Repo, Sync) - API routes with authentication - FastAPI main application with lifespan management - ORM models (SshKey, Server, Repo, SyncLog) Frontend (Phase 7): - Vue 3 + Element Plus + Pinia + Vue Router - API client with Axios and interceptors - State management stores - All page components (Dashboard, Servers, Repos, SyncLogs, SshKeys, Settings) Deployment (Phase 8): - README with quick start guide - Startup script (start.sh) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
152 lines
5.3 KiB
Python
152 lines
5.3 KiB
Python
"""
|
|
Tests for Status API routes.
|
|
|
|
Tests the following endpoints:
|
|
- GET /api/status
|
|
- GET /api/status/health
|
|
"""
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
VALID_SSH_KEY = """-----BEGIN OPENSSH PRIVATE KEY-----
|
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
|
QyNTUxOQAAACB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQAAAJC9AVH1vQFR
|
|
AAAAAtzc2gtZWQyNTUxOQAAACB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQA
|
|
AAECB5WfkA8wgP/KvdGFNC1ZCbBmjZnKpM/LOXRDJS7NfRAQAAAHHZpXRvaXRvQVJNVjJH
|
|
AAAAFGZpbGVzeXN0ZW0uY2ZnAAAAAQAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
AAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAEAAAAEWNvbW1lbnQ6IHRlc3Qga2V5AQIDBAUHBg=="""
|
|
|
|
|
|
class TestGetStatus:
|
|
"""Tests for GET /api/status endpoint."""
|
|
|
|
def test_get_status_unauthenticated(self, client: TestClient):
|
|
"""Test getting status without authentication."""
|
|
response = client.get("/api/status")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["code"] == 0
|
|
assert data["message"] == "System status retrieved successfully"
|
|
assert data["data"]["status"] == "healthy"
|
|
assert data["data"]["version"] == "1.0.0"
|
|
assert data["data"]["authenticated"] is False
|
|
assert "database" in data["data"]
|
|
assert data["data"]["database"]["status"] == "connected"
|
|
# Storage paths should not be included for unauthenticated
|
|
assert "storage" not in data["data"]
|
|
|
|
def test_get_status_authenticated(self, client: TestClient):
|
|
"""Test getting status with authentication."""
|
|
response = client.get(
|
|
"/api/status",
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["code"] == 0
|
|
assert data["data"]["authenticated"] is True
|
|
assert "storage" in data["data"]
|
|
assert "data_dir" in data["data"]["storage"]
|
|
assert "repos_dir" in data["data"]["storage"]
|
|
assert "ssh_keys_dir" in data["data"]["storage"]
|
|
assert "db_path" in data["data"]["storage"]
|
|
|
|
def test_get_status_with_data(self, client: TestClient):
|
|
"""Test getting status when data exists."""
|
|
# Create an SSH key
|
|
client.post(
|
|
"/api/ssh-keys",
|
|
json={"name": "test-key", "private_key": VALID_SSH_KEY},
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
# Get status
|
|
response = client.get(
|
|
"/api/status",
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["data"]["database"]["ssh_keys_count"] == 1
|
|
assert data["data"]["database"]["servers_count"] == 0
|
|
assert data["data"]["database"]["repos_count"] == 0
|
|
|
|
def test_get_status_database_counts(self, client: TestClient):
|
|
"""Test database counts in status are accurate."""
|
|
# Create multiple items
|
|
client.post(
|
|
"/api/ssh-keys",
|
|
json={"name": "key-1", "private_key": VALID_SSH_KEY},
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
client.post(
|
|
"/api/ssh-keys",
|
|
json={"name": "key-2", "private_key": VALID_SSH_KEY},
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
# Create a server
|
|
ssh_response = client.post(
|
|
"/api/ssh-keys",
|
|
json={"name": "server-key", "private_key": VALID_SSH_KEY},
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
ssh_key_id = ssh_response.json()["data"]["id"]
|
|
|
|
client.post(
|
|
"/api/servers",
|
|
json={
|
|
"name": "test-server",
|
|
"url": "https://gitea.example.com",
|
|
"api_token": "test-token",
|
|
"ssh_key_id": ssh_key_id
|
|
},
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
# Get status
|
|
response = client.get(
|
|
"/api/status",
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["data"]["database"]["ssh_keys_count"] == 3
|
|
assert data["data"]["database"]["servers_count"] == 1
|
|
|
|
|
|
class TestHealthCheck:
|
|
"""Tests for GET /api/status/health endpoint."""
|
|
|
|
def test_health_check(self, client: TestClient):
|
|
"""Test the health check endpoint."""
|
|
response = client.get("/api/status/health")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["code"] == 0
|
|
assert data["data"]["status"] == "ok"
|
|
assert data["message"] == "Service is healthy"
|
|
|
|
def test_health_check_no_auth_required(self, client: TestClient):
|
|
"""Test health check works without authentication."""
|
|
response = client.get("/api/status/health")
|
|
|
|
assert response.status_code == 200
|
|
|
|
def test_health_check_with_auth(self, client: TestClient):
|
|
"""Test health check works with authentication."""
|
|
response = client.get(
|
|
"/api/status/health",
|
|
headers={"Authorization": "Bearer test-token"}
|
|
)
|
|
|
|
assert response.status_code == 200
|