"""PR-Worker-Pool-Registry-1B 정정 #2 — /result 소유권 검증. worker A 가 claim 한 job 을 worker B 가 /result 호출 → 404. """ from __future__ import annotations import os import sys import uuid import pytest import pytest_asyncio sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "app")) from httpx import ASGITransport, AsyncClient from sqlalchemy import text from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from _worker_pool_helpers import ( cleanup_worker_capabilities, cleanup_worker_jobs, ensure_user, get_database_url, mint_access_token, ) @pytest_asyncio.fixture async def db_session(monkeypatch): monkeypatch.setenv("LAPTOP_WORKER_BOT_USERNAME", "laptop-worker-bot") engine = create_async_engine(get_database_url()) sm = async_sessionmaker(engine, expire_on_commit=False) async with sm() as session: yield session await engine.dispose() @pytest_asyncio.fixture async def worker_token(db_session): await ensure_user(db_session, "laptop-worker-bot") return mint_access_token("laptop-worker-bot") @pytest.mark.asyncio async def test_other_worker_cannot_submit_result(db_session, worker_token): """worker A 의 processing job → worker B 가 /result → 404.""" from main import app owner_id = await ensure_user(db_session, "test-owner-own-1b") w_a = f"test-own-1b-a-{uuid.uuid4().hex[:6]}" w_b = f"test-own-1b-b-{uuid.uuid4().hex[:6]}" for w in (w_a, w_b): await db_session.execute( text( "INSERT INTO worker_capabilities (worker_id, user_id, device_label, " "worker_class, tier) VALUES (:w, :u, 'lbl', 'laptop', 'laptop_small')" ), {"w": w, "u": owner_id}, ) job_id = ( await db_session.execute( text( "INSERT INTO worker_jobs (user_id, job_type, status, worker_id, " "attempts, claimed_at) VALUES (:u, 'test-own-1b', 'processing', :w, 1, NOW()) " "RETURNING id" ), {"u": owner_id, "w": w_a}, ) ).scalar_one() await db_session.commit() try: async with AsyncClient( transport=ASGITransport(app=app), base_url="http://test" ) as c: r = await c.post( "/internal/worker/result", json={ "job_id": job_id, "worker_id": w_b, "status": "completed", "result": {"ok": True}, }, headers={"Authorization": f"Bearer {worker_token}"}, ) assert r.status_code == 404, r.text # job 은 여전히 processing (worker_id=w_a) res = await db_session.execute( text("SELECT status, worker_id FROM worker_jobs WHERE id = :i"), {"i": job_id}, ) s, w_id = res.first() assert s == "processing" assert w_id == w_a finally: await cleanup_worker_jobs(db_session, "test-own-1b") await cleanup_worker_capabilities(db_session, "test-own-1b")