feat: complete Git Repo Manager MVP implementation
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>
This commit is contained in:
251
tests/test_schemas.py
Normal file
251
tests/test_schemas.py
Normal file
@@ -0,0 +1,251 @@
|
||||
"""
|
||||
Tests for all Pydantic schemas.
|
||||
"""
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from app.schemas.common import SuccessResponse, ErrorResponse
|
||||
from app.schemas.ssh_key import SshKeyCreate, SshKeyResponse
|
||||
from app.schemas.server import ServerCreate, ServerUpdate, ServerResponse
|
||||
from app.schemas.repo import RepoResponse, CommitInfo
|
||||
from app.schemas.sync_log import SyncLogResponse
|
||||
|
||||
|
||||
class TestCommonSchemas:
|
||||
"""Test common response schemas."""
|
||||
|
||||
def test_success_response_with_data(self):
|
||||
"""Test SuccessResponse with data."""
|
||||
response = SuccessResponse(code=0, data={"id": 1}, message="success")
|
||||
assert response.code == 0
|
||||
assert response.data == {"id": 1}
|
||||
assert response.message == "success"
|
||||
|
||||
def test_success_response_default_values(self):
|
||||
"""Test SuccessResponse with default values."""
|
||||
response = SuccessResponse(data={"test": "value"})
|
||||
assert response.code == 0
|
||||
assert response.message == "success"
|
||||
|
||||
def test_error_response(self):
|
||||
"""Test ErrorResponse."""
|
||||
response = ErrorResponse(code=404, message="Not found")
|
||||
assert response.code == 404
|
||||
assert response.message == "Not found"
|
||||
assert response.data is None
|
||||
|
||||
def test_error_response_with_data(self):
|
||||
"""Test ErrorResponse with additional data."""
|
||||
response = ErrorResponse(
|
||||
code=400,
|
||||
message="Validation error",
|
||||
data={"field": "name", "error": "required"}
|
||||
)
|
||||
assert response.code == 400
|
||||
assert response.data == {"field": "name", "error": "required"}
|
||||
|
||||
|
||||
class TestSshKeySchemas:
|
||||
"""Test SSH key schemas."""
|
||||
|
||||
def test_ssh_key_create_valid(self):
|
||||
"""Test SshKeyCreate with valid data."""
|
||||
key = SshKeyCreate(
|
||||
name="test-key",
|
||||
private_key="-----BEGIN OPENSSH PRIVATE KEY-----\ntest\ntest\n-----END OPENSSH PRIVATE KEY-----"
|
||||
)
|
||||
assert key.name == "test-key"
|
||||
assert "private_key" in key.model_dump()
|
||||
|
||||
def test_ssh_key_create_empty_name_fails(self):
|
||||
"""Test SshKeyCreate fails with empty name."""
|
||||
with pytest.raises(ValueError):
|
||||
SshKeyCreate(
|
||||
name=" ",
|
||||
private_key="some-key"
|
||||
)
|
||||
|
||||
def test_ssh_key_create_empty_private_key_fails(self):
|
||||
"""Test SshKeyCreate fails with empty private_key."""
|
||||
with pytest.raises(ValueError):
|
||||
SshKeyCreate(
|
||||
name="test-key",
|
||||
private_key=""
|
||||
)
|
||||
|
||||
def test_ssh_key_response(self):
|
||||
"""Test SshKeyResponse."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
response = SshKeyResponse(
|
||||
id=1,
|
||||
name="test-key",
|
||||
fingerprint="SHA256:abc123",
|
||||
created_at=timestamp
|
||||
)
|
||||
assert response.id == 1
|
||||
assert response.name == "test-key"
|
||||
assert response.fingerprint == "SHA256:abc123"
|
||||
assert response.created_at == timestamp
|
||||
|
||||
|
||||
class TestServerSchemas:
|
||||
"""Test server schemas."""
|
||||
|
||||
def test_server_create_valid(self):
|
||||
"""Test ServerCreate with valid data."""
|
||||
server = ServerCreate(
|
||||
name="test-server",
|
||||
url="https://gitea.example.com",
|
||||
api_token="test-token",
|
||||
ssh_key_id=1,
|
||||
local_path="/data/test"
|
||||
)
|
||||
assert server.name == "test-server"
|
||||
assert server.sync_enabled is False
|
||||
assert server.schedule_cron is None
|
||||
|
||||
def test_server_create_with_sync(self):
|
||||
"""Test ServerCreate with sync enabled."""
|
||||
server = ServerCreate(
|
||||
name="test-server",
|
||||
url="https://gitea.example.com",
|
||||
api_token="test-token",
|
||||
ssh_key_id=1,
|
||||
local_path="/data/test",
|
||||
sync_enabled=True,
|
||||
schedule_cron="0 */6 * * *"
|
||||
)
|
||||
assert server.sync_enabled is True
|
||||
assert server.schedule_cron == "0 */6 * * *"
|
||||
|
||||
def test_server_create_invalid_ssh_key_id(self):
|
||||
"""Test ServerCreate fails with invalid ssh_key_id."""
|
||||
with pytest.raises(ValueError):
|
||||
ServerCreate(
|
||||
name="test-server",
|
||||
url="https://gitea.example.com",
|
||||
api_token="test-token",
|
||||
ssh_key_id=0, # Must be > 0
|
||||
local_path="/data/test"
|
||||
)
|
||||
|
||||
def test_server_update_partial(self):
|
||||
"""Test ServerUpdate with partial data."""
|
||||
update = ServerUpdate(name="updated-name")
|
||||
assert update.name == "updated-name"
|
||||
assert update.url is None
|
||||
assert update.api_token is None
|
||||
|
||||
def test_server_response(self):
|
||||
"""Test ServerResponse."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
response = ServerResponse(
|
||||
id=1,
|
||||
name="test-server",
|
||||
url="https://gitea.example.com",
|
||||
ssh_key_id=1,
|
||||
sync_enabled=True,
|
||||
schedule_cron="0 */6 * * *",
|
||||
local_path="/data/test",
|
||||
status="success",
|
||||
created_at=timestamp,
|
||||
updated_at=timestamp
|
||||
)
|
||||
assert response.id == 1
|
||||
assert response.status == "success"
|
||||
assert response.sync_enabled is True
|
||||
|
||||
|
||||
class TestRepoSchemas:
|
||||
"""Test repository schemas."""
|
||||
|
||||
def test_commit_info(self):
|
||||
"""Test CommitInfo schema."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
commit = CommitInfo(
|
||||
hash="a1b2c3d4",
|
||||
author="Test Author <test@example.com>",
|
||||
message="Test commit",
|
||||
timestamp=timestamp
|
||||
)
|
||||
assert commit.hash == "a1b2c3d4"
|
||||
assert commit.author == "Test Author <test@example.com>"
|
||||
assert commit.timestamp == timestamp
|
||||
|
||||
def test_repo_response(self):
|
||||
"""Test RepoResponse schema."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
repo = RepoResponse(
|
||||
id=1,
|
||||
server_id=1,
|
||||
name="test-repo",
|
||||
full_name="org/test-repo",
|
||||
clone_url="https://gitea.example.com/org/test-repo.git",
|
||||
local_path="/data/test/org/test-repo",
|
||||
last_sync_at=timestamp,
|
||||
status="success",
|
||||
created_at=timestamp
|
||||
)
|
||||
assert repo.id == 1
|
||||
assert repo.name == "test-repo"
|
||||
assert repo.last_sync_at == timestamp
|
||||
assert repo.status == "success"
|
||||
|
||||
|
||||
class TestSyncLogSchemas:
|
||||
"""Test sync log schemas."""
|
||||
|
||||
def test_sync_log_response_success(self):
|
||||
"""Test SyncLogResponse for successful sync."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
log = SyncLogResponse(
|
||||
id=1,
|
||||
repo_id=1,
|
||||
status="success",
|
||||
started_at=timestamp,
|
||||
finished_at=timestamp + 300,
|
||||
commits_count=5,
|
||||
error_msg=None,
|
||||
created_at=timestamp
|
||||
)
|
||||
assert log.id == 1
|
||||
assert log.status == "success"
|
||||
assert log.commits_count == 5
|
||||
assert log.error_msg is None
|
||||
|
||||
def test_sync_log_response_error(self):
|
||||
"""Test SyncLogResponse for failed sync."""
|
||||
timestamp = int(datetime.utcnow().timestamp())
|
||||
log = SyncLogResponse(
|
||||
id=2,
|
||||
repo_id=1,
|
||||
status="error",
|
||||
started_at=timestamp,
|
||||
finished_at=timestamp + 60,
|
||||
commits_count=None,
|
||||
error_msg="Connection timeout",
|
||||
created_at=timestamp
|
||||
)
|
||||
assert log.status == "error"
|
||||
assert log.commits_count is None
|
||||
assert log.error_msg == "Connection timeout"
|
||||
|
||||
|
||||
class TestSchemaExports:
|
||||
"""Test that all schemas are properly exported."""
|
||||
|
||||
def test_all_schemas_importable(self):
|
||||
"""Test that all schemas can be imported from app.schemas."""
|
||||
from app.schemas import (
|
||||
SuccessResponse,
|
||||
ErrorResponse,
|
||||
SshKeyCreate,
|
||||
SshKeyResponse,
|
||||
ServerCreate,
|
||||
ServerUpdate,
|
||||
ServerResponse,
|
||||
RepoResponse,
|
||||
CommitInfo,
|
||||
SyncLogResponse
|
||||
)
|
||||
# If we got here, all imports succeeded
|
||||
assert True
|
||||
Reference in New Issue
Block a user