feat: Implement project management with new models, repositories, and API endpoints, and enhance character management with project association and DTOs.

This commit is contained in:
xds
2026-02-09 16:06:54 +03:00
parent 668aadcdc9
commit 458b6ebfc3
42 changed files with 728 additions and 60 deletions

View File

@@ -0,0 +1,101 @@
import pytest
from fastapi.testclient import TestClient
from unittest.mock import MagicMock
from motor.motor_asyncio import AsyncIOMotorClient
import os
import asyncio
from main import app
from api.endpoints.auth import get_current_user
from api.dependency import get_dao
from repos.dao import DAO
from models.Character import Character
# Config for test DB
MONGO_HOST = os.getenv("MONGO_HOST", "mongodb://admin:super_secure_password@31.59.58.220:27017")
DB_NAME = "bot_db_test_chars"
# Mock User
MOCK_USER_ID = "507f1f77bcf86cd799439011"
MOCK_USER = {
"_id": MOCK_USER_ID,
"username": "testuser",
"is_admin": False,
"status": "allowed"
}
# Override get_current_user to bypass auth
def mock_get_current_user():
return MOCK_USER
app.dependency_overrides[get_current_user] = mock_get_current_user
# Setup Real DAO with Test DB
client_mongo = AsyncIOMotorClient(MONGO_HOST)
dao = DAO(client_mongo, db_name=DB_NAME)
def mock_get_dao():
return dao
app.dependency_overrides[get_dao] = mock_get_dao
client = TestClient(app)
@pytest.fixture(scope="module", autouse=True)
def setup_teardown():
# Setup: Ensure clean state
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(client_mongo[DB_NAME]["characters"].drop())
yield
# Teardown
loop.run_until_complete(client_mongo[DB_NAME]["characters"].drop())
loop.close()
def test_character_crud_flow():
# 1. Create Character
create_payload = {
"name": "Test Character",
"character_bio": "A bio for test character",
"character_image_doc_tg_id": "file_123",
"avatar_image": "http://example.com/avatar.jpg"
}
response = client.post("/api/characters/", json=create_payload)
assert response.status_code == 200, response.text
char_data = response.json()
assert char_data["name"] == create_payload["name"]
assert char_data["created_by"] == MOCK_USER_ID
char_id = char_data["id"]
assert char_id is not None
# 2. Get Character
response = client.get(f"/api/characters/{char_id}")
assert response.status_code == 200
assert response.json()["id"] == char_id
# 3. Update Character
update_payload = {
"name": "Updated Name",
"character_bio": "Updated bio"
}
response = client.put(f"/api/characters/{char_id}", json=update_payload)
assert response.status_code == 200
updated_data = response.json()
assert updated_data["name"] == "Updated Name"
assert updated_data["character_bio"] == "Updated bio"
# Verify update persistent
response = client.get(f"/api/characters/{char_id}")
assert response.json()["name"] == "Updated Name"
# 4. Delete Character
response = client.delete(f"/api/characters/{char_id}")
assert response.status_code == 204
# Verify deletion
response = client.get(f"/api/characters/{char_id}")
assert response.status_code == 404, "Deleted character should return 404"

View File

@@ -0,0 +1,64 @@
import os
import pytest
from fastapi.testclient import TestClient
from unittest.mock import MagicMock
# 1. Set Auth Bypass and Test Config
os.environ["DB_NAME"] = "bot_db_test_integration"
# We keep MONGO_HOST as is (it works in verified script)
# 2. Import app AFTER setting env
from main import app
from api.endpoints.auth import get_current_user
# 3. Override Auth
MOCK_USER_ID = "507f1f77bcf86cd799439011"
MOCK_USER = {
"_id": MOCK_USER_ID,
"username": "testuser",
"is_admin": False,
"status": "allowed",
"project_ids": []
}
def mock_get_current_user():
return MOCK_USER
app.dependency_overrides[get_current_user] = mock_get_current_user
client = TestClient(app)
def test_character_crud_lifecycle():
# 1. Create
create_payload = {
"name": "Integration Test Char",
"character_bio": "Testing with real app structure",
"character_image_doc_tg_id": "doc_123",
"avatar_image": "http://example.com/img.jpg"
}
response = client.post("/api/characters/", json=create_payload)
assert response.status_code == 200, response.text
char_data = response.json()
assert char_data["name"] == create_payload["name"]
char_id = char_data["id"]
# 2. Get
response = client.get(f"/api/characters/{char_id}")
assert response.status_code == 200
assert response.json()["id"] == char_id
# 3. Update
update_payload = {"name": "Updated Int Name"}
response = client.put(f"/api/characters/{char_id}", json=update_payload)
assert response.status_code == 200
assert response.json()["name"] == "Updated Int Name"
# 4. Delete
response = client.delete(f"/api/characters/{char_id}")
assert response.status_code == 204
# 5. Verify Delete
response = client.get(f"/api/characters/{char_id}")
assert response.status_code == 404