Skip to content

Commit

Permalink
Melhoria nas validações e novos testes (#28)
Browse files Browse the repository at this point in the history
* fix: 🐛 Modificações realizadas nas funções validate(),  checkErrorsPerSchema(), checkMissingProperty(), revalidateSchema()

- validate():Criei uma variavel booleana(objTreated) para auxiliar na validação dos objetos.

- checkErrorsPerSchema():Criei uma variavel booleana(itemTreated) que verifica se aquele
item do objeto já teve seu erro tratado.

- checkMissingProperty():Utiliza a variavel objTreated para verificar se
  aquele objeto já teve seu erro tratado.

- revalidateSchema():Implementei uma verificação que valida se aquele
  objeto já teve seu erro tratado e então defini o valor da variavel
  objTreated.

* perf: ⚡ Implementado novos testes unitários e melhorias nos logs

Adicionado testes caixa preta para a funcão validate

Co-authored-by: Gabriel Tellaroli Ramos <[email protected]>
  • Loading branch information
joaquimsn and Gabriel-Tellaroli committed Apr 23, 2021
1 parent 8529899 commit 26b583c
Show file tree
Hide file tree
Showing 11 changed files with 709 additions and 32 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/codacy-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.

name: Codacy Security Scan
name: Codacy

on: ['push']

jobs:
codacy-security-scan:
name: Codacy Security Scan
name: Codacy Analysis
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
Expand All @@ -21,7 +21,7 @@ jobs:

# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@2.0.1
uses: codacy/codacy-analysis-cli-action@3.0.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/format-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Lint and format
on: ['push']
jobs:
format:
name: Lint and format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -19,7 +20,7 @@ jobs:
npm ci
npm run format
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4.1.2
uses: stefanzweifel/git-auto-commit-action@v4.10.0
with:
commit_message: 'style: :lipstick: Apply formatting changes'
branch: ${{ github.head_ref }}
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ name: Test
on: [push, pull_request]
jobs:
run:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand Down
82 changes: 57 additions & 25 deletions datalayer-validation-core.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const schemaParser = require('./schema-parser');
const Ajv = require('ajv');
const debugging = process.env.PENGUIN_DEBUGGING || false;
const debugging = process.env.PENGUIN_DEBUGGING;
let fullValidation = [];
let objTreated;
let itemTreated;
let partialError = { occurrences: 0, trace: '' };

const ajv = new Ajv({
schemaId: 'auto',
Expand All @@ -26,6 +29,7 @@ function validationResult(status, message, dlObject, objectName, keyName) {
dataLayerObject: dlObject,
objectName: objectName,
keyName: keyName,
partialError: partialError,
});
}

Expand Down Expand Up @@ -58,41 +62,54 @@ function checkValidEvent(schemaItem, dataLayer) {
*/
function revalidateSchema(shadowSchema, errorMessage, dataLayer, schemaIndex, schemaArray, dlObj) {
let tempObj = JSON.parse(JSON.stringify(dataLayer));
let innerSchema = JSON.parse(JSON.stringify(shadowSchema)); //ajustei o innerSchema pra receber o objeto como uma nova instância, e não por referência
let verify_required = Object.keys(innerSchema).indexOf('required'); //Verifica se existe required dentro do innerSchema
let innerSchema = JSON.parse(JSON.stringify(shadowSchema));
let verify_required = Object.keys(innerSchema).indexOf('required');

if (verify_required == -1) {
let found = innerSchema.contains.required.indexOf(errorMessage.params.missingProperty);

if (found > -1) {
dlObjProperty = errorMessage.params.missingProperty;

innerSchema.contains.required = innerSchema.contains.required.filter((keyword) => keyword === dlObjProperty); //Então agora ele passa a remover do required todas as propriedades que não são iguais à que está dentro do tempObj
innerSchema.contains.required = innerSchema.contains.required.filter((keyword) => keyword === dlObjProperty);

for (prop in innerSchema.contains.properties) {
if (prop !== dlObjProperty) {
delete innerSchema.contains.properties[prop];
} //e faz o mesmo com as propriedades do schema pra igualar e deixar ele somente com o que precisa ser validado
}
}

let isInnerSchemaEmpty =
Object.entries(innerSchema.contains.properties).length === 0 && dataLayer.constructor === Object; //um safe check pra garantir que o objeto não ficou vazio
Object.entries(innerSchema.contains.properties).length === 0 && dataLayer.constructor === Object;

if (
innerSchema.contains.required.length > 0 &&
!isInnerSchemaEmpty &&
/*ajv.validate(innerSchema, tempObj) &&*/ Object.keys(innerSchema.contains.properties)[0] !== 'event'
Object.keys(innerSchema.contains.properties)[0] !== 'event'
) {
//essa validação tava cagada pq ele tava validando o event no nível de base e fodendo com a porra toda. Isso ainda pode ser um problema mais pra frente se alguém
validationResult(
'ERROR',
`Hit sent without the following property: ${errorMessage.params.missingProperty}`,
JSON.stringify(dlObj, null, 2),
'',
errorMessage.params.missingProperty
);
if (errorMessage.dataPath.indexOf(Object.keys(schemaArray[schemaIndex].properties)[1]) > -1) {
schemaArray.splice(schemaIndex, 1);
try {
let schemaItemKeys = Object.keys(schemaArray[schemaIndex].properties);
if (errorMessage.dataPath.indexOf(schemaItemKeys[1]) > -1) {
if (errorMessage.dataPath.indexOf('[0]') > -1) {
schemaArray.splice(schemaIndex, 1);
objTreated = true;
}
}
} catch (e) {
if (schemaArray[schemaIndex] == undefined) {
partialError.occurrences++;
partialError.trace = e;
trace(e);
} else {
trace('Objeto ' + errorMessage.dataPath + ' já teve seu erro tratado!!');
}
}
}
} else {
Expand All @@ -109,7 +126,7 @@ function revalidateSchema(shadowSchema, errorMessage, dataLayer, schemaIndex, sc
}
}
} else {
let found = innerSchema.required.indexOf(errorMessage.params.missingProperty); //ainda mantive esse laço que checa se o schema interno tem a propriedade descrita na mensagem de erro filtrada
let found = innerSchema.required.indexOf(errorMessage.params.missingProperty);

if (found > -1) {
//e caso o valor seja encontrado
Expand All @@ -118,34 +135,41 @@ function revalidateSchema(shadowSchema, errorMessage, dataLayer, schemaIndex, sc
} else {
dlObjProperty = Object.keys(tempObj)[0];
}
innerSchema.required = innerSchema.required.filter((keyword) => keyword === dlObjProperty); //Então agora ele passa a remover do required todas as propriedades que não são iguais à que está dentro do tempObj
innerSchema.required = innerSchema.required.filter((keyword) => keyword === dlObjProperty);

for (prop in innerSchema.properties) {
if (prop !== dlObjProperty) {
delete innerSchema.properties[prop];
} //e faz o mesmo com as propriedades do schema pra igualar e deixar ele somente com o que precisa ser validado
}
}
let isInnerSchemaEmpty = Object.entries(innerSchema.properties).length === 0 && dataLayer.constructor === Object; //um safe check pra garantir que o objeto não ficou vazio
let isInnerSchemaEmpty = Object.entries(innerSchema.properties).length === 0 && dataLayer.constructor === Object;

if (
innerSchema.required.length > 0 &&
!isInnerSchemaEmpty &&
/*ajv.validate(innerSchema, tempObj) &&*/ Object.keys(innerSchema.properties)[0] !== 'event'
Object.keys(innerSchema.properties)[0] !== 'event'
) {
//essa validação tava cagada pq ele tava validando o event no nível de base e fodendo com a porra toda. Isso ainda pode ser um problema mais pra frente se alguém
validationResult(
'ERROR',
`Hit "${errorMessage.dataPath}" sent without the following property: ${errorMessage.params.missingProperty}`,
JSON.stringify(dlObj, null, 2),
errorMessage.dataPath,
errorMessage.params.missingProperty
);
// TODO: Avaliar melhor essa lógica
if (
schemaIndex < schemaArray.length &&
errorMessage.dataPath.indexOf(Object.keys(schemaArray[schemaIndex].properties)[1]) > -1
) {
schemaArray.splice(schemaIndex, 1);
try {
let schemaItemKeys = Object.keys(schemaArray[schemaIndex].properties);
if (errorMessage.dataPath.indexOf(schemaItemKeys[1]) > -1) {
schemaArray.splice(schemaIndex, 1);
objTreated = true;
}
} catch (e) {
if (schemaArray[schemaIndex] == undefined) {
partialError.occurrences++;
partialError.trace = e;
trace(e);
} else {
trace('Objeto ' + errorMessage.dataPath + ' já teve seu erro tratado!!');
}
}
}
} else {
Expand Down Expand Up @@ -175,7 +199,7 @@ function checkMissingProperty(schemaItem, dataLayer) {
let errors = ajv.errors;

trace(`retorno ajv ${JSON.stringify(array)}`);
if (!valid) {
if (!valid && !objTreated) {
errors
.filter((error) => error.schema.constructor === Object && error.keyword === 'required')
.map((eachError) => {
Expand Down Expand Up @@ -206,10 +230,13 @@ function checkMissingProperty(schemaItem, dataLayer) {
* @param {*} dataLayer
*/
function checkErrorsPerSchema(schemaItem, dataLayer) {
itemTreated = false;
schemaItem.forEach((item, index) => {
let valid = ajv.validate(item, dataLayer);
let errors = ajv.errors;

if (itemTreated) return;

if (!valid && item.required[1] == Object.keys(dataLayer)[1]) {
errors
.filter((error) => {
Expand Down Expand Up @@ -254,6 +281,7 @@ function checkErrorsPerSchema(schemaItem, dataLayer) {
}
});
schemaItem.splice(index, 1);
itemTreated = true;
}
});
}
Expand Down Expand Up @@ -281,12 +309,16 @@ let validate = (schema, dataLayer, callback) => {
let schemaItem = schema.array.items;
let isSchemaEmpty = schemaItem.length === 0;
let isObjEmpty = Object.entries(dataLayer).length === 0 && dataLayer.constructor === Object;
objTreated = false;
itemTreated = false;

if (isSchemaEmpty) {
validationResult('ERROR', `No more items to validate`, JSON.stringify(dataLayer));
} else if (!checkValidEvent(schemaItem, dataLayer) && !isObjEmpty) {
checkMissingProperty(schemaItem, dataLayer);
checkErrorsPerSchema(schemaItem, dataLayer);
if (!objTreated) {
checkErrorsPerSchema(schemaItem, dataLayer);
}
} else if (isObjEmpty) {
checkMissingEvents(schemaItem, dataLayer);
}
Expand All @@ -300,7 +332,7 @@ let validate = (schema, dataLayer, callback) => {
* @param {Object} log Que será apresentado no stdout
*/
function trace(log) {
if (debugging) {
if (debugging === 'true') {
console.log(log);
}
}
Expand Down
Loading

0 comments on commit 26b583c

Please sign in to comment.