From 96ec6fed26b640f2fa3c9156076ae04c2d98a897 Mon Sep 17 00:00:00 2001 From: Dylan Mendelowitz Date: Wed, 23 Jun 2021 16:03:56 -0400 Subject: [PATCH 1/2] Adding config file validator --- src/application/app.js | 8 ++------ src/helpers/configValidator.js | 17 +++++++++++++++++ src/helpers/schemas/config.schema.json | 2 +- test/application/app.test.js | 12 +++++++----- test/helpers/configValidator.test.js | 24 ++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 src/helpers/configValidator.js create mode 100644 test/helpers/configValidator.test.js diff --git a/src/application/app.js b/src/application/app.js index d61761c4..1908649c 100644 --- a/src/application/app.js +++ b/src/application/app.js @@ -7,6 +7,7 @@ const { sendEmailNotification, zipErrors } = require('./tools/emailNotifications const { extractDataForPatients } = require('./tools/mcodeExtraction'); const { maskMRN } = require('../helpers/patientUtils'); const { parsePatientIds } = require('../helpers/appUtils'); +const { validateConfig } = require('../helpers/configValidator'); function getConfig(pathToConfig) { // Checks pathToConfig points to valid JSON file @@ -20,7 +21,7 @@ function getConfig(pathToConfig) { function checkInputAndConfig(config, fromDate, toDate) { // Check input args and needed config variables based on client being used - const { patientIdCsvPath } = config; + validateConfig(config); // Check if `fromDate` is a valid date if (fromDate && !moment(fromDate).isValid()) { @@ -31,11 +32,6 @@ function checkInputAndConfig(config, fromDate, toDate) { if (toDate && !moment(toDate).isValid()) { throw new Error('-t/--to-date is not a valid date.'); } - - // Check if there is a path to the MRN CSV within our config JSON - if (!patientIdCsvPath) { - throw new Error('patientIdCsvPath is required in config file'); - } } async function mcodeApp(Client, fromDate, toDate, pathToConfig, pathToRunLogs, debug, allEntries) { diff --git a/src/helpers/configValidator.js b/src/helpers/configValidator.js new file mode 100644 index 00000000..a31d4806 --- /dev/null +++ b/src/helpers/configValidator.js @@ -0,0 +1,17 @@ +const Ajv = require('ajv'); +const metaSchema = require('ajv/lib/refs/json-schema-draft-06.json'); +const configSchema = require('./schemas/config.schema.json'); + +const ajv = new Ajv({ logger: false, allErrors: true }); +ajv.addMetaSchema(metaSchema); +const validator = ajv.addSchema(configSchema, 'config'); + +function validateConfig(config) { + const valid = validator.validate('config', config); + const errors = ajv.errorsText(validator.errors, { dataVar: 'config' }); + if (!valid) throw new Error(`Error(s) found in config file: ${errors}`); +} + +module.exports = { + validateConfig, +}; diff --git a/src/helpers/schemas/config.schema.json b/src/helpers/schemas/config.schema.json index ebe678a7..8df6e9ff 100644 --- a/src/helpers/schemas/config.schema.json +++ b/src/helpers/schemas/config.schema.json @@ -1,6 +1,6 @@ { "$id": "csv-config", - "$schema": "https://json-schema.org/draft/2020-12/schema", + "$schema": "http://json-schema.org/draft-06/schema#", "description": "Schema for mcode-extraction-framework config files", "type": "object", "properties": { diff --git a/test/application/app.test.js b/test/application/app.test.js index 18a2bf8d..86897761 100644 --- a/test/application/app.test.js +++ b/test/application/app.test.js @@ -20,17 +20,19 @@ describe('App Tests', () => { }); describe('checkInputAndConfig', () => { + const config = { patientIdCsvPath: '', extractors: [] }; it('should throw error when fromDate is invalid.', () => { - expect(() => checkInputAndConfig(testConfig, '2020-06-31')).toThrowError('-f/--from-date is not a valid date.'); + expect(() => checkInputAndConfig(config, '2020-06-31')).toThrowError('-f/--from-date is not a valid date.'); }); it('should throw error when toDate is invalid date.', () => { - expect(() => checkInputAndConfig(testConfig, '2020-06-30', '2020-06-31')).toThrowError('-t/--to-date is not a valid date.'); + expect(() => checkInputAndConfig(config, '2020-06-30', '2020-06-31')).toThrowError('-t/--to-date is not a valid date.'); }); - it('should throw error when patientIdCsvPath not provided in config', () => { - expect(() => checkInputAndConfig({})).toThrowError('patientIdCsvPath is required in config file'); + it('should throw error when config is not valid', () => { + expect(() => checkInputAndConfig({})) + .toThrowError('Error(s) found in config file: config should have required property \'patientIdCsvPath\', config should have required property \'extractors\''); }); it('should not throw error when all args are valid', () => { - expect(() => checkInputAndConfig(testConfig, '2020-06-01', '2020-06-30')).not.toThrowError(); + expect(() => checkInputAndConfig(config, '2020-06-01', '2020-06-30')).not.toThrowError(); }); }); }); diff --git a/test/helpers/configValidator.test.js b/test/helpers/configValidator.test.js new file mode 100644 index 00000000..456783a7 --- /dev/null +++ b/test/helpers/configValidator.test.js @@ -0,0 +1,24 @@ +const { validateConfig } = require('../../src/helpers/configValidator.js'); + +describe('validateConfig', () => { + const missingPropertyConfig = { patientIdCsvPath: '' }; + const wrongTypeConfig = { patientIdCsvPath: '', extractors: 12 }; + const wrongFormatConfig = { patientIdCsvPath: '', extractors: [], commonExtractorArgs: { baseFhirUrl: 'wrong' } }; + const validConfig = { patientIdCsvPath: '', extractors: [] }; + + test('Should throw error when config file is missing required property', () => { + expect(() => validateConfig(missingPropertyConfig)).toThrowError('Error(s) found in config file: config should have required property \'extractors\''); + }); + + test('Should throw error when property is of incorrect type', () => { + expect(() => validateConfig(wrongTypeConfig)).toThrowError('Error(s) found in config file: config.extractors should be array'); + }); + + test('Should throw error when property has incorrect format', () => { + expect(() => validateConfig(wrongFormatConfig)).toThrowError('Error(s) found in config file: config.commonExtractorArgs.baseFhirUrl should match format "uri"'); + }); + + test('Should not throw error when config file is valid', () => { + expect(() => validateConfig(validConfig)).not.toThrow(); + }); +}); From 058d331eb7218b3990f75e8b09aa778e43ad30cb Mon Sep 17 00:00:00 2001 From: Dylan Mendelowitz Date: Mon, 28 Jun 2021 11:48:18 -0400 Subject: [PATCH 2/2] Adding debug level logs about config validation --- src/helpers/configValidator.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/helpers/configValidator.js b/src/helpers/configValidator.js index a31d4806..6aca537b 100644 --- a/src/helpers/configValidator.js +++ b/src/helpers/configValidator.js @@ -1,5 +1,6 @@ const Ajv = require('ajv'); const metaSchema = require('ajv/lib/refs/json-schema-draft-06.json'); +const logger = require('./logger'); const configSchema = require('./schemas/config.schema.json'); const ajv = new Ajv({ logger: false, allErrors: true }); @@ -7,9 +8,11 @@ ajv.addMetaSchema(metaSchema); const validator = ajv.addSchema(configSchema, 'config'); function validateConfig(config) { + logger.debug('Validating config file'); const valid = validator.validate('config', config); const errors = ajv.errorsText(validator.errors, { dataVar: 'config' }); if (!valid) throw new Error(`Error(s) found in config file: ${errors}`); + logger.debug('Config file validated successfully'); } module.exports = {