'use strict'; /* eslint-disable no-unused-expressions */ const AwsProvider = require('../provider/awsProvider'); const AwsDeploy = require('./index'); const chai = require('chai'); const Serverless = require('../../../Serverless'); const sinon = require('sinon'); const path = require('path'); // Configure chai chai.use(require('chai-as-promised')); chai.use(require('sinon-chai')); const expect = require('chai').expect; describe('AwsDeploy', () => { let awsDeploy; let serverless; let options; beforeEach(() => { serverless = new Serverless(); options = { stage: 'dev', region: 'us-east-1', }; serverless.setProvider('aws', new AwsProvider(serverless, options)); serverless.config.servicePath = 'foo'; awsDeploy = new AwsDeploy(serverless, options); }); describe('#constructor()', () => { it('should set the serverless instance', () => { expect(awsDeploy.serverless).to.equal(serverless); }); it('should set options', () => { expect(awsDeploy.options).to.equal(options); }); it('should set the service path if provided', () => { expect(awsDeploy.servicePath).to.equal('foo'); }); it('should default to an empty service path if not provided', () => { serverless.config.servicePath = false; awsDeploy = new AwsDeploy(serverless, options); expect(awsDeploy.servicePath).to.equal(''); }); it('should use the options package path if provided', () => { options.package = 'package-options'; awsDeploy = new AwsDeploy(serverless, options); expect(awsDeploy.packagePath).to.equal('package-options'); }); it('should use the services package path if provided', () => { serverless.service = { package: { path: 'package-service', }, }; awsDeploy = new AwsDeploy(serverless, options); expect(awsDeploy.packagePath).to.equal('package-service'); }); it('should default to the .serverless directory as the package path', () => { expect(awsDeploy.packagePath).to.equal(path.join('foo', '.serverless')); }); it('should set the provider variable to an instance of AwsProvider', () => expect(awsDeploy.provider).to.be.instanceof(AwsProvider)); it('should have commands', () => expect(awsDeploy.commands).to.be.not.empty); it('should have hooks', () => expect(awsDeploy.hooks).to.be.not.empty); }); describe('hooks', () => { let spawnStub; let createStackStub; let setBucketNameStub; let checkForChangesStub; beforeEach(() => { spawnStub = sinon.stub(serverless.pluginManager, 'spawn'); createStackStub = sinon.stub(awsDeploy, 'createStack').resolves(); setBucketNameStub = sinon.stub(awsDeploy, 'setBucketName').resolves(); checkForChangesStub = sinon.stub(awsDeploy, 'checkForChanges').resolves(); }); afterEach(() => { serverless.pluginManager.spawn.restore(); awsDeploy.createStack.restore(); awsDeploy.setBucketName.restore(); awsDeploy.checkForChanges.restore(); }); describe('"before:deploy:deploy" hook', () => { let existsDeploymentBucketStub; let extendedValidateStub; let spawnPackageStub; let spawnAwsCommonValidateStub; let spawnAwsCommonMoveArtifactsToTemp; beforeEach(() => { extendedValidateStub = sinon.stub(awsDeploy, 'extendedValidate').resolves(); existsDeploymentBucketStub = sinon.stub(awsDeploy, 'existsDeploymentBucket').resolves(); spawnPackageStub = spawnStub.withArgs('package').resolves(); spawnAwsCommonValidateStub = spawnStub.withArgs('aws:common:validate').resolves(); spawnAwsCommonMoveArtifactsToTemp = spawnStub .withArgs('aws:common:moveArtifactsToTemp') .resolves(); }); afterEach(() => { awsDeploy.extendedValidate.restore(); }); it('should use the default packaging mechanism if no packaging config is provided', () => { awsDeploy.options.package = false; awsDeploy.serverless.service.package.path = false; return awsDeploy.hooks['before:deploy:deploy']().then(() => { expect(spawnAwsCommonValidateStub.calledOnce).to.equal(true); expect(extendedValidateStub.calledAfter(spawnAwsCommonValidateStub)).to.equal(true); expect(spawnAwsCommonMoveArtifactsToTemp.calledOnce).to.equal(false); }); }); it('should move the artifacts to the tmp dir if options based config is provided', () => { awsDeploy.options.package = true; awsDeploy.serverless.service.package.path = false; return awsDeploy.hooks['before:deploy:deploy']().then(() => { expect(spawnAwsCommonValidateStub.calledOnce).to.equal(true); expect( spawnAwsCommonMoveArtifactsToTemp.calledAfter(spawnAwsCommonValidateStub) ).to.equal(true); expect(extendedValidateStub.calledAfter(spawnAwsCommonMoveArtifactsToTemp)).to.equal( true ); expect(spawnPackageStub.calledOnce).to.equal(false); }); }); it('should move the artifacts to the tmp dir if service based config is provided', () => { awsDeploy.options.package = false; awsDeploy.serverless.service.package.path = true; return awsDeploy.hooks['before:deploy:deploy']().then(() => { expect(spawnAwsCommonValidateStub.calledOnce).to.equal(true); expect( spawnAwsCommonMoveArtifactsToTemp.calledAfter(spawnAwsCommonValidateStub) ).to.equal(true); expect(extendedValidateStub.calledAfter(spawnAwsCommonMoveArtifactsToTemp)).to.equal( true ); expect(spawnPackageStub.calledOnce).to.equal(false); }); }); it('should be called existsDeploymentBucket method if deploymentBucket is provided', () => { const bucketName = 'com.serverless.deploys'; awsDeploy.serverless.service.provider.deploymentBucket = bucketName; awsDeploy.options.package = true; awsDeploy.serverless.service.package.path = false; return awsDeploy.hooks['before:deploy:deploy']().then(() => { expect(spawnAwsCommonValidateStub.calledOnce).to.equal(true); expect(existsDeploymentBucketStub.calledAfter(spawnAwsCommonValidateStub)).to.equal(true); expect( spawnAwsCommonMoveArtifactsToTemp.calledAfter(existsDeploymentBucketStub) ).to.equal(true); expect(extendedValidateStub.calledAfter(spawnAwsCommonMoveArtifactsToTemp)).to.equal( true ); expect(spawnPackageStub.calledOnce).to.equal(false); }); }); }); it('should run "deploy:deploy" hook', () => { const spawnAwsDeployDeployStub = spawnStub.withArgs('aws:deploy:deploy').resolves(); return awsDeploy.hooks['deploy:deploy']().then(() => { expect(spawnAwsDeployDeployStub.calledOnce).to.equal(true); }); }); it('should run "deploy:finalize" hook', () => { const spawnAwsDeployFinalizeStub = spawnStub.withArgs('aws:deploy:finalize').resolves(); return awsDeploy.hooks['deploy:finalize']().then(() => { expect(spawnAwsDeployFinalizeStub.calledOnce).to.equal(true); }); }); it('should run "aws:deploy:deploy:createStack" hook', () => awsDeploy.hooks['aws:deploy:deploy:createStack']().then(() => { expect(createStackStub.calledOnce).to.equal(true); })); it('should run "aws:deploy:deploy:checkForChanges" hook', () => awsDeploy.hooks['aws:deploy:deploy:checkForChanges']().then(() => { expect(setBucketNameStub.calledOnce).to.equal(true); expect(checkForChangesStub.calledAfter(setBucketNameStub)).to.equal(true); })); describe('"aws:deploy:deploy:uploadArtifacts" hook', () => { let uploadArtifactsStub; beforeEach(() => { uploadArtifactsStub = sinon.stub(awsDeploy, 'uploadArtifacts').resolves(); }); afterEach(() => { awsDeploy.uploadArtifacts.restore(); }); it('should upload the artifacts if a deployment is necessary', () => expect(awsDeploy.hooks['aws:deploy:deploy:uploadArtifacts']()).to.be.fulfilled.then(() => { expect(uploadArtifactsStub).to.have.been.calledOnce; })); it('should resolve if no deployment is necessary', () => { awsDeploy.serverless.service.provider.shouldNotDeploy = true; return expect(awsDeploy.hooks['aws:deploy:deploy:uploadArtifacts']()).to.be.fulfilled.then( () => { expect(uploadArtifactsStub).to.not.have.been.called; } ); }); }); describe('"aws:deploy:deploy:validateTemplate" hook', () => { let validateTemplateStub; beforeEach(() => { validateTemplateStub = sinon.stub(awsDeploy, 'validateTemplate').resolves(); }); afterEach(() => { awsDeploy.validateTemplate.restore(); }); it('should validate the template if a deployment is necessary', () => expect(awsDeploy.hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then(() => { expect(validateTemplateStub).to.have.been.calledOnce; })); it('should resolve if no deployment is necessary', () => { awsDeploy.serverless.service.provider.shouldNotDeploy = true; return expect(awsDeploy.hooks['aws:deploy:deploy:validateTemplate']()).to.be.fulfilled.then( () => { expect(validateTemplateStub).to.not.have.been.called; } ); }); }); describe('"aws:deploy:deploy:updateStack" hook', () => { let updateStackStub; beforeEach(() => { updateStackStub = sinon.stub(awsDeploy, 'updateStack').resolves(); }); afterEach(() => { awsDeploy.updateStack.restore(); }); it('should update the stack if a deployment is necessary', () => expect(awsDeploy.hooks['aws:deploy:deploy:updateStack']()).to.be.fulfilled.then(() => { expect(updateStackStub).to.have.been.calledOnce; })); it('should resolve if no deployment is necessary', () => { awsDeploy.serverless.service.provider.shouldNotDeploy = true; return expect(awsDeploy.hooks['aws:deploy:deploy:updateStack']()).to.be.fulfilled.then( () => { expect(updateStackStub).to.not.have.been.called; } ); }); }); describe('"aws:deploy:finalize:cleanup" hook', () => { let cleanupS3BucketStub; let spawnAwsCommonCleanupTempDirStub; beforeEach(() => { cleanupS3BucketStub = sinon.stub(awsDeploy, 'cleanupS3Bucket').resolves(); spawnAwsCommonCleanupTempDirStub = spawnStub .withArgs('aws:common:cleanupTempDir') .resolves(); }); afterEach(() => { awsDeploy.cleanupS3Bucket.restore(); }); it('should do the default cleanup if no packaging config is used', () => { awsDeploy.options.package = false; awsDeploy.serverless.service.package.path = false; return awsDeploy.hooks['aws:deploy:finalize:cleanup']().then(() => { expect(cleanupS3BucketStub.calledOnce).to.equal(true); expect(spawnAwsCommonCleanupTempDirStub.calledOnce).to.equal(false); }); }); it('should cleanup the tmp dir if options based packaging config is used', () => { awsDeploy.options.package = true; awsDeploy.serverless.service.package.path = false; return awsDeploy.hooks['aws:deploy:finalize:cleanup']().then(() => { expect(cleanupS3BucketStub.calledOnce).to.equal(true); expect(spawnAwsCommonCleanupTempDirStub.calledAfter(cleanupS3BucketStub)).to.equal(true); }); }); it('should cleanup the tmp dir if service based packaging config is used', () => { awsDeploy.options.package = false; awsDeploy.serverless.service.package.path = true; return awsDeploy.hooks['aws:deploy:finalize:cleanup']().then(() => { expect(cleanupS3BucketStub.calledOnce).to.equal(true); expect(spawnAwsCommonCleanupTempDirStub.calledAfter(cleanupS3BucketStub)).to.equal(true); }); }); it('should not cleanup if a deployment was not necessary', () => { awsDeploy.serverless.service.provider.shouldNotDeploy = true; return awsDeploy.hooks['aws:deploy:finalize:cleanup']().then(() => { expect(cleanupS3BucketStub.called).to.equal(false); expect(spawnAwsCommonCleanupTempDirStub.called).to.equal(false); }); }); }); }); });