""" 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