UNPKG

@testim/testim-cli

Version:

Command line interface for running Testing on you CI

375 lines (295 loc) 27.7 kB
'use strict'; var _createClass = require('babel-runtime/helpers/create-class')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var _getIterator = require('babel-runtime/core-js/get-iterator')['default']; var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; var _Promise = require('babel-runtime/core-js/promise')['default']; var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; Object.defineProperty(exports, '__esModule', { value: true }); var _child_process = require('child_process'); var _child_process2 = _interopRequireDefault(_child_process); var _wdioDotReporter = require('wdio-dot-reporter'); var _wdioDotReporter2 = _interopRequireDefault(_wdioDotReporter); var _utilsConfigParser = require('./utils/ConfigParser'); var _utilsConfigParser2 = _interopRequireDefault(_utilsConfigParser); var _utilsBaseReporter = require('./utils/BaseReporter'); var _utilsBaseReporter2 = _interopRequireDefault(_utilsBaseReporter); var Launcher = (function () { function Launcher(configFile, argv) { _classCallCheck(this, Launcher); this.configParser = new _utilsConfigParser2['default'](); this.configParser.addConfigFile(configFile); this.configParser.merge(argv); this.reporter = this.initReporter(); this.argv = argv; this.configFile = configFile; this.exitCode = 0; this.hasTriggeredExitRoutine = false; this.hasStartedAnyProcess = false; this.processes = []; this.schedule = []; } /** * check if multiremote or wdio test */ _createClass(Launcher, [{ key: 'isMultiremote', value: function isMultiremote() { var caps = this.configParser.getCapabilities(); return !Array.isArray(caps); } /** * initialise reporter */ }, { key: 'initReporter', value: function initReporter() { var reporter = new _utilsBaseReporter2['default'](); var config = this.configParser.getConfig(); /** * if no reporter is set or config property is in a wrong format * just use the dot reporter */ if (!config.reporter || !Array.isArray(config.reporter)) { reporter.add(new _wdioDotReporter2['default'](reporter)); return reporter; } var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = _getIterator(config.reporter), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _reporter = _step.value; try { var Reporter = require('wdio-' + _reporter + '-reporter'); _reporter.add(new Reporter(_reporter)); } catch (e) { throw new Error('reporter "wdio-' + _reporter + '-reporter" is not installed'); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator['return']) { _iterator['return'](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return reporter; } /** * run sequence * @return {Promise} that only gets resolves with either an exitCode or an error */ }, { key: 'run', value: function run() { var config, caps, _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, capabilities, exitCode; return _regeneratorRuntime.async(function run$(context$2$0) { var _this = this; while (1) switch (context$2$0.prev = context$2$0.next) { case 0: config = this.configParser.getConfig(); caps = this.configParser.getCapabilities(); this.reporter.emit('start'); context$2$0.prev = 3; context$2$0.next = 6; return _regeneratorRuntime.awrap(config.onPrepare(config, caps)); case 6: context$2$0.next = 11; break; case 8: context$2$0.prev = 8; context$2$0.t0 = context$2$0['catch'](3); return context$2$0.abrupt('return', context$2$0.t0); case 11: if (!this.isMultiremote()) { context$2$0.next = 13; break; } return context$2$0.abrupt('return', this.startInstance(this.configParser.getSpecs(), caps)); case 13: _iteratorNormalCompletion2 = true; _didIteratorError2 = false; _iteratorError2 = undefined; context$2$0.prev = 16; /** * schedule test runs */ for (_iterator2 = _getIterator(caps); !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { capabilities = _step2.value; this.schedule.push({ specs: this.configParser.getSpecs(capabilities.specs, capabilities.exclude), availableInstances: capabilities.maxInstances || config.maxInstances || 1, runningInstances: 0 }); } /** * catches ctrl+c event */ context$2$0.next = 24; break; case 20: context$2$0.prev = 20; context$2$0.t1 = context$2$0['catch'](16); _didIteratorError2 = true; _iteratorError2 = context$2$0.t1; case 24: context$2$0.prev = 24; context$2$0.prev = 25; if (!_iteratorNormalCompletion2 && _iterator2['return']) { _iterator2['return'](); } case 27: context$2$0.prev = 27; if (!_didIteratorError2) { context$2$0.next = 30; break; } throw _iteratorError2; case 30: return context$2$0.finish(27); case 31: return context$2$0.finish(24); case 32: process.on('SIGINT', this.exitHandler.bind(this)); /** * make sure the program will not close instantly */ process.stdin.resume(); context$2$0.next = 36; return _regeneratorRuntime.awrap(new _Promise(function (resolve, reject) { _this.resolve = resolve; _this.runSpecs(); })); case 36: exitCode = context$2$0.sent; context$2$0.prev = 37; context$2$0.next = 40; return _regeneratorRuntime.awrap(config.onComplete(exitCode)); case 40: context$2$0.next = 45; break; case 42: context$2$0.prev = 42; context$2$0.t2 = context$2$0['catch'](37); return context$2$0.abrupt('return', context$2$0.t2); case 45: return context$2$0.abrupt('return', exitCode); case 46: case 'end': return context$2$0.stop(); } }, null, this, [[3, 8], [16, 20, 24, 32], [25,, 27, 31], [37, 42]]); } /** * run multiple single remote tests */ }, { key: 'runSpecs', value: function runSpecs() { var _this2 = this; var specsLeft = 0; var isRunning = false; this.schedule.forEach(function (capability, cid) { var specFiles = capability.specs.length; specsLeft += specFiles; for (var i = 0; i < capability.availableInstances && i < specFiles; i++) { _this2.startInstance([capability.specs.pop()], cid); capability.availableInstances--; capability.runningInstances++; } isRunning = isRunning || capability.runningInstances > 0; }); return specsLeft === 0 && !isRunning; } /** * Start instance in a child process. * @param {Object|Object[]} capabilities desired capabilities of instance */ }, { key: 'startInstance', value: function startInstance(specs, i) { var childProcess = _child_process2['default'].fork(__dirname + '/runner.js', [], { cwd: process.cwd() }); this.processes.push(childProcess); childProcess.on('message', this.messageHandler.bind(this)).on('exit', this.endHandler.bind(this)); childProcess.send({ cid: i, command: 'run', configFile: this.configFile, argv: this.argv, specs: specs, isMultiremote: this.isMultiremote() }); } /** * emit event from child process to reporter * @param {Object} m event object */ }, { key: 'messageHandler', value: function messageHandler(m) { this.hasStartedAnyProcess = true; /** * update schedule */ if (m.event === 'runner:end' || m.event === 'runner:error') { this.schedule[m.cid].availableInstances++; this.schedule[m.cid].runningInstances--; } if (m.event === 'runner:error') { this.reporter.emit('error', m); } this.reporter.emit(m.event, m); } /** * Closes test runner process once all instances finished and excited process. * @param {Number} childProcessExitCode exit code of child process */ }, { key: 'endHandler', value: function endHandler(childProcessExitCode) { this.exitCode = this.exitCode || childProcessExitCode; if (!this.isMultiremote() && !this.runSpecs()) { return; } this.reporter.emit('end', { sigint: this.hasTriggeredExitRoutine, exitCode: this.exitCode }); this.resolve(this.exitCode); } /** * Make sure all started selenium sessions get closed properly and prevent * having dead driver processes. To do so let the runner end its Selenium * session first before killing */ }, { key: 'exitHandler', value: function exitHandler() { if (this.hasTriggeredExitRoutine || !this.hasStartedAnyProcess) { console.log('\nKilling process, bye!'); return this.resolve(1); } console.log('\n\nEnd selenium sessions properly ...\n(press crtl+c again to hard kill the runner)\n'); this.hasTriggeredExitRoutine = true; } }]); return Launcher; })(); exports['default'] = Launcher; module.exports = exports['default']; /** * if it is an object run multiremote test */ //# sourceMappingURL=data:application/json;base64,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QUFDLElBQUksQ0FBQyxvQkFBb0IsRUFBRTtBQUM1RCx1QkFBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFBO0FBQ3RDLHVCQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUE7YUFDekI7O0FBRUQsbUJBQU8sQ0FBQyxHQUFHLDBGQUlqQixDQUFBOztBQUVNLGdCQUFJLENBQUMsdUJBQXVCLEdBQUcsSUFBSSxDQUFBO1NBQ3RDOzs7V0F4TkMsUUFBUTs7O3FCQTJOQyxRQUFRIiwiZmlsZSI6ImxhdW5jaGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoaWxkIGZyb20gJ2NoaWxkX3Byb2Nlc3MnXG5pbXBvcnQgRG90UmVwb3J0ZXIgZnJvbSAnd2Rpby1kb3QtcmVwb3J0ZXInXG5cbmltcG9ydCBDb25maWdQYXJzZXIgZnJvbSAnLi91dGlscy9Db25maWdQYXJzZXInXG5pbXBvcnQgQmFzZVJlcG9ydGVyIGZyb20gJy4vdXRpbHMvQmFzZVJlcG9ydGVyJ1xuXG5cbmNsYXNzIExhdW5jaGVyIHtcbiAgICBjb25zdHJ1Y3RvciAoY29uZmlnRmlsZSwgYXJndikge1xuICAgICAgICB0aGlzLmNvbmZpZ1BhcnNlciA9IG5ldyBDb25maWdQYXJzZXIoKVxuICAgICAgICB0aGlzLmNvbmZpZ1BhcnNlci5hZGRDb25maWdGaWxlKGNvbmZpZ0ZpbGUpXG4gICAgICAgIHRoaXMuY29uZmlnUGFyc2VyLm1lcmdlKGFyZ3YpXG5cbiAgICAgICAgdGhpcy5yZXBvcnRlciA9IHRoaXMuaW5pdFJlcG9ydGVyKClcblxuICAgICAgICB0aGlzLmFyZ3YgPSBhcmd2XG4gICAgICAgIHRoaXMuY29uZmlnRmlsZSA9IGNvbmZpZ0ZpbGVcblxuICAgICAgICB0aGlzLmV4aXRDb2RlID0gMFxuICAgICAgICB0aGlzLmhhc1RyaWdnZXJlZEV4aXRSb3V0aW5lID0gZmFsc2VcbiAgICAgICAgdGhpcy5oYXNTdGFydGVkQW55UHJvY2VzcyA9IGZhbHNlXG4gICAgICAgIHRoaXMucHJvY2Vzc2VzID0gW11cbiAgICAgICAgdGhpcy5zY2hlZHVsZSA9IFtdXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY2hlY2sgaWYgbXVsdGlyZW1vdGUgb3Igd2RpbyB0ZXN0XG4gICAgICovXG4gICAgaXNNdWx0aXJlbW90ZSAoKSB7XG4gICAgICAgIGxldCBjYXBzID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q2FwYWJpbGl0aWVzKClcbiAgICAgICAgcmV0dXJuICFBcnJheS5pc0FycmF5KGNhcHMpXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaW5pdGlhbGlzZSByZXBvcnRlclxuICAgICAqL1xuICAgIGluaXRSZXBvcnRlciAoKSB7XG4gICAgICAgIGxldCByZXBvcnRlciA9IG5ldyBCYXNlUmVwb3J0ZXIoKVxuICAgICAgICBsZXQgY29uZmlnID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q29uZmlnKClcblxuICAgICAgICAvKipcbiAgICAgICAgICogaWYgbm8gcmVwb3J0ZXIgaXMgc2V0IG9yIGNvbmZpZyBwcm9wZXJ0eSBpcyBpbiBhIHdyb25nIGZvcm1hdFxuICAgICAgICAgKiBqdXN0IHVzZSB0aGUgZG90IHJlcG9ydGVyXG4gICAgICAgICAqL1xuICAgICAgICBpZiAoIWNvbmZpZy5yZXBvcnRlciB8fCAhQXJyYXkuaXNBcnJheShjb25maWcucmVwb3J0ZXIpKSB7XG4gICAgICAgICAgICByZXBvcnRlci5hZGQobmV3IERvdFJlcG9ydGVyKHJlcG9ydGVyKSlcbiAgICAgICAgICAgIHJldHVybiByZXBvcnRlclxuICAgICAgICB9XG5cbiAgICAgICAgZm9yIChsZXQgcmVwb3J0ZXIgb2YgY29uZmlnLnJlcG9ydGVyKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGxldCBSZXBvcnRlciA9IHJlcXVpcmUoYHdkaW8tJHtyZXBvcnRlcn0tcmVwb3J0ZXJgKVxuICAgICAgICAgICAgICAgIHJlcG9ydGVyLmFkZChuZXcgUmVwb3J0ZXIocmVwb3J0ZXIpKVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgcmVwb3J0ZXIgXCJ3ZGlvLSR7cmVwb3J0ZXJ9LXJlcG9ydGVyXCIgaXMgbm90IGluc3RhbGxlZGApXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVwb3J0ZXJcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBydW4gc2VxdWVuY2VcbiAgICAgKiBAcmV0dXJuICB7UHJvbWlzZX0gdGhhdCBvbmx5IGdldHMgcmVzb2x2ZXMgd2l0aCBlaXRoZXIgYW4gZXhpdENvZGUgb3IgYW4gZXJyb3JcbiAgICAgKi9cbiAgICBhc3luYyBydW4gKCkge1xuICAgICAgICBsZXQgY29uZmlnID0gdGhpcy5jb25maWdQYXJzZXIuZ2V0Q29uZmlnKClcbiAgICAgICAgbGV0IGNhcHMgPSB0aGlzLmNvbmZpZ1BhcnNlci5nZXRDYXBhYmlsaXRpZXMoKVxuXG4gICAgICAgIHRoaXMucmVwb3J0ZXIuZW1pdCgnc3RhcnQnKVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgY29uZmlnLm9uUHJlcGFyZShjb25maWcsIGNhcHMpXG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBlXG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogaWYgaXQgaXMgYW4gb2JqZWN0IHJ1biBtdWx0aXJlbW90ZSB0ZXN0XG4gICAgICAgICAqL1xuICAgICAgICBpZiAodGhpcy5pc011bHRpcmVtb3RlKCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnN0YXJ0SW5zdGFuY2UodGhpcy5jb25maWdQYXJzZXIuZ2V0U3BlY3MoKSwgY2FwcylcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBzY2hlZHVsZSB0ZXN0IHJ1bnNcbiAgICAgICAgICovXG4gICAgICAgIGZvciAobGV0IGNhcGFiaWxpdGllcyBvZiBjYXBzKSB7XG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlLnB1c2goe1xuICAgICAgICAgICAgICAgIHNwZWNzOiB0aGlzLmNvbmZpZ1BhcnNlci5nZXRTcGVjcyhjYXBhYmlsaXRpZXMuc3BlY3MsIGNhcGFiaWxpdGllcy5leGNsdWRlKSxcbiAgICAgICAgICAgICAgICBhdmFpbGFibGVJbnN0YW5jZXM6IGNhcGFiaWxpdGllcy5tYXhJbnN0YW5jZXMgfHwgY29uZmlnLm1heEluc3RhbmNlcyB8fCAxLFxuICAgICAgICAgICAgICAgIHJ1bm5pbmdJbnN0YW5jZXM6IDBcbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogY2F0Y2hlcyBjdHJsK2MgZXZlbnRcbiAgICAgICAgICovXG4gICAgICAgIHByb2Nlc3Mub24oJ1NJR0lOVCcsIHRoaXMuZXhpdEhhbmRsZXIuYmluZCh0aGlzKSlcblxuICAgICAgICAvKipcbiAgICAgICAgICogbWFrZSBzdXJlIHRoZSBwcm9ncmFtIHdpbGwgbm90IGNsb3NlIGluc3RhbnRseVxuICAgICAgICAgKi9cbiAgICAgICAgcHJvY2Vzcy5zdGRpbi5yZXN1bWUoKVxuXG4gICAgICAgIGxldCBleGl0Q29kZSA9IGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVzb2x2ZSA9IHJlc29sdmVcbiAgICAgICAgICAgIHRoaXMucnVuU3BlY3MoKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBjb25maWcub25Db21wbGV0ZShleGl0Q29kZSlcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIGVcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZXhpdENvZGVcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBydW4gbXVsdGlwbGUgc2luZ2xlIHJlbW90ZSB0ZXN0c1xuICAgICAqL1xuICAgIHJ1blNwZWNzICgpIHtcbiAgICAgICAgbGV0IHNwZWNzTGVmdCA9IDBcbiAgICAgICAgbGV0IGlzUnVubmluZyA9IGZhbHNlXG5cbiAgICAgICAgdGhpcy5zY2hlZHVsZS5mb3JFYWNoKChjYXBhYmlsaXR5LCBjaWQpID0+IHtcbiAgICAgICAgICAgIGxldCBzcGVjRmlsZXMgPSBjYXBhYmlsaXR5LnNwZWNzLmxlbmd0aFxuICAgICAgICAgICAgc3BlY3NMZWZ0ICs9IHNwZWNGaWxlc1xuXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNhcGFiaWxpdHkuYXZhaWxhYmxlSW5zdGFuY2VzICYmIGkgPCBzcGVjRmlsZXM7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhcnRJbnN0YW5jZShbY2FwYWJpbGl0eS5zcGVjcy5wb3AoKV0sIGNpZClcbiAgICAgICAgICAgICAgICBjYXBhYmlsaXR5LmF2YWlsYWJsZUluc3RhbmNlcy0tXG4gICAgICAgICAgICAgICAgY2FwYWJpbGl0eS5ydW5uaW5nSW5zdGFuY2VzKytcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlzUnVubmluZyA9IGlzUnVubmluZyB8fCBjYXBhYmlsaXR5LnJ1bm5pbmdJbnN0YW5jZXMgPiAwXG4gICAgICAgIH0pXG5cbiAgICAgICAgcmV0dXJuIHNwZWNzTGVmdCA9PT0gMCAmJiAhaXNSdW5uaW5nXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU3RhcnQgaW5zdGFuY2UgaW4gYSBjaGlsZCBwcm9jZXNzLlxuICAgICAqIEBwYXJhbSAge09iamVjdHxPYmplY3RbXX0gY2FwYWJpbGl0aWVzICBkZXNpcmVkIGNhcGFiaWxpdGllcyBvZiBpbnN0YW5jZVxuICAgICAqL1xuICAgIHN0YXJ0SW5zdGFuY2UgKHNwZWNzLCBpKSB7XG4gICAgICAgIGxldCBjaGlsZFByb2Nlc3MgPSBjaGlsZC5mb3JrKF9fZGlybmFtZSArICcvcnVubmVyLmpzJywgW10sIHtcbiAgICAgICAgICAgIGN3ZDogcHJvY2Vzcy5jd2QoKVxuICAgICAgICB9KVxuXG4gICAgICAgIHRoaXMucHJvY2Vzc2VzLnB1c2goY2hpbGRQcm9jZXNzKVxuXG4gICAgICAgIGNoaWxkUHJvY2Vzc1xuICAgICAgICAgICAgLm9uKCdtZXNzYWdlJywgdGhpcy5tZXNzYWdlSGFuZGxlci5iaW5kKHRoaXMpKVxuICAgICAgICAgICAgLm9uKCdleGl0JywgdGhpcy5lbmRIYW5kbGVyLmJpbmQodGhpcykpXG5cbiAgICAgICAgY2hpbGRQcm9jZXNzLnNlbmQoe1xuICAgICAgICAgICAgY2lkOiBpLFxuICAgICAgICAgICAgY29tbWFuZDogJ3J1bicsXG4gICAgICAgICAgICBjb25maWdGaWxlOiB0aGlzLmNvbmZpZ0ZpbGUsXG4gICAgICAgICAgICBhcmd2OiB0aGlzLmFyZ3YsXG4gICAgICAgICAgICBzcGVjczogc3BlY3MsXG4gICAgICAgICAgICBpc011bHRpcmVtb3RlOiB0aGlzLmlzTXVsdGlyZW1vdGUoKVxuICAgICAgICB9KVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGVtaXQgZXZlbnQgZnJvbSBjaGlsZCBwcm9jZXNzIHRvIHJlcG9ydGVyXG4gICAgICogQHBhcmFtICB7T2JqZWN0fSBtICBldmVudCBvYmplY3RcbiAgICAgKi9cbiAgICBtZXNzYWdlSGFuZGxlciAobSkge1xuICAgICAgICB0aGlzLmhhc1N0YXJ0ZWRBbnlQcm9jZXNzID0gdHJ1ZVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB1cGRhdGUgc2NoZWR1bGVcbiAgICAgICAgICovXG4gICAgICAgIGlmIChtLmV2ZW50ID09PSAncnVubmVyOmVuZCcgfHwgbS5ldmVudCA9PT0gJ3J1bm5lcjplcnJvcicpIHtcbiAgICAgICAgICAgIHRoaXMuc2NoZWR1bGVbbS5jaWRdLmF2YWlsYWJsZUluc3RhbmNlcysrXG4gICAgICAgICAgICB0aGlzLnNjaGVkdWxlW20uY2lkXS5ydW5uaW5nSW5zdGFuY2VzLS1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtLmV2ZW50ID09PSAncnVubmVyOmVycm9yJykge1xuICAgICAgICAgICAgdGhpcy5yZXBvcnRlci5lbWl0KCdlcnJvcicsIG0pXG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJlcG9ydGVyLmVtaXQobS5ldmVudCwgbSlcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGVzdCBydW5uZXIgcHJvY2VzcyBvbmNlIGFsbCBpbnN0YW5jZXMgZmluaXNoZWQgYW5kIGV4Y2l0ZWQgcHJvY2Vzcy5cbiAgICAgKiBAcGFyYW0gIHtOdW1iZXJ9IGNoaWxkUHJvY2Vzc0V4aXRDb2RlICBleGl0IGNvZGUgb2YgY2hpbGQgcHJvY2Vzc1xuICAgICAqL1xuICAgIGVuZEhhbmRsZXIgKGNoaWxkUHJvY2Vzc0V4aXRDb2RlKSB7XG4gICAgICAgIHRoaXMuZXhpdENvZGUgPSB0aGlzLmV4aXRDb2RlIHx8IGNoaWxkUHJvY2Vzc0V4aXRDb2RlXG5cbiAgICAgICAgaWYgKCF0aGlzLmlzTXVsdGlyZW1vdGUoKSAmJiAhdGhpcy5ydW5TcGVjcygpKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucmVwb3J0ZXIuZW1pdCgnZW5kJywge1xuICAgICAgICAgICAgc2lnaW50OiB0aGlzLmhhc1RyaWdnZXJlZEV4aXRSb3V0aW5lLFxuICAgICAgICAgICAgZXhpdENvZGU6IHRoaXMuZXhpdENvZGVcbiAgICAgICAgfSlcblxuICAgICAgICB0aGlzLnJlc29sdmUodGhpcy5leGl0Q29kZSlcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNYWtlIHN1cmUgYWxsIHN0YXJ0ZWQgc2VsZW5pdW0gc2Vzc2lvbnMgZ2V0IGNsb3NlZCBwcm9wZXJseSBhbmQgcHJldmVudFxuICAgICAqIGhhdmluZyBkZWFkIGRyaXZlciBwcm9jZXNzZXMuIFRvIGRvIHNvIGxldCB0aGUgcnVubmVyIGVuZCBpdHMgU2VsZW5pdW1cbiAgICAgKiBzZXNzaW9uIGZpcnN0IGJlZm9yZSBraWxsaW5nXG4gICAgICovXG4gICAgZXhpdEhhbmRsZXIgKCkge1xuICAgICAgICBpZiAodGhpcy5oYXNUcmlnZ2VyZWRFeGl0Um91dGluZSB8fCAhdGhpcy5oYXNTdGFydGVkQW55UHJvY2Vzcykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1xcbktpbGxpbmcgcHJvY2VzcywgYnllIScpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNvbHZlKDEpXG4gICAgICAgIH1cblxuICAgICAgICBjb25zb2xlLmxvZyhgXG5cbkVuZCBzZWxlbml1bSBzZXNzaW9ucyBwcm9wZXJseSAuLi5cbihwcmVzcyBjcnRsK2MgYWdhaW4gdG8gaGFyZCBraWxsIHRoZSBydW5uZXIpXG5gKVxuXG4gICAgICAgIHRoaXMuaGFzVHJpZ2dlcmVkRXhpdFJvdXRpbmUgPSB0cnVlXG4gICAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBMYXVuY2hlclxuIl19