Skip to content

Commit

Permalink
Merge 08e781d into 7ef271b
Browse files Browse the repository at this point in the history
  • Loading branch information
ianFar96 committed Nov 14, 2022
2 parents 7ef271b + 08e781d commit 9d24bc0
Show file tree
Hide file tree
Showing 6 changed files with 411 additions and 9 deletions.
31 changes: 25 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,31 @@ const baseSchema = {
},
}

function concatEnvSchemas(schema, otherSchema) {
return {
function mergeJsonSchemas(schema, otherSchema) {
const { properties: schemaProperties, ...schemaWithoutProperties } = schema
const { properties: otherSchemaProperties, ...otherSchemaWithoutProperties } = otherSchema
const mergedSchema = {
type: 'object',
required: schema.required.concat(otherSchema.required),
properties: {
...schema.properties,
...otherSchema.properties,
...schemaProperties,
...otherSchemaProperties,
},
allOf: [
schemaWithoutProperties,
otherSchemaWithoutProperties,
],
additionalProperties: false,
}
return mergedSchema
}

function getOverlappingKeys(properties, otherProperties) {
const propertiesNames = Object.keys(properties)
const otherPropertiesNames = Object.keys(otherProperties)
const overlappingProperties = propertiesNames.filter(propertyName =>
otherPropertiesNames.includes(propertyName)
)
return overlappingProperties
}

function getCustomHeaders(headersKeyToProxy, headers) {
Expand Down Expand Up @@ -291,7 +306,11 @@ const defaultSchema = { type: 'object', required: [], properties: {} }
function initCustomServiceEnvironment(envSchema = defaultSchema) {
return function customService(asyncInitFunction, serviceOptions) {
async function index(fastify, opts) {
fastify.register(fastifyEnv, { schema: concatEnvSchemas(baseSchema, envSchema), data: opts })
const overlappingPropertiesNames = getOverlappingKeys(baseSchema.properties, envSchema.properties)
if (overlappingPropertiesNames.length > 0) {
throw new Error(`The provided Environment JSON Schema includes properties declared in the Base JSON Schema of the custom-plugin-lib, please remove them from your schema. The properties to remove are: ${overlappingPropertiesNames.join(', ')}`)
}
fastify.register(fastifyEnv, { schema: mergeJsonSchemas(baseSchema, envSchema), data: opts })
fastify.register(fastifyFormbody)
fastify.register(fp(decorateRequestAndFastifyInstance), { asyncInitFunction, serviceOptions })
}
Expand Down
135 changes: 132 additions & 3 deletions tests/environment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ const baseEnv = {
MICROSERVICE_GATEWAY_SERVICE_NAME,
}

let fastify
async function setupFastify(filePath, envVariables) {
const fastify = await lc39(filePath, {
fastify = await lc39(filePath, {
logLevel: 'silent',
envVariables,
})
Expand All @@ -58,6 +59,10 @@ tap.test('Test Environment variables', test => {
const headersToTest = ['USERID_HEADER_KEY', 'GROUPS_HEADER_KEY', 'CLIENTTYPE_HEADER_KEY', 'BACKOFFICE_HEADER_KEY', 'MICROSERVICE_GATEWAY_SERVICE_NAME']
headersToTest.forEach(header => testEnvVariableIsNotEmptyString(test, header))

tap.afterEach(async() => {
if (fastify) { fastify.close() }
})

test.test('Should fail if required properties are missing', async assert => {
const { ...badEnv } = baseEnv
delete badEnv.USERID_HEADER_KEY
Expand Down Expand Up @@ -92,8 +97,132 @@ tap.test('Test Environment variables', test => {
MICROSERVICE_GATEWAY_SERVICE_NAME: '172.16.0.0',
}

const fastify = await setupFastify('./tests/services/plain-custom-service.js', options)
assert.ok(fastify)
await assert.resolves(async() => {
await setupFastify('./tests/services/plain-custom-service.js', options)
})

assert.end()
})

test.test('Should fail since BASE_REQUIRED_FIELD is not present and CONDITION_FIELD is true and CONDITION_TRUE_REQUIRED_FIELD is not present', async assert => {
const env = {
...baseEnv,
CONDITION_FIELD: true,
}

// NOTE: use try catch instead of assert.reject to customize error message assertion
assert.plan(1)
try {
await setupFastify('./tests/services/if-then-else-env-validation-custom-service.js', env)
} catch (error) {
const errorMessage = 'env must have required property \'CONDITION_TRUE_REQUIRED_FIELD\', env must match "then" schema, env must have required property \'BASE_REQUIRED_FIELD\''
assert.strictSame(error.message, errorMessage)
}

assert.end()
})

test.test('Should fail since CONDITION_FIELD is false and CONDITION_FALSE_REQUIRED_FIELD is not present', async assert => {
const env = {
...baseEnv,
CONDITION_FIELD: false,
}

// NOTE: use try catch instead of assert.reject to customize error message assertion
assert.plan(1)
try {
await setupFastify('./tests/services/if-then-else-env-validation-custom-service.js', env)
} catch (error) {
const errorMessage = 'env must have required property \'CONDITION_FALSE_REQUIRED_FIELD\', env must match "else" schema, env must have required property \'BASE_REQUIRED_FIELD\''
assert.strictSame(error.message, errorMessage)
}

assert.end()
})

test.test('Should pass since CONDITION_FIELD is true and CONDITION_FALSE_REQUIRED_FIELD is present', async assert => {
const env = {
...baseEnv,
BASE_REQUIRED_FIELD: 'some-value',
CONDITION_FIELD: true,
CONDITION_TRUE_REQUIRED_FIELD: 'some-value',
}

await assert.resolves(async() => {
await setupFastify('./tests/services/if-then-else-env-validation-custom-service.js', env)
})

assert.end()
})

test.test('Should fail since none of the anyOf required fields are present', async assert => {
// NOTE: use try catch instead of assert.reject to customize error message assertion
assert.plan(1)
try {
await setupFastify('./tests/services/any-of-env-validation-custom-service.js', baseEnv)
} catch (error) {
const errorMessage = 'env must have required property \'ANY_OF_REQUIRED_FIELD_1\', env must have required property \'ANY_OF_REQUIRED_FIELD_2\', env must match a schema in anyOf'
assert.strictSame(error.message, errorMessage)
}

assert.end()
})

test.test('Should pass since one of the anyOf required fields is present', async assert => {
const env = {
...baseEnv,
ANY_OF_REQUIRED_FIELD_1: 'some-value',
}

await assert.resolves(async() => {
await setupFastify('./tests/services/any-of-env-validation-custom-service.js', env)
})

assert.end()
})

test.test('Should fail since not all of the allOf required fields are present', async assert => {
const env = {
...baseEnv,
ALL_OF_REQUIRED_FIELD_1: 'some-value',
}

// NOTE: use try catch instead of assert.reject to customize error message assertion
assert.plan(1)
try {
await setupFastify('./tests/services/all-of-env-validation-custom-service.js', env)
} catch (error) {
const errorMessage = 'env must have required property \'ALL_OF_REQUIRED_FIELD_2\''
assert.strictSame(error.message, errorMessage)
}

assert.end()
})

test.test('Should pass since all of the allOf required fields are present', async assert => {
const env = {
...baseEnv,
ALL_OF_REQUIRED_FIELD_1: 'some-value',
ALL_OF_REQUIRED_FIELD_2: 'some-value',
}

await assert.resolves(async() => {
await setupFastify('./tests/services/all-of-env-validation-custom-service.js', env)
})

assert.end()
})

test.test('Should fail since the env has properties already present in the baseEnv of the lib', async assert => {
// NOTE: use try catch instead of assert.reject to customize error message assertion
assert.plan(1)
try {
await setupFastify('./tests/services/overlapping-env-validation-custom-service.js', baseEnv)
} catch (error) {
const errorMessage = 'The provided Environment JSON Schema includes properties declared in the Base JSON Schema of the custom-plugin-lib, please remove them from your schema. The properties to remove are: USERID_HEADER_KEY, USER_PROPERTIES_HEADER_KEY, GROUPS_HEADER_KEY, CLIENTTYPE_HEADER_KEY'
assert.strictSame(error.message, errorMessage)
}

assert.end()
})

Expand Down
60 changes: 60 additions & 0 deletions tests/services/all-of-env-validation-custom-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2019 Mia srl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict'

const fastifyRoutes = require('@fastify/routes')

const properties = {
ALL_OF_REQUIRED_FIELD_1: { type: 'string' },
ALL_OF_REQUIRED_FIELD_2: { type: 'string' },
}

const envJsonSchema = {
type: 'object',
properties,
required: [],
allOf: [
{
required: [
'ALL_OF_REQUIRED_FIELD_1',
],
},
{
required: [
'ALL_OF_REQUIRED_FIELD_2',
],
},
],
}

const customService = require('../../index')(envJsonSchema)

module.exports = customService(async function clientGroups(service) {
service.register(fastifyRoutes)
service.addRawCustomPlugin('GET', '/', (request, reply) => {
reply.send('Hello world!')
})
})

module.exports.healthinessHandler = async function healthinessHandler(fastify) {
fastify.assert.ok(fastify.getServiceProxy)
fastify.assert.ok(fastify.getHttpClient)
fastify.assert.ok(fastify.routes)
return {
statusOk: true,
}
}
60 changes: 60 additions & 0 deletions tests/services/any-of-env-validation-custom-service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2019 Mia srl
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict'

const fastifyRoutes = require('@fastify/routes')

const properties = {
ANY_OF_REQUIRED_FIELD_1: { type: 'string' },
ANY_OF_REQUIRED_FIELD_2: { type: 'string' },
}

const envJsonSchema = {
type: 'object',
properties,
required: [],
anyOf: [
{
required: [
'ANY_OF_REQUIRED_FIELD_1',
],
},
{
required: [
'ANY_OF_REQUIRED_FIELD_2',
],
},
],
}

const customService = require('../../index')(envJsonSchema)

module.exports = customService(async function clientGroups(service) {
service.register(fastifyRoutes)
service.addRawCustomPlugin('GET', '/', (request, reply) => {
reply.send('Hello world!')
})
})

module.exports.healthinessHandler = async function healthinessHandler(fastify) {
fastify.assert.ok(fastify.getServiceProxy)
fastify.assert.ok(fastify.getHttpClient)
fastify.assert.ok(fastify.routes)
return {
statusOk: true,
}
}
Loading

0 comments on commit 9d24bc0

Please sign in to comment.