Files
KiloStar/tests/unit/test_api_workflow_auth.py
T
zhaoxi a53ffebe0e feat: 新增工具插件、系统日志、workflow配置及前端优化
1. 新增工具插件(edit_file, python_executor, search_file, shell_executor, write_file)
2. 新增系统事件日志模块和API
3. 新增workflow配置文件和详情API
4. 前端增加SSE、错误边界、设置引导等组件
5. 优化认证加密、速率限制、配置加载等工具模块
6. 删除废弃的cluster和health API
7. 补充单元测试和集成测试

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 07:34:43 +00:00

114 lines
4.1 KiB
Python

"""workflow 路由鉴权测试:SSE / reply / resume / detail / graph 端点归属校验。"""
from __future__ import annotations
import types
from unittest.mock import AsyncMock
import pytest
from fastapi import FastAPI
from httpx import AsyncClient, ASGITransport
from kilostar.api.workflow import workflow_router
from kilostar.utils.access import Accessor, TokenData
def _fake_user(user_id: str = "alice"):
return TokenData(user_id=user_id, username=user_id)
def _make_workflow(owner: str = "alice"):
return types.SimpleNamespace(
trace_id="trace-1",
user_id=owner,
title="test",
status="running",
)
@pytest.fixture
def app_alice():
app = FastAPI()
app.include_router(workflow_router)
app.dependency_overrides[Accessor.get_current_user] = lambda: _fake_user("alice")
return app
def _register_pg(fake_actors, owner: str = "alice"):
pg = types.SimpleNamespace()
pg.get_workflow = types.SimpleNamespace(remote=AsyncMock(return_value=_make_workflow(owner)))
pg.get_workflow_context = types.SimpleNamespace(remote=AsyncMock(return_value=None))
pg.get_workflow_graph_state = types.SimpleNamespace(remote=AsyncMock(return_value=None))
fake_actors.register("postgres_database", pg)
return pg
@pytest.mark.asyncio
async def test_detail_forbidden_other_user(app_alice, fake_actors):
_register_pg(fake_actors, owner="bob")
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.get("/api/v1/workflow/trace-1")
assert resp.status_code == 403
@pytest.mark.asyncio
async def test_detail_not_found(app_alice, fake_actors):
pg = types.SimpleNamespace()
pg.get_workflow = types.SimpleNamespace(remote=AsyncMock(return_value=None))
fake_actors.register("postgres_database", pg)
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.get("/api/v1/workflow/trace-nonexist")
assert resp.status_code == 404
@pytest.mark.asyncio
async def test_reply_forbidden_other_user(app_alice, fake_actors):
_register_pg(fake_actors, owner="bob")
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.post("/api/v1/workflow/reply/trace-1", json={"message": "hi"})
assert resp.status_code == 403
@pytest.mark.asyncio
async def test_resume_forbidden_other_user(app_alice, fake_actors):
_register_pg(fake_actors, owner="bob")
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.post("/api/v1/workflow/trace-1/resume")
assert resp.status_code == 403
@pytest.mark.asyncio
async def test_resume_not_found(app_alice, fake_actors):
pg = types.SimpleNamespace()
pg.get_workflow = types.SimpleNamespace(remote=AsyncMock(return_value=None))
fake_actors.register("postgres_database", pg)
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.post("/api/v1/workflow/trace-nonexist/resume")
assert resp.status_code == 404
@pytest.mark.asyncio
async def test_graph_forbidden_other_user(app_alice, fake_actors):
_register_pg(fake_actors, owner="bob")
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.get("/api/v1/workflow/trace-1/graph")
assert resp.status_code == 403
@pytest.mark.asyncio
async def test_sse_forbidden_other_user(app_alice, fake_actors):
_register_pg(fake_actors, owner="bob")
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.get("/api/v1/workflow/sse/trace-1")
assert resp.status_code == 403
@pytest.mark.asyncio
async def test_sse_not_found(app_alice, fake_actors):
pg = types.SimpleNamespace()
pg.get_workflow = types.SimpleNamespace(remote=AsyncMock(return_value=None))
fake_actors.register("postgres_database", pg)
async with AsyncClient(transport=ASGITransport(app=app_alice), base_url="http://t") as c:
resp = await c.get("/api/v1/workflow/sse/trace-nonexist")
assert resp.status_code == 404