ask-cli
Version:
Alexa Skills Kit (ASK) Command Line Interfaces
383 lines (353 loc) • 19.1 kB
JavaScript
const { expect } = require('chai');
const sinon = require('sinon');
const path = require('path');
const fs = require('fs');
const fse = require('fs-extra');
const DeployCommand = require('@src/commands/deploy');
const helper = require('@src/commands/deploy/helper');
const optionModel = require('@src/commands/option-model');
const CliWarn = require('@src/exceptions/cli-warn');
const ResourcesConfig = require('@src/model/resources-config');
const Messenger = require('@src/view/messenger');
const profileHelper = require('@src/utils/profile-helper');
const stringUtils = require('@src/utils/string-utils');
const CONSTANTS = require('@src/utils/constants');
describe('Commands deploy test - command class test', () => {
const FIXTURE_RESOURCES_CONFIG_FILE_PATH = path.join(process.cwd(), 'test', 'unit', 'fixture', 'model', 'regular-proj', 'ask-resources.json');
const FIXTURE_MANIFEST_FILE = path.join(process.cwd(), 'test', 'unit', 'fixture', 'model', 'manifest.json');
const TEST_PROFILE = 'default';
const TEST_DEBUG = false;
const TEST_IGNORE_HASH = false;
let infoStub;
let errorStub;
let warnStub;
beforeEach(() => {
infoStub = sinon.stub();
errorStub = sinon.stub();
warnStub = sinon.stub();
sinon.stub(Messenger, 'getInstance').returns({
info: infoStub,
error: errorStub,
warn: warnStub
});
});
afterEach(() => {
sinon.restore();
});
it('| validate command information is set correctly', () => {
const instance = new DeployCommand(optionModel);
expect(instance.name()).equal('deploy');
expect(instance.description()).equal('deploy the skill project');
expect(instance.requiredOptions()).deep.equal([]);
expect(instance.optionalOptions()).deep.equal(['ignore-hash', 'profile', 'debug']);
});
describe('validate command handle', () => {
const TEST_CMD = {
profile: TEST_PROFILE,
debug: TEST_DEBUG,
ignoreHash: TEST_IGNORE_HASH
};
const TEST_SKILL_METADATA_SRC = './skillPackage';
let instance;
let pathStub;
beforeEach(() => {
sinon.stub(profileHelper, 'runtimeProfile').returns(TEST_PROFILE);
pathStub = sinon.stub(path, 'join');
pathStub.withArgs(process.cwd(), CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG).returns(FIXTURE_RESOURCES_CONFIG_FILE_PATH);
pathStub.withArgs(TEST_SKILL_METADATA_SRC, CONSTANTS.FILE_PATH.SKILL_PACKAGE.MANIFEST).returns(FIXTURE_MANIFEST_FILE);
pathStub.callThrough();
instance = new DeployCommand(optionModel);
});
afterEach(() => {
sinon.restore();
});
describe('command handle - before deploy resources', () => {
it('| when profile is not correct, expect throw error', (done) => {
// setup
profileHelper.runtimeProfile.throws(new Error('error'));
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('error');
expect(errorStub.args[0][0].message).equal('error');
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when ResourcesConfig initiation fails, expect throw error', (done) => {
// setup
pathStub.withArgs(process.cwd(), CONSTANTS.FILE_PATH.ASK_RESOURCES_JSON_CONFIG).returns('invalidPath');
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('File invalidPath not exists.');
expect(errorStub.callCount).equal(0);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(1);
done();
});
});
it('| when deployer is alexa-hosted-deployer, expect throw warning', (done) => {
// setup
sinon.stub(ResourcesConfig.prototype, 'getSkillInfraType').returns(CONSTANTS.DEPLOYER_TYPE.HOSTED.NAME);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).instanceOf(CliWarn);
expect(errorStub.callCount).equal(0);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(1);
done();
});
});
it('| when skillPackage src is not set, expect throw error', (done) => {
// setup
sinon.stub(stringUtils, 'isNonBlankString').returns(false);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('Skill package src is not found in ask-resources.json.');
expect(errorStub.args[0][0].message).equal('Skill package src is not found in ask-resources.json.');
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when skillPackage src does not exist, expect throw error', (done) => {
// setup
sinon.stub(fse, 'existsSync').withArgs('./skillPackage').returns(false);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('The skillMetadata src file ./skillPackage does not exist.');
expect(errorStub.args[0][0].message).equal('The skillMetadata src file ./skillPackage does not exist.');
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| when Manifest initiation fails, expect throw error', (done) => {
// setup
sinon.stub(fse, 'existsSync').withArgs('./skillPackage').returns(true);
fse.existsSync.withArgs('invalidPath').returns(false);
sinon.stub(stringUtils, 'isNonBlankString').returns(true);
path.join.withArgs('./skillPackage', CONSTANTS.FILE_PATH.SKILL_PACKAGE.MANIFEST).returns('invalidPath');
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err.message).equal('File invalidPath not exists.');
expect(errorStub.callCount).equal(0);
expect(infoStub.callCount).equal(0);
expect(warnStub.callCount).equal(1);
done();
});
});
});
describe('command handle - deploy skill metadata', () => {
beforeEach(() => {
sinon.stub(fse, 'existsSync').returns(true);
});
it('| helper deploy skill metadata fails, expect throw error', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1, 'error');
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal('error');
expect(errorStub.args[0][0]).equal('error');
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(warnStub.callCount).equal(0);
done();
});
});
it('| helper deploy skill metadata with same hash skip result, expect display the message and continue', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1,
'The hash of current skill package folder does not change compared to the last deploy hash result, '
+ 'CLI will skip the deploy of skill package.');
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, 'error');
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal('error');
expect(errorStub.args[0][0]).equal('error');
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0].startsWith('Skill ID:')).equal(true);
expect(warnStub.callCount).equal(1);
done();
});
});
it('| helper deploy skill metadata and no skillCode portion of work, expect quit with no error', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1,
'The hash of current skill package folder does not change compared to the last deploy hash result, '
+ 'CLI will skip the deploy of skill package.');
sinon.stub(ResourcesConfig.prototype, 'getCodeRegions').returns([]);
sinon.stub(helper, 'enableSkill').callsArgWith(2);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(undefined);
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0].startsWith('Skill ID:')).equal(true);
expect(errorStub.callCount).equal(0);
expect(warnStub.callCount).equal(1);
done();
});
});
});
describe('command handle - build skill code', () => {
beforeEach(() => {
sinon.stub(fse, 'existsSync').returns(true);
});
it('| helper build skill code fails, expect throw error', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1);
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, 'error');
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal('error');
expect(errorStub.args[0][0]).equal('error');
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0]).equal('Skill package deployed successfully.');
expect(infoStub.args[2][0].startsWith('Skill ID:')).equal(true);
expect(infoStub.args[3][0]).equal('\n==================== Build Skill Code ====================');
expect(warnStub.callCount).equal(0);
done();
});
});
});
describe('command handle - deploy skill infrastructure', () => {
const TEST_CODE_BUILD_RESULT = [{
src: 'codeSrc',
build: {
file: 'buildFile',
folder: 'buildFolder'
},
buildFlow: 'build-flow',
regionsList: ['default', 'NA']
}];
const TEST_CODE_SRC_BASENAME = 'base';
beforeEach(() => {
sinon.stub(fse, 'existsSync').returns(true);
});
it('| helper deploy skill infra without infraType, expect skip the flow by calling back', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1);
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, null, TEST_CODE_BUILD_RESULT);
sinon.stub(helper, 'deploySkillInfrastructure').callsArgWith(2, 'error');
sinon.stub(helper, 'enableSkill').callsArgWith(2);
sinon.stub(stringUtils, 'isNonBlankString').returns(true);
stringUtils.isNonBlankString.withArgs('@ask-cli/cfn-deployer').returns(false);
sinon.stub(path, 'resolve').returns(TEST_CODE_SRC_BASENAME);
sinon.stub(fs, 'statSync').returns({
isDirectory: () => true
});
path.join.withArgs(TEST_CODE_SRC_BASENAME).returns(TEST_CODE_SRC_BASENAME);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(undefined);
expect(infoStub.callCount).equal(6);
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0]).equal('Skill package deployed successfully.');
expect(infoStub.args[2][0].startsWith('Skill ID:')).equal(true);
expect(infoStub.args[3][0]).equal('\n==================== Build Skill Code ====================');
expect(infoStub.args[4][0]).equal('Skill code built successfully.');
expect(infoStub.args[5][0]).equal(`Code for region default+NA built to ${TEST_CODE_BUILD_RESULT[0].build.file} successfully \
with build flow ${TEST_CODE_BUILD_RESULT[0].buildFlow}.`);
expect(warnStub.callCount).equal(0);
done();
});
});
it('| helper deploy skill infra fails, expect throw error', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1);
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, null, TEST_CODE_BUILD_RESULT);
sinon.stub(helper, 'deploySkillInfrastructure').callsArgWith(3, 'error');
sinon.stub(helper, 'enableSkill').callsArgWith(2);
sinon.stub(path, 'resolve').returns(TEST_CODE_SRC_BASENAME);
sinon.stub(fs, 'statSync').returns({
isDirectory: () => true
});
path.join.withArgs(TEST_CODE_SRC_BASENAME).returns(TEST_CODE_SRC_BASENAME);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal('error');
expect(errorStub.args[0][0]).equal('error');
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0]).equal('Skill package deployed successfully.');
expect(infoStub.args[2][0].startsWith('Skill ID:')).equal(true);
expect(infoStub.args[3][0]).equal('\n==================== Build Skill Code ====================');
expect(infoStub.args[4][0]).equal('Skill code built successfully.');
expect(infoStub.args[5][0]).equal(`Code for region default+NA built to ${TEST_CODE_BUILD_RESULT[0].build.file} successfully \
with build flow ${TEST_CODE_BUILD_RESULT[0].buildFlow}.`);
expect(infoStub.args[6][0]).equal('\n==================== Deploy Skill Infrastructure ====================');
expect(warnStub.callCount).equal(0);
done();
});
});
it('| deploy skill all pass, expect deploy succeeds and enbalSkill get called', (done) => {
// setup
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1);
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, null, TEST_CODE_BUILD_RESULT);
sinon.stub(helper, 'deploySkillInfrastructure').callsArgWith(3);
sinon.stub(helper, 'enableSkill').callsArgWith(2);
sinon.stub(path, 'resolve').returns(TEST_CODE_SRC_BASENAME);
sinon.stub(fs, 'statSync').returns({
isDirectory: () => true
});
path.join.withArgs(TEST_CODE_SRC_BASENAME).returns(TEST_CODE_SRC_BASENAME);
// call
instance.handle(TEST_CMD, (err) => {
// verify
expect(err).equal(undefined);
expect(errorStub.callCount).equal(0);
expect(infoStub.callCount).equal(8);
expect(infoStub.args[0][0]).equal('==================== Deploy Skill Metadata ====================');
expect(infoStub.args[1][0]).equal('Skill package deployed successfully.');
expect(infoStub.args[2][0].startsWith('Skill ID:')).equal(true);
expect(infoStub.args[3][0]).equal('\n==================== Build Skill Code ====================');
expect(infoStub.args[4][0]).equal('Skill code built successfully.');
expect(infoStub.args[5][0]).equal(`Code for region default+NA built to ${TEST_CODE_BUILD_RESULT[0].build.file} successfully \
with build flow ${TEST_CODE_BUILD_RESULT[0].buildFlow}.`);
expect(infoStub.args[6][0]).equal('\n==================== Deploy Skill Infrastructure ====================');
expect(infoStub.args[7][0]).equal('Skill infrastructures deployed successfully through @ask-cli/cfn-deployer.');
expect(warnStub.callCount).equal(0);
expect(helper.enableSkill.calledOnce).equal(true);
done();
});
});
});
describe('command handle - enable skill', () => {
const TEST_CODE_BUILD_RESULT = [{
src: 'codeSrc',
build: {
file: 'buildFile',
folder: 'buildFolder'
},
buildFlow: 'build-flow',
regionsList: ['default', 'NA']
}];
beforeEach(() => {
sinon.stub(fse, 'existsSync').returns(true);
});
it('| can callbcak error when enable fails', (done) => {
// setup
const TEST_ERROR = 'error';
sinon.stub(helper, 'deploySkillMetadata').callsArgWith(1);
sinon.stub(helper, 'buildSkillCode').callsArgWith(2, null, TEST_CODE_BUILD_RESULT);
sinon.stub(helper, 'deploySkillInfrastructure').callsArgWith(3);
sinon.stub(helper, 'enableSkill').callsArgWith(2, 'error');
instance.handle(TEST_CMD, (err) => {
expect(errorStub.args[0][0]).equal(TEST_ERROR);
expect(err).equal(TEST_ERROR);
done();
});
});
});
});
});