mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Initial version of plugin installer
This commit is contained in:
parent
015d3abd83
commit
56d3eba858
27 changed files with 2286 additions and 206 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -13,3 +13,4 @@ target
|
|||
*.log
|
||||
esvm
|
||||
.htpasswd
|
||||
src/server/bin/plugins
|
|
@ -58,12 +58,14 @@
|
|||
"http-auth": "^2.2.5",
|
||||
"joi": "^6.4.3",
|
||||
"js-yaml": "^3.2.5",
|
||||
"lodash": "^3.9.3",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"lodash": "^3.9.3",
|
||||
"mockery": "^1.4.0",
|
||||
"moment": "^2.10.3",
|
||||
"numeral": "^1.5.3",
|
||||
"request": "^2.40.0",
|
||||
"requirefrom": "^0.2.0",
|
||||
"rimraf": "^2.4.0",
|
||||
"semver": "^4.3.6",
|
||||
"serve-favicon": "^2.2.0",
|
||||
"through": "^2.3.6"
|
||||
|
@ -95,14 +97,14 @@
|
|||
"husky": "^0.8.1",
|
||||
"istanbul": "^0.3.15",
|
||||
"jade": "^1.8.2",
|
||||
"license-checker": "3.0.3",
|
||||
"libesvm": "^1.0.1",
|
||||
"license-checker": "3.0.3",
|
||||
"load-grunt-config": "^0.7.0",
|
||||
"marked": "^0.3.3",
|
||||
"marked-text-renderer": "^0.1.0",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mocha": "^2.2.5",
|
||||
"nock": "^1.6.0",
|
||||
"nock": "^2.7.0",
|
||||
"npm": "^2.11.0",
|
||||
"opn": "^1.0.0",
|
||||
"path-browserify": "0.0.0",
|
||||
|
|
|
@ -9,6 +9,7 @@ set NODE=%DIR%\node\node.exe
|
|||
set SERVER=%DIR%\src\bin\kibana.js
|
||||
set NODE_ENV="production"
|
||||
set CONFIG_PATH=%DIR%\config\kibana.yml
|
||||
REM set NPM (TODO: Need to define the env variable to the install of npm. TALK TO CHRIS/JOE)
|
||||
|
||||
TITLE Kibana Server @@version
|
||||
|
||||
|
@ -16,6 +17,4 @@ TITLE Kibana Server @@version
|
|||
|
||||
:finally
|
||||
|
||||
ENDLOCAL
|
||||
|
||||
|
||||
ENDLOCAL
|
|
@ -1,5 +1,8 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
//process.env.NODE_DEBUG = 'net';
|
||||
//process.env.NODE_DEBUG = 'request';
|
||||
|
||||
var _ = require('lodash');
|
||||
var program = require('commander');
|
||||
require('../lib/commanderExtensions.js')(program);
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
var _ = require('lodash');
|
||||
var zlib = require('zlib');
|
||||
var Promise = require('bluebird');
|
||||
var request = require('request');
|
||||
var tar = require('tar');
|
||||
var Path = require('path');
|
||||
var fs = Promise.promisifyAll(require('fs'));
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
module.exports = function (source, dest, downloadLogger) {
|
||||
downloadLogger = downloadLogger || _.noop;
|
||||
return new Promise(function (resolve, reject) {
|
||||
var gunzip = zlib.createGunzip();
|
||||
var progress = new EventEmitter();
|
||||
|
||||
var tarExtract = tar.Extract({ path: dest, strip: 1 });
|
||||
|
||||
request.get(source)
|
||||
.on('response', function (resp) {
|
||||
var total = parseInt(resp.headers['content-length'], 10);
|
||||
var docInfo = {
|
||||
level: 'INFO',
|
||||
type: 'progress',
|
||||
op: 'downloading',
|
||||
total: total,
|
||||
timestamp: new Date(),
|
||||
message: 'Downloading ' + total + ' bytes'
|
||||
};
|
||||
|
||||
downloadLogger(progress, docInfo);
|
||||
})
|
||||
.on('data', function (buffer) {
|
||||
progress.emit('progress', buffer.length);
|
||||
})
|
||||
.on('error', reject)
|
||||
.on('end', function () {
|
||||
progress.emit('message', '\nDownload Complete.\n');
|
||||
progress.emit('message', 'Extracting archive.\n');
|
||||
})
|
||||
.pipe(gunzip)
|
||||
.on('error', reject)
|
||||
.pipe(tarExtract)
|
||||
.on('end', function () {
|
||||
progress.emit('message', 'Extraction complete.\n');
|
||||
resolve();
|
||||
})
|
||||
.on('error', reject);
|
||||
});
|
||||
};
|
|
@ -1,23 +1,37 @@
|
|||
var npm = require('npm');
|
||||
var Promise = require('bluebird');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var Promise = require('bluebird');
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
module.exports = function (dest) {
|
||||
module.exports = function (dest, logger) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
//var cwd = process.cwd();
|
||||
npm.load(function (err) {
|
||||
process.chdir(dest);
|
||||
//throw an exception if package.json does not exist
|
||||
try {
|
||||
var packageFile = path.join(dest, 'package.json');
|
||||
fs.statSync(packageFile);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT')
|
||||
throw e;
|
||||
|
||||
var blah = path.join(dest, 'package.json');
|
||||
npm.commands.install([blah], function (er, data) {
|
||||
if (er) {
|
||||
console.error(er);
|
||||
}
|
||||
//process.chdir(cwd);
|
||||
});
|
||||
npm.on('log', function (message) {
|
||||
console.log(message);
|
||||
});
|
||||
reject(new Error('Plugin does not contain package.json file'));
|
||||
}
|
||||
|
||||
var cmd = (process.env.NPM) ? process.env.NPM : 'npm';
|
||||
cmd += ' install';
|
||||
|
||||
var child = exec(cmd, { cwd: dest });
|
||||
child.on('error', function (err) {
|
||||
reject(err);
|
||||
});
|
||||
child.on('exit', function (code, signal) {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('npm install failed.'));
|
||||
}
|
||||
});
|
||||
|
||||
logger.error(child.stderr);
|
||||
logger.log(child.stdout);
|
||||
});
|
||||
};
|
|
@ -1,109 +1,36 @@
|
|||
module.exports = function (program) {
|
||||
var expiry = require('expiry-js');
|
||||
var downloadAndExpand = require('./downloadAndExpand.js');
|
||||
var npmInstall = require('./npmInstall.js');
|
||||
var baseUrl = 'https://s3.amazonaws.com/jimtars/';
|
||||
var settings;
|
||||
|
||||
function parseSeconds(val) {
|
||||
var result;
|
||||
|
||||
try {
|
||||
//Is there is no unit specified, assume seconds
|
||||
var re = /([a-zA-Z]+)/g;
|
||||
if (!re.exec(val)) {
|
||||
val += 's';
|
||||
}
|
||||
|
||||
var timeVal = expiry(val);
|
||||
result = timeVal.asSeconds();
|
||||
} catch (ex) { }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseSettings(options) {
|
||||
var settings = {
|
||||
timeout: 0,
|
||||
silent: false
|
||||
};
|
||||
|
||||
if (options.timeout) {
|
||||
settings.timeout = options.timeout;
|
||||
}
|
||||
|
||||
if (options.silent) {
|
||||
settings.silent = options.silent;
|
||||
}
|
||||
|
||||
if (options.install) {
|
||||
settings.action = 'install';
|
||||
settings.plugin = options.install;
|
||||
}
|
||||
|
||||
if (options.remove) {
|
||||
settings.action = 'remove';
|
||||
settings.plugin = options.remove;
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
function log(message) {
|
||||
if (settings.silent) return;
|
||||
|
||||
process.stdout.write(message);
|
||||
}
|
||||
|
||||
function downloadLogger(progress, docInfo) {
|
||||
var totalBytes = docInfo.total;
|
||||
var runningTotal = 0;
|
||||
|
||||
log(docInfo.message + '\n');
|
||||
|
||||
progress.on('progress', function (data) {
|
||||
runningTotal += data;
|
||||
var percent = Math.round(runningTotal / totalBytes * 100);
|
||||
if (percent % 10 === 0) {
|
||||
log('.');
|
||||
}
|
||||
});
|
||||
|
||||
progress.on('message', function (message) {
|
||||
log(message);
|
||||
});
|
||||
}
|
||||
var settingParser = require('./settingParser');
|
||||
var installer = require('./pluginInstaller');
|
||||
var remover = require('./pluginRemover');
|
||||
var pluginLogger = require('./pluginLogger');
|
||||
|
||||
module.exports = function (program) {
|
||||
function processCommand(command, options) {
|
||||
settings = parseSettings(command);
|
||||
|
||||
if (!settings.action) {
|
||||
console.error('Please specify either --install or --remove.');
|
||||
process.exit(1);
|
||||
var settings;
|
||||
try {
|
||||
settings = settingParser.parse(command);
|
||||
} catch (ex) {
|
||||
//The logger has not yet been initialized.
|
||||
console.error(ex.message);
|
||||
process.exit(64);
|
||||
}
|
||||
|
||||
var logger = pluginLogger(settings.silent);
|
||||
|
||||
if (settings.action === 'install') {
|
||||
//require('./plugin_install.js')(settings);
|
||||
log('Running download and install.\n');
|
||||
var sourceUrl = 'https://download.elastic.co/kibana/plugins/test-plugin-1.0.0.tgz';
|
||||
var destPath = './plugins/' + settings.plugin;
|
||||
|
||||
downloadAndExpand(sourceUrl, destPath, downloadLogger)
|
||||
.catch(function (e) {
|
||||
console.error('Error installing plugin: ' + e);
|
||||
})
|
||||
.then(function () {
|
||||
npmInstall(destPath);
|
||||
});
|
||||
installer.install(settings, logger);
|
||||
}
|
||||
if (settings.action === 'remove') {
|
||||
remover.remove(settings, logger);
|
||||
}
|
||||
}
|
||||
|
||||
program
|
||||
.command('plugin')
|
||||
.description('Maintain Plugins')
|
||||
.option('-i, --install <plugin>', 'The plugin to install')
|
||||
.option('-i, --install <org>/<plugin>/<version>', 'The plugin to install')
|
||||
.option('-r, --remove <plugin>', 'The plugin to remove')
|
||||
.option('-s, --silent', 'Disable process messaging')
|
||||
.option('-t, --timeout <duration>', 'Length of time before failing; 0 for never fail', parseSeconds)
|
||||
.option('-u, --url <url>', 'Specify download url')
|
||||
.option('-t, --timeout <duration>', 'Length of time before failing; 0 for never fail', settingParser.parseMilliseconds)
|
||||
.action(processCommand);
|
||||
};
|
39
src/server/bin/plugin/pluginCleaner.js
Normal file
39
src/server/bin/plugin/pluginCleaner.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
var rimraf = require('rimraf');
|
||||
var fs = require('fs');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
module.exports = {
|
||||
cleanPrevious: cleanPrevious,
|
||||
cleanError: cleanError
|
||||
};
|
||||
|
||||
function cleanPrevious(settings, logger) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
fs.statSync(settings.workingPath);
|
||||
|
||||
logger.log('Found previous install attempt. Deleting...');
|
||||
try {
|
||||
rimraf.sync(settings.workingPath);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
return resolve();
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT')
|
||||
return reject(e);
|
||||
|
||||
return resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cleanError(settings) {
|
||||
//delete the working directory.
|
||||
//At this point we're bailing, so swallow any errors on delete.
|
||||
try {
|
||||
rimraf.sync(settings.workingPath);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
}
|
||||
}
|
65
src/server/bin/plugin/pluginDownloader.js
Normal file
65
src/server/bin/plugin/pluginDownloader.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
var _ = require('lodash');
|
||||
var zlib = require('zlib');
|
||||
var Promise = require('bluebird');
|
||||
var request = require('request');
|
||||
var tar = require('tar');
|
||||
var path = require('path');
|
||||
var progressReporter = require('./progressReporter.js');
|
||||
|
||||
module.exports = {
|
||||
download: download,
|
||||
_downloadSingle: downloadSingle
|
||||
};
|
||||
|
||||
//Attempts to download each url in turn until one is successful
|
||||
function download(settings, logger) {
|
||||
var urls = settings.urls;
|
||||
|
||||
function tryNext() {
|
||||
var sourceUrl = urls.shift();
|
||||
if (!sourceUrl) {
|
||||
throw new Error('Not a valid url.');
|
||||
}
|
||||
|
||||
logger.log('attempting to download ' + sourceUrl);
|
||||
|
||||
return downloadSingle(sourceUrl, settings.workingPath, settings.timeout, logger)
|
||||
.catch(function (err) {
|
||||
if (err.message === 'ENOTFOUND') {
|
||||
return tryNext();
|
||||
}
|
||||
if (err.message === 'EEXTRACT') {
|
||||
throw (new Error('Error extracting the plugin archive'));
|
||||
}
|
||||
throw (err);
|
||||
});
|
||||
}
|
||||
|
||||
return tryNext();
|
||||
}
|
||||
|
||||
//Attempts to download a single url
|
||||
function downloadSingle(source, dest, timeout, logger) {
|
||||
var gunzip = zlib.createGunzip();
|
||||
var tarExtract = tar.Extract({ path: dest, strip: 1 });
|
||||
|
||||
var requestOptions = { url: source };
|
||||
if (timeout !== 0) {
|
||||
requestOptions.timeout = timeout;
|
||||
}
|
||||
|
||||
var req = request.get(requestOptions);
|
||||
var reporter = progressReporter(logger, req);
|
||||
|
||||
req
|
||||
.on('response', reporter.handleResponse)
|
||||
.on('data', reporter.handleData)
|
||||
.on('error', _.partial(reporter.handleError, 'ENOTFOUND'))
|
||||
.pipe(gunzip)
|
||||
.on('error', _.partial(reporter.handleError, 'EEXTRACT'))
|
||||
.pipe(tarExtract)
|
||||
.on('error', _.partial(reporter.handleError, 'EEXTRACT'))
|
||||
.on('end', reporter.handleEnd);
|
||||
|
||||
return reporter.deferred;
|
||||
}
|
40
src/server/bin/plugin/pluginInstaller.js
Normal file
40
src/server/bin/plugin/pluginInstaller.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var downloader = require('./pluginDownloader.js');
|
||||
var cleaner = require('./pluginCleaner.js');
|
||||
var npmInstall = require('./npmInstall.js');
|
||||
var fs = require('fs');
|
||||
|
||||
module.exports = {
|
||||
install: install
|
||||
};
|
||||
|
||||
function install(settings, logger) {
|
||||
logger.log('installing ' + settings.package);
|
||||
|
||||
try {
|
||||
fs.statSync(settings.pluginPath);
|
||||
|
||||
logger.error('Plugin ' + settings.package + ' already exists. Please remove before installing a new version.');
|
||||
process.exit(70);
|
||||
} catch (e) {
|
||||
if (e.code !== 'ENOENT')
|
||||
throw e;
|
||||
}
|
||||
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.then(function () {
|
||||
return downloader.download(settings, logger);
|
||||
})
|
||||
.then(function () {
|
||||
return npmInstall(settings.workingPath, logger);
|
||||
})
|
||||
.then(function (curious) {
|
||||
fs.renameSync(settings.workingPath, settings.pluginPath);
|
||||
logger.log('Plugin installation complete!');
|
||||
})
|
||||
.catch(function (e) {
|
||||
logger.error('Plugin installation was unsuccessful.');
|
||||
logger.error(e.message);
|
||||
cleaner.cleanError(settings);
|
||||
process.exit(70);
|
||||
});
|
||||
}
|
41
src/server/bin/plugin/pluginLogger.js
Normal file
41
src/server/bin/plugin/pluginLogger.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
module.exports = function (silent) {
|
||||
var previousLineEnded = true;
|
||||
silent = !!silent;
|
||||
|
||||
function log(data, sameLine) {
|
||||
if (silent) return;
|
||||
|
||||
if (!sameLine && !previousLineEnded) {
|
||||
process.stdout.write('\n');
|
||||
}
|
||||
|
||||
//if data is a stream, pipe it.
|
||||
if (data.readable) {
|
||||
data.pipe(process.stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sameLine) data += '\n';
|
||||
process.stdout.write(data);
|
||||
previousLineEnded = !sameLine;
|
||||
}
|
||||
|
||||
function error(data) {
|
||||
if (!previousLineEnded) {
|
||||
process.stderr.write('\n');
|
||||
}
|
||||
|
||||
//if data is a stream, pipe it.
|
||||
if (data.readable) {
|
||||
data.pipe(process.stderr);
|
||||
return;
|
||||
}
|
||||
process.stderr.write(data + '\n');
|
||||
previousLineEnded = true;
|
||||
}
|
||||
|
||||
return {
|
||||
log: log,
|
||||
error: error
|
||||
};
|
||||
};
|
25
src/server/bin/plugin/pluginRemover.js
Normal file
25
src/server/bin/plugin/pluginRemover.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
var fs = require('fs');
|
||||
var rimraf = require('rimraf');
|
||||
|
||||
module.exports = {
|
||||
remove: remove
|
||||
};
|
||||
|
||||
function remove(settings, logger) {
|
||||
try {
|
||||
try {
|
||||
fs.statSync(settings.pluginPath);
|
||||
}
|
||||
catch (e) {
|
||||
logger.log('Plugin ' + settings.package + ' does not exist.');
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log('Removing ' + settings.package + '...');
|
||||
|
||||
rimraf.sync(settings.pluginPath);
|
||||
} catch (ex) {
|
||||
logger.error(ex.message);
|
||||
process.exit(74);
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
module.exports = function (settings) {
|
||||
var downloadAndExpand = require('./downloadAndExpand.js');
|
||||
var npmInstall = require('./npmInstall.js');
|
||||
|
||||
function log(message) {
|
||||
if (settings.silent) return;
|
||||
|
||||
process.stdout.write(message);
|
||||
}
|
||||
|
||||
function downloadLogger(progress, docInfo) {
|
||||
var totalBytes = docInfo.total;
|
||||
var runningTotal = 0;
|
||||
|
||||
log(docInfo.message + '\n');
|
||||
|
||||
progress.on('progress', function (data) {
|
||||
runningTotal += data;
|
||||
var percent = Math.round(runningTotal / totalBytes * 100);
|
||||
if (percent % 10 === 0) {
|
||||
log('.');
|
||||
}
|
||||
});
|
||||
|
||||
progress.on('message', function (message) {
|
||||
log(message);
|
||||
});
|
||||
}
|
||||
|
||||
log('Running download and install.\n');
|
||||
var sourceUrl = 'https://download.elastic.co/kibana/plugins/test-plugin-1.0.0.tgz';
|
||||
var destPath = './plugins/' + settings.plugin;
|
||||
|
||||
downloadAndExpand(sourceUrl, destPath, downloadLogger)
|
||||
.catch(function (e) {
|
||||
console.error('Error installing plugin: ' + e);
|
||||
})
|
||||
.then(function () {
|
||||
npmInstall(destPath);
|
||||
});
|
||||
};
|
71
src/server/bin/plugin/progressReporter.js
Normal file
71
src/server/bin/plugin/progressReporter.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
var Promise = require('bluebird');
|
||||
|
||||
/*
|
||||
Responsible for reporting the progress of the file request stream
|
||||
*/
|
||||
module.exports = function (logger, request) {
|
||||
var oldDotCount = 0;
|
||||
var runningTotal = 0;
|
||||
var totalSize = 0;
|
||||
var hasError = false;
|
||||
var _resolve;
|
||||
var _reject;
|
||||
var _resp;
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
_resolve = resolve;
|
||||
_reject = reject;
|
||||
});
|
||||
|
||||
function handleError(errorMessage, err) {
|
||||
if (hasError) return;
|
||||
|
||||
if (err) logger.error(err);
|
||||
hasError = true;
|
||||
request.abort();
|
||||
_reject(new Error(errorMessage));
|
||||
}
|
||||
|
||||
function handleResponse(resp) {
|
||||
_resp = resp;
|
||||
if (resp.statusCode >= 400) {
|
||||
handleError('ENOTFOUND', null);
|
||||
} else {
|
||||
totalSize = parseInt(resp.headers['content-length'], 10) || 0;
|
||||
var totalDesc = totalSize || 'unknown number of';
|
||||
|
||||
logger.log('Downloading ' + totalDesc + ' bytes', true);
|
||||
}
|
||||
}
|
||||
|
||||
//Should log a dot for every 5% of progress
|
||||
//Note: no progress is logged if the plugin is downloaded in a single packet
|
||||
function handleData(buffer) {
|
||||
if (hasError) return;
|
||||
if (!totalSize) return;
|
||||
|
||||
runningTotal += buffer.length;
|
||||
var dotCount = Math.round(runningTotal / totalSize * 100 / 5);
|
||||
if (dotCount > 20) dotCount = 20;
|
||||
for (var i = 0; i < (dotCount - oldDotCount) ; i++) {
|
||||
logger.log('.', true);
|
||||
}
|
||||
oldDotCount = dotCount;
|
||||
}
|
||||
|
||||
function handleEnd() {
|
||||
if (hasError) return;
|
||||
|
||||
logger.log('Download Complete.');
|
||||
_resolve();
|
||||
}
|
||||
|
||||
return {
|
||||
deferred: promise,
|
||||
handleResponse: handleResponse,
|
||||
handleError: handleError,
|
||||
handleData: handleData,
|
||||
handleEnd: handleEnd,
|
||||
hasError: function () { return hasError; }
|
||||
};
|
||||
};
|
116
src/server/bin/plugin/settingParser.js
Normal file
116
src/server/bin/plugin/settingParser.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
var path = require('path');
|
||||
var expiry = require('expiry-js');
|
||||
|
||||
module.exports = {
|
||||
parse: parse,
|
||||
parseMilliseconds: parseMilliseconds
|
||||
};
|
||||
|
||||
function parseMilliseconds(val) {
|
||||
var result;
|
||||
|
||||
try {
|
||||
var timeVal = expiry(val);
|
||||
result = timeVal.asMilliseconds();
|
||||
} catch (ex) {
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function generateDownloadUrl(settings) {
|
||||
var version = (settings.version) || 'latest';
|
||||
var filename = settings.package + '-' + version + '.tar.gz';
|
||||
|
||||
return 'https://download.elastic.co/' + settings.organization + '/' + settings.package + '/' + filename;
|
||||
}
|
||||
|
||||
function generateGithubUrl(settings) {
|
||||
var version = (settings.version) || 'master';
|
||||
var filename = version + '.tar.gz';
|
||||
|
||||
return 'https://github.com/' + settings.organization + '/' + settings.package + '/archive/' + filename;
|
||||
}
|
||||
|
||||
function parse(options) {
|
||||
var parts;
|
||||
var settings = {
|
||||
timeout: 0,
|
||||
silent: false,
|
||||
urls: []
|
||||
};
|
||||
|
||||
settings.workingPath = path.resolve(__dirname, '..', 'plugins', '.plugin.installing');
|
||||
|
||||
if (options.timeout) {
|
||||
settings.timeout = options.timeout;
|
||||
}
|
||||
|
||||
if (options.silent) {
|
||||
settings.silent = options.silent;
|
||||
}
|
||||
|
||||
if (options.url) {
|
||||
settings.urls.push(options.url);
|
||||
}
|
||||
|
||||
if (options.install) {
|
||||
settings.action = 'install';
|
||||
parts = options.install.split('/');
|
||||
|
||||
if (options.url) {
|
||||
if (parts.length !== 1) {
|
||||
throw new Error('Invalid install option. When providing a url, please use the format <plugin>.');
|
||||
}
|
||||
|
||||
settings.package = parts.shift();
|
||||
} else {
|
||||
if (parts.length < 2 || parts.length > 3) {
|
||||
throw new Error('Invalid install option. Please use the format <org>/<plugin>/<version>.');
|
||||
}
|
||||
|
||||
settings.organization = parts.shift();
|
||||
settings.package = parts.shift();
|
||||
settings.version = parts.shift();
|
||||
|
||||
|
||||
//settings.urls.push('http://www.piyrwljgdambcz.edu/blah.zip');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/badurl1.tar.gz');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/badurl2.tar.gz');
|
||||
//settings.urls.push('I should break everything!!!');
|
||||
settings.urls.push('https://s3.amazonaws.com/jimtars/badurl3.tar.gz');
|
||||
settings.urls.push('https://s3.amazonaws.com/jimtars/badurl4.tar.gz');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/badurl5.tar.gz');
|
||||
//settings.urls.push('http://localhost:3000/corrupt.tar.gz');
|
||||
//settings.urls.push('https://github.com/spalger/test-plugin/archive/master.tar.gz');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/bowling.tar.gz');
|
||||
settings.urls.push('https://s3.amazonaws.com/jimtars/BowlingFull.tar.gz');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/badurl6.tar.gz');
|
||||
//settings.urls.push('https://s3.amazonaws.com/jimtars/badurl7.tar.gz');
|
||||
|
||||
//settings.urls.push(generateDownloadUrl(settings));
|
||||
//settings.urls.push(generateGithubUrl(settings));
|
||||
}
|
||||
}
|
||||
|
||||
if (options.remove) {
|
||||
settings.action = 'remove';
|
||||
parts = options.remove.split('/');
|
||||
|
||||
if (parts.length !== 1) {
|
||||
throw new Error('Invalid remove option. Please use the format <plugin>.');
|
||||
}
|
||||
settings.package = parts.shift();
|
||||
}
|
||||
|
||||
if (!settings.action || (options.install && options.remove)) {
|
||||
throw new Error('Please specify either --install or --remove.');
|
||||
}
|
||||
|
||||
if (settings.package) {
|
||||
settings.pluginPath = path.resolve(__dirname, '..', 'plugins', settings.package);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
72
test/unit/server/bin/plugin/npmInstall.js
Normal file
72
test/unit/server/bin/plugin/npmInstall.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
var root = require('requirefrom')('');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var nock = require('nock');
|
||||
var glob = require('glob');
|
||||
var rimraf = require('rimraf');
|
||||
var fs = require('fs');
|
||||
var join = require('path').join;
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
var npmInstall = root('src/server/bin/plugin/npmInstall');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('npmInstall', function () {
|
||||
|
||||
var logger;
|
||||
var testWorkingPath;
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
testWorkingPath = join(__dirname, '.test.data');
|
||||
rimraf.sync(testWorkingPath);
|
||||
sinon.stub(logger, 'log', function (data, sameLine) {
|
||||
data.pipe(process.stdout);
|
||||
});
|
||||
sinon.stub(logger, 'error', function (data) {
|
||||
data.pipe(process.stderr);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
rimraf.sync(testWorkingPath);
|
||||
});
|
||||
|
||||
it('should throw an error if there is no package.json file in the archive', function () {
|
||||
fs.mkdir(testWorkingPath, function (e) { });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return npmInstall(testWorkingPath, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/package.json/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should rethrow any errors other than "ENOENT" from fs.statSync', function () {
|
||||
fs.mkdir(testWorkingPath, function (e) {});
|
||||
|
||||
sinon.stub(fs, 'statSync', function () {
|
||||
throw new Error('This is unexpected.');
|
||||
});
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return npmInstall(testWorkingPath, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/This is unexpected./);
|
||||
|
||||
fs.statSync.restore();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
130
test/unit/server/bin/plugin/plugin.js
Normal file
130
test/unit/server/bin/plugin/plugin.js
Normal file
|
@ -0,0 +1,130 @@
|
|||
var root = require('requirefrom')('');
|
||||
var plugin = root('src/server/bin/plugin/plugin');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var installer = root('src/server/bin/plugin/pluginInstaller');
|
||||
var remover = root('src/server/bin/plugin/pluginRemover');
|
||||
var settingParser = root('src/server/bin/plugin/settingParser');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('settings.action', function () {
|
||||
|
||||
var program = {
|
||||
command: function () { return program; },
|
||||
description: function () { return program; },
|
||||
option: function () { return program; },
|
||||
action: function (processCommand) {
|
||||
processCommand();
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(function () {
|
||||
sinon.stub(remover, 'remove');
|
||||
sinon.stub(installer, 'install');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
remover.remove.restore();
|
||||
installer.install.restore();
|
||||
settingParser.parse.restore();
|
||||
});
|
||||
|
||||
it('should call remove if settings.action is "remove"', function () {
|
||||
sinon.stub(settingParser, 'parse', function () {
|
||||
return {
|
||||
action: 'remove'
|
||||
};
|
||||
});
|
||||
|
||||
plugin(program);
|
||||
|
||||
expect(remover.remove.called).to.be(true);
|
||||
expect(installer.install.called).to.be(false);
|
||||
});
|
||||
|
||||
it('should call install if settings.action is "install"', function () {
|
||||
sinon.stub(settingParser, 'parse', function () {
|
||||
return {
|
||||
action: 'install'
|
||||
};
|
||||
});
|
||||
|
||||
plugin(program);
|
||||
|
||||
expect(remover.remove.called).to.be(false);
|
||||
expect(installer.install.called).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('commander options', function () {
|
||||
|
||||
var program = {
|
||||
command: function () { return program; },
|
||||
description: function () { return program; },
|
||||
option: function () { return program; },
|
||||
action: function () { return program; }
|
||||
};
|
||||
|
||||
it('should define the command', function () {
|
||||
sinon.spy(program, 'command');
|
||||
|
||||
plugin(program);
|
||||
expect(program.command.calledWith('plugin')).to.be(true);
|
||||
|
||||
program.command.restore();
|
||||
});
|
||||
|
||||
it('should define the description', function () {
|
||||
sinon.spy(program, 'description');
|
||||
|
||||
plugin(program);
|
||||
expect(program.description.calledWith('Maintain Plugins')).to.be(true);
|
||||
|
||||
program.description.restore();
|
||||
});
|
||||
|
||||
it('should define the command line options', function () {
|
||||
var spy = sinon.spy(program, 'option');
|
||||
|
||||
var options = [
|
||||
/-i/,
|
||||
/-r/,
|
||||
/-s/,
|
||||
/-u/,
|
||||
/-t/
|
||||
];
|
||||
|
||||
plugin(program);
|
||||
|
||||
for (var i = 0; i < spy.callCount; i++) {
|
||||
var call = spy.getCall(i);
|
||||
for (var o = 0; o < options.length; o++) {
|
||||
var option = options[o];
|
||||
if (call.args[0].match(option)) {
|
||||
options.splice(o, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(options).to.have.length(0);
|
||||
});
|
||||
|
||||
it('should call the action function', function () {
|
||||
sinon.spy(program, 'action');
|
||||
|
||||
plugin(program);
|
||||
expect(program.action.calledOnce).to.be(true);
|
||||
|
||||
program.action.restore();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
137
test/unit/server/bin/plugin/pluginCleaner.js
Normal file
137
test/unit/server/bin/plugin/pluginCleaner.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
var root = require('requirefrom')('');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var fs = require('fs');
|
||||
var rimraf = require('rimraf');
|
||||
var cleaner = root('src/server/bin/plugin/pluginCleaner');
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('pluginCleaner', function () {
|
||||
|
||||
var settings = {
|
||||
workingPath: 'dummy'
|
||||
};
|
||||
|
||||
describe('cleanPrevious', function () {
|
||||
var errorStub;
|
||||
var logger;
|
||||
var progress;
|
||||
var request;
|
||||
beforeEach(function () {
|
||||
errorStub = sinon.stub();
|
||||
logger = pluginLogger(false);
|
||||
sinon.stub(logger, 'log');
|
||||
sinon.stub(logger, 'error');
|
||||
request = {
|
||||
abort: sinon.stub(),
|
||||
emit: sinon.stub()
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
fs.statSync.restore();
|
||||
rimraf.sync.restore();
|
||||
});
|
||||
|
||||
it('should resolve if the working path does not exist', function () {
|
||||
sinon.stub(rimraf, 'sync');
|
||||
sinon.stub(fs, 'statSync', function () {
|
||||
var error = new Error('ENOENT');
|
||||
error.code = 'ENOENT';
|
||||
throw error;
|
||||
});
|
||||
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should rethrow any exception except ENOENT from fs.statSync', function () {
|
||||
sinon.stub(rimraf, 'sync');
|
||||
sinon.stub(fs, 'statSync', function () {
|
||||
var error = new Error('An Unhandled Error');
|
||||
throw error;
|
||||
});
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function () {
|
||||
expect(errorStub.called).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should log a message if there was a working directory', function () {
|
||||
sinon.stub(rimraf, 'sync');
|
||||
sinon.stub(fs, 'statSync');
|
||||
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(logger.log.calledWith('Found previous install attempt. Deleting...')).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should rethrow any exception from rimraf.sync', function () {
|
||||
sinon.stub(fs, 'statSync');
|
||||
sinon.stub(rimraf, 'sync', function () {
|
||||
throw new Error('I am an error thrown by rimraf');
|
||||
});
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function () {
|
||||
expect(errorStub.called).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should resolve if the working path is deleted', function () {
|
||||
sinon.stub(rimraf, 'sync');
|
||||
sinon.stub(fs, 'statSync');
|
||||
|
||||
return cleaner.cleanPrevious(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('cleanError', function () {
|
||||
|
||||
afterEach(function () {
|
||||
rimraf.sync.restore();
|
||||
});
|
||||
|
||||
it('should attempt to delete the working directory', function () {
|
||||
sinon.stub(rimraf, 'sync');
|
||||
|
||||
cleaner.cleanError(settings);
|
||||
expect(rimraf.sync.calledWith(settings.workingPath)).to.be(true);
|
||||
});
|
||||
|
||||
it('should swallow any errors thrown by rimraf.sync', function () {
|
||||
sinon.stub(rimraf, 'sync', function () {
|
||||
throw new Error('Something bad happened.');
|
||||
});
|
||||
|
||||
expect(cleaner.cleanError).withArgs(settings).to.not.throwError();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
278
test/unit/server/bin/plugin/pluginDownloader.js
Normal file
278
test/unit/server/bin/plugin/pluginDownloader.js
Normal file
|
@ -0,0 +1,278 @@
|
|||
var root = require('requirefrom')('');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var nock = require('nock');
|
||||
var glob = require('glob');
|
||||
var rimraf = require('rimraf');
|
||||
var join = require('path').join;
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
var downloader = root('src/server/bin/plugin/pluginDownloader');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin downloader', function () {
|
||||
|
||||
var testWorkingPath;
|
||||
var logger;
|
||||
|
||||
describe('_downloadSingle', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
testWorkingPath = join(__dirname, '.test.data');
|
||||
rimraf.sync(testWorkingPath);
|
||||
sinon.stub(logger, 'log');
|
||||
sinon.stub(logger, 'error');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
rimraf.sync(testWorkingPath);
|
||||
});
|
||||
|
||||
it('should throw an ENOTFOUND error for a 404 error', function () {
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.get('/plugin.tar.gz')
|
||||
.reply(404);
|
||||
|
||||
var source = 'http://www.files.com/plugin.tar.gz';
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader._downloadSingle(source, testWorkingPath, 0, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('download and extract a valid plugin', function () {
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.defaultReplyHeaders({
|
||||
'content-length': '10'
|
||||
})
|
||||
.get('/plugin.tar.gz')
|
||||
.replyWithFile(200, __dirname + '/replies/test-plugin-master.tar.gz');
|
||||
|
||||
var source = 'http://www.files.com/plugin.tar.gz';
|
||||
|
||||
return downloader._downloadSingle(source, testWorkingPath, 0, logger)
|
||||
.then(function (data) {
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([
|
||||
'README.md',
|
||||
'index.js',
|
||||
'package.json',
|
||||
'public',
|
||||
'public/app.js'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should abort the download and extraction for a corrupt archive.', function () {
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.get('/plugin.tar.gz')
|
||||
.replyWithFile(200, __dirname + '/replies/corrupt.tar.gz');
|
||||
|
||||
var source = 'http://www.files.com/plugin.tar.gz';
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader._downloadSingle(source, testWorkingPath, 0, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('download', function () {
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
sinon.stub(logger, 'log');
|
||||
sinon.stub(logger, 'error');
|
||||
testWorkingPath = join(__dirname, '.test.data');
|
||||
rimraf.sync(testWorkingPath);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
rimraf.sync(testWorkingPath);
|
||||
});
|
||||
|
||||
it('loop through bad urls until it finds a good one.', function () {
|
||||
var settings = {
|
||||
urls: [
|
||||
'http://www.files.com/badfile1.tar.gz',
|
||||
'http://www.files.com/badfile2.tar.gz',
|
||||
'http://www.files.com/goodfile.tar.gz'
|
||||
],
|
||||
workingPath: testWorkingPath,
|
||||
timeout: 0
|
||||
};
|
||||
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.defaultReplyHeaders({
|
||||
'content-length': '10'
|
||||
})
|
||||
.get('/badfile1.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile2.tar.gz')
|
||||
.reply(404)
|
||||
.get('/goodfile.tar.gz')
|
||||
.replyWithFile(200, __dirname + '/replies/test-plugin-master.tar.gz');
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader.download(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
|
||||
expect(logger.log.getCall(0).args[0]).to.match(/badfile1.tar.gz/);
|
||||
expect(logger.log.getCall(1).args[0]).to.match(/badfile2.tar.gz/);
|
||||
expect(logger.log.getCall(2).args[0]).to.match(/goodfile.tar.gz/);
|
||||
expect(logger.log.lastCall.args[0]).to.match(/complete/i);
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([
|
||||
'README.md',
|
||||
'index.js',
|
||||
'package.json',
|
||||
'public',
|
||||
'public/app.js'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('stop looping through urls when it finds a good one.', function () {
|
||||
var settings = {
|
||||
urls: [
|
||||
'http://www.files.com/badfile1.tar.gz',
|
||||
'http://www.files.com/badfile2.tar.gz',
|
||||
'http://www.files.com/goodfile.tar.gz',
|
||||
'http://www.files.com/badfile3.tar.gz'
|
||||
],
|
||||
workingPath: testWorkingPath,
|
||||
timeout: 0
|
||||
};
|
||||
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.defaultReplyHeaders({
|
||||
'content-length': '10'
|
||||
})
|
||||
.get('/badfile1.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile2.tar.gz')
|
||||
.reply(404)
|
||||
.get('/goodfile.tar.gz')
|
||||
.replyWithFile(200, __dirname + '/replies/test-plugin-master.tar.gz')
|
||||
.get('/badfile3.tar.gz')
|
||||
.reply(404);
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader.download(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
|
||||
for (var i = 0; i < logger.log.callCount; i++) {
|
||||
expect(logger.log.getCall(i).args[0]).to.not.match(/badfile3.tar.gz/);
|
||||
}
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([
|
||||
'README.md',
|
||||
'index.js',
|
||||
'package.json',
|
||||
'public',
|
||||
'public/app.js'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('Throw an error when it doesn\'t find a good url.', function () {
|
||||
var settings = {
|
||||
urls: [
|
||||
'http://www.files.com/badfile1.tar.gz',
|
||||
'http://www.files.com/badfile2.tar.gz',
|
||||
'http://www.files.com/badfile3.tar.gz'
|
||||
],
|
||||
workingPath: testWorkingPath,
|
||||
timeout: 0
|
||||
};
|
||||
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.defaultReplyHeaders({
|
||||
'content-length': '10'
|
||||
})
|
||||
.get('/badfile1.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile2.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile3.tar.gz')
|
||||
.reply(404);
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader.download(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/not a valid/i);
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('Throw an error when it tries to use an invalid url.', function () {
|
||||
var settings = {
|
||||
urls: [
|
||||
'http://www.files.com/badfile1.tar.gz',
|
||||
'http://www.files.com/badfile2.tar.gz',
|
||||
'I should break everything',
|
||||
'http://www.files.com/badfile3.tar.gz'
|
||||
],
|
||||
workingPath: testWorkingPath,
|
||||
timeout: 0
|
||||
};
|
||||
|
||||
var couchdb = nock('http://www.files.com')
|
||||
.defaultReplyHeaders({
|
||||
'content-length': '10'
|
||||
})
|
||||
.get('/badfile1.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile2.tar.gz')
|
||||
.reply(404)
|
||||
.get('/badfile3.tar.gz')
|
||||
.reply(404);
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return downloader.download(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/invalid/i);
|
||||
|
||||
for (var i = 0; i < logger.log.callCount; i++) {
|
||||
expect(logger.log.getCall(i).args[0]).to.not.match(/badfile3.tar.gz/);
|
||||
}
|
||||
|
||||
var files = glob.sync('**/*', { cwd: testWorkingPath });
|
||||
expect(files).to.eql([]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
70
test/unit/server/bin/plugin/pluginInstaller.js
Normal file
70
test/unit/server/bin/plugin/pluginInstaller.js
Normal file
|
@ -0,0 +1,70 @@
|
|||
var root = require('requirefrom')('');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var nock = require('nock');
|
||||
var glob = require('glob');
|
||||
var rimraf = require('rimraf');
|
||||
var fs = require('fs');
|
||||
var join = require('path').join;
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
var pluginInstaller = root('src/server/bin/plugin/pluginInstaller');
|
||||
var cleaner = root('src/server/bin/plugin/pluginCleaner');
|
||||
var Promise = require('bluebird');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('pluginInstaller', function () {
|
||||
|
||||
var logger;
|
||||
var testWorkingPath;
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
testWorkingPath = join(__dirname, '.test.data');
|
||||
rimraf.sync(testWorkingPath);
|
||||
sinon.stub(logger, 'log');
|
||||
sinon.stub(logger, 'error');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
rimraf.sync(testWorkingPath);
|
||||
});
|
||||
|
||||
it('should throw an error if the workingPath already exists.', function () {
|
||||
sinon.stub(process, 'exit');
|
||||
fs.mkdir(testWorkingPath, function (e) {});
|
||||
|
||||
var settings = {
|
||||
pluginPath: testWorkingPath
|
||||
};
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return pluginInstaller.install(settings, logger)
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(logger.error.firstCall.args[0]).to.match(/already exists/);
|
||||
expect(process.exit.called).to.be(true);
|
||||
process.exit.restore();
|
||||
});
|
||||
});
|
||||
|
||||
it('should rethrow any non "ENOENT" error from fs.', function () {
|
||||
sinon.stub(fs, 'statSync', function () {
|
||||
throw new Error('This is unexpected.');
|
||||
});
|
||||
|
||||
var settings = {
|
||||
pluginPath: testWorkingPath
|
||||
};
|
||||
|
||||
expect(pluginInstaller.install).withArgs(settings, logger).to.throwException(/this is unexpected/i);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
102
test/unit/server/bin/plugin/pluginLogger.js
Normal file
102
test/unit/server/bin/plugin/pluginLogger.js
Normal file
|
@ -0,0 +1,102 @@
|
|||
var root = require('requirefrom')('');
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('logger', function () {
|
||||
|
||||
var logger;
|
||||
|
||||
describe('logger.log', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
sinon.spy(process.stdout, 'write');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
process.stdout.write.restore();
|
||||
});
|
||||
|
||||
it('should log messages to the console and append a new line', function () {
|
||||
var message = 'this is my message';
|
||||
|
||||
logger.log(message);
|
||||
expect(process.stdout.write.calledWith(message + '\n')).to.be(true);
|
||||
});
|
||||
|
||||
it('should log messages to the console and append not append a new line', function () {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
logger.log('.', true);
|
||||
}
|
||||
logger.log('Done!');
|
||||
|
||||
expect(process.stdout.write.callCount).to.be(12);
|
||||
expect(process.stdout.write.getCall(0).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(1).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(2).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(3).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(4).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(5).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(6).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(7).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(8).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(9).args[0]).to.be('.');
|
||||
expect(process.stdout.write.getCall(10).args[0]).to.be('\n');
|
||||
expect(process.stdout.write.getCall(11).args[0]).to.be('Done!\n');
|
||||
});
|
||||
|
||||
it('should not log any messages when silent is set', function () {
|
||||
logger = pluginLogger(true);
|
||||
|
||||
var message = 'this is my message';
|
||||
logger.log(message);
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
logger.log('.', true);
|
||||
}
|
||||
logger.log('Done!');
|
||||
|
||||
expect(process.stdout.write.callCount).to.be(0);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('logger.error', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
sinon.spy(process.stderr, 'write');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
process.stderr.write.restore();
|
||||
});
|
||||
|
||||
it('should log error messages to the console and append a new line', function () {
|
||||
var message = 'this is my error';
|
||||
|
||||
logger.error(message);
|
||||
expect(process.stderr.write.calledWith(message + '\n')).to.be(true);
|
||||
});
|
||||
|
||||
|
||||
it('should log error messages to the console regardless of silent setting', function () {
|
||||
logger = pluginLogger(true);
|
||||
var message = 'this is my error';
|
||||
|
||||
logger.error(message);
|
||||
expect(process.stderr.write.calledWith(message + '\n')).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
738
test/unit/server/bin/plugin/progressReporter.js
Normal file
738
test/unit/server/bin/plugin/progressReporter.js
Normal file
|
@ -0,0 +1,738 @@
|
|||
var root = require('requirefrom')('');
|
||||
var expect = require('expect.js');
|
||||
var sinon = require('sinon');
|
||||
var progressReporter = root('src/server/bin/plugin/progressReporter');
|
||||
var pluginLogger = root('src/server/bin/plugin/pluginLogger');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('progressReporter', function () {
|
||||
|
||||
var logger;
|
||||
var progress;
|
||||
var request;
|
||||
beforeEach(function () {
|
||||
logger = pluginLogger(false);
|
||||
sinon.stub(logger, 'log');
|
||||
sinon.stub(logger, 'error');
|
||||
request = {
|
||||
abort: sinon.stub(),
|
||||
emit: sinon.stub()
|
||||
};
|
||||
progress = progressReporter(logger, request);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
logger.log.restore();
|
||||
logger.error.restore();
|
||||
});
|
||||
|
||||
describe('handleResponse', function () {
|
||||
|
||||
describe('bad response codes', function () {
|
||||
|
||||
it('should set the state to error for response code = 400', function () {
|
||||
progress.handleResponse({ statusCode: 400 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 401', function () {
|
||||
progress.handleResponse({ statusCode: 401 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 402', function () {
|
||||
progress.handleResponse({ statusCode: 402 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 403', function () {
|
||||
progress.handleResponse({ statusCode: 403 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 404', function () {
|
||||
progress.handleResponse({ statusCode: 404 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 405', function () {
|
||||
progress.handleResponse({ statusCode: 405 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 406', function () {
|
||||
progress.handleResponse({ statusCode: 406 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 407', function () {
|
||||
progress.handleResponse({ statusCode: 407 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 408', function () {
|
||||
progress.handleResponse({ statusCode: 408 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 409', function () {
|
||||
progress.handleResponse({ statusCode: 409 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 410', function () {
|
||||
progress.handleResponse({ statusCode: 410 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 411', function () {
|
||||
progress.handleResponse({ statusCode: 411 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 412', function () {
|
||||
progress.handleResponse({ statusCode: 412 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 413', function () {
|
||||
progress.handleResponse({ statusCode: 413 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 414', function () {
|
||||
progress.handleResponse({ statusCode: 414 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 415', function () {
|
||||
progress.handleResponse({ statusCode: 415 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 416', function () {
|
||||
progress.handleResponse({ statusCode: 416 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 417', function () {
|
||||
progress.handleResponse({ statusCode: 417 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 500', function () {
|
||||
progress.handleResponse({ statusCode: 500 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 501', function () {
|
||||
progress.handleResponse({ statusCode: 501 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 502', function () {
|
||||
progress.handleResponse({ statusCode: 502 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 503', function () {
|
||||
progress.handleResponse({ statusCode: 503 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 504', function () {
|
||||
progress.handleResponse({ statusCode: 504 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 505', function () {
|
||||
progress.handleResponse({ statusCode: 505 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(errorStub.lastCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('good response codes', function () {
|
||||
|
||||
it('should set the state to error for response code = 200', function () {
|
||||
progress.handleResponse({ statusCode: 200, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 201', function () {
|
||||
progress.handleResponse({ statusCode: 201, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 202', function () {
|
||||
progress.handleResponse({ statusCode: 202, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 203', function () {
|
||||
progress.handleResponse({ statusCode: 203, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 204', function () {
|
||||
progress.handleResponse({ statusCode: 204, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 205', function () {
|
||||
progress.handleResponse({ statusCode: 205, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 206', function () {
|
||||
progress.handleResponse({ statusCode: 206, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 300', function () {
|
||||
progress.handleResponse({ statusCode: 300, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 301', function () {
|
||||
progress.handleResponse({ statusCode: 301, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 302', function () {
|
||||
progress.handleResponse({ statusCode: 302, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 303', function () {
|
||||
progress.handleResponse({ statusCode: 303, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 304', function () {
|
||||
progress.handleResponse({ statusCode: 304, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 305', function () {
|
||||
progress.handleResponse({ statusCode: 305, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 306', function () {
|
||||
progress.handleResponse({ statusCode: 306, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the state to error for response code = 307', function () {
|
||||
progress.handleResponse({ statusCode: 307, headers: { 'content-length': 1000 } });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/1000/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should log "unknown number of" for response codes < 400 without content-length header', function () {
|
||||
progress.handleResponse({ statusCode: 200, headers: {} });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(logger.log.callCount - 2).args[0]).to.match(/unknown number/);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('handleData', function () {
|
||||
|
||||
it('should do nothing if the reporter is in an error state', function () {
|
||||
progress.handleResponse({ statusCode: 400 });
|
||||
progress.handleData({ length: 100 });
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(progress.hasError()).to.be(true);
|
||||
expect(request.abort.called).to.be(true);
|
||||
expect(logger.log.callCount).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing if handleResponse hasn\'t successfully executed yet', function () {
|
||||
progress.handleData({ length: 100 });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(logger.log.callCount).to.be(1);
|
||||
expect(logger.log.lastCall.args[0]).to.match(/complete/i);
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing if handleResponse was called without a content-length header', function () {
|
||||
progress.handleResponse({ statusCode: 200, headers: {} });
|
||||
progress.handleData({ length: 100 });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(logger.log.callCount).to.be(2);
|
||||
expect(logger.log.getCall(0).args[0]).to.match(/downloading/i);
|
||||
expect(logger.log.getCall(1).args[0]).to.match(/complete/i);
|
||||
});
|
||||
});
|
||||
|
||||
it('should show a max of 20 dots for full prgress', function () {
|
||||
progress.handleResponse({ statusCode: 200, headers: { 'content-length': 1000 } });
|
||||
progress.handleData({ length: 1000 });
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(logger.log.callCount).to.be(22);
|
||||
expect(logger.log.getCall(0).args[0]).to.match(/downloading/i);
|
||||
expect(logger.log.getCall(1).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(2).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(3).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(4).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(5).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(6).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(7).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(8).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(9).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(10).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(11).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(12).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(13).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(14).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(15).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(16).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(17).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(18).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(19).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(20).args[0]).to.be('.');
|
||||
expect(logger.log.getCall(21).args[0]).to.match(/complete/i);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should show dot for each 5% of completion', function () {
|
||||
progress.handleResponse({ statusCode: 200, headers: { 'content-length': 1000 } });
|
||||
expect(logger.log.callCount).to.be(1);
|
||||
|
||||
progress.handleData({ length: 50 }); //5%
|
||||
expect(logger.log.callCount).to.be(2);
|
||||
|
||||
progress.handleData({ length: 100 }); //15%
|
||||
expect(logger.log.callCount).to.be(4);
|
||||
|
||||
progress.handleData({ length: 200 }); //25%
|
||||
expect(logger.log.callCount).to.be(8);
|
||||
|
||||
progress.handleData({ length: 590 }); //94%
|
||||
expect(logger.log.callCount).to.be(20);
|
||||
|
||||
progress.handleData({ length: 60 }); //100%
|
||||
expect(logger.log.callCount).to.be(21);
|
||||
|
||||
//Any progress over 100% should be ignored.
|
||||
progress.handleData({ length: 9999 });
|
||||
expect(logger.log.callCount).to.be(21);
|
||||
|
||||
progress.handleEnd();
|
||||
expect(logger.log.callCount).to.be(22);
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.getCall(0).args[0]).to.match(/downloading/i);
|
||||
expect(logger.log.getCall(21).args[0]).to.match(/complete/i);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('handleEnd', function () {
|
||||
|
||||
it('should reject the deferred with a ENOTFOUND error if the reporter is in an error state', function () {
|
||||
progress.handleResponse({ statusCode: 400 });
|
||||
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.firstCall.args[0].message).to.match(/ENOTFOUND/);
|
||||
expect(errorStub.called).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should resolve if the reporter is not in an error state', function () {
|
||||
progress.handleResponse({ statusCode: 307, headers: { 'content-length': 1000 } });
|
||||
|
||||
progress.handleEnd();
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(false);
|
||||
expect(logger.log.lastCall.args[0]).to.match(/complete/i);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('handleError', function () {
|
||||
|
||||
it('should log any errors', function () {
|
||||
progress.handleError('ERRORMESSAGE', new Error('oops!'));
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(logger.error.callCount).to.be(1);
|
||||
expect(logger.error.lastCall.args[0]).to.match(/oops!/);
|
||||
});
|
||||
});
|
||||
|
||||
it('should set the error state of the reporter', function () {
|
||||
progress.handleError('ERRORMESSAGE', new Error('oops!'));
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(progress.hasError()).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore all errors except the first.', function () {
|
||||
progress.handleError('ERRORMESSAGE', new Error('oops!'));
|
||||
progress.handleError('ERRORMESSAGE', new Error('second error!'));
|
||||
progress.handleError('ERRORMESSAGE', new Error('third error!'));
|
||||
progress.handleError('ERRORMESSAGE', new Error('fourth error!'));
|
||||
|
||||
var errorStub = sinon.stub();
|
||||
return progress.deferred
|
||||
.catch(errorStub)
|
||||
.then(function (data) {
|
||||
expect(errorStub.called).to.be(true);
|
||||
expect(logger.error.callCount).to.be(1);
|
||||
expect(logger.error.lastCall.args[0]).to.match(/oops!/);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
BIN
test/unit/server/bin/plugin/replies/corrupt.tar.gz
Normal file
BIN
test/unit/server/bin/plugin/replies/corrupt.tar.gz
Normal file
Binary file not shown.
13
test/unit/server/bin/plugin/replies/package.json
Normal file
13
test/unit/server/bin/plugin/replies/package.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "test-plugin",
|
||||
"version": "1.0.0",
|
||||
"description": "just a test plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://website.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "2.9.30"
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
}
|
BIN
test/unit/server/bin/plugin/replies/plugin-no-package.gz
Normal file
BIN
test/unit/server/bin/plugin/replies/plugin-no-package.gz
Normal file
Binary file not shown.
BIN
test/unit/server/bin/plugin/replies/test-plugin-master.tar.gz
Normal file
BIN
test/unit/server/bin/plugin/replies/test-plugin-master.tar.gz
Normal file
Binary file not shown.
287
test/unit/server/bin/plugin/settingParser.js
Normal file
287
test/unit/server/bin/plugin/settingParser.js
Normal file
|
@ -0,0 +1,287 @@
|
|||
var root = require('requirefrom')('');
|
||||
var settingParser = root('src/server/bin/plugin/settingParser');
|
||||
var path = require('path');
|
||||
var expect = require('expect.js');
|
||||
|
||||
describe('kibana cli', function () {
|
||||
|
||||
describe('plugin installer', function () {
|
||||
|
||||
describe('command line option parsing', function () {
|
||||
|
||||
describe('parseMilliseconds function', function () {
|
||||
|
||||
it('should return 0 for an empty string', function () {
|
||||
var value = '';
|
||||
|
||||
var result = settingParser.parseMilliseconds(value);
|
||||
|
||||
expect(result).to.be(0);
|
||||
});
|
||||
|
||||
it('should return 0 for a number with an invalid unit of measure', function () {
|
||||
var result = settingParser.parseMilliseconds('1gigablasts');
|
||||
expect(result).to.be(0);
|
||||
});
|
||||
|
||||
it('should assume a number with no unit of measure is specified as milliseconds', function () {
|
||||
var result = settingParser.parseMilliseconds(1);
|
||||
expect(result).to.be(1);
|
||||
|
||||
result = settingParser.parseMilliseconds('1');
|
||||
expect(result).to.be(1);
|
||||
});
|
||||
|
||||
it('should interpret a number with "s" as the unit of measure as seconds', function () {
|
||||
var result = settingParser.parseMilliseconds('5s');
|
||||
expect(result).to.be(5 * 1000);
|
||||
});
|
||||
|
||||
it('should interpret a number with "second" as the unit of measure as seconds', function () {
|
||||
var result = settingParser.parseMilliseconds('5second');
|
||||
expect(result).to.be(5 * 1000);
|
||||
});
|
||||
|
||||
it('should interpret a number with "seconds" as the unit of measure as seconds', function () {
|
||||
var result = settingParser.parseMilliseconds('5seconds');
|
||||
expect(result).to.be(5 * 1000);
|
||||
});
|
||||
|
||||
it('should interpret a number with "m" as the unit of measure as minutes', function () {
|
||||
var result = settingParser.parseMilliseconds('9m');
|
||||
expect(result).to.be(9 * 1000 * 60);
|
||||
});
|
||||
|
||||
it('should interpret a number with "minute" as the unit of measure as minutes', function () {
|
||||
var result = settingParser.parseMilliseconds('9minute');
|
||||
expect(result).to.be(9 * 1000 * 60);
|
||||
});
|
||||
|
||||
it('should interpret a number with "minutes" as the unit of measure as minutes', function () {
|
||||
var result = settingParser.parseMilliseconds('9minutes');
|
||||
expect(result).to.be(9 * 1000 * 60);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parse function', function () {
|
||||
|
||||
it('should require the user to specify either install and remove', function () {
|
||||
options.install = null;
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Please specify either --install or --remove./);
|
||||
});
|
||||
|
||||
it('should not allow the user to specify both install and remove', function () {
|
||||
options.remove = 'package';
|
||||
options.install = 'org/package/version';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Please specify either --install or --remove./);
|
||||
});
|
||||
|
||||
var options;
|
||||
beforeEach(function () {
|
||||
options = { install: 'dummy/dummy' };
|
||||
});
|
||||
|
||||
describe('silent option', function () {
|
||||
|
||||
it('should default to false', function () {
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('silent', false);
|
||||
});
|
||||
|
||||
it('should set settings.silent property to true', function () {
|
||||
options.silent = true;
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('silent', true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('timeout option', function () {
|
||||
|
||||
it('should default to 0 (milliseconds)', function () {
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('timeout', 0);
|
||||
});
|
||||
|
||||
it('should set settings.timeout property to specified value', function () {
|
||||
options.timeout = 1234;
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('timeout', 1234);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('install option', function () {
|
||||
|
||||
it('should set settings.action property to "install"', function () {
|
||||
options.install = 'org/package/version';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('action', 'install');
|
||||
});
|
||||
|
||||
it('should allow two parts to the install parameter', function () {
|
||||
options.install = 'kibana/test-plugin';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.not.throwException();
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('organization', 'kibana');
|
||||
expect(settings).to.have.property('package', 'test-plugin');
|
||||
expect(settings).to.have.property('version', undefined);
|
||||
});
|
||||
|
||||
it('should allow three parts to the install parameter', function () {
|
||||
options.install = 'kibana/test-plugin/v1.0.1';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.not.throwException();
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('organization', 'kibana');
|
||||
expect(settings).to.have.property('package', 'test-plugin');
|
||||
expect(settings).to.have.property('version', 'v1.0.1');
|
||||
});
|
||||
|
||||
it('should not allow one part to the install parameter', function () {
|
||||
options.install = 'test-plugin';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Invalid install option. Please use the format <org>\/<plugin>\/<version>./);
|
||||
});
|
||||
|
||||
it('should not allow more than three parts to the install parameter', function () {
|
||||
options.install = 'kibana/test-plugin/v1.0.1/dummy';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Invalid install option. Please use the format <org>\/<plugin>\/<version>./);
|
||||
});
|
||||
|
||||
it('should populate the urls collection properly when no version specified', function () {
|
||||
options.install = 'kibana/test-plugin';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings.urls).to.have.property('length', 2);
|
||||
expect(settings.urls).to.contain('https://download.elastic.co/kibana/test-plugin/test-plugin-latest.tar.gz');
|
||||
expect(settings.urls).to.contain('https://github.com/kibana/test-plugin/archive/master.tar.gz');
|
||||
});
|
||||
|
||||
it('should populate the urls collection properly version specified', function () {
|
||||
options.install = 'kibana/test-plugin/v1.1.1';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings.urls).to.have.property('length', 2);
|
||||
expect(settings.urls).to.contain('https://download.elastic.co/kibana/test-plugin/test-plugin-v1.1.1.tar.gz');
|
||||
expect(settings.urls).to.contain('https://github.com/kibana/test-plugin/archive/v1.1.1.tar.gz');
|
||||
});
|
||||
|
||||
it('should populate the pluginPath', function () {
|
||||
options.install = 'kibana/test-plugin';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
var expected = path.resolve(__dirname, '..', '..', '..', '..', '..', 'src', 'server', 'bin', 'plugins', 'test-plugin');
|
||||
|
||||
expect(settings).to.have.property('pluginPath', expected);
|
||||
});
|
||||
|
||||
describe('with url option', function () {
|
||||
|
||||
it('should allow one part to the install parameter', function () {
|
||||
options.install = 'test-plugin';
|
||||
options.url = 'http://www.google.com/plugin.tar.gz';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.not.throwException();
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('package', 'test-plugin');
|
||||
});
|
||||
|
||||
it('should not allow more than one part to the install parameter', function () {
|
||||
options.url = 'http://www.google.com/plugin.tar.gz';
|
||||
options.install = 'kibana/test-plugin';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Invalid install option. When providing a url, please use the format <plugin>./);
|
||||
});
|
||||
|
||||
it('should result in only the specified url in urls collection', function () {
|
||||
var url = 'http://www.google.com/plugin.tar.gz';
|
||||
options.install = 'test-plugin';
|
||||
options.url = url;
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('urls');
|
||||
expect(settings.urls).to.be.an('array');
|
||||
expect(settings.urls).to.have.property('length', 1);
|
||||
expect(settings.urls).to.contain(url);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('remove option', function () {
|
||||
|
||||
it('should set settings.action property to "remove"', function () {
|
||||
options.install = null;
|
||||
options.remove = 'package';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('action', 'remove');
|
||||
});
|
||||
|
||||
it('should allow one part to the remove parameter', function () {
|
||||
options.install = null;
|
||||
options.remove = 'test-plugin';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
|
||||
expect(settings).to.have.property('package', 'test-plugin');
|
||||
});
|
||||
|
||||
it('should not allow more than one part to the install parameter', function () {
|
||||
options.install = null;
|
||||
options.remove = 'kibana/test-plugin';
|
||||
|
||||
expect(settingParser.parse).withArgs(options)
|
||||
.to.throwException(/Invalid remove option. Please use the format <plugin>./);
|
||||
});
|
||||
|
||||
it('should populate the pluginPath', function () {
|
||||
options.install = null;
|
||||
options.remove = 'test-plugin';
|
||||
|
||||
var settings = settingParser.parse(options);
|
||||
var expected = path.resolve(__dirname, '..', '..', '..', '..', '..', 'src', 'server', 'bin', 'plugins', 'test-plugin');
|
||||
|
||||
expect(settings).to.have.property('pluginPath', expected);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue