瀏覽代碼

补充任务恢复接口的幂等与账号隔离测试

LSamien 1 月之前
父節點
當前提交
88f0bf0c1a
共有 1 個文件被更改,包括 20 次插入 和 1 次删除
  1. 20 1
      tests/server/workspaceRoutes.test.ts

+ 20 - 1
tests/server/workspaceRoutes.test.ts

@@ -2,7 +2,8 @@
 import { mkdtempSync, rmSync, readFileSync } from 'node:fs'
 import { tmpdir } from 'node:os'
 import { join } from 'node:path'
-import { afterEach, beforeEach, describe, expect, it } from 'vitest'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { randomUUID } from 'node:crypto'
 import request from 'supertest'
 import type Koa from 'koa'
 import { createApplication, type ApplicationRuntime } from '../../src/server/app'
@@ -94,6 +95,24 @@ afterEach(() => {
   rmSync(home, { recursive: true, force: true })
 })
 describe('application workspace HTTP contract', () => {
+  it('resumes a stopped goal from a real user request without duplicating its run',async()=>{
+    vi.spyOn(runtime.workspaceRuntime,'wake').mockImplementation(()=>{})
+    vi.spyOn(runtime.workspaceRuntime.teamTools,'requireAvailable').mockResolvedValue()
+    const lead=runtime.workspace.createAgent('first',{name:'任务负责人',profile:'default',canManageTeam:true})
+    const member=runtime.workspace.createAgent('first',{name:'成员',profile:'default'})
+    const source=runtime.workspace.list<any>('first','conversation').find(c=>c.kind==='direct'&&c.memberIds[0]===lead.id)!
+    const original=runtime.workspaceRuntime.send('first',source.id,{requestId:randomUUID(),content:'完成任务'})
+    const team=runtime.workspace.createGroup('first',{name:'任务组',memberIds:[lead.id,member.id],administratorId:lead.id})
+    const task=runtime.workspace.tasks('first',team.id)[0]!
+    runtime.workspaceRuntime.tasks.begin('first',task,lead,'完成任务',{conversationId:source.id,runId:original.id,agentId:lead.id})
+    await req('post',`/api/app/conversations/${team.id}/tasks/${task.id}/stop`).send({}).expect(200)
+    const input={requestId:randomUUID()}
+    const resumed=await req('post',`/api/app/conversations/${team.id}/tasks/${task.id}/resume`).send(input).expect(200)
+    expect(resumed.body.goal.status).toBe('running')
+    const repeated=await req('post',`/api/app/conversations/${team.id}/tasks/${task.id}/resume`).send(input).expect(200)
+    expect(repeated.body.run.id).toBe(resumed.body.run.id)
+    await req('post',`/api/app/conversations/${team.id}/tasks/${task.id}/resume`,'second').send({requestId:randomUUID()}).expect(404)
+  })
   it('grants team management only with a ready bridge and persists explicit revocation', async () => {
     const denied = await req('post','/api/app/agents').send({name:'老板',profile:'default',canManageTeam:true}).expect(409)
     expect(denied.body.code).toBe('team_tools_unavailable')