first commit
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
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
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user