Initial commit: KPI Management System Backend

Features:
- FastAPI backend with JWT authentication
- MySQL database with SQLAlchemy ORM
- KPI workflow: draft → pending → approved → evaluation → completed
- Ollama LLM API integration for AI features
- Gitea API integration for version control
- Complete API endpoints for KPI, dashboard, notifications

Tables: KPI_D_* prefix naming convention

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-11 16:20:57 +08:00
commit f810ddc2ea
48 changed files with 4950 additions and 0 deletions

97
tests/test_auth.py Normal file
View File

@@ -0,0 +1,97 @@
"""
認證 API 測試
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from app.core.security import get_password_hash
from tests.factories import EmployeeFactory
class TestAuthAPI:
"""認證 API 測試"""
def test_login_success(self, client: TestClient, db: Session):
"""測試:登入成功"""
# Arrange
employee = EmployeeFactory.create(db)
# Act
response = client.post(
"/api/auth/login",
json={
"employee_no": employee.employee_no,
"password": "password123",
},
)
# Assert
assert response.status_code == 200
data = response.json()
assert "access_token" in data
assert "refresh_token" in data
assert data["token_type"] == "bearer"
def test_login_wrong_password(self, client: TestClient, db: Session):
"""測試:密碼錯誤"""
# Arrange
employee = EmployeeFactory.create(db)
# Act
response = client.post(
"/api/auth/login",
json={
"employee_no": employee.employee_no,
"password": "wrong_password",
},
)
# Assert
assert response.status_code == 401
def test_login_user_not_found(self, client: TestClient):
"""測試:使用者不存在"""
response = client.post(
"/api/auth/login",
json={
"employee_no": "NOTEXIST",
"password": "password123",
},
)
assert response.status_code == 401
def test_login_inactive_user(self, client: TestClient, db: Session):
"""測試:帳號停用"""
# Arrange
employee = EmployeeFactory.create(db, status="inactive")
# Act
response = client.post(
"/api/auth/login",
json={
"employee_no": employee.employee_no,
"password": "password123",
},
)
# Assert
assert response.status_code == 401
def test_get_me_success(
self, client: TestClient, auth_headers: dict, test_employee
):
"""測試:取得當前使用者"""
response = client.get("/api/auth/me", headers=auth_headers)
assert response.status_code == 200
data = response.json()
assert data["id"] == test_employee.id
assert data["employee_no"] == test_employee.employee_no
def test_get_me_unauthorized(self, client: TestClient):
"""測試:未認證"""
response = client.get("/api/auth/me")
assert response.status_code == 403