Skip to content
This repository has been archived by the owner on Apr 16, 2022. It is now read-only.

Fn::Select #104

Merged
merged 11 commits into from
Feb 15, 2018
4 changes: 3 additions & 1 deletion data/aws_intrinsic_functions.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"Fn::ImportValue": {"supportedFunctions": ["Fn::Base64", "Fn::FindInMap", "Fn::If", "Fn::Join", "Fn::Select", "Fn::Split", "Fn::Sub", "Fn::Ref"]},
"Fn::Join": {},
"Fn::Select": {},
"Fn::Select::Index": {"supportedFunctions": ["Ref", "Fn::FindInMap"]},
"Fn::Select::List": {"supportedFunctions" : ["Fn::FindInMap", "Fn::GetAtt", "Fn::GetAZs", "Fn::If", "Fn::Split", "Ref"] },
"Fn::Split": {},
"Fn::Sub": { "supportedFunctions": ["Fn::Base64", "Fn::FindInMap", "Fn::GetAtt", "Fn::GetAZs", "Fn::If", "Fn::Join", "Fn::Select", "Ref"]},
"Ref": {}
}
}
6 changes: 3 additions & 3 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function cleanupYaml(ref: any){
let key = Object.keys(ref)[i];

// Resolve the function
if(ref[key].hasOwnProperty('class') && ref[key].hasOwnProperty('data')){
if( ref[key] !== null && ref[key].hasOwnProperty('class') && ref[key].hasOwnProperty('data')){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that I needed to make a couple of changes to the parser to block the script from trying to parse out null entries in yaml arrays.


// We have a Yaml generated object

Expand Down Expand Up @@ -96,12 +96,12 @@ function cleanupYaml(ref: any){
ref[key] = {};
ref[key][outputKeyName] = outputData;

}else if(key != 'Attributes' && typeof ref[key] == "object"){
}else if(key != 'Attributes' && typeof ref[key] == "object" && ref[key] !== null){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here too.

The result of this was that I had to modify the invalid json doc, so that it would also be invalid yaml

lastPlaceInTemplate = ref;
lastKeyInTemplate = key;
cleanupYaml(ref[key]);
}


}
}
}
243 changes: 242 additions & 1 deletion src/test/validatorTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,247 @@ describe('validator', () => {
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['warn']).to.have.lengthOf(1);
});
describe('Fn::Select', () => {
it("should pass validation, with flat list and intrinsic list", () => {
const input = require('../../testData/valid/json/5_valid_intrinsic_select.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['crit']).to.have.lengthOf(0);
expect(result['errors']['warn']).to.have.lengthOf(0);
});
it("should pass validation with Parameter Collection", () => {
const input = require('../../testData/valid/json/5_valid_intrinsic_select_2.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['crit']).to.have.lengthOf(0);
expect(result['errors']['warn']).to.have.lengthOf(0);
});


it("should error if index is greater than list size", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_1.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element is not a list or a function", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_2.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is not a number or does not parse to a number", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_3.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is not defined or is null", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_4.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if only one element as argument list", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_5.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element is null or undefined", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_6.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element does not resolve to a list", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_7.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element does not resolve to a number", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_8.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element attempts an invalid intrinsic function", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_9.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is anything other than non-array object, number or string", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_10.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would also be good to ensure the YAML shorthand is working as expected.

AvailabilityZone: !Select 
  - 0
  - !GetAZs 
    Ref: 'AWS::Region'

AvailabilityZone: !Select 
  - 0
  - Fn::GetAZs: !Ref 'AWS::Region'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep


it("should error if second element attempts an invalid intrinsic function", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_11.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element contains a list with null values", () => {
const input = require('../../testData/invalid/json/5_invalid_intrinsic_select_12.json');
let result = validator.validateJsonObject(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
// console.log(result['errors']['crit'][0]['message']);
});

});


});

describe('Fn::Select', () => {
it('should validate in yaml with literal and intrinic elements in array', () => {
const input = './testData/valid/yaml/5_valid_intrinsic_select.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['crit']).to.have.lengthOf(0);
expect(result['errors']['warn']).to.have.lengthOf(0);


});

it('should validate in yaml with Comma Separated List Param', () => {
const input = './testData/valid/yaml/5_valid_intrinsic_select_2.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', true);
expect(result['errors']['crit']).to.have.lengthOf(0);
expect(result['errors']['warn']).to.have.lengthOf(0);


});


it("should error if index is greater than list size", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_1.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element is not a list or a function", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_2.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is not a number or does not parse to a number", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_3.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is not defined or is null", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_4.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if only one element as argument list", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_5.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element is null or undefined", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_6.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element does not resolve to a list", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_7.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element does not resolve to a number", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_8.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element attempts an invalid intrinsic function", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_9.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if first element is anything other than non-array object, number or string", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_10.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});

it("should error if second element attempts an invalid intrinsic function", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_11.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});
it("should error if second element contains a list with null values", () => {
const input = './testData/invalid/yaml/5_invalid_intrinsic_select_12.yaml';
let result = validator.validateFile(input);
expect(result).to.have.deep.property('templateValid', false);
expect(result['errors']['crit']).to.have.lengthOf(1);
expect(result['errors']['warn']).to.have.lengthOf(0);
console.log(result['errors']['crit'][0]['message']);
});



});

Expand Down Expand Up @@ -836,4 +1077,4 @@ describe('validator', () => {

})
});
});
});
Loading