UNPKG

terra-toolkit

Version:

Utilities to help when developing terra modules.

362 lines (303 loc) 11 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _child_process = require("child_process"); var _retry = _interopRequireDefault(require("async/retry")); var _http = _interopRequireDefault(require("http")); var _path = _interopRequireDefault(require("path")); var _services = _interopRequireDefault(require("../../../config/wdio/services.default-config")); var _logger = _interopRequireDefault(require("../../../scripts/utils/logger")); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var context = '[Terra-Toolkit:selenium-docker]'; /** * Webdriver.io SeleniumDockerService * provides standalone chrome selenium docker automation. */ var SeleniumDockerService = /*#__PURE__*/function () { function SeleniumDockerService() { (0, _classCallCheck2.default)(this, SeleniumDockerService); this.getSeleniumStatus = this.getSeleniumStatus.bind(this); } /** * Start up docker container before all workers get launched. * @param {Object} config wdio configuration object * @param {Array.<Object>} capabilities list of capabilities details */ (0, _createClass2.default)(SeleniumDockerService, [{ key: "onPrepare", value: function () { var _onPrepare = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(config) { var dockerInfo; return _regenerator.default.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: this.config = _objectSpread(_objectSpread({}, _services.default.seleniumDocker), config.seleniumDocker || {}); this.host = config.host; this.port = config.port; this.path = config.path; if (!this.config.enabled) { _context.next = 22; break; } _context.next = 7; return this.getDockerInfo(); case 7: dockerInfo = _context.sent; if (!(dockerInfo.Swarm.LocalNodeState !== 'active')) { _context.next = 11; break; } _context.next = 11; return this.initSwarm(); case 11: _context.next = 13; return this.getStack(); case 13: if (!_context.sent) { _context.next = 18; break; } _context.next = 16; return this.removeStack(); case 16: _context.next = 18; return this.ensureNetworkRemoved(); case 18: _context.next = 20; return this.deployStack(); case 20: _context.next = 22; return this.ensureSelenium(); case 22: case "end": return _context.stop(); } } }, _callee, this); })); function onPrepare(_x) { return _onPrepare.apply(this, arguments); } return onPrepare; }() /** * Clean up docker container after all workers got shut down and the process is about to exit. */ }, { key: "onComplete", value: function () { var _onComplete = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() { return _regenerator.default.wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: if (!this.config.enabled) { _context2.next = 5; break; } _context2.next = 3; return this.removeStack(); case 3: _context2.next = 5; return this.ensureNetworkRemoved(); case 5: case "end": return _context2.stop(); } } }, _callee2, this); })); function onComplete() { return _onComplete.apply(this, arguments); } return onComplete; }() /** * Waits for selenium to startup and be ready within the configured container. * @return {Promise} */ }, { key: "ensureSelenium", value: function ensureSelenium() { var _this = this; return new Promise(function (resolve, reject) { _logger.default.log('Ensuring selenium status is ready', { context: context }); (0, _retry.default)({ times: _this.config.retries, interval: _this.config.retryInterval }, _this.getSeleniumStatus, function (err, result) { if (err) { reject(_logger.default.error(JSON.stringify(err), { context: context })); } else { resolve(result); } }); }); } /** * Gets the stack information. * @return {Promise} which resolves to a string representing the stack, or null if none exists. */ }, { key: "getStack", value: function getStack() { return new Promise(function (resolve) { (0, _child_process.exec)('docker stack ls | grep wdio', function (error, stdout) { resolve(stdout); }); }); } /** * Gets information about the docker environment. * @return {Promise} which resolves to a JSON object describing the docker environment. */ }, { key: "getDockerInfo", value: function getDockerInfo() { return this.execute('docker info --format "{{json .}}"').then(function (result) { return JSON.parse(result); }); } /** * Gets the stack default network. * @return {Promise} which resolves to a string representing the network, or null if none exists. */ }, { key: "getNetwork", value: function getNetwork() { return this.execute('docker network ls --filter name=wdio --format "{{.ID}}: {{.Driver}}"'); } /** * Initializes the docker swarm. See https://docs.docker.com/engine/reference/commandline/swarm_init/#related-commands * @return {Promise} */ }, { key: "initSwarm", value: function initSwarm() { _logger.default.log('Initializing docker swarm', { context: context }); return this.execute('docker swarm init'); } /** * Deploys the docker selenium hub stack * @return {Promise} */ }, { key: "deployStack", value: function deployStack() { _logger.default.log('Deploying docker selenium stack', { context: context }); return this.execute("docker stack deploy --compose-file ".concat(this.config.composeFile, " wdio")); } /** * Stops the docker stack * @return {Promise} */ }, { key: "removeStack", value: function removeStack() { _logger.default.log('Removing docker selenium stack', { context: context }); return this.execute('docker stack rm wdio'); } /** * Executes an arbitrary command and returns a promise. * @param {String} command - The command to execute * @return {Promise} */ }, { key: "execute", value: function execute(command) { return new Promise(function (resolve, reject) { (0, _child_process.exec)(command, function (error, stdout) { if (error) { reject(error); } else { resolve(stdout); } }); }); } /** * Ensures the stack default network is removed. * @return {Promise} */ }, { key: "ensureNetworkRemoved", value: function ensureNetworkRemoved() { var _this2 = this; return new Promise(function (resolve, reject) { (0, _retry.default)({ times: 1000, interval: 10 }, function (callback) { // If there is a network, it will register as an error in the callback _this2.getNetwork().then(callback).catch(callback); }, function (err, result) { if (err) { reject(err); } else { resolve(result); } }); }); } /** * Gets the status of the selenium server. * @param {function} callback taking (err, result). */ }, { key: "getSeleniumStatus", value: function getSeleniumStatus(callback) { _http.default.get({ host: this.host, port: this.port, path: _path.default.posix.join(this.path || '/wd/hub', 'status') }, function (res) { var statusCode = res.statusCode; if (statusCode !== 200) { callback('Request failed'); return; } res.setEncoding('utf8'); var rawData = ''; res.on('data', function (chunk) { rawData += chunk; }); res.on('end', function () { try { var status = JSON.parse(rawData); if (status.value && status.value.ready) { callback(null, status); } else { callback(status); } } catch (e) { callback("Request failed: ".concat(e.message)); } }); }).on('error', function (e) { callback("Request failed: ".concat(e.message)); }); } }]); return SeleniumDockerService; }(); exports.default = SeleniumDockerService;