diff --git a/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts b/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts index c46743ae59..4fd4949478 100644 --- a/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/LocalTaskWorker.test.ts @@ -82,14 +82,18 @@ describe('LocalTaskWorker', () => { it('can trigger to abort wait', async () => { const fn = jest.fn(); + const controller = new AbortController(); const worker = new LocalTaskWorker('a', fn, logger); - worker.start({ - version: 2, - initialDelayDuration: 'PT0.2S', - cadence: 'PT0.2S', - timeoutAfterDuration: 'PT1S', - }); + worker.start( + { + version: 2, + initialDelayDuration: 'PT0.2S', + cadence: 'PT0.2S', + timeoutAfterDuration: 'PT1S', + }, + { signal: controller.signal }, + ); // TODO(freben): Rewrite to fake timers - tried, but it wouldn't work expect(fn).toHaveBeenCalledTimes(0); @@ -100,5 +104,6 @@ describe('LocalTaskWorker', () => { worker.trigger(); await new Promise(r => setTimeout(r, 10)); expect(fn).toHaveBeenCalledTimes(2); + controller.abort(); }); }); diff --git a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts index efbad2e8b6..50bea27d27 100644 --- a/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts +++ b/packages/backend-tasks/src/tasks/PluginTaskSchedulerJanitor.test.ts @@ -22,6 +22,7 @@ import waitForExpect from 'wait-for-expect'; import { migrateBackendTasks } from '../database/migrateBackendTasks'; import { DbTasksRow, DB_TASKS_TABLE } from '../database/tables'; import { PluginTaskSchedulerJanitor } from './PluginTaskSchedulerJanitor'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; const insertTask = async (knex: Knex, task: DbTasksRow) => { return knex(DB_TASKS_TABLE) @@ -45,6 +46,7 @@ describe('PluginTaskSchedulerJanitor', () => { 'MYSQL_8', ], }); + const testScopedSignal = createTestScopedSignal(); jest.setTimeout(60_000); @@ -77,8 +79,7 @@ describe('PluginTaskSchedulerJanitor', () => { logger, }); - const abortController = new AbortController(); - worker.start(abortController.signal); + worker.start(testScopedSignal()); await waitForExpect(async () => { await expect(getTask(knex)).resolves.toEqual( @@ -90,8 +91,6 @@ describe('PluginTaskSchedulerJanitor', () => { }), ); }); - - abortController.abort(); }, ); }); diff --git a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts index 6aa77dd7fe..8e419437bc 100644 --- a/packages/backend-tasks/src/tasks/TaskScheduler.test.ts +++ b/packages/backend-tasks/src/tasks/TaskScheduler.test.ts @@ -19,6 +19,7 @@ import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils'; import { Duration } from 'luxon'; import waitForExpect from 'wait-for-expect'; import { TaskScheduler } from './TaskScheduler'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; jest.setTimeout(60_000); @@ -27,6 +28,7 @@ describe('TaskScheduler', () => { const databases = TestDatabases.create({ ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], }); + const testScopedSignal = createTestScopedSignal(); async function createDatabase( databaseId: TestDatabaseId, @@ -51,6 +53,7 @@ describe('TaskScheduler', () => { id: 'task1', timeout: Duration.fromMillis(5000), frequency: Duration.fromMillis(5000), + signal: testScopedSignal(), fn, }); @@ -71,6 +74,7 @@ describe('TaskScheduler', () => { id: 'task2', timeout: Duration.fromMillis(5000), frequency: { cron: '* * * * * *' }, + signal: testScopedSignal(), fn, }); diff --git a/packages/backend-tasks/src/tasks/TaskWorker.test.ts b/packages/backend-tasks/src/tasks/TaskWorker.test.ts index 71d02274e2..3022f59060 100644 --- a/packages/backend-tasks/src/tasks/TaskWorker.test.ts +++ b/packages/backend-tasks/src/tasks/TaskWorker.test.ts @@ -22,6 +22,7 @@ import { migrateBackendTasks } from '../database/migrateBackendTasks'; import { DbTasksRow, DB_TASKS_TABLE } from '../database/tables'; import { TaskWorker } from './TaskWorker'; import { TaskSettingsV2 } from './types'; +import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal'; jest.setTimeout(60_000); @@ -30,6 +31,7 @@ describe('TaskWorker', () => { const databases = TestDatabases.create({ ids: ['POSTGRES_13', 'POSTGRES_9', 'SQLITE_3', 'MYSQL_8'], }); + const testScopedSignal = createTestScopedSignal(); beforeEach(() => { jest.resetAllMocks(); @@ -135,7 +137,7 @@ describe('TaskWorker', () => { }; const checkFrequency = Duration.fromObject({ milliseconds: 100 }); const worker = new TaskWorker('task1', fn, knex, logger, checkFrequency); - worker.start(settings); + worker.start(settings, { signal: testScopedSignal() }); await waitForExpect(() => { expect(logger.error).toHaveBeenCalled(); @@ -158,7 +160,7 @@ describe('TaskWorker', () => { }; const checkFrequency = Duration.fromObject({ milliseconds: 100 }); const worker = new TaskWorker('task1', fn, knex, logger, checkFrequency); - worker.start(settings); + worker.start(settings, { signal: testScopedSignal() }); await waitForExpect(() => { expect(fn).toHaveBeenCalledTimes(3); @@ -321,7 +323,7 @@ describe('TaskWorker', () => { logger, Duration.fromMillis(10), ); - await worker2.start(settings); + await worker2.start(settings, { signal: testScopedSignal() }); // We eventually abort the first worker just to make sure that the second // one for sure will get a go at running the task diff --git a/packages/backend-tasks/src/tasks/__testUtils__/createTestScopedSignal.ts b/packages/backend-tasks/src/tasks/__testUtils__/createTestScopedSignal.ts new file mode 100644 index 0000000000..6a497ea266 --- /dev/null +++ b/packages/backend-tasks/src/tasks/__testUtils__/createTestScopedSignal.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function createTestScopedSignal(): () => AbortSignal { + let testAbortController = new AbortController(); + + beforeEach(() => { + testAbortController = new AbortController(); + }); + afterEach(() => { + testAbortController.abort(); + }); + + return () => testAbortController.signal; +}