2016-10-11 18:00:37 +07:00

382 lines
12 KiB
JavaScript

'use strict';
const sinon = require('sinon');
const BbPromise = require('bluebird');
const expect = require('chai').expect;
const Serverless = require('../../../Serverless');
const AwsSdk = require('../');
const proxyquire = require('proxyquire');
describe('AWS SDK', () => {
let awsSdk;
let serverless;
beforeEach(() => {
const options = {
stage: 'dev',
region: 'us-east-1',
};
serverless = new Serverless(options);
awsSdk = new AwsSdk(serverless, options);
awsSdk.serverless.cli = new serverless.classes.CLI();
});
describe('#constructor()', () => {
it('should set AWS instance', () => {
expect(typeof awsSdk.sdk).to.not.equal('undefined');
});
it('should set Serverless instance', () => {
expect(typeof awsSdk.serverless).to.not.equal('undefined');
});
it('should set AWS proxy', () => {
process.env.proxy = 'http://a.b.c.d:n';
const newAwsSdk = new AwsSdk(serverless);
expect(typeof newAwsSdk.sdk.config.httpOptions.agent).to.not.equal('undefined');
// clear env
delete process.env.proxy;
});
it('should set AWS timeout', () => {
process.env.AWS_CLIENT_TIMEOUT = '120000';
const newAwsSdk = new AwsSdk(serverless);
expect(typeof newAwsSdk.sdk.config.httpOptions.timeout).to.not.equal('undefined');
// clear env
delete process.env.AWS_CLIENT_TIMEOUT;
});
});
describe('#request()', () => {
it('should call correct aws method', () => {
// mocking S3 for testing
class FakeS3 {
constructor(credentials) {
this.credentials = credentials;
}
putObject() {
return {
send: (cb) => cb(null, { called: true }),
};
}
}
awsSdk.sdk = {
S3: FakeS3,
};
awsSdk.serverless.service.environment = {
vars: {},
stages: {
dev: {
vars: {
profile: 'default',
},
regions: {},
},
},
};
return awsSdk.request('S3', 'putObject', {}, 'dev', 'us-east-1').then(data => {
expect(data.called).to.equal(true);
});
});
it('should retry if error code is 429', function (done) {
this.timeout(10000);
let first = true;
const error = {
statusCode: 429,
message: 'Testing retry',
};
class FakeS3 {
constructor(credentials) {
this.credentials = credentials;
}
error() {
return {
send(cb) {
if (first) {
cb(error);
} else {
cb(undefined, {});
}
first = false;
},
};
}
}
awsSdk.sdk = {
S3: FakeS3,
};
awsSdk.request('S3', 'error', {}, 'dev', 'us-east-1')
.then(data => {
// eslint-disable-next-line no-unused-expressions
expect(data).to.exist;
// eslint-disable-next-line no-unused-expressions
expect(first).to.be.false;
done();
})
.catch(done);
});
it('should reject errors', (done) => {
const error = {
statusCode: 500,
message: 'Some error message',
};
class FakeS3 {
constructor(credentials) {
this.credentials = credentials;
}
error() {
return {
send(cb) {
cb(error);
},
};
}
}
awsSdk.sdk = {
S3: FakeS3,
};
awsSdk.request('S3', 'error', {}, 'dev', 'us-east-1')
.then(() => done('Should not succeed'))
.catch(() => done());
});
it('should return ref to docs for missing credentials', (done) => {
const error = {
statusCode: 403,
message: 'Missing credentials in config',
};
class FakeS3 {
constructor(credentials) {
this.credentials = credentials;
}
error() {
return {
send(cb) {
cb(error);
},
};
}
}
awsSdk.sdk = {
S3: FakeS3,
};
awsSdk.request('S3', 'error', {}, 'dev', 'us-east-1')
.then(() => done('Should not succeed'))
.catch((err) => {
expect(err.message).to.contain('https://git.io/viZAC');
done();
})
.catch(done);
});
});
describe('#getCredentials()', () => {
const mockCreds = (configParam) => {
const config = configParam;
delete config.credentials;
return config;
};
const awsStub = sinon.stub().returns();
const AwsSdkProxyquired = proxyquire('../index.js', {
'aws-sdk': awsStub,
});
let newAwsSdk;
beforeEach(() => {
newAwsSdk = new AwsSdkProxyquired(serverless);
});
it('should set region for credentials', () => {
const credentials = newAwsSdk.getCredentials('teststage', 'testregion');
expect(credentials.region).to.equal('testregion');
});
it('should get credentials from provider', () => {
serverless.service.provider.profile = 'notDefault';
const credentials = newAwsSdk.getCredentials();
expect(credentials.credentials.profile).to.equal('notDefault');
});
it('should not set credentials if empty profile is set', () => {
serverless.service.provider.profile = '';
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should not set credentials if credentials is an empty object', () => {
serverless.service.provider.credentials = {};
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should not set credentials if credentials has undefined values', () => {
serverless.service.provider.credentials = {
accessKeyId: undefined,
secretAccessKey: undefined,
sessionToken: undefined,
};
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should not set credentials if credentials has empty string values', () => {
serverless.service.provider.credentials = {
accessKeyId: '',
secretAccessKey: '',
sessionToken: '',
};
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should get credentials from provider declared credentials', () => {
const tmpAccessKeyID = process.env.AWS_ACCESS_KEY_ID;
const tmpAccessKeySecret = process.env.AWS_SECRET_ACCESS_KEY;
const tmpSessionToken = process.env.AWS_SESSION_TOKEN;
delete process.env.AWS_ACCESS_KEY_ID;
delete process.env.AWS_SECRET_ACCESS_KEY;
delete process.env.AWS_SESSION_TOKEN;
serverless.service.provider.credentials = {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey',
sessionToken: 'sessionToken',
};
const credentials = newAwsSdk.getCredentials('teststage', 'testregion');
expect(credentials.credentials).to.deep.eql(serverless.service.provider.credentials);
process.env.AWS_ACCESS_KEY_ID = tmpAccessKeyID;
process.env.AWS_SECRET_ACCESS_KEY = tmpAccessKeySecret;
process.env.AWS_SESSION_TOKEN = tmpSessionToken;
});
it('should get credentials from environment declared for-all-stages credentials', () => {
const prevVal = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_SESSION_TOKEN,
};
const testVal = {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey',
sessionToken: 'sessionToken',
};
process.env.AWS_ACCESS_KEY_ID = testVal.accessKeyId;
process.env.AWS_SECRET_ACCESS_KEY = testVal.secretAccessKey;
process.env.AWS_SESSION_TOKEN = testVal.sessionToken;
const credentials = newAwsSdk.getCredentials('teststage', 'testregion');
process.env.AWS_ACCESS_KEY_ID = prevVal.accessKeyId;
process.env.AWS_SECRET_ACCESS_KEY = prevVal.secretAccessKey;
process.env.AWS_SESSION_TOKEN = prevVal.sessionToken;
expect(credentials.credentials).to.deep.eql(testVal);
});
it('should get credentials from environment declared stage specific credentials', () => {
const prevVal = {
accessKeyId: process.env.AWS_TESTSTAGE_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_TESTSTAGE_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_TESTSTAGE_SESSION_TOKEN,
};
const testVal = {
accessKeyId: 'accessKeyId',
secretAccessKey: 'secretAccessKey',
sessionToken: 'sessionToken',
};
process.env.AWS_TESTSTAGE_ACCESS_KEY_ID = testVal.accessKeyId;
process.env.AWS_TESTSTAGE_SECRET_ACCESS_KEY = testVal.secretAccessKey;
process.env.AWS_TESTSTAGE_SESSION_TOKEN = testVal.sessionToken;
const credentials = newAwsSdk.getCredentials('teststage', 'testregion');
process.env.AWS_TESTSTAGE_ACCESS_KEY_ID = prevVal.accessKeyId;
process.env.AWS_TESTSTAGE_SECRET_ACCESS_KEY = prevVal.secretAccessKey;
process.env.AWS_TESTSTAGE_SESSION_TOKEN = prevVal.sessionToken;
expect(credentials.credentials).to.deep.eql(testVal);
});
it('should not set credentials if profile is not set', () => {
serverless.service.provider.profile = undefined;
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should not set credentials if empty profile is set', () => {
serverless.service.provider.profile = '';
const credentials = mockCreds(newAwsSdk.getCredentials('teststage', 'testregion'));
expect(credentials).to.eql({ region: 'testregion' });
});
it('should get credentials from provider declared profile', () => {
serverless.service.provider.profile = 'notDefault';
const credentials = newAwsSdk.getCredentials();
expect(credentials.credentials.profile).to.equal('notDefault');
});
it('should get credentials from environment declared for-all-stages profile', () => {
const prevVal = process.env.AWS_PROFILE;
process.env.AWS_PROFILE = 'notDefault';
const credentials = newAwsSdk.getCredentials();
process.env.AWS_PROFILE = prevVal;
expect(credentials.credentials.profile).to.equal('notDefault');
});
it('should get credentials from environment declared stage-specific profile', () => {
const prevVal = process.env.AWS_TESTSTAGE_PROFILE;
process.env.AWS_TESTSTAGE_PROFILE = 'notDefault';
const credentials = newAwsSdk.getCredentials('teststage', 'testregion');
process.env.AWS_TESTSTAGE_PROFILE = prevVal;
expect(credentials.credentials.profile).to.equal('notDefault');
});
});
describe('#getServerlessDeploymentBucketName', () => {
it('should return the name of the serverless deployment bucket', () => {
const options = {
stage: 'dev',
region: 'us-east-1',
};
const describeStackResourcesStub = sinon
.stub(awsSdk, 'request')
.returns(BbPromise.resolve({
StackResourceDetail: {
PhysicalResourceId: 'serverlessDeploymentBucketName',
},
}));
return awsSdk.getServerlessDeploymentBucketName(options.stage, options.region)
.then((bucketName) => {
expect(describeStackResourcesStub.calledOnce).to.be.equal(true);
expect(describeStackResourcesStub.calledWith(options.stage, options.region));
expect(describeStackResourcesStub.args[0][0]).to.equal('CloudFormation');
expect(describeStackResourcesStub.args[0][1]).to.equal('describeStackResource');
expect(describeStackResourcesStub.args[0][2].StackName)
.to.equal(`${awsSdk.serverless.service.service}-${options.stage}`);
expect(bucketName).to.equal('serverlessDeploymentBucketName');
awsSdk.request.restore();
});
});
});
describe('#getStackName', () => {
it('should return the stack name', () => {
serverless.service.service = 'myservice';
expect(awsSdk.getStackName('dev')).to.equal('myservice-dev');
});
});
});