diff --git a/tests/api.v2/helpers/pipeline/pipelineConstruct/__snapshots__/qcHelpers.test.js.snap b/tests/api.v2/helpers/pipeline/pipelineConstruct/__snapshots__/qcHelpers.test.js.snap index 58ef2f283..8fff7e473 100644 --- a/tests/api.v2/helpers/pipeline/pipelineConstruct/__snapshots__/qcHelpers.test.js.snap +++ b/tests/api.v2/helpers/pipeline/pipelineConstruct/__snapshots__/qcHelpers.test.js.snap @@ -1,5 +1,73 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`helper functions for skeletons returns configureEmbedding only if the config has no changes and the previous run failed 1`] = ` +Object { + "ConfigureEmbedding": Object { + "Next": "EndOfPipeline", + "XCatch": Array [ + Object { + "ErrorEquals": Array [ + "States.ALL", + ], + "Next": "HandleError", + "ResultPath": "$.errorInfo", + }, + ], + "XConstructorArgs": Object { + "perSample": false, + "taskName": "configureEmbedding", + }, + "XStepType": "create-new-step", + }, + "DataIntegration": Object { + "Next": "ConfigureEmbedding", + "XCatch": Array [ + Object { + "ErrorEquals": Array [ + "States.ALL", + ], + "Next": "HandleError", + "ResultPath": "$.errorInfo", + }, + ], + "XConstructorArgs": Object { + "perSample": false, + "taskName": "dataIntegration", + "uploadCountMatrix": true, + }, + "XStepType": "create-new-step", + }, + "DoubletScoresFilterMap": Object { + "Catch": Array [ + Object { + "ErrorEquals": Array [ + "States.ALL", + ], + "Next": "HandleError", + "ResultPath": "$.errorInfo", + }, + ], + "ItemsPath": "$.samples", + "Iterator": Object { + "StartAt": "DoubletScoresFilter", + "States": Object { + "DoubletScoresFilter": Object { + "End": true, + "XConstructorArgs": Object { + "perSample": true, + "taskName": "doubletScores", + }, + "XStepType": "create-new-step", + }, + }, + }, + "Next": "DataIntegration", + "ResultPath": null, + "Type": "Map", + }, +} +`; + exports[`helper functions for skeletons returns from first not-completed step if the config has changes after that 1`] = ` Object { "CellSizeDistributionFilterMap": Object { @@ -180,7 +248,7 @@ Object { } `; -exports[`helper functions for skeletons returns from first not-completed step if the config has no changes 1`] = ` +exports[`helper functions for skeletons returns from first not-completed step if the config has no changes and the previous run failed 1`] = ` Object { "ConfigureEmbedding": Object { "Next": "EndOfPipeline", diff --git a/tests/api.v2/helpers/pipeline/pipelineConstruct/qcHelpers.test.js b/tests/api.v2/helpers/pipeline/pipelineConstruct/qcHelpers.test.js index 812baf087..72e07dfe0 100644 --- a/tests/api.v2/helpers/pipeline/pipelineConstruct/qcHelpers.test.js +++ b/tests/api.v2/helpers/pipeline/pipelineConstruct/qcHelpers.test.js @@ -3,10 +3,19 @@ const { getQcStepsToRun } = require('../../../../../src/api.v2/helpers/pipeline/ const { buildQCPipelineSteps } = require('../../../../../src/api.v2/helpers/pipeline/pipelineConstruct/skeletons/qcPipelineSkeleton'); const fake = require('../../../../test-utils/constants'); +const CellLevelMeta = require('../../../../../src/api.v2/model/CellLevelMeta'); +const ExperimentExecution = require('../../../../../src/api.v2/model/ExperimentExecution'); + jest.mock('../../../../../src/api.v2/helpers/s3/fileExists', () => ({ fileExists: jest.fn(() => true), })); +jest.mock('../../../../../src/api.v2/model/CellLevelMeta'); +jest.mock('../../../../../src/api.v2/model/ExperimentExecution'); + +const cellLevelMetaInstance = new CellLevelMeta(); +const experimentExecutionInstance = new ExperimentExecution(); + const processingConfig = [ { name: 'numGenesVsNumUmis', @@ -103,6 +112,18 @@ const processingConfig = [ }, ]; +const mockCellLevelMetadataCheck = (currentCellLevelMetadataId, previousRunCellLevelMetadataId) => { + cellLevelMetaInstance.getMetadataByExperimentIds.mockReturnValueOnce( + Promise.resolve([{ id: currentCellLevelMetadataId }]), + ); + + experimentExecutionInstance.find.mockReturnValueOnce({ + first: () => Promise.resolve( + { lastPipelineParams: { cellMetadataId: previousRunCellLevelMetadataId } }, + ), + }); +}; + describe('helper functions for skeletons', () => { it('returns the first changed step if it is before all the completed steps', async () => { const completedSteps = ['ClassifierFilter']; @@ -120,7 +141,21 @@ describe('helper functions for skeletons', () => { expect(stateMachine).toMatchSnapshot(); }); - it('returns from first not-completed step if the config has no changes', async () => { + it('returns from first not-completed step if the config has no changes and the previous run failed', async () => { + const completedSteps = [ + 'ClassifierFilter', + 'CellSizeDistributionFilter', + 'MitochondrialContentFilter', + 'NumGenesVsNumUmisFilter', + ]; + + const qcSteps = await getQcStepsToRun(fake.EXPERIMENT_ID, [], completedSteps, 'FAILED'); + expect(qcSteps[0]).toEqual('DoubletScoresFilterMap'); + const stateMachine = buildQCPipelineSteps(qcSteps); + expect(stateMachine).toMatchSnapshot(); + }); + + it('returns configureEmbedding only if the config has no changes and the previous run failed', async () => { const completedSteps = [ 'ClassifierFilter', 'CellSizeDistributionFilter', @@ -128,9 +163,22 @@ describe('helper functions for skeletons', () => { 'NumGenesVsNumUmisFilter', ]; - const qcSteps = await getQcStepsToRun(fake.EXPERIMENT_ID, [], completedSteps); + const qcSteps = await getQcStepsToRun(fake.EXPERIMENT_ID, [], completedSteps, 'FAILED'); expect(qcSteps[0]).toEqual('DoubletScoresFilterMap'); const stateMachine = buildQCPipelineSteps(qcSteps); expect(stateMachine).toMatchSnapshot(); }); + + it('Throws if the config has no changes', async () => { + mockCellLevelMetadataCheck('sameCellLevelId', 'sameCellLevelId'); + + const completedSteps = [ + 'ClassifierFilter', + 'CellSizeDistributionFilter', + 'MitochondrialContentFilter', + 'NumGenesVsNumUmisFilter', + ]; + + expect(async () => await getQcStepsToRun(fake.EXPERIMENT_ID, [], completedSteps, 'SUCCEEDED')).rejects.toThrow(); + }); });