mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat(API): Add cancel status filters to the public api executions endpoint (#19136)
This commit is contained in:
@@ -13,7 +13,7 @@ get:
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: ['error', 'success', 'waiting']
|
||||
enum: ['canceled', 'error', 'success', 'waiting']
|
||||
- name: workflowId
|
||||
in: query
|
||||
description: Workflow to filter the executions by.
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import {
|
||||
createTeamProject,
|
||||
createManyWorkflows,
|
||||
createTeamProject,
|
||||
createWorkflow,
|
||||
mockInstance,
|
||||
shareWorkflowWithUsers,
|
||||
testDb,
|
||||
mockInstance,
|
||||
} from '@n8n/backend-test-utils';
|
||||
import type { User, ExecutionEntity } from '@n8n/db';
|
||||
import type { ExecutionEntity, User } from '@n8n/db';
|
||||
import type { ExecutionStatus } from 'n8n-workflow';
|
||||
|
||||
import type { ActiveWorkflowManager } from '@/active-workflow-manager';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
|
||||
import {
|
||||
createdExecutionWithStatus,
|
||||
createErrorExecution,
|
||||
createExecution,
|
||||
createManyExecutions,
|
||||
createSuccessfulExecution,
|
||||
createWaitingExecution,
|
||||
} from '../shared/db/executions';
|
||||
import { createMemberWithApiKey, createOwnerWithApiKey } from '../shared/db/users';
|
||||
import type { SuperAgentTest } from '../shared/types';
|
||||
@@ -238,46 +239,6 @@ describe('GET /executions', () => {
|
||||
|
||||
test('should fail due to invalid API Key', testWithAPIKey('get', '/executions', 'abcXYZ'));
|
||||
|
||||
test('should retrieve all successful executions', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
const successfulExecution = await createSuccessfulExecution(workflow);
|
||||
|
||||
await createErrorExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'success',
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.length).toBe(1);
|
||||
expect(response.body.nextCursor).toBe(null);
|
||||
|
||||
const {
|
||||
id,
|
||||
finished,
|
||||
mode,
|
||||
retryOf,
|
||||
retrySuccessId,
|
||||
startedAt,
|
||||
stoppedAt,
|
||||
workflowId,
|
||||
waitTill,
|
||||
status,
|
||||
} = response.body.data[0];
|
||||
|
||||
expect(id).toBeDefined();
|
||||
expect(finished).toBe(true);
|
||||
expect(mode).toEqual(successfulExecution.mode);
|
||||
expect(retrySuccessId).toBeNull();
|
||||
expect(retryOf).toBeNull();
|
||||
expect(startedAt).not.toBeNull();
|
||||
expect(stoppedAt).not.toBeNull();
|
||||
expect(workflowId).toBe(successfulExecution.workflowId);
|
||||
expect(waitTill).toBeNull();
|
||||
expect(status).toBe(successfulExecution.status);
|
||||
});
|
||||
|
||||
test('should paginate two executions', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
@@ -335,86 +296,41 @@ describe('GET /executions', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('should retrieve all error executions', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
describe('with query status', () => {
|
||||
type AllowedQueryStatus = 'success' | 'error' | 'canceled' | 'waiting';
|
||||
test.each`
|
||||
queryStatus | entityStatus
|
||||
${'canceled'} | ${'canceled'}
|
||||
${'error'} | ${'error'}
|
||||
${'error'} | ${'crashed'}
|
||||
${'success'} | ${'success'}
|
||||
${'waiting'} | ${'waiting'}
|
||||
`(
|
||||
'should retrieve all $queryStatus executions',
|
||||
async ({
|
||||
queryStatus,
|
||||
entityStatus,
|
||||
}: { queryStatus: AllowedQueryStatus; entityStatus: ExecutionStatus }) => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
await createSuccessfulExecution(workflow);
|
||||
await createdExecutionWithStatus(workflow, queryStatus === 'success' ? 'error' : 'success');
|
||||
|
||||
const errorExecution = await createErrorExecution(workflow);
|
||||
const expectedExecution = await createdExecutionWithStatus(workflow, entityStatus);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'error',
|
||||
});
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: queryStatus,
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.length).toBe(1);
|
||||
expect(response.body.nextCursor).toBe(null);
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.length).toBe(1);
|
||||
expect(response.body.nextCursor).toBe(null);
|
||||
|
||||
const {
|
||||
id,
|
||||
finished,
|
||||
mode,
|
||||
retryOf,
|
||||
retrySuccessId,
|
||||
startedAt,
|
||||
stoppedAt,
|
||||
workflowId,
|
||||
waitTill,
|
||||
status,
|
||||
} = response.body.data[0];
|
||||
const { id, status } = response.body.data[0];
|
||||
|
||||
expect(id).toBeDefined();
|
||||
expect(finished).toBe(false);
|
||||
expect(mode).toEqual(errorExecution.mode);
|
||||
expect(retrySuccessId).toBeNull();
|
||||
expect(retryOf).toBeNull();
|
||||
expect(startedAt).not.toBeNull();
|
||||
expect(stoppedAt).not.toBeNull();
|
||||
expect(workflowId).toBe(errorExecution.workflowId);
|
||||
expect(waitTill).toBeNull();
|
||||
expect(status).toBe(errorExecution.status);
|
||||
});
|
||||
|
||||
test('should return all waiting executions', async () => {
|
||||
const workflow = await createWorkflow({}, owner);
|
||||
|
||||
await createSuccessfulExecution(workflow);
|
||||
|
||||
await createErrorExecution(workflow);
|
||||
|
||||
const waitingExecution = await createWaitingExecution(workflow);
|
||||
|
||||
const response = await authOwnerAgent.get('/executions').query({
|
||||
status: 'waiting',
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.body.data.length).toBe(1);
|
||||
expect(response.body.nextCursor).toBe(null);
|
||||
|
||||
const {
|
||||
id,
|
||||
finished,
|
||||
mode,
|
||||
retryOf,
|
||||
retrySuccessId,
|
||||
startedAt,
|
||||
stoppedAt,
|
||||
workflowId,
|
||||
waitTill,
|
||||
status,
|
||||
} = response.body.data[0];
|
||||
|
||||
expect(id).toBeDefined();
|
||||
expect(finished).toBe(false);
|
||||
expect(mode).toEqual(waitingExecution.mode);
|
||||
expect(retrySuccessId).toBeNull();
|
||||
expect(retryOf).toBeNull();
|
||||
expect(startedAt).not.toBeNull();
|
||||
expect(stoppedAt).not.toBeNull();
|
||||
expect(workflowId).toBe(waitingExecution.workflowId);
|
||||
expect(new Date(waitTill).getTime()).toBeGreaterThan(Date.now() - 1000);
|
||||
expect(status).toBe(waitingExecution.status);
|
||||
expect(id).toBeDefined();
|
||||
expect(status).toBe(expectedExecution.status);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('should retrieve all executions of specific workflow', async () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
AnnotationTagRepository,
|
||||
} from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import type { AnnotationVote, IWorkflowBase } from 'n8n-workflow';
|
||||
import type { AnnotationVote, ExecutionStatus, IWorkflowBase } from 'n8n-workflow';
|
||||
|
||||
import { ExecutionService } from '@/executions/execution.service';
|
||||
import { Telemetry } from '@/telemetry';
|
||||
@@ -104,6 +104,20 @@ export async function createWaitingExecution(workflow: IWorkflowBase) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an execution with a given status in the DB and assign it to a workflow.
|
||||
*/
|
||||
export async function createdExecutionWithStatus(workflow: IWorkflowBase, status: ExecutionStatus) {
|
||||
const execution: Partial<ExecutionEntity> = {
|
||||
status,
|
||||
finished: status === 'success' ? true : false,
|
||||
stoppedAt: ['crashed', 'error'].includes(status) ? new Date() : undefined,
|
||||
waitTill: status === 'waiting' ? new Date() : undefined,
|
||||
};
|
||||
|
||||
return await createExecution(execution, workflow);
|
||||
}
|
||||
|
||||
export async function annotateExecution(
|
||||
executionId: string,
|
||||
annotation: { vote?: AnnotationVote | null; tags?: string[] },
|
||||
|
||||
Reference in New Issue
Block a user