diff --git a/packages/cli/src/workflows/workflowHistory/workflowHistoryManager.ee.ts b/packages/cli/src/workflows/workflowHistory/workflowHistoryManager.ee.ts index 0fe5de0b24..a7af16f5bc 100644 --- a/packages/cli/src/workflows/workflowHistory/workflowHistoryManager.ee.ts +++ b/packages/cli/src/workflows/workflowHistory/workflowHistoryManager.ee.ts @@ -1,9 +1,9 @@ -import { WorkflowHistoryRepository } from '@/databases/repositories'; 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 { getWorkflowHistoryPruneTime, isWorkflowHistoryEnabled } from './workflowHistoryHelper.ee'; -import { DateTime } from 'luxon'; -import { LessThan } from 'typeorm'; @Service() export class WorkflowHistoryManager { diff --git a/packages/cli/test/integration/shared/testDb.ts b/packages/cli/test/integration/shared/testDb.ts index f56a62a604..7f8f2e33b8 100644 --- a/packages/cli/test/integration/shared/testDb.ts +++ b/packages/cli/test/integration/shared/testDb.ts @@ -118,7 +118,7 @@ export async function terminate() { export async function truncate(collections: CollectionName[]) { const [tag, rest] = separate(collections, (c) => c === 'Tag'); - if (tag) { + if (tag.length) { await Container.get(TagRepository).delete({}); await Container.get(WorkflowTagMappingRepository).delete({}); } diff --git a/packages/cli/test/integration/workflowHistoryManager.test.ts b/packages/cli/test/integration/workflowHistoryManager.test.ts index 892b368de8..e03d3b4b0e 100644 --- a/packages/cli/test/integration/workflowHistoryManager.test.ts +++ b/packages/cli/test/integration/workflowHistoryManager.test.ts @@ -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 config from '@/config'; -import { DateTime } from 'luxon'; import { In } from 'typeorm'; +import { DateTime } from 'luxon'; -let licenseMock: License; -let licensePruneTime = -1; -let licenseEnabled = true; -let manager: WorkflowHistoryManager; +import config from '@/config'; +import { WorkflowHistoryRepository } from '@/databases/repositories'; +import { License } from '@/License'; +import { WorkflowHistoryManager } from '@/workflows/workflowHistory/workflowHistoryManager.ee'; -beforeAll(async () => { - await testDb.init(); - - 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(); -}); +import * as testDb from './shared/testDb'; +import { mockInstance } from './shared/utils'; describe('Workflow History Manager', () => { - test('should prune on interval', () => { - jest.useFakeTimers(); + const license = mockInstance(License); + let repo: WorkflowHistoryRepository; + let manager: WorkflowHistoryManager; - manager = new WorkflowHistoryManager(Container.get(WorkflowHistoryRepository)); - manager.init(); + beforeAll(async () => { + 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 currentCount = pruneSpy.mock.calls.length; - jest.runOnlyPendingTimers(); + jest.useFakeTimers(); + manager.init(); + jest.runOnlyPendingTimers(); expect(pruneSpy).toBeCalledTimes(currentCount + 1); jest.runOnlyPendingTimers(); expect(pruneSpy).toBeCalledTimes(currentCount + 2); + + manager.shutdown(); + jest.clearAllTimers(); + jest.useRealTimers(); + pruneSpy.mockRestore(); }); test('should not prune when not licensed', async () => { - // Set a prune time just to make sure it gets to the delete - config.set('workflowHistory.pruneTime', 24); - - 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); + license.isWorkflowHistoryLicensed.mockReturnValue(false); + await createWorkflowHistory(); + await pruneAndAssertCount(); }); 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); - - 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); + await createWorkflowHistory(); + await pruneAndAssertCount(); }); test('should not prune when both prune times are -1 (infinite)', async () => { - config.set('workflowHistory.pruneTime', -1); - licensePruneTime = -1; - - 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); + await createWorkflowHistory(); + await pruneAndAssertCount(); }); test('should prune when config prune time is not -1 (infinite)', async () => { config.set('workflowHistory.pruneTime', 24); - licensePruneTime = -1; - - 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); + await createWorkflowHistory(); + await pruneAndAssertCount(0); }); test('should prune when license prune time is not -1 (infinite)', async () => { - config.set('workflowHistory.pruneTime', -1); - licensePruneTime = 24; + license.getWorkflowHistoryPruneLimit.mockReturnValue(24); - 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); + await createWorkflowHistory(); + await pruneAndAssertCount(0); }); test('should only prune versions older than prune time', async () => { config.set('workflowHistory.pruneTime', 24); - licensePruneTime = -1; - const repo = Container.get(WorkflowHistoryRepository); - manager = new WorkflowHistoryManager(repo); - manager.init(); + const recentVersions = await createWorkflowHistory(0); + const oldVersions = await createWorkflowHistory(); - const workflow = await testDb.createWorkflow(); - const recentVersions = await testDb.createManyWorkflowHistoryItems(workflow.id, 10); - const oldVersions = await testDb.createManyWorkflowHistoryItems( - workflow.id, - 10, - DateTime.now().minus({ days: 2 }).toJSDate(), - ); + await pruneAndAssertCount(10, 20); - 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( await repo.count({ where: { versionId: In(recentVersions.map((i) => i.versionId)) } }), ).toBe(10); @@ -205,4 +96,26 @@ describe('Workflow History Manager', () => { await repo.count({ where: { versionId: In(oldVersions.map((i) => i.versionId)) } }), ).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); + }; });