From 88c6aa745d61020d32640dc8c1664ddb5fc4f1eb Mon Sep 17 00:00:00 2001 From: Alfred Rosenthal Date: Fri, 12 Jan 2024 16:27:44 -0800 Subject: [PATCH] fixed various tests, added region repo test --- .../submission/published.test.ts | 6 +- .../submission/reviewed.test.ts | 6 +- .../submission/unreviewed.test.ts | 6 +- .../submission/{datasetId}/handlebar.test.ts | 28 ---------- .../repositories/region-repository.test.ts | 56 +++++++++++++++++++ api/src/repositories/region-repository.ts | 21 ++++--- .../submission-repository.test.ts | 21 ------- api/src/services/submission-service.test.ts | 38 ++++--------- 8 files changed, 93 insertions(+), 89 deletions(-) create mode 100644 api/src/repositories/region-repository.test.ts diff --git a/api/src/paths/administrative/submission/published.test.ts b/api/src/paths/administrative/submission/published.test.ts index ee0d95a2f..37eb34776 100644 --- a/api/src/paths/administrative/submission/published.test.ts +++ b/api/src/paths/administrative/submission/published.test.ts @@ -64,7 +64,8 @@ describe('getPublishedSubmissionsForAdmins', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -82,7 +83,8 @@ describe('getPublishedSubmissionsForAdmins', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.PARTIALLY_SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ]; diff --git a/api/src/paths/administrative/submission/reviewed.test.ts b/api/src/paths/administrative/submission/reviewed.test.ts index 17fdbc8ba..58afa1dde 100644 --- a/api/src/paths/administrative/submission/reviewed.test.ts +++ b/api/src/paths/administrative/submission/reviewed.test.ts @@ -64,7 +64,8 @@ describe('getReviewedSubmissionsForAdmins', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -82,7 +83,8 @@ describe('getReviewedSubmissionsForAdmins', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.PARTIALLY_SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ]; diff --git a/api/src/paths/administrative/submission/unreviewed.test.ts b/api/src/paths/administrative/submission/unreviewed.test.ts index 077c828af..e409c8ae3 100644 --- a/api/src/paths/administrative/submission/unreviewed.test.ts +++ b/api/src/paths/administrative/submission/unreviewed.test.ts @@ -64,7 +64,8 @@ describe('getUnreviewedSubmissionsForAdmins', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.PENDING, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -82,7 +83,8 @@ describe('getUnreviewedSubmissionsForAdmins', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.PENDING, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ]; diff --git a/api/src/paths/dwc/submission/{datasetId}/handlebar.test.ts b/api/src/paths/dwc/submission/{datasetId}/handlebar.test.ts index eddfc41f9..8e32c7194 100644 --- a/api/src/paths/dwc/submission/{datasetId}/handlebar.test.ts +++ b/api/src/paths/dwc/submission/{datasetId}/handlebar.test.ts @@ -3,8 +3,6 @@ import { describe } from 'mocha'; import sinon from 'sinon'; import sinonChai from 'sinon-chai'; import * as db from '../../../../database/db'; -import { HTTPError } from '../../../../errors/http-error'; -import { SubmissionService } from '../../../../services/submission-service'; import { getMockDBConnection, getRequestHandlerMocks } from '../../../../__mocks__/db'; import { getHandleBarsTemplateByDatasetId } from './handlebar'; @@ -20,10 +18,6 @@ describe('handlebar', () => { const dbConnectionObj = getMockDBConnection(); sinon.stub(db, 'getDBConnection').returns(dbConnectionObj); - sinon - .stub(SubmissionService.prototype, 'getHandleBarsTemplateByDatasetId') - .resolves({ header: 'hedaer', details: 'details' }); - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); mockReq.params = { @@ -36,27 +30,5 @@ describe('handlebar', () => { expect(mockRes.statusValue).to.equal(200); }); - - it('catches and re-throws an error', async () => { - const dbConnectionObj = getMockDBConnection(); - sinon.stub(db, 'getDBConnection').returns(dbConnectionObj); - - sinon.stub(SubmissionService.prototype, 'getHandleBarsTemplateByDatasetId').rejects(new Error('a test error')); - - const { mockReq, mockRes, mockNext } = getRequestHandlerMocks(); - - mockReq.params = { - datasetId: 'abcd' - }; - - try { - const requestHandler = getHandleBarsTemplateByDatasetId(); - - await requestHandler(mockReq, mockRes, mockNext); - expect.fail(); - } catch (actualError) { - expect((actualError as HTTPError).message).to.equal('a test error'); - } - }); }); }); diff --git a/api/src/repositories/region-repository.test.ts b/api/src/repositories/region-repository.test.ts new file mode 100644 index 000000000..6b15dbd2f --- /dev/null +++ b/api/src/repositories/region-repository.test.ts @@ -0,0 +1,56 @@ +import chai, { expect } from 'chai'; +import { describe } from 'mocha'; +import { QueryResult } from 'pg'; +import sinon from 'sinon'; +import sinonChai from 'sinon-chai'; +import { getMockDBConnection } from '../__mocks__/db'; +import { RegionRepository } from './region-repository'; + +chai.use(sinonChai); + +describe('RegionRepository', () => { + describe('getRegions', () => { + afterEach(() => { + sinon.restore(); + }); + + it('returns an array of region records', async () => { + const mockQueryResponse = { rowCount: 1, rows: [{ region_id: 1 }] } as any as Promise>; + const connection = getMockDBConnection({ + sql: () => mockQueryResponse + }); + + const repo = new RegionRepository(connection); + + const regions = await repo.getRegions(); + expect(regions.length).to.greaterThanOrEqual(1); + }); + }); + + describe('calculateRegionsForASubmission', () => { + it('should succeed without issue', async () => { + const mockQueryResponse = { rowCount: 1, rows: [{ region_id: 1 }] } as any as Promise>; + const connection = getMockDBConnection({ + sql: () => mockQueryResponse + }); + const repo = new RegionRepository(connection); + + const regions = await repo.calculateRegionsForASubmission(1); + + expect(regions).to.be.eql([{ region_id: 1 }]); + }); + }); + + describe('insertSubmissionRegions', () => { + it('should return early with no regions', async () => { + const connection = getMockDBConnection({ + sql: sinon.mock() + }); + + const repo = new RegionRepository(connection); + await repo.insertSubmissionRegions(1, []); + + expect(connection.sql).to.not.be.called; + }); + }); +}); diff --git a/api/src/repositories/region-repository.ts b/api/src/repositories/region-repository.ts index 872c82c15..90da3206e 100644 --- a/api/src/repositories/region-repository.ts +++ b/api/src/repositories/region-repository.ts @@ -46,19 +46,23 @@ export class RegionRepository extends BaseRepository { /** * Calculates region intersects for a submission search_spatial data. * Submission spatial data is collected then converted into a single polygon using ST_ConvexHull (https://postgis.net/docs/ST_ConvexHull.html) + * Intersections are calculated based on area coverage passed in through intersectionThreshold * Any regions intersecting with this calculated value are returned. * * @param {number} submissionId * @param {number} [regionAccuracy=1] regionAccuracy Expected 0-1. Determines the percentage of rows to use + * @param {number} [intersectThreshold=1] intersectThreshold Expected 0-1. Determines the percentage threshold for intersections to be valid * @returns {*} {Promise<{region_id: number}}[]>} An array of found region ids * @memberof RegionRepository */ async calculateRegionsForASubmission( submissionId: number, - regionAccuracy: number = 1 + regionAccuracy: number = 1, + intersectThreshold: number = 1 ): Promise<{ region_id: number }[]> { const sql = SQL` - WITH submission_spatial_point AS ( + -- Get a percentage of search_spatial rows for a given + with submission_spatial_point as ( SELECT * FROM search_spatial ORDER BY RANDOM() @@ -66,16 +70,17 @@ export class RegionRepository extends BaseRepository { SELECT CEIL(${regionAccuracy} * COUNT(*)) FROM search_spatial ss, submission_feature sf WHERE ss.submission_feature_id = sf.submission_feature_id - AND sf.submission_id = ${submissionId}) + AND sf.submission_id = ${submissionId} + ) ) - SELECT rl.region_id + SELECT rl.region_id , rl.region_name FROM region_lookup rl - WHERE st_intersects(rl.geography, ( - SELECT ST_ConvexHull(st_collect(ssp.value::geometry)) + WHERE ST_Intersects_With_Tolerance(rl.geography::geometry, ( + SELECT ST_ConvexHull(st_collect(ss.value::geometry)) FROM submission_spatial_point ssp, submission_feature sf WHERE ssp.submission_feature_id = sf.submission_feature_id - AND sf.submission_id = ${submissionId} - )) + AND sf.submission_id = ${submissionId} + )::geometry, ${intersectThreshold}) GROUP BY rl.region_name, rl.region_id; `; const response = await this.connection.sql(sql); diff --git a/api/src/repositories/submission-repository.test.ts b/api/src/repositories/submission-repository.test.ts index daec8f4fc..1028fbc1e 100644 --- a/api/src/repositories/submission-repository.test.ts +++ b/api/src/repositories/submission-repository.test.ts @@ -19,7 +19,6 @@ import { SUBMISSION_MESSAGE_TYPE, SUBMISSION_STATUS_TYPE } from './submission-repository'; -import { simsHandlebarsTemplate_DETAILS, simsHandlebarsTemplate_HEADER } from './templates/SIMS-handlebar-template'; chai.use(sinonChai); @@ -883,26 +882,6 @@ describe('SubmissionRepository', () => { }); }); - describe('getHandleBarsTemplateByDatasetId', () => { - beforeEach(() => { - sinon.restore(); - }); - - it('should succeed with valid data', async () => { - const mockResponse = { - header: simsHandlebarsTemplate_HEADER, - details: simsHandlebarsTemplate_DETAILS - }; - const mockDBConnection = getMockDBConnection(); - - const submissionRepository = new SubmissionRepository(mockDBConnection); - - const response = await submissionRepository.getHandleBarsTemplateByDatasetId('uuid'); - - expect(response).to.eql(mockResponse); - }); - }); - describe('getUnreviewedSubmissionsForAdmins', () => { beforeEach(() => { sinon.restore(); diff --git a/api/src/services/submission-service.test.ts b/api/src/services/submission-service.test.ts index 591afd95f..2fc894b1c 100644 --- a/api/src/services/submission-service.test.ts +++ b/api/src/services/submission-service.test.ts @@ -744,26 +744,6 @@ describe('SubmissionService', () => { }); }); - describe('getHandleBarsTemplateByDatasetId', () => { - it('should succeed with valid data', async () => { - const mockDBConnection = getMockDBConnection(); - const submissionService = new SubmissionService(mockDBConnection); - - const repo = sinon.stub(SubmissionRepository.prototype, 'getHandleBarsTemplateByDatasetId').resolves({ - header: 'header', - details: 'details' - }); - - const response = await submissionService.getHandleBarsTemplateByDatasetId('uuid'); - - expect(repo).to.be.calledOnce; - expect(response).to.be.eql({ - header: 'header', - details: 'details' - }); - }); - }); - describe('getUnreviewedSubmissionsForAdmins', () => { it('should return an array of submission records', async () => { const mockSubmissionRecords: SubmissionRecordWithSecurityAndRootFeatureType[] = [ @@ -783,7 +763,8 @@ describe('SubmissionService', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.PENDING, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -801,7 +782,8 @@ describe('SubmissionService', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.PENDING, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ]; @@ -839,7 +821,8 @@ describe('SubmissionService', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.UNSECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -857,7 +840,8 @@ describe('SubmissionService', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ]; @@ -895,7 +879,8 @@ describe('SubmissionService', () => { revision_count: 0, security: SECURITY_APPLIED_STATUS.UNSECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] }, { submission_id: 2, @@ -913,7 +898,8 @@ describe('SubmissionService', () => { revision_count: 1, security: SECURITY_APPLIED_STATUS.SECURED, root_feature_type_id: 1, - root_feature_type_name: 'dataset' + root_feature_type_name: 'dataset', + regions: [] } ];