firmament-yargs
Version:
Typescript classes for building CLI node applications
451 lines • 18.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const inversify_config_1 = require("../inversify.config");
const chai_1 = require("chai");
const sinon = require("sinon");
const _ = require("lodash");
const path = require("path");
const pathToScripts = path.resolve(__dirname, '../../ts/test/shell-scripts');
const testScript = path.resolve(pathToScripts, 'kitchen-sink.sh');
const testArgs = [
'arg1',
'arg2'
];
function checkError(error, code = 0, signal = '', stdOut = '', stdErr = '') {
chai_1.expect(error).to.exist;
chai_1.expect(error.message).to.be.not.empty;
checkResult(error.message, code, signal, stdOut, stdErr);
}
function checkResult(result, code = 0, signal = '', stdOut = '', stdErr = '') {
const resultObj = JSON.parse(result);
chai_1.expect(resultObj.code).to.equal(code);
chai_1.expect(resultObj.signal).to.equal(signal);
chai_1.expect(resultObj.stderrText).to.equal(stdErr);
chai_1.expect(resultObj.stdoutText).to.equal(stdOut);
}
function getNewSpawnOptions() {
return _.clone({
preSpawnMessage: 'PreSpawn Message',
postSpawnMessage: 'PostSpawn Message',
suppressDiagnostics: true,
suppressStdErr: true,
suppressStdOut: true,
cacheStdErr: true,
cacheStdOut: true,
suppressResult: true,
suppressFinalError: true,
sudoUser: '',
sudoPassword: '',
forceNullChildProcess: false
});
}
function getArgArray() {
return [
testScript,
'writeToStdOutErrExitWithErrCode',
'0',
'writeToStdOut',
'writeToStdErr',
...testArgs
];
}
describe('Testing Spawn Creation/Force Error', () => {
before(() => {
});
after(() => {
});
it('should be created by kernel', (done) => {
const spawn = inversify_config_1.default.get('Spawn');
chai_1.expect(spawn).to.exist;
done();
});
it('should have final callback with error', (done) => {
const spawn = inversify_config_1.default.get('Spawn');
spawn.forceError = true;
spawn.spawnShellCommandAsync(null, null, null, (err) => {
chai_1.expect(err).to.exist;
chai_1.expect(err.message).to.equal('force error: spawnShellCommandAsync');
done();
});
});
});
describe('Testing Spawn ', () => {
let spawn;
let argArray;
let spawnOptions;
let sinonSandbox;
let cbStdOutSpy;
let cbStdErrSpy;
let cbDiagnosticSpy;
function cbStatusMock(err, result) {
if (err) {
cbStdErrSpy(err, result);
}
else {
cbStdOutSpy(err, result);
}
}
const o = {
cbStdOutCall: () => {
},
cbStdErrCall: () => {
},
cbStatus: () => {
},
cbDiagnostic: () => {
}
};
before(() => {
});
after(() => {
});
beforeEach(() => {
spawn = inversify_config_1.default.get('Spawn');
argArray = getArgArray();
spawnOptions = getNewSpawnOptions();
sinonSandbox = sinon.createSandbox();
cbDiagnosticSpy = sinonSandbox.spy(o, 'cbDiagnostic');
cbStdOutSpy = sinonSandbox.spy(o, 'cbStdOutCall');
cbStdErrSpy = sinonSandbox.spy(o, 'cbStdErrCall');
});
afterEach(() => {
sinonSandbox.restore();
});
it('spawnShellCommandAsync: undefined options, exit with code 0', (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions = undefined;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: null options, exit with code 0', (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions = null;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: null options, undefined arguments exit with code 0', (done) => {
argArray = undefined;
spawnOptions = null;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.exist;
chai_1.expect(err.message).to.equal('"file" argument must be a non-empty string');
chai_1.expect(result).to.not.exist;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: null options, null arguments exit with code 0', (done) => {
argArray = null;
spawnOptions = null;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.exist;
chai_1.expect(err.message).to.equal('"file" argument must be a non-empty string');
chai_1.expect(result).to.not.exist;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: no result, exit with code 0', (done) => {
argArray[1] = 'exitWithErrCode';
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
chai_1.expect(result).to.be.empty;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: no result, yes diagnostics, exit with code 0', (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.suppressDiagnostics = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
chai_1.expect(result).to.be.empty;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: yes result, exit with code 0', (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.suppressResult = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: no result, no finalError, exit with code 3', (done) => {
argArray[1] = 'exitWithErrCode';
argArray[2] = '3';
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
chai_1.expect(result).to.be.empty;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: no result, yes finalError, exit with code 3', (done) => {
argArray[1] = 'exitWithErrCode';
argArray[2] = '3';
spawnOptions.suppressFinalError = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
checkError(err, 3);
chai_1.expect(result).to.be.empty;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: yes result, yes finalError, exit with code 3', (done) => {
argArray[1] = 'exitWithErrCode';
argArray[2] = '3';
spawnOptions.suppressFinalError = false;
spawnOptions.suppressResult = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
checkError(err, 3);
checkResult(result, 3);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: yes result, no finalError, exit with code 3', (done) => {
argArray[1] = 'exitWithErrCode';
argArray[2] = '3';
spawnOptions.suppressResult = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result, 3);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: yes result, no finalError, yes stdout, yes stderr, exit with code 0', (done) => {
spawnOptions.suppressStdOut = false;
spawnOptions.suppressStdErr = false;
spawnOptions.suppressResult = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, cbStatusMock, (err, result) => {
chai_1.expect(err).to.not.exist;
const concatArgs = testArgs.join('');
checkResult(result, 0, '', concatArgs, concatArgs);
chai_1.expect(cbStdErrSpy.called).to.be.true;
chai_1.expect(cbStdOutSpy.called).to.be.true;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it('spawnShellCommandAsync: edge: yes suppressStdErr, no cacheStdErr', (done) => {
spawnOptions.suppressResult = false;
spawnOptions.cacheStdOut = false;
spawnOptions.cacheStdErr = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, cbStatusMock, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it(`spawnShellCommandAsync:edge: fire 'error' event on child process`, (done) => {
spawnOptions.suppressResult = false;
spawnOptions.suppressFinalError = false;
const cp = spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
checkResult(result, 30, 'SIGUSR1');
checkError(err, 30, 'SIGUSR1');
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
cp.emit('error', 30, 'SIGUSR1');
});
it(`spawnShellCommandAsync:edge: EACCES on bad cmd`, (done) => {
argArray[0] = '/';
spawnOptions.suppressResult = false;
spawnOptions.suppressFinalError = false;
spawn.spawnShellCommandAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(result).to.not.exist;
chai_1.expect(err['code']).to.equal('EACCES');
chai_1.expect(err['errno']).to.equal('EACCES');
chai_1.expect(err.message).to.equal('spawn EACCES');
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
});
describe('Testing SudoSpawn ', () => {
let spawn;
let argArray;
let spawnOptions;
let sinonSandbox;
let cbStdOutSpy;
let cbStdErrSpy;
let cbDiagnosticSpy;
const o = {
cbStdOutCall: () => {
},
cbStdErrCall: () => {
},
cbStatus: () => {
},
cbDiagnostic: () => {
}
};
before(() => {
});
after(() => {
});
beforeEach(() => {
spawn = inversify_config_1.default.get('Spawn');
argArray = getArgArray();
spawnOptions = getNewSpawnOptions();
sinonSandbox = sinon.createSandbox();
cbDiagnosticSpy = sinonSandbox.spy(o, 'cbDiagnostic');
cbStdOutSpy = sinonSandbox.spy(o, 'cbStdOutCall');
cbStdErrSpy = sinonSandbox.spy(o, 'cbStdErrCall');
});
afterEach(() => {
sinonSandbox.restore();
});
it(`sudoSpawnAsync: forceError `, (done) => {
spawn.forceError = true;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.exist;
chai_1.expect(err.message).to.equal('force error: sudoSpawnAsync');
chai_1.expect(result).to.not.exist;
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: spawnOptions is undefined, `, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions = undefined;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
checkError(err, 1);
checkResult(result, 1);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: spawnOptions is null, `, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions = null;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
checkError(err, 1);
checkResult(result, 1);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.true;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: non-existent user should return error`, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.sudoUser = 'poopuser';
spawnOptions.sudoPassword = 'pooppassword';
spawnOptions.suppressFinalError = false;
spawnOptions.suppressStdErr = false;
spawnOptions.suppressResult = false;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
const stdErr = 'sudo: unknown user: poopuser\nsudo: unable to initialize policy plugin\n';
checkError(err, 1, '', '', stdErr);
checkResult(result, 1, '', '', stdErr);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: existing user but bad password should return error`, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.sudoUser = 'vagrant';
spawnOptions.sudoPassword = 'pooppassword';
spawnOptions.suppressFinalError = false;
spawnOptions.suppressStdErr = false;
spawnOptions.suppressResult = false;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
const errStdErr = '#login-prompt#Sorry, try again.\n' +
'#login-prompt#Sorry, try again.\n' +
'#login-prompt#sudo: 3 incorrect password attempts\n';
const resultStdErr = 'Sorry, try again.\n' +
'Sorry, try again.\n' +
'sudo: 3 incorrect password attempts\n';
checkError(err, 1, '', '', errStdErr);
checkResult(result, 1, '', '', resultStdErr);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: forceNullChildProcess should return error`, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.sudoUser = 'vagrant';
spawnOptions.sudoPassword = 'pooppassword';
spawnOptions.suppressFinalError = false;
spawnOptions.suppressStdErr = false;
spawnOptions.suppressResult = false;
spawnOptions.forceNullChildProcess = true;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(result).to.not.exist;
chai_1.expect(err.message).to.be.equal('error: forceNullChildProcess');
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
it(`sudoSpawnAsync: existing user and good password`, (done) => {
argArray[1] = 'exitWithErrCode';
spawnOptions.sudoUser = 'vagrant';
spawnOptions.sudoPassword = 'password';
spawnOptions.suppressFinalError = false;
spawnOptions.suppressStdErr = false;
spawnOptions.suppressResult = false;
spawn.sudoSpawnAsync(argArray, spawnOptions, o.cbStatus, (err, result) => {
chai_1.expect(err).to.not.exist;
checkResult(result);
chai_1.expect(cbStdErrSpy.called).to.be.false;
chai_1.expect(cbStdOutSpy.called).to.be.false;
chai_1.expect(cbDiagnosticSpy.called).to.be.false;
done();
}, o.cbDiagnostic);
});
});
//# sourceMappingURL=spawn.test.js.map