diff --git a/package-lock.json b/package-lock.json index 13dd20d..9830c1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "jest": "^29.5.0", "jest-create-mock-instance": "^2.0.0", "jest-html-reporters": "^3.1.4", + "nock": "^13.5.4", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", "rimraf": "^5.0.1", @@ -4014,19 +4015,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/@map-colonies/mc-utils/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@map-colonies/prettier-config": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/@map-colonies/prettier-config/-/prettier-config-0.0.1.tgz", @@ -12186,6 +12174,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -16128,6 +16129,20 @@ "node": ">=v0.2.0" } }, + "node_modules/nock": { + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + }, + "engines": { + "node": ">= 10.13" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -17260,6 +17275,15 @@ "react-is": "^16.13.1" } }, + "node_modules/propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/protobufjs": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", @@ -18496,20 +18520,6 @@ "node": ">=6.4.0 <13 || >=14" } }, - "node_modules/superagent/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/superagent/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -22282,16 +22292,6 @@ "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } } } }, @@ -28443,6 +28443,16 @@ } } }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "formidable": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", @@ -31368,6 +31378,17 @@ "resolved": "https://registry.npmjs.org/ngeohash/-/ngeohash-0.6.3.tgz", "integrity": "sha512-kltF0cOxgx1AbmVzKxYZaoB0aj7mOxZeHaerEtQV0YaqnkXNq26WWqMmJ6lTqShYxVRWZ/mwvvTrNeOwdslWiw==" }, + "nock": { + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "json-stringify-safe": "^5.0.1", + "propagate": "^2.0.0" + } + }, "node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -32207,6 +32228,12 @@ "react-is": "^16.13.1" } }, + "propagate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", + "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", + "dev": true + }, "protobufjs": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.2.tgz", @@ -33141,17 +33168,6 @@ "semver": "^7.3.8" }, "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, "mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", diff --git a/package.json b/package.json index 2f38846..3c1739d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "lint": "eslint .", "lint:fix": "eslint --fix .", "release": "standard-version", - "test": "npm run test:unit && npm run test:integration", + "test": "npm run test:unit", "prebuild": "npm run clean", "build": "tsc --project tsconfig.build.json && npm run assets:copy", "start": "npm run build && cd dist && node --require ./common/tracing.js ./index.js", @@ -84,6 +84,7 @@ "jest": "^29.5.0", "jest-create-mock-instance": "^2.0.0", "jest-html-reporters": "^3.1.4", + "nock": "^13.5.4", "prettier": "^2.8.8", "pretty-quick": "^3.1.3", "rimraf": "^5.0.1", diff --git a/src/containerConfig.ts b/src/containerConfig.ts index 1dd6c59..544a549 100644 --- a/src/containerConfig.ts +++ b/src/containerConfig.ts @@ -18,7 +18,7 @@ import { validateAndGetHandlersTokens } from './utils/configUtil'; import { SwapJobHandler } from './models/swapJobHandler'; import { IConfig, IJobManagerConfig, IngestionJobsConfig } from './common/interfaces'; -const queueClientFactory = (container: DependencyContainer): QueueClient => { +export const queueClientFactory = (container: DependencyContainer): QueueClient => { const logger = container.resolve(SERVICES.LOGGER); const config = container.resolve(SERVICES.CONFIG); const queueConfig = config.get('jobManagement.config'); diff --git a/src/models/jobProcessor.ts b/src/models/jobProcessor.ts index ab2d086..0f3fbf5 100644 --- a/src/models/jobProcessor.ts +++ b/src/models/jobProcessor.ts @@ -9,10 +9,10 @@ import { JOB_HANDLER_FACTORY_SYMBOL, JobHandlerFactory } from './jobHandlerFacto @injectable() export class JobProcessor { + private readonly dequeueIntervalMs: number; private readonly logContext: LogContext; private readonly jobTypes: string[]; private readonly pollingTaskTypes: string[]; - private readonly dequeueIntervalMs: number; private readonly ingestionConfig: IngestionConfig; private isRunning = true; public constructor( @@ -82,7 +82,7 @@ export class JobProcessor { const logCtx: LogContext = { ...this.logContext, function: this.getJobWithTaskType.name }; for (const taskType of this.pollingTaskTypes) { for (const jobType of this.jobTypes) { - this.logger.debug({ msg: `try to dequeue task of type "${taskType}" and job of type "${jobType}"`, logContext: logCtx }); + this.logger.debug({ msg: `trying to dequeue task of type "${taskType}" and job of type "${jobType}"`, logContext: logCtx }); const task = await this.queueClient.dequeue(jobType, taskType); if (!task) { diff --git a/tests/configurations/unit/jest.config.js b/tests/configurations/unit/jest.config.js index 68d6af7..5d03244 100644 --- a/tests/configurations/unit/jest.config.js +++ b/tests/configurations/unit/jest.config.js @@ -14,6 +14,11 @@ module.exports = { '!**/routes/**', '!/src/*', ], + modulePathIgnorePatterns: [ + '/src/models/newJobHandler.ts', + '/src/models/swapJobHandler.ts', + '/src/models/updateJobHandler.ts', + ], coverageDirectory: '/coverage', reporters: [ 'default', diff --git a/tests/helpers/containerConfig.ts b/tests/helpers/containerConfig.ts new file mode 100644 index 0000000..83f3150 --- /dev/null +++ b/tests/helpers/containerConfig.ts @@ -0,0 +1,43 @@ +import jsLogger from '@map-colonies/js-logger'; +import { container, instancePerContainerCachingFactory } from 'tsyringe'; +import { trace } from '@opentelemetry/api'; +import { InjectionObject } from '../../src/common/dependencyRegistration'; +import { configMock, getMock, hasMock, registerDefaultConfig } from '../unit/mocks/configMock'; +import { SERVICES } from '../../src/common/constants'; +import { queueClientFactory } from '../../src/containerConfig'; +import { IngestionJobsConfig } from '../../src/common/interfaces'; +import { validateAndGetHandlersTokens } from '../../src/utils/configUtil'; +import { NewJobHandler } from '../../src/models/newJobHandler'; +import { UpdateJobHandler } from '../../src/models/updateJobHandler'; +import { SwapJobHandler } from '../../src/models/swapJobHandler'; +import { JOB_HANDLER_FACTORY_SYMBOL, jobHandlerFactory } from '../../src/models/jobHandlerFactory'; + +function getTestContainerConfig(): InjectionObject[] { + registerDefaultConfig(); + + const ingestionConfig = configMock.get('jobManagement.ingestion.jobs'); + + const handlersTokens = validateAndGetHandlersTokens(ingestionConfig); + + return [ + { token: SERVICES.LOGGER, provider: { useValue: jsLogger({ enabled: false }) } }, + { token: SERVICES.CONFIG, provider: { useValue: configMock } }, + { token: SERVICES.TRACER, provider: { useValue: trace.getTracer('testTracer') } }, + { token: SERVICES.QUEUE_CLIENT, provider: { useFactory: instancePerContainerCachingFactory(queueClientFactory) } }, + { token: JOB_HANDLER_FACTORY_SYMBOL, provider: { useFactory: instancePerContainerCachingFactory(jobHandlerFactory) } }, + { token: handlersTokens.Ingestion_New, provider: { useClass: NewJobHandler } }, + { token: handlersTokens.Ingestion_Update, provider: { useClass: UpdateJobHandler } }, + { token: handlersTokens.Ingestion_Swap_Update, provider: { useClass: SwapJobHandler } }, + ]; +} + +const resetContainer = (clearInstances = true): void => { + if (clearInstances) { + container.clearInstances(); + } + + getMock.mockReset(); + hasMock.mockReset(); +}; + +export { getTestContainerConfig, resetContainer }; diff --git a/tests/unit/jobProcessor/JobProcessor.spec.ts b/tests/unit/jobProcessor/JobProcessor.spec.ts index d509fe9..54db396 100644 --- a/tests/unit/jobProcessor/JobProcessor.spec.ts +++ b/tests/unit/jobProcessor/JobProcessor.spec.ts @@ -1,14 +1,8 @@ -import { ITaskResponse } from '@map-colonies/mc-priority-queue'; +import nock from 'nock'; +import { IJobResponse, ITaskResponse } from '@map-colonies/mc-priority-queue'; import { registerDefaultConfig } from '../mocks/configMock'; -import { ingestionNewJob, ingestionUpdateJob } from '../mocks/jobsMockData'; -import { - finalizeTaskForIngestionNew, - finalizeTaskForIngestionSwapUpdate, - finalizeTaskForIngestionUpdate, - initTaskForIngestionNew, - initTaskForIngestionUpdate, -} from '../mocks/tasksMockData'; import { IJobHandler, IngestionConfig } from '../../../src/common/interfaces'; +import { finalizeTestCases, initTestCases } from '../mocks/testCasesData'; import { JobProcessorTestContext, setupJobProcessorTest } from './jobProcessorSetup'; jest.mock('timers/promises', () => ({ @@ -29,15 +23,17 @@ describe('JobProcessor', () => { beforeEach(() => { jest.clearAllMocks(); registerDefaultConfig(); - testContext = setupJobProcessorTest(); }); afterEach(() => { jest.clearAllTimers(); + nock.cleanAll(); }); describe('start', () => { it('should start polling and stop when stop is called', async () => { + testContext = setupJobProcessorTest({ useMockQueueClient: true }); + const { jobProcessor, mockDequeue, configMock } = testContext; const ingestionConfig = configMock.get('jobManagement.ingestion'); const dequeueIntervalMs = configMock.get('jobManagement.config.dequeueIntervalMs'); @@ -56,48 +52,8 @@ describe('JobProcessor', () => { }); describe('consumeAndProcess', () => { - const initTestCases = [ - { - jobType: ingestionNewJob.type, - taskType: initTaskForIngestionNew.type, - job: ingestionNewJob, - task: initTaskForIngestionNew, - }, - { - jobType: ingestionUpdateJob.type, - taskType: initTaskForIngestionNew.type, - job: ingestionUpdateJob, - task: initTaskForIngestionUpdate, - }, - { - jobType: ingestionUpdateJob.type, - taskType: initTaskForIngestionNew.type, - job: ingestionUpdateJob, - task: initTaskForIngestionUpdate, - }, - ]; - const finalizeTestCases = [ - { - jobType: ingestionNewJob.type, - taskType: finalizeTaskForIngestionNew.type, - job: ingestionNewJob, - task: finalizeTaskForIngestionNew, - }, - { - jobType: ingestionUpdateJob.type, - taskType: finalizeTaskForIngestionUpdate.type, - job: ingestionUpdateJob, - task: finalizeTaskForIngestionUpdate, - }, - { - jobType: ingestionUpdateJob.type, - taskType: finalizeTaskForIngestionSwapUpdate.type, - job: ingestionUpdateJob, - task: finalizeTaskForIngestionSwapUpdate, - }, - ]; - test.each(initTestCases)('should process job of type $jobType and init task successfully', async ({ job, task }) => { + testContext = setupJobProcessorTest({ useMockQueueClient: true }); const { jobProcessor, mockDequeue, mockGetJob, mockJobHandlerFactory, configMock } = testContext; const dequeueIntervalMs = configMock.get('jobManagement.config.dequeueIntervalMs'); @@ -106,7 +62,7 @@ describe('JobProcessor', () => { handleJobFinalize: jest.fn().mockResolvedValue(undefined), }; mockDequeue.mockResolvedValueOnce(task as ITaskResponse); - mockGetJob.mockResolvedValueOnce(job); + mockGetJob.mockResolvedValueOnce(job as unknown as IJobResponse); mockJobHandlerFactory.mockReturnValueOnce(mockHandler); const processPromise = jobProcessor.start(); @@ -121,6 +77,7 @@ describe('JobProcessor', () => { }); test.each(finalizeTestCases)('should process job of type $jobType and finalize task successfully', async ({ job, task }) => { + testContext = setupJobProcessorTest({ useMockQueueClient: true }); const { jobProcessor, mockDequeue, mockGetJob, mockJobHandlerFactory, configMock } = testContext; const dequeueIntervalMs = configMock.get('jobManagement.config.dequeueIntervalMs'); @@ -129,7 +86,7 @@ describe('JobProcessor', () => { handleJobFinalize: jest.fn().mockResolvedValue(undefined), }; mockDequeue.mockResolvedValueOnce(task as ITaskResponse); - mockGetJob.mockResolvedValueOnce(job); + mockGetJob.mockResolvedValueOnce(job as unknown as IJobResponse); mockJobHandlerFactory.mockReturnValueOnce(mockHandler); const processPromise = jobProcessor.start(); @@ -143,4 +100,47 @@ describe('JobProcessor', () => { expect(mockHandler.handleJobFinalize).toHaveBeenCalledWith(job); }); }); + + describe('getJobWithTaskType', () => { + test.each([...initTestCases, ...finalizeTestCases])( + 'dequeue $taskType task and get $jobType job with corresponding taskType', + async ({ jobType, taskType, job, task }) => { + jest.useRealTimers(); + + testContext = setupJobProcessorTest({ useMockQueueClient: false }); + + const { jobProcessor, configMock, queueClient } = testContext; + const jobManagerBaseUrl = configMock.get('jobManagement.config.jobManagerBaseUrl'); + const heartbeatBaseUrl = configMock.get('jobManagement.config.heartbeat.baseUrl'); + const consumeTaskUrl = `/tasks/${jobType}/${taskType}/startPending`; + const misMatchRegex = /^\/tasks\/[^/]+\/[^/]+\/startPending$/; + + nock.emitter.on('no match', () => { + nock(jobManagerBaseUrl).post(misMatchRegex).reply(404, undefined).persist(); + }); + + nock(jobManagerBaseUrl) + .post(consumeTaskUrl) + .reply(200, { ...task }) + .persist() + .get(`/jobs/${task.jobId}?shouldReturnTasks=false`) + .reply(200, { ...job }) + .persist(); + + nock(heartbeatBaseUrl).post(`/heartbeat/${task.id}`).reply(200, 'ok').persist(); + + const dequeueSpy = jest.spyOn(queueClient, 'dequeue'); + const getJobSpy = jest.spyOn(queueClient.jobManagerClient, 'getJob'); + + const jobAndTaskType = await jobProcessor['getJobWithTaskType'](); + + expect(dequeueSpy).toHaveBeenCalledWith(jobType, taskType); + expect(getJobSpy).toHaveBeenCalledWith(task.jobId); + expect(jobAndTaskType?.taskType).toEqual(taskType); + expect(jobAndTaskType?.job).toEqual(job); + + await queueClient.heartbeatClient.stop(task.id); + } + ); + }); }); diff --git a/tests/unit/jobProcessor/jobProcessorSetup.ts b/tests/unit/jobProcessor/jobProcessorSetup.ts index ce176ae..6909134 100644 --- a/tests/unit/jobProcessor/jobProcessorSetup.ts +++ b/tests/unit/jobProcessor/jobProcessorSetup.ts @@ -4,6 +4,7 @@ import { TaskHandler as QueueClient } from '@map-colonies/mc-priority-queue'; import { JobProcessor } from '../../../src/models/jobProcessor'; import { JobHandlerFactory } from '../../../src/models/jobHandlerFactory'; import { configMock } from '../mocks/configMock'; +import { IJobManagerConfig } from '../../../src/common/interfaces'; export type MockDequeue = jest.MockedFunction<(jobType: string, taskType: string) => Promise | null>>; export type MockGetJob = jest.MockedFunction<(jobId: string) => Promise>>; @@ -14,9 +15,10 @@ export interface JobProcessorTestContext { mockDequeue: MockDequeue; mockGetJob: MockGetJob; configMock: typeof configMock; + queueClient: QueueClient; } -export function setupJobProcessorTest(): JobProcessorTestContext { +export function setupJobProcessorTest({ useMockQueueClient = false }: { useMockQueueClient?: boolean }): JobProcessorTestContext { const mockLogger = jsLogger({ enabled: false }); const mockJobHandlerFactory = jest.fn(); @@ -31,13 +33,24 @@ export function setupJobProcessorTest(): JobProcessorTestContext { }, } as unknown as jest.Mocked; - const jobProcessor = new JobProcessor(mockLogger, configMock, mockJobHandlerFactory, mockQueueClient); + const jobManagerConfig = configMock.get('jobManagement.config'); + const queueClientInstance = new QueueClient( + mockLogger, + jobManagerConfig.jobManagerBaseUrl, + jobManagerConfig.heartbeat.baseUrl, + jobManagerConfig.dequeueIntervalMs, + jobManagerConfig.heartbeat.intervalMs + ); + + const queueClient = useMockQueueClient ? mockQueueClient : queueClientInstance; + const jobProcessor = new JobProcessor(mockLogger, configMock, mockJobHandlerFactory, queueClient); return { jobProcessor, mockJobHandlerFactory, mockDequeue, mockGetJob, configMock, + queueClient, }; } diff --git a/tests/unit/mocks/configMock.ts b/tests/unit/mocks/configMock.ts index 8c8ceae..080c876 100644 --- a/tests/unit/mocks/configMock.ts +++ b/tests/unit/mocks/configMock.ts @@ -81,9 +81,9 @@ const registerDefaultConfig = (): void => { }, jobManagement: { config: { - jobManagerBaseUrl: 'http://localhost:8081', + jobManagerBaseUrl: 'http://job-manager', heartbeat: { - baseUrl: 'http://localhost:8083', + baseUrl: 'http://heart-beat', intervalMs: 3000, }, dequeueIntervalMs: 3000, diff --git a/tests/unit/mocks/jobsMockData.ts b/tests/unit/mocks/jobsMockData.ts index cb1f3ba..f7720d9 100644 --- a/tests/unit/mocks/jobsMockData.ts +++ b/tests/unit/mocks/jobsMockData.ts @@ -1,8 +1,9 @@ -import { ProductType, Transparency } from '@map-colonies/mc-model-types'; -import { OperationStatus } from '@map-colonies/mc-priority-queue'; +import { NewRasterLayer, ProductType, Transparency, UpdateRasterLayer } from '@map-colonies/mc-model-types'; +import { IJobResponse, OperationStatus } from '@map-colonies/mc-priority-queue'; +import { PolygonPart } from '@map-colonies/mc-model-types'; /* eslint-disable @typescript-eslint/no-magic-numbers */ -const partData = [ +const partData: PolygonPart[] = [ { id: 'avi', name: 'string', @@ -24,14 +25,14 @@ const partData = [ description: 'string', resolutionMeter: 8000, resolutionDegree: 0.703125, - imagingTimeEndUTC: new Date('2024-01-28T13:47:43.427Z'), - imagingTimeBeginUTC: new Date('2024-01-28T13:47:43.427Z'), + imagingTimeEndUTC: '2024-01-28T13:47:43.427Z' as unknown as Date, + imagingTimeBeginUTC: '2024-01-28T13:47:43.427Z' as unknown as Date, sourceResolutionMeter: 8000, horizontalAccuracyCE90: 10, }, ]; -export const ingestionNewJob = { +export const ingestionNewJob: IJobResponse = { id: 'de57d743-3155-4a28-86c8-9c181faabd94', resourceId: 'some-product-id', version: '1.0', @@ -64,12 +65,12 @@ export const ingestionNewJob = { domain: 'RASTER', isCleaned: false, priority: 1000, - expirationDate: undefined, - internalId: undefined, - producerName: undefined, + expirationDate: '2024-07-21T10:59:23.510Z' as unknown as Date, + internalId: 'some-internal-id', + producerName: 'string', productName: 'akProduct', productType: ProductType.ORTHOPHOTO, - additionalIdentifiers: undefined, + additionalIdentifiers: 'some-additional-identifiers', taskCount: 1, completedTasks: 0, failedTasks: 0, @@ -81,7 +82,7 @@ export const ingestionNewJob = { updated: '2024-07-21T10:59:23.510Z', }; -export const ingestionUpdateJob = { +export const ingestionUpdateJob: IJobResponse = { id: 'd027b3aa-272b-4dc9-91d7-ba8343af5ed1', resourceId: 'another-product-id', version: '1.0', @@ -103,12 +104,12 @@ export const ingestionUpdateJob = { domain: 'RASTER', isCleaned: false, priority: 1000, - expirationDate: undefined, - internalId: undefined, - producerName: undefined, + expirationDate: '2024-07-21T10:59:23.510Z' as unknown as Date, + internalId: '2024-07-21T10:59:23.510Z', + producerName: 'string', productName: 'akProduct', productType: ProductType.ORTHOPHOTO, - additionalIdentifiers: undefined, + additionalIdentifiers: 'some-additional-identifiers', taskCount: 1, completedTasks: 0, failedTasks: 0, @@ -120,7 +121,7 @@ export const ingestionUpdateJob = { updated: '2024-07-21T10:59:23.510Z', }; -export const ingestionSwapUpdateJob = { +export const ingestionSwapUpdateJob: IJobResponse = { id: 'c023b3ba-272b-4dc9-92d7-ba8343af5ed9', resourceId: 'another-product-id', version: '1.0', @@ -142,12 +143,12 @@ export const ingestionSwapUpdateJob = { domain: 'RASTER', isCleaned: false, priority: 1000, - expirationDate: undefined, - internalId: undefined, - producerName: undefined, + expirationDate: '2024-07-21T10:59:23.510Z' as unknown as Date, + internalId: 'some-internal-id', + producerName: 'string', productName: 'akProduct', productType: ProductType.ORTHOPHOTO, - additionalIdentifiers: undefined, + additionalIdentifiers: 'some-additional-identifiers', taskCount: 1, completedTasks: 0, failedTasks: 0, diff --git a/tests/unit/mocks/tasksMockData.ts b/tests/unit/mocks/tasksMockData.ts index 16abaa6..7be0cdd 100644 --- a/tests/unit/mocks/tasksMockData.ts +++ b/tests/unit/mocks/tasksMockData.ts @@ -1,113 +1,114 @@ -export const initTaskForIngestionNew = { +import { ITaskResponse, OperationStatus } from '@map-colonies/mc-priority-queue'; + +//copied from Ingestion-Trigger, should be moved to a shared library (Mc-Models) +export interface IPollingTaskParameters { + blockDuplication?: boolean; +} + +export const initTaskForIngestionNew: ITaskResponse = { id: '4a5486bd-6269-4898-b9b1-647fe56d6ae2', type: 'init', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'de57d743-3155-4a28-86c8-9c181faabd94', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; -export const initTaskForIngestionUpdate = { +export const initTaskForIngestionUpdate: ITaskResponse = { id: 'c3f42c71-8324-4103-86ca-8f043645fdb8', type: 'init', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'd027b3aa-272b-4dc9-91d7-ba8343af5ed1', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; -export const initTaskForIngestionSwapUpdate = { +export const initTaskForIngestionSwapUpdate: ITaskResponse = { id: '018ccf1d-1adb-4c9e-8d80-1b311c6ad41f', type: 'init', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'c023b3ba-272b-4dc9-92d7-ba8343af5ed9', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; -export const finalizeTaskForIngestionNew = { +export const finalizeTaskForIngestionNew: ITaskResponse = { id: '4a5486bd-6269-4898-b9b1-647fe56d6ae2', type: 'finalize', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'de57d743-3155-4a28-86c8-9c181faabd94', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; -export const finalizeTaskForIngestionUpdate = { +export const finalizeTaskForIngestionUpdate: ITaskResponse = { id: 'c3f42c71-8324-4103-86ca-8f043645fdb8', type: 'finalize', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'd027b3aa-272b-4dc9-91d7-ba8343af5ed1', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; -export const finalizeTaskForIngestionSwapUpdate = { +export const finalizeTaskForIngestionSwapUpdate: ITaskResponse = { id: '018ccf1d-1adb-4c9e-8d80-1b311c6ad41f', type: 'finalize', description: '', parameters: { blockDuplication: true, }, - status: 'In-Progress', + status: OperationStatus.IN_PROGRESS, percentage: 0, reason: '', attempts: 0, jobId: 'c023b3ba-272b-4dc9-92d7-ba8343af5ed9', resettable: true, // eslint-disable-next-line @typescript-eslint/naming-convention - block_duplication: false, created: '2024-07-21T10:59:23.510Z', updated: '2024-07-24T07:43:10.528Z', }; diff --git a/tests/unit/mocks/testCasesData.ts b/tests/unit/mocks/testCasesData.ts new file mode 100644 index 0000000..95858b2 --- /dev/null +++ b/tests/unit/mocks/testCasesData.ts @@ -0,0 +1,58 @@ +import { IJobResponse, ITaskResponse } from '@map-colonies/mc-priority-queue'; +import { ingestionNewJob, ingestionUpdateJob } from '../mocks/jobsMockData'; +import { + finalizeTaskForIngestionNew, + finalizeTaskForIngestionSwapUpdate, + finalizeTaskForIngestionUpdate, + initTaskForIngestionNew, + initTaskForIngestionUpdate, + IPollingTaskParameters, +} from '../mocks/tasksMockData'; + +interface IngestionTestCase { + jobType: string; + taskType: string; + job: IJobResponse; + task: ITaskResponse; +} + +export const initTestCases: IngestionTestCase[] = [ + { + jobType: ingestionNewJob.type, + taskType: initTaskForIngestionNew.type, + job: ingestionNewJob, + task: initTaskForIngestionNew, + }, + { + jobType: ingestionUpdateJob.type, + taskType: initTaskForIngestionNew.type, + job: ingestionUpdateJob, + task: initTaskForIngestionUpdate, + }, + { + jobType: ingestionUpdateJob.type, + taskType: initTaskForIngestionNew.type, + job: ingestionUpdateJob, + task: initTaskForIngestionUpdate, + }, +]; +export const finalizeTestCases = [ + { + jobType: ingestionNewJob.type, + taskType: finalizeTaskForIngestionNew.type, + job: ingestionNewJob, + task: finalizeTaskForIngestionNew, + }, + { + jobType: ingestionUpdateJob.type, + taskType: finalizeTaskForIngestionUpdate.type, + job: ingestionUpdateJob, + task: finalizeTaskForIngestionUpdate, + }, + { + jobType: ingestionUpdateJob.type, + taskType: finalizeTaskForIngestionSwapUpdate.type, + job: ingestionUpdateJob, + task: finalizeTaskForIngestionSwapUpdate, + }, +];