227 lines
6.6 KiB
Python
227 lines
6.6 KiB
Python
"""
|
|
Tests for API_Service task management endpoints.
|
|
"""
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from httpx import AsyncClient
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from shared.models import User, Account, Task
|
|
from auth_service.app.utils.security import create_access_token
|
|
from shared.crypto import encrypt_cookie, derive_key
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def test_user(db_session: AsyncSession) -> User:
|
|
"""Create a test user."""
|
|
user = User(
|
|
username="testuser",
|
|
email="test@example.com",
|
|
hashed_password="hashed_password",
|
|
)
|
|
db_session.add(user)
|
|
await db_session.commit()
|
|
await db_session.refresh(user)
|
|
return user
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def test_account(db_session: AsyncSession, test_user: User) -> Account:
|
|
"""Create a test account."""
|
|
key = derive_key("test-cookie-key")
|
|
ciphertext, iv = encrypt_cookie("test_cookie_data", key)
|
|
|
|
account = Account(
|
|
user_id=test_user.id,
|
|
weibo_user_id="123456",
|
|
remark="Test Account",
|
|
encrypted_cookies=ciphertext,
|
|
iv=iv,
|
|
status="pending",
|
|
)
|
|
db_session.add(account)
|
|
await db_session.commit()
|
|
await db_session.refresh(account)
|
|
return account
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def auth_headers(test_user: User) -> dict:
|
|
"""Generate JWT auth headers for test user."""
|
|
token = create_access_token({"sub": test_user.id})
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_task_valid_cron(
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
test_account: Account,
|
|
auth_headers: dict,
|
|
):
|
|
"""Test creating a task with valid cron expression."""
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.post(
|
|
f"/api/v1/accounts/{test_account.id}/tasks",
|
|
json={"cron_expression": "0 9 * * *"},
|
|
headers=auth_headers,
|
|
)
|
|
|
|
assert response.status_code == 201
|
|
data = response.json()
|
|
assert data["success"] is True
|
|
assert data["data"]["cron_expression"] == "0 9 * * *"
|
|
assert data["data"]["is_enabled"] is True
|
|
assert data["data"]["account_id"] == test_account.id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_create_task_invalid_cron(
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
test_account: Account,
|
|
auth_headers: dict,
|
|
):
|
|
"""Test creating a task with invalid cron expression."""
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.post(
|
|
f"/api/v1/accounts/{test_account.id}/tasks",
|
|
json={"cron_expression": "invalid cron"},
|
|
headers=auth_headers,
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
data = response.json()
|
|
assert data["success"] is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_tasks(
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
test_account: Account,
|
|
auth_headers: dict,
|
|
):
|
|
"""Test listing tasks for an account."""
|
|
# Create two tasks
|
|
task1 = Task(account_id=test_account.id, cron_expression="0 9 * * *", is_enabled=True)
|
|
task2 = Task(account_id=test_account.id, cron_expression="0 18 * * *", is_enabled=False)
|
|
db_session.add_all([task1, task2])
|
|
await db_session.commit()
|
|
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.get(
|
|
f"/api/v1/accounts/{test_account.id}/tasks",
|
|
headers=auth_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["success"] is True
|
|
assert len(data["data"]) == 2
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_task(
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
test_account: Account,
|
|
auth_headers: dict,
|
|
):
|
|
"""Test updating a task (enable/disable)."""
|
|
task = Task(account_id=test_account.id, cron_expression="0 9 * * *", is_enabled=True)
|
|
db_session.add(task)
|
|
await db_session.commit()
|
|
await db_session.refresh(task)
|
|
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.put(
|
|
f"/api/v1/tasks/{task.id}",
|
|
json={"is_enabled": False},
|
|
headers=auth_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["success"] is True
|
|
assert data["data"]["is_enabled"] is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_delete_task(
|
|
db_session: AsyncSession,
|
|
test_user: User,
|
|
test_account: Account,
|
|
auth_headers: dict,
|
|
):
|
|
"""Test deleting a task."""
|
|
task = Task(account_id=test_account.id, cron_expression="0 9 * * *", is_enabled=True)
|
|
db_session.add(task)
|
|
await db_session.commit()
|
|
await db_session.refresh(task)
|
|
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.delete(
|
|
f"/api/v1/tasks/{task.id}",
|
|
headers=auth_headers,
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["success"] is True
|
|
|
|
# Verify task is deleted
|
|
from sqlalchemy import select
|
|
result = await db_session.execute(select(Task).where(Task.id == task.id))
|
|
deleted_task = result.scalar_one_or_none()
|
|
assert deleted_task is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_access_other_user_task_forbidden(
|
|
db_session: AsyncSession,
|
|
test_account: Account,
|
|
):
|
|
"""Test that users cannot access tasks from other users' accounts."""
|
|
# Create another user
|
|
other_user = User(
|
|
username="otheruser",
|
|
email="other@example.com",
|
|
hashed_password="hashed_password",
|
|
)
|
|
db_session.add(other_user)
|
|
await db_session.commit()
|
|
await db_session.refresh(other_user)
|
|
|
|
# Create a task for test_account
|
|
task = Task(account_id=test_account.id, cron_expression="0 9 * * *", is_enabled=True)
|
|
db_session.add(task)
|
|
await db_session.commit()
|
|
await db_session.refresh(task)
|
|
|
|
# Try to access with other_user's token
|
|
other_token = create_access_token({"sub": other_user.id})
|
|
other_headers = {"Authorization": f"Bearer {other_token}"}
|
|
|
|
from api_service.app.main import app
|
|
|
|
async with AsyncClient(app=app, base_url="http://test") as client:
|
|
response = await client.put(
|
|
f"/api/v1/tasks/{task.id}",
|
|
json={"is_enabled": False},
|
|
headers=other_headers,
|
|
)
|
|
|
|
assert response.status_code == 403
|