mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 21:07:28 -08:00
ci: Fix WorkflowHistoryManager tests (no-changelog) (#7356)
[DB Tests](https://github.com/n8n-io/n8n/actions/runs/6418058186)
This commit is contained in:
parent
7ebf8f327a
commit
169175080a
|
@ -1,9 +1,9 @@
|
||||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
|
import { LessThan } from 'typeorm';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||||
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
||||||
import { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
import { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee';
|
||||||
import { DateTime } from 'luxon';
|
|
||||||
import { LessThan } from 'typeorm';
|
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class WorkflowHistoryManager {
|
export class WorkflowHistoryManager {
|
||||||
|
|
|
@ -118,7 +118,7 @@ export async function terminate() {
|
||||||
export async function truncate(collections: CollectionName[]) {
|
export async function truncate(collections: CollectionName[]) {
|
||||||
const [tag, rest] = separate(collections, (c) => c === 'Tag');
|
const [tag, rest] = separate(collections, (c) => c === 'Tag');
|
||||||
|
|
||||||
if (tag) {
|
if (tag.length) {
|
||||||
await Container.get(TagRepository).delete({});
|
await Container.get(TagRepository).delete({});
|
||||||
await Container.get(WorkflowTagMappingRepository).delete({});
|
await Container.get(WorkflowTagMappingRepository).delete({});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,203 +1,94 @@
|
||||||
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
|
||||||
import * as testDb from './shared/testDb';
|
|
||||||
import { License } from '@/License';
|
|
||||||
import { mockInstance } from './shared/utils';
|
|
||||||
import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee';
|
|
||||||
import Container from 'typedi';
|
import Container from 'typedi';
|
||||||
import config from '@/config';
|
|
||||||
import { DateTime } from 'luxon';
|
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import { DateTime } from 'luxon';
|
||||||
|
|
||||||
let licenseMock: License;
|
import config from '@/config';
|
||||||
let licensePruneTime = -1;
|
import { WorkflowHistoryRepository } from '@/databases/repositories';
|
||||||
let licenseEnabled = true;
|
import { License } from '@/License';
|
||||||
let manager: WorkflowHistoryManager;
|
import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee';
|
||||||
|
|
||||||
beforeAll(async () => {
|
import * as testDb from './shared/testDb';
|
||||||
await testDb.init();
|
import { mockInstance } from './shared/utils';
|
||||||
|
|
||||||
licenseMock = mockInstance(License, {
|
|
||||||
isWorkflowHistoryLicensed() {
|
|
||||||
return licenseEnabled;
|
|
||||||
},
|
|
||||||
getWorkflowHistoryPruneLimit() {
|
|
||||||
return licensePruneTime;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await testDb.truncate([WorkflowHistoryRepository]);
|
|
||||||
jest.useRealTimers();
|
|
||||||
jest.clearAllMocks();
|
|
||||||
config.set('workflowHistory.enabled', true);
|
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
|
||||||
licensePruneTime = -1;
|
|
||||||
licenseEnabled = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
manager?.shutdown();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Workflow History Manager', () => {
|
describe('Workflow History Manager', () => {
|
||||||
test('should prune on interval', () => {
|
const license = mockInstance(License);
|
||||||
jest.useFakeTimers();
|
let repo: WorkflowHistoryRepository;
|
||||||
|
let manager: WorkflowHistoryManager;
|
||||||
|
|
||||||
manager = new WorkflowHistoryManager(Container.get(WorkflowHistoryRepository));
|
beforeAll(async () => {
|
||||||
manager.init();
|
await testDb.init();
|
||||||
|
repo = Container.get(WorkflowHistoryRepository);
|
||||||
|
manager = Container.get(WorkflowHistoryManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await testDb.truncate(['Workflow']);
|
||||||
|
jest.clearAllMocks();
|
||||||
|
|
||||||
|
config.set('workflowHistory.enabled', true);
|
||||||
|
config.set('workflowHistory.pruneTime', -1);
|
||||||
|
|
||||||
|
license.isWorkflowHistoryLicensed.mockReturnValue(true);
|
||||||
|
license.getWorkflowHistoryPruneLimit.mockReturnValue(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should prune on interval', () => {
|
||||||
const pruneSpy = jest.spyOn(manager, 'prune');
|
const pruneSpy = jest.spyOn(manager, 'prune');
|
||||||
const currentCount = pruneSpy.mock.calls.length;
|
const currentCount = pruneSpy.mock.calls.length;
|
||||||
|
|
||||||
jest.runOnlyPendingTimers();
|
jest.useFakeTimers();
|
||||||
|
manager.init();
|
||||||
|
|
||||||
|
jest.runOnlyPendingTimers();
|
||||||
expect(pruneSpy).toBeCalledTimes(currentCount + 1);
|
expect(pruneSpy).toBeCalledTimes(currentCount + 1);
|
||||||
|
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
expect(pruneSpy).toBeCalledTimes(currentCount + 2);
|
expect(pruneSpy).toBeCalledTimes(currentCount + 2);
|
||||||
|
|
||||||
|
manager.shutdown();
|
||||||
|
jest.clearAllTimers();
|
||||||
|
jest.useRealTimers();
|
||||||
|
pruneSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not prune when not licensed', async () => {
|
test('should not prune when not licensed', async () => {
|
||||||
// Set a prune time just to make sure it gets to the delete
|
license.isWorkflowHistoryLicensed.mockReturnValue(false);
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
await createWorkflowHistory();
|
||||||
|
await pruneAndAssertCount();
|
||||||
licenseEnabled = false;
|
|
||||||
|
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
|
||||||
manager = new WorkflowHistoryManager(repo);
|
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
|
||||||
await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).not.toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not prune when licensed but disabled', async () => {
|
test('should not prune when licensed but disabled', async () => {
|
||||||
// Set a prune time just to make sure it gets to the delete
|
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
|
||||||
|
|
||||||
config.set('workflowHistory.enabled', false);
|
config.set('workflowHistory.enabled', false);
|
||||||
|
await createWorkflowHistory();
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
await pruneAndAssertCount();
|
||||||
manager = new WorkflowHistoryManager(repo);
|
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
|
||||||
await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).not.toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not prune when both prune times are -1 (infinite)', async () => {
|
test('should not prune when both prune times are -1 (infinite)', async () => {
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
await createWorkflowHistory();
|
||||||
licensePruneTime = -1;
|
await pruneAndAssertCount();
|
||||||
|
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
|
||||||
manager = new WorkflowHistoryManager(repo);
|
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
|
||||||
await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).not.toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should prune when config prune time is not -1 (infinite)', async () => {
|
test('should prune when config prune time is not -1 (infinite)', async () => {
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
config.set('workflowHistory.pruneTime', 24);
|
||||||
licensePruneTime = -1;
|
await createWorkflowHistory();
|
||||||
|
await pruneAndAssertCount(0);
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
|
||||||
manager = new WorkflowHistoryManager(repo);
|
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
|
||||||
await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should prune when license prune time is not -1 (infinite)', async () => {
|
test('should prune when license prune time is not -1 (infinite)', async () => {
|
||||||
config.set('workflowHistory.pruneTime', -1);
|
license.getWorkflowHistoryPruneLimit.mockReturnValue(24);
|
||||||
licensePruneTime = 24;
|
|
||||||
|
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
await createWorkflowHistory();
|
||||||
manager = new WorkflowHistoryManager(repo);
|
await pruneAndAssertCount(0);
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
|
||||||
await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should only prune versions older than prune time', async () => {
|
test('should only prune versions older than prune time', async () => {
|
||||||
config.set('workflowHistory.pruneTime', 24);
|
config.set('workflowHistory.pruneTime', 24);
|
||||||
licensePruneTime = -1;
|
|
||||||
|
|
||||||
const repo = Container.get(WorkflowHistoryRepository);
|
const recentVersions = await createWorkflowHistory(0);
|
||||||
manager = new WorkflowHistoryManager(repo);
|
const oldVersions = await createWorkflowHistory();
|
||||||
manager.init();
|
|
||||||
|
|
||||||
const workflow = await testDb.createWorkflow();
|
await pruneAndAssertCount(10, 20);
|
||||||
const recentVersions = await testDb.createManyWorkflowHistoryItems(workflow.id, 10);
|
|
||||||
const oldVersions = await testDb.createManyWorkflowHistoryItems(
|
|
||||||
workflow.id,
|
|
||||||
10,
|
|
||||||
DateTime.now().minus({ days: 2 }).toJSDate(),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(await repo.count()).toBe(20);
|
|
||||||
|
|
||||||
const deleteSpy = jest.spyOn(repo, 'delete');
|
|
||||||
await manager.prune();
|
|
||||||
expect(deleteSpy).toBeCalled();
|
|
||||||
expect(await repo.count()).toBe(10);
|
|
||||||
expect(
|
expect(
|
||||||
await repo.count({ where: { versionId: In(recentVersions.map((i) => i.versionId)) } }),
|
await repo.count({ where: { versionId: In(recentVersions.map((i) => i.versionId)) } }),
|
||||||
).toBe(10);
|
).toBe(10);
|
||||||
|
@ -205,4 +96,26 @@ describe('Workflow History Manager', () => {
|
||||||
await repo.count({ where: { versionId: In(oldVersions.map((i) => i.versionId)) } }),
|
await repo.count({ where: { versionId: In(oldVersions.map((i) => i.versionId)) } }),
|
||||||
).toBe(0);
|
).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const createWorkflowHistory = async (ageInDays = 2) => {
|
||||||
|
const workflow = await testDb.createWorkflow();
|
||||||
|
const time = DateTime.now().minus({ days: ageInDays }).toJSDate();
|
||||||
|
return testDb.createManyWorkflowHistoryItems(workflow.id, 10, time);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pruneAndAssertCount = async (finalCount = 10, initialCount = 10) => {
|
||||||
|
expect(await repo.count()).toBe(initialCount);
|
||||||
|
|
||||||
|
const deleteSpy = jest.spyOn(repo, 'delete');
|
||||||
|
await manager.prune();
|
||||||
|
|
||||||
|
if (initialCount === finalCount) {
|
||||||
|
expect(deleteSpy).not.toBeCalled();
|
||||||
|
} else {
|
||||||
|
expect(deleteSpy).toBeCalled();
|
||||||
|
}
|
||||||
|
deleteSpy.mockRestore();
|
||||||
|
|
||||||
|
expect(await repo.count()).toBe(finalCount);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue