Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
188 lines
5.1 KiB
TypeScript
188 lines
5.1 KiB
TypeScript
import { createWorkflow, testDb } from '@n8n/backend-test-utils';
|
|
import { ExecutionDataRepository, ExecutionRepository } from '@n8n/db';
|
|
import { Container } from '@n8n/di';
|
|
import { stringify } from 'flatted';
|
|
import type { IRunExecutionData, IRunExecutionDataAll } from 'n8n-workflow';
|
|
|
|
describe('ExecutionRepository', () => {
|
|
beforeAll(async () => {
|
|
await testDb.init();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
await testDb.truncate(['WorkflowEntity', 'ExecutionEntity']);
|
|
});
|
|
|
|
afterAll(async () => {
|
|
await testDb.terminate();
|
|
});
|
|
|
|
describe('run execution data migration', () => {
|
|
it('should automatically migrate IRunExecutionDataV0 to V1 when reading', async () => {
|
|
const executionRepo = Container.get(ExecutionRepository);
|
|
const executionDataRepo = Container.get(ExecutionDataRepository);
|
|
const workflow = await createWorkflow({ settings: { executionOrder: 'v1' } });
|
|
|
|
// Create V0 data with string destinationNode
|
|
const v0Data: IRunExecutionDataAll = {
|
|
version: 0,
|
|
startData: { destinationNode: 'TestNode' },
|
|
resultData: { runData: {} },
|
|
};
|
|
|
|
// Insert execution with V0 data directly into the database
|
|
const { identifiers } = await executionRepo.insert({
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'success',
|
|
finished: true,
|
|
createdAt: new Date(),
|
|
});
|
|
const executionId = identifiers[0].id as string;
|
|
await executionDataRepo.insert({
|
|
executionId,
|
|
workflowData: { id: workflow.id, connections: {}, nodes: [], name: workflow.name },
|
|
data: stringify(v0Data),
|
|
});
|
|
|
|
// Read the execution back
|
|
const execution = await executionRepo.findSingleExecution(executionId, {
|
|
includeData: true,
|
|
unflattenData: true,
|
|
});
|
|
|
|
// Verify that the data was migrated to V1
|
|
const data = execution?.data as IRunExecutionData;
|
|
expect(data.version).toBe(1);
|
|
expect(data.startData?.destinationNode).toEqual({
|
|
nodeName: 'TestNode',
|
|
mode: 'inclusive',
|
|
});
|
|
});
|
|
});
|
|
describe('findByStopExecutionsFilter', () => {
|
|
it('should find executions by status', async () => {
|
|
const executionRepo = Container.get(ExecutionRepository);
|
|
const workflow = await createWorkflow();
|
|
|
|
// Insert executions with different statuses
|
|
await executionRepo.insert([
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'running',
|
|
finished: false,
|
|
createdAt: new Date(),
|
|
},
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'success',
|
|
finished: true,
|
|
createdAt: new Date(),
|
|
},
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'error',
|
|
finished: false,
|
|
createdAt: new Date(),
|
|
},
|
|
]);
|
|
|
|
// Find executions with status 'running' and 'error'
|
|
const executions = await executionRepo.findByStopExecutionsFilter({
|
|
status: ['running', 'error'],
|
|
workflowId: workflow.id,
|
|
});
|
|
|
|
expect(executions).toHaveLength(2);
|
|
});
|
|
|
|
it('should find executions by startedAfter and startedBefore', async () => {
|
|
const executionRepo = Container.get(ExecutionRepository);
|
|
const workflow = await createWorkflow();
|
|
|
|
// Insert executions with different start times
|
|
const now = new Date();
|
|
const pastDate = new Date(now.getTime() - 1000 * 60 * 60); // 1 hour ago
|
|
const futureDate = new Date(now.getTime() + 1000 * 60 * 60); // 1 hour later
|
|
|
|
await executionRepo.insert([
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: pastDate,
|
|
status: 'running',
|
|
finished: false,
|
|
createdAt: pastDate,
|
|
},
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: now,
|
|
status: 'success',
|
|
finished: true,
|
|
createdAt: now,
|
|
},
|
|
{
|
|
workflowId: workflow.id,
|
|
mode: 'manual',
|
|
startedAt: futureDate,
|
|
status: 'error',
|
|
finished: false,
|
|
createdAt: futureDate,
|
|
},
|
|
]);
|
|
|
|
// Find executions started between pastDate and now
|
|
const executions = await executionRepo.findByStopExecutionsFilter({
|
|
startedAfter: new Date(pastDate.getTime() + 1).toISOString(),
|
|
startedBefore: new Date(futureDate.getTime() - 1).toISOString(),
|
|
status: ['running', 'success', 'error'],
|
|
workflowId: workflow.id,
|
|
});
|
|
|
|
expect(executions).toHaveLength(1);
|
|
});
|
|
|
|
it('should find executions for all workflows when workflowId is "all"', async () => {
|
|
const executionRepo = Container.get(ExecutionRepository);
|
|
const workflow1 = await createWorkflow();
|
|
const workflow2 = await createWorkflow();
|
|
|
|
// Insert executions for different workflows
|
|
await executionRepo.insert([
|
|
{
|
|
workflowId: workflow1.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'running',
|
|
finished: false,
|
|
createdAt: new Date(),
|
|
},
|
|
{
|
|
workflowId: workflow2.id,
|
|
mode: 'manual',
|
|
startedAt: new Date(),
|
|
status: 'success',
|
|
finished: true,
|
|
createdAt: new Date(),
|
|
},
|
|
]);
|
|
|
|
// Find executions for all workflows
|
|
const executions = await executionRepo.findByStopExecutionsFilter({
|
|
status: ['running', 'success'],
|
|
workflowId: 'all',
|
|
});
|
|
|
|
expect(executions).toHaveLength(2);
|
|
});
|
|
});
|
|
});
|