Skip to content

Commit

Permalink
[BIOMAGE-999] Add unit tests for the gem2s API point (#150)
Browse files Browse the repository at this point in the history
* Add gem2s.test.js (modelled on pipeline.test.js)

* Replace double with single quotes in spec

* Improve coverage

* Add test for invalid notification

* Add test for gem2s pipeline creation

* Reorder mocks

* Avoid using stringify unnecessarily

* Fix typos
  • Loading branch information
robioson authored and ivababukova committed Jul 19, 2021
1 parent 2bacbd3 commit d64e4d6
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 16 deletions.
3 changes: 3 additions & 0 deletions src/api/route-services/__mocks__/experiment.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ const mockUpdateProcessingConfig = jest.fn(
}),
);

const mockSaveGem2sHandle = jest.fn(() => {});

const mock = jest.fn().mockImplementation(() => ({
getExperimentData: mockExperimentData,
deleteExperiment: mockDeleteExperiment,
Expand All @@ -118,6 +120,7 @@ const mock = jest.fn().mockImplementation(() => ({
updateCellSets: mockUpdateCellSets,
getProcessingConfig: mockGetProcessingConfig,
updateProcessingConfig: mockUpdateProcessingConfig,
saveGem2sHandle: mockSaveGem2sHandle,
experimentsTableName: 'experiments-test',
}));

Expand Down
8 changes: 4 additions & 4 deletions src/specs/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ paths:
'200':
description: OK
description: Deletes a plot and table for a given experiment with the data specified.
"/experiments/{experimentId}/gem2s":
'/experiments/{experimentId}/gem2s':
parameters:
- schema:
type: string
Expand All @@ -570,15 +570,15 @@ paths:
x-eov-operation-id: gem2s#create
x-eov-operation-handler: routes/gem2s
responses:
"200":
'200':
description: OK
content:
application/json:
schema:
type: object
properties: {}
description: This path will create a new pipeline that can run a state machine with gem2s tasks.
"/experiments/{experimentId}/pipelines": # this should be changed to /qc at some point
'/experiments/{experimentId}/pipelines': # this should be changed to /qc at some point
parameters:
- schema:
type: string
Expand Down Expand Up @@ -940,4 +940,4 @@ paths:
content:
application/json:
schema:
$ref: ./models/HTTPError.v1.yaml
$ref: ./models/HTTPError.v1.yaml
179 changes: 179 additions & 0 deletions tests/api/routes/gem2s.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
const express = require('express');
const request = require('supertest');
const https = require('https');
const _ = require('lodash');

const logger = require('../../../src/utils/logging');
const expressLoader = require('../../../src/loaders/express');
const CacheSingleton = require('../../../src/cache');
const gem2sResponse = require('../../../src/api/route-services/gem2s-response');
const { createGem2SPipeline } = require('../../../src/api/general-services/pipeline-manage');

jest.mock('sns-validator');
jest.mock('aws-xray-sdk');
jest.mock('../../../src/utils/authMiddlewares');
jest.mock('../../../src/utils/logging');
jest.mock('../../../src/cache');
jest.mock('../../../src/api/route-services/gem2s-response');
jest.mock('../../../src/api/general-services/pipeline-manage');
jest.mock('../../../src/api/route-services/experiment');

const basicMsg = {
MessageId: 'da8827d4-ffc2-5efb-82c1-70f929b2081d',
ResponseMetadata: {
RequestId: '826314a1-e99f-5fe7-b845-438c3fef9901',
HTTPStatusCode: 200,
HTTPHeaders: {
'x-amzn-requestid': '826314a1-e99f-5fe7-b845-438c3fef9901',
'content-type': 'text/xml',
'content-length': '294',
date: 'Thu, 07 May 2020 09:26:08 GMT',
},
RetryAttempts: 0,
},
};


describe('tests for gem2s route', () => {
let app = null;

beforeEach(async () => {
CacheSingleton.createMock({});

const mockApp = await expressLoader(express());
app = mockApp.app;
});

afterEach(() => {
logger.log.mockClear();
logger.error.mockClear();
jest.clearAllMocks();
});

it('Can handle valid notifications', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'Notification';
validMsg = JSON.stringify(validMsg);

gem2sResponse.mockImplementation(() => { });

await request(app)
.post('/v1/gem2sResults')
.send(validMsg)
.set('Content-type', 'text/plain')
.expect(200)
.expect('ok');

expect(logger.error).toHaveBeenCalledTimes(0);
expect(gem2sResponse).toHaveBeenCalledTimes(1);
});

it('Returns nok for invalid notifications', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'Notification';
validMsg = JSON.stringify(validMsg);

gem2sResponse.mockImplementation(() => { throw new Error(); });

await request(app)
.post('/v1/gem2sResults')
.send(validMsg)
.set('Content-type', 'text/plain')
.expect(200)
.expect('nok');

expect(logger.error).toHaveBeenCalled();
expect(gem2sResponse).toHaveBeenCalledTimes(1);
});

it('Validating the response throws an error', async () => {
const invalidMsg = JSON.stringify(basicMsg);
https.get = jest.fn();

await request(app)
.post('/v1/gem2sResults')
.send(invalidMsg)
.set('Content-type', 'text/plain')
.expect(200)
.expect('nok');

expect(logger.error).toHaveBeenCalled();
expect(https.get).toHaveBeenCalledTimes(0);
});

it('Can handle message subscription', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'SubscriptionConfirmation';
validMsg = JSON.stringify(validMsg);

https.get = jest.fn();

await request(app)
.post('/v1/gem2sResults')
.send(validMsg)
.set('Content-type', 'text/plain')
.expect(200);

expect(logger.error).toHaveBeenCalledTimes(0);
expect(https.get).toHaveBeenCalledTimes(1);
});

it('Can handle message unsubscription', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'UnsubscribeConfirmation';
validMsg = JSON.stringify(validMsg);

https.get = jest.fn();

await request(app)
.post('/v1/gem2sResults')
.send(validMsg)
.set('Content-type', 'text/plain')
.expect(200);

expect(logger.error).toHaveBeenCalledTimes(0);
expect(https.get).toHaveBeenCalledTimes(1);
});

it('Returns an error for malformed work', async () => {
const brokenMsg = '';

await request(app)
.post('/v1/gem2sResults')
.send(brokenMsg)
.set('Content-type', 'text/plain')
.expect(200)
.expect('nok');
});

it('Returns an error when message in sns is malformed', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'NotificationMalformed';
validMsg = JSON.stringify(validMsg);

gem2sResponse.mockImplementation(() => { });

await request(app)
.post('/v1/gem2sResults')
.send(validMsg)
.set('Content-type', 'text/plain')
.expect(200)
.expect('nok');

expect(logger.error).toHaveBeenCalled();
});

it('Creates a new pipeline for gem2s execution', async (done) => {
createGem2SPipeline.mockReturnValue({});

request(app)
.post('/v1/experiments/someId/gem2s')
.expect(200)
.end((err) => {
if (err) {
return done(err);
}
return done();
});
});
});
23 changes: 11 additions & 12 deletions tests/api/routes/pipelines.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

const express = require('express');
const request = require('supertest');
const https = require('https');
Expand All @@ -12,7 +11,7 @@ jest.mock('aws-xray-sdk');
jest.mock('../../../src/utils/logging');
jest.mock('../../../src/cache');

const basicMsg = JSON.stringify({
const basicMsg = {
MessageId: 'da8827d4-ffc2-5efb-82c1-70f929b2081d',
ResponseMetadata: {
RequestId: '826314a1-e99f-5fe7-b845-438c3fef9901',
Expand All @@ -25,7 +24,7 @@ const basicMsg = JSON.stringify({
},
RetryAttempts: 0,
},
});
};


describe('PipelineResults route', () => {
Expand All @@ -44,7 +43,7 @@ describe('PipelineResults route', () => {
});

it('Can handle notifications', async () => {
let validMsg = _.cloneDeep(JSON.parse(basicMsg));
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'Notification';
validMsg = JSON.stringify(validMsg);

Expand All @@ -62,7 +61,7 @@ describe('PipelineResults route', () => {
});

it('Validating the response throws an error', async () => {
const invalidMsg = _.cloneDeep(basicMsg);
const invalidMsg = JSON.stringify(basicMsg);
https.get = jest.fn();

await request(app)
Expand All @@ -76,8 +75,8 @@ describe('PipelineResults route', () => {
expect(https.get).toHaveBeenCalledTimes(0);
});

it('Can handle message subscribtion', async () => {
let validMsg = _.cloneDeep(JSON.parse(basicMsg));
it('Can handle message subscription', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'SubscriptionConfirmation';
validMsg = JSON.stringify(validMsg);

Expand All @@ -93,8 +92,8 @@ describe('PipelineResults route', () => {
expect(https.get).toHaveBeenCalledTimes(1);
});

it('Can handle message unsubscribtion', async () => {
let validMsg = _.cloneDeep(JSON.parse(basicMsg));
it('Can handle message unsubscription', async () => {
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'UnsubscribeConfirmation';
validMsg = JSON.stringify(validMsg);

Expand All @@ -110,8 +109,8 @@ describe('PipelineResults route', () => {
expect(https.get).toHaveBeenCalledTimes(1);
});

it('Get malformatted work results returns an error', async () => {
const brokenMsg = JSON.stringify();
it('Returns an error for malformed work', async () => {
const brokenMsg = '';

await request(app)
.post('/v1/pipelineResults')
Expand All @@ -122,7 +121,7 @@ describe('PipelineResults route', () => {
});

it('Returns an error when message in sns is malformed', async () => {
let validMsg = _.cloneDeep(JSON.parse(basicMsg));
let validMsg = _.cloneDeep(basicMsg);
validMsg.Type = 'NotificationMalformed';
validMsg = JSON.stringify(validMsg);

Expand Down

0 comments on commit d64e4d6

Please sign in to comment.