New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS: Add fallback support in ${cf} and ${s3} #5758

Merged
merged 2 commits into from Jan 31, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+137 −1
Diff settings

Always

Just for now

Copy path View file
@@ -451,14 +451,19 @@ class Variables {
* in the given variable strings string. * in the given variable strings string.
*/ */
overwrite(variableStrings, variableMatch, propertyString) { overwrite(variableStrings, variableMatch, propertyString) {
// A sentinel to rid rejected Promises, so any of resolved value can be used as fallback.
const FAIL_TOKEN = {};
const variableValues = variableStrings.map(variableString => const variableValues = variableStrings.map(variableString =>
this.getValueFromSource(variableString, propertyString)); this.getValueFromSource(variableString, propertyString)
.catch(unused => FAIL_TOKEN)); // eslint-disable-line no-unused-vars

const validValue = value => ( const validValue = value => (
value !== null && value !== null &&
typeof value !== 'undefined' && typeof value !== 'undefined' &&
!(typeof value === 'object' && _.isEmpty(value)) !(typeof value === 'object' && _.isEmpty(value))
); );
return BbPromise.all(variableValues) return BbPromise.all(variableValues)
.then(values => values.filter(v => v !== FAIL_TOKEN))
.then(values => { .then(values => {
let deepPropertyString = variableMatch; let deepPropertyString = variableMatch;
let deepProperties = 0; let deepProperties = 0;
Copy path View file
@@ -124,6 +124,137 @@ describe('Variables', () => {
}); });
}); });
}); });

describe('fallback', () => {
it('should fallback if ${self} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${self:nonExistent, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

it('should fallback if ${opt} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${opt:nonExistent, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

it('should fallback if ${env} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${env:nonExistent, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

describe('file syntax', () => {
it('should fallback if file does not exist but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${file(~/config.yml):xyz, "fallback"}',
};

const fileExistsStub = sinon.stub(serverless.utils, 'fileExistsSync').returns(false);
const realpathSync = sinon.stub(fse, 'realpathSync').returns(`${os.homedir()}/config.yml`);

return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
}).finally(() => {
fileExistsStub.restore();
realpathSync.restore();
});
});

it('should fallback if file exists but given key not found and fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${file(~/config.yml):xyz, "fallback"}',
};

const fileExistsStub = sinon.stub(serverless.utils, 'fileExistsSync').returns(true);
const realpathSync = sinon.stub(fse, 'realpathSync').returns(`${os.homedir()}/config.yml`);
const readFileSyncStub = sinon.stub(serverless.utils, 'readFileSync').returns({
test: 1,
test2: 'test2',
});

return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
}).finally(() => {
fileExistsStub.restore();
realpathSync.restore();
readFileSyncStub.restore();
});
});
});

describe('aws-specific syntax', () => {
let awsProvider;
let requestStub;
beforeEach(() => {
awsProvider = new AwsProvider(serverless, {});
requestStub = sinon.stub(awsProvider, 'request', () =>
BbPromise.reject(new serverless.classes.Error('Not found.', 400)));
});
afterEach(() => {
requestStub.restore();
});
it('should fallback if ${s3} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${s3:bucket/key, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

it('should fallback if ${cf} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${cf:stack.value, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

it('should fallback if ${ssm} syntax fail to populate but fallback is provided', () => {
serverless.variables.service.custom = {
settings: '${ssm:/path/param, "fallback"}',
};
return serverless.variables.populateService().should.be.fulfilled.then((result) => {
expect(result.custom).to.be.deep.eql({
settings: 'fallback',
});
});
});

it('should throw an error if fallback fails too', () => {
serverless.variables.service.custom = {
settings: '${s3:bucket/key, ${ssm:/path/param}}',
};
return serverless.variables.populateService().should.be.rejected;
});
});
});

describe('#prepopulateService', () => { describe('#prepopulateService', () => {
// TL;DR: call populateService to test prepopulateService (note addition of 'pre') // TL;DR: call populateService to test prepopulateService (note addition of 'pre')
// //
ProTip! Use n and p to navigate between commits in a pull request.