Files
sim/apps/sim/app/api/workflows/[id]/execute/route.async.test.ts
Vikhyath Mondreti dda012eae9 feat(concurrency): bullmq based concurrency control system (#3605)
* feat(concurrency): bullmq based queueing system

* fix bun lock

* remove manual execs off queues

* address comments

* fix legacy team limits

* cleanup enterprise typing code

* inline child triggers

* fix status check

* address more comments

* optimize reconciler scan

* remove dead code

* add to landing page

* Add load testing framework

* update bullmq

* fix

* fix headless path

---------

Co-authored-by: Theodore Li <teddy@zenobiapay.com>
2026-03-27 13:11:35 -07:00

170 lines
4.5 KiB
TypeScript

/**
* @vitest-environment node
*/
import { createMockRequest } from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'
const {
mockCheckHybridAuth,
mockAuthorizeWorkflowByWorkspacePermission,
mockPreprocessExecution,
mockEnqueue,
mockEnqueueWorkspaceDispatch,
} = vi.hoisted(() => ({
mockCheckHybridAuth: vi.fn(),
mockAuthorizeWorkflowByWorkspacePermission: vi.fn(),
mockPreprocessExecution: vi.fn(),
mockEnqueue: vi.fn().mockResolvedValue('job-123'),
mockEnqueueWorkspaceDispatch: vi.fn().mockResolvedValue('job-123'),
}))
vi.mock('@/lib/auth/hybrid', () => ({
checkHybridAuth: mockCheckHybridAuth,
hasExternalApiCredentials: vi.fn().mockReturnValue(true),
AuthType: {
SESSION: 'session',
API_KEY: 'api_key',
INTERNAL_JWT: 'internal_jwt',
},
}))
vi.mock('@/lib/workflows/utils', () => ({
authorizeWorkflowByWorkspacePermission: mockAuthorizeWorkflowByWorkspacePermission,
createHttpResponseFromBlock: vi.fn(),
workflowHasResponseBlock: vi.fn().mockReturnValue(false),
}))
vi.mock('@/lib/execution/preprocessing', () => ({
preprocessExecution: mockPreprocessExecution,
}))
vi.mock('@/lib/core/async-jobs', () => ({
getJobQueue: vi.fn().mockResolvedValue({
enqueue: mockEnqueue,
startJob: vi.fn(),
completeJob: vi.fn(),
markJobFailed: vi.fn(),
}),
shouldExecuteInline: vi.fn().mockReturnValue(false),
shouldUseBullMQ: vi.fn().mockReturnValue(true),
}))
vi.mock('@/lib/core/bullmq', () => ({
createBullMQJobData: vi.fn((payload: unknown, metadata?: unknown) => ({ payload, metadata })),
}))
vi.mock('@/lib/core/workspace-dispatch', () => ({
enqueueWorkspaceDispatch: mockEnqueueWorkspaceDispatch,
waitForDispatchJob: vi.fn(),
}))
vi.mock('@/lib/core/utils/request', () => ({
generateRequestId: vi.fn().mockReturnValue('req-12345678'),
}))
vi.mock('@/lib/core/utils/urls', () => ({
getBaseUrl: vi.fn().mockReturnValue('http://localhost:3000'),
}))
vi.mock('@/lib/execution/call-chain', () => ({
SIM_VIA_HEADER: 'x-sim-via',
parseCallChain: vi.fn().mockReturnValue([]),
validateCallChain: vi.fn().mockReturnValue(null),
buildNextCallChain: vi.fn().mockReturnValue(['workflow-1']),
}))
vi.mock('@/lib/logs/execution/logging-session', () => ({
LoggingSession: vi.fn().mockImplementation(() => ({})),
}))
vi.mock('@/background/workflow-execution', () => ({
executeWorkflowJob: vi.fn(),
}))
vi.mock('@sim/logger', () => ({
createLogger: vi.fn().mockReturnValue({
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
}),
}))
vi.mock('uuid', () => ({
validate: vi.fn().mockReturnValue(true),
v4: vi.fn().mockReturnValue('execution-123'),
}))
import { POST } from './route'
describe('workflow execute async route', () => {
beforeEach(() => {
vi.clearAllMocks()
mockCheckHybridAuth.mockResolvedValue({
success: true,
userId: 'session-user-1',
authType: 'session',
})
mockAuthorizeWorkflowByWorkspacePermission.mockResolvedValue({
allowed: true,
workflow: {
id: 'workflow-1',
userId: 'owner-1',
workspaceId: 'workspace-1',
},
})
mockPreprocessExecution.mockResolvedValue({
success: true,
actorUserId: 'actor-1',
workflowRecord: {
id: 'workflow-1',
userId: 'owner-1',
workspaceId: 'workspace-1',
},
})
})
it('queues async execution with matching correlation metadata', async () => {
const req = createMockRequest(
'POST',
{ input: { hello: 'world' } },
{
'Content-Type': 'application/json',
'X-Execution-Mode': 'async',
}
)
const params = Promise.resolve({ id: 'workflow-1' })
const response = await POST(req as any, { params })
const body = await response.json()
expect(response.status).toBe(202)
expect(body.executionId).toBe('execution-123')
expect(body.jobId).toBe('job-123')
expect(mockEnqueueWorkspaceDispatch).toHaveBeenCalledWith(
expect.objectContaining({
id: 'execution-123',
workspaceId: 'workspace-1',
lane: 'runtime',
queueName: 'workflow-execution',
bullmqJobName: 'workflow-execution',
metadata: {
workflowId: 'workflow-1',
userId: 'actor-1',
correlation: {
executionId: 'execution-123',
requestId: 'req-12345678',
source: 'workflow',
workflowId: 'workflow-1',
triggerType: 'manual',
},
},
})
)
})
})