"use strict"; /** * Steps to manage proxy. * * These methods are mixed with glacejs [Steps](https://glacejs.github.io/glace-core/Steps.html) * class and available via its instance [$](https://glacejs.github.io/glace-core/global.html#$) * in tests. * * @mixin ProxySteps * @prop {string} webUrl - Web application URL. * @prop {GlobalProxy} globalProxy - Global proxy instance. * @prop {HttpProxy} httpProxy - HTTP proxy instance. */ var url = require("url"); var util = require("util"); var _ = require("lodash"); var expect = require("chai").expect; var U = require("glace-utils"); require("./fixtures"); var GlobalProxy = require("./globalProxy"); var HttpProxy = require("./httpProxy"); var LOG = U.logger; var ProxySteps = { __GlobalProxy: GlobalProxy, __HttpProxy: HttpProxy, registerProxy: function (opts) { /** * Helper to register proxy classes. * * @memberOf ProxySteps * @method registerProxy * @instance * @arg {object} [opts] - Options. * @arg {object} [opts.GlobalProxy] - Global proxy class. * @arg {object} [opts.HttpProxy] - HTTP proxy class. * @example * * $.registerProxy({ GlobalProxy: MyGlobalProxy, HttpProxy: MyHttpProxy }); */ opts = U.defVal(opts, {}); this.__GlobalProxy = U.defVal(opts.GlobalProxy, this.__GlobalProxy); this.__HttpProxy = U.defVal(opts.HttpProxy, this.__HttpProxy); }, startHttpProxy: async function (opts) { /** * Step to start HTTP proxy. Step recall will be skipped if proxy wasn't * stopped before. * * @async * @memberOf ProxySteps * @method startHttpProxy * @instance * @arg {object} [opts] - Step options. * @arg {string} [opts.webUrl] - Web application url which will * be proxied. Default value will be requested from `config.web.url` * if it is specified. * @arg {boolean} [opts.useCache] - Flag to use proxy cache for * responses. Default value will be requested from `config.useCache` * if it is specified. * @arg {number} [opts.timeout] - Proxy timeout to break connection. * Default value will be requested from `config.timeout.proxy`. * @arg {number} [opts.reconnect] - Number of proxy reconnects on failure. * @arg {number} [opts.port] - Proxy port. Default value will be * requested from `config.proxyPort`. * @arg {boolean} [opts.check=true] - Flag to check that proxy was launched. * @return {Promise<string>} Proxied URL. * @return {Promise<boolean>} `false` if step was skipped * @throws {AssertionError} If proxy was not launched. * @example * * var proxiedUrl = await $.startHttpProxy(); * var proxiedUrl = await $.startHttpProxy({ webUrl: "http://example.com", }); * var proxiedUrl = await $.startHttpProxy({ webUrl: "http://example.com", port: 8080 }); */ if (this._isProxyStarted) { LOG.warn("Step to start proxy was passed already"); return false; }; opts = U.defVal(opts, {}); var webUrl = U.defVal(opts.webUrl, CONF.web && CONF.web.url); var useCache = U.defVal(opts.useCache, CONF.cache.use); var timeout = U.defVal(opts.timeout, CONF.proxy.timeout); var reconnect = U.defVal(opts.reconnect, CONF.proxy.reconnect); var port = U.defVal(opts.port, CONF.proxy.port); var check = U.defVal(opts.check, true); allure.step("Start http proxy"); expect(webUrl, "Web URL for http proxy isn't specified").to.exist; LOG.info("Starting http proxy..."); this.httpProxy = this.httpProxy || new this.__HttpProxy({ url: webUrl, useCache: useCache, timeout: timeout, reconnect: reconnect, port: port }); await this.httpProxy.start(); if (check) { expect(this.httpProxy.isRunning, "HTTP proxy was not launched").be.true; }; this._isProxyStarted = true; this.webUrl = _.trim( this.httpProxy.url + url.parse(CONF.web.url).pathname, "/"); LOG.info("Http proxy is started"); allure.pass(); return this.webUrl; }, getProxyUrl: function (opts) { /** * Step to get proxy URL. * * @memberOf ProxySteps * @method getProxyUrl * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that proxy URL is * defined. * @return {string} Proxy URL. * @throws {AssertionError} If proxy URL isn't defined. * @example * * var proxiedUrl = $.getProxiedUrl(); */ opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Get http proxy url"); LOG.info("Getting http proxy url..."); if (check) { expect(this.httpProxy.url, "HTTP proxy was not launched").to.exist; }; LOG.info("Http proxy url is got"); allure.pass(); return this.httpProxy.url; }, stopHttpProxy: async function (opts) { /** * Step to stop HTTP proxy. Step call will be skipped if proxy wasn't * launched before. * * @async * @memberOf ProxySteps * @method stopHttpProxy * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that proxy was * stopped. * @return {Promise<boolean>} `true` if step was passed, `false` if was * skipped. * @throws {AssertionError} If proxy wasn't stopped. * @example * * await $.stopHttpProxy(); */ if (!this._isProxyStarted) { LOG.warn("Step to start HTTP proxy wasn't passed yet"); return false; }; opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Stop http proxy"); LOG.info("Stopping http proxy..."); await this.httpProxy.stop(); if (check) { expect(this.httpProxy.isRunning, "HTTP proxy wasn't stopped").be.false; }; this.webUrl = CONF.web.url; this._isProxyStarted = false; LOG.info("Http proxy is stopped"); allure.pass(); return true; }, startGlobalProxy: async function (opts) { /** * Step to start global proxy. Step recall will be skipped if global * proxy wasn't stopped before. * * @async * @memberOf ProxySteps * @method startGlobalProxy * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.useCache] - Flag to use proxy cache for * responses. Default value will be requested from `config.useCache` * if it is specified. * @arg {number} [opts.timeout] - Proxy timeout to break connection. * Default value will be requested from `config.timeout.proxy`. * @arg {number} [opts.reconnect] - Number of proxy reconnects on failure. * @arg {number} [opts.port] - Proxy port. Default value will be * requested from `config.globalProxyPort`. * @arg {boolean} [opts.check=true] - Flag to check that proxy was launched. * @return {Promise<boolean>} `true` if step was passed, `false` if was * skipped. * @throws {AssertionError} If global proxy was not launched. * @example * * await $.startGlobalProxy(); * await $.startGlobalProxy({ timeout: 30000 }); */ if (this._isGlobalProxyStarted) { LOG.warn("Step to start global proxy was passed already"); return false; }; opts = U.defVal(opts, {}); var useCache = U.defVal(opts.useCache, CONF.cache.use); var timeout = U.defVal(opts.timeout, CONF.proxy.timeout); var reconnect = U.defVal(opts.reconnect, CONF.proxy.reconnect); var port = U.defVal(opts.port, CONF.proxy.globalPort); const sslCaDir = U.defVal(opts.sslCaDir, CONF.proxy.sslCaDir); var check = U.defVal(opts.check, true); allure.step("Start global proxy"); LOG.info("Starting global proxy..."); this.globalProxy = this.globalProxy || new this.__GlobalProxy({ useCache: useCache, timeout: timeout, reconnect: reconnect, port: port, sslCaDir: sslCaDir, installCertificate: CONF.proxy.installCertificate }); await this.globalProxy.start(); if (check) { expect(this.globalProxy.isRunning, "Global proxy was not launched") .to.be.true; }; this._isGlobalProxyStarted = true; LOG.info("Global proxy is started"); allure.pass(); return true; }, stopGlobalProxy: async function (opts) { /** * Step to stop global proxy. Step call will be skipped if global proxy * wasn't launched before. * * @async * @memberOf ProxySteps * @method stopGlobalProxy * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that global * proxy was stopped. * @return {Promise<boolean>} `true` if step was passed, `false` if was * skipped. * @throws {AssertionError} If global proxy wasn't stopped. * @example * * await $.stopGlobalProxy(); */ if (!this._isGlobalProxyStarted) { LOG.warn("Step to start global proxy wasn't passed yet"); return false; }; opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Stop global proxy"); LOG.info("Stopping global proxy..."); await this.globalProxy.stop(); if (check) { expect(this.globalProxy.isRunning, "Global proxy wasn't stopped").be.false; }; this._isGlobalProxyStarted = false; LOG.info("Global proxy is stopped"); allure.pass(); return true; }, limitProxySpeed: function (speed, opts) { /** * Step to limit proxy speed. * * @memberOf ProxySteps * @method limitProxySpeed * @instance * @arg {number|object} speed - Proxy limited speed, kb/s. * @arg {?number} [speed.req] - Requests speed, kb/s. * @arg {?number} [speed.res] - Responses speed, kb/s. * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that proxy speed * is limited. * @return {boolean} `true` if step was passed. * @throws {AssertionError} If proxy speed is not limited. * @example * * $.limitProxySpeed(512); * $.limitProxySpeed({ res: 512 }); */ this._checkProxy(); opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step(util.format("Limit proxy speed to", speed, "kb/s")); LOG.info(util.format("Limiting proxy speed to", speed, "kb/s...")); if (this.httpProxy) { this.httpProxy.setSpeed(speed); }; if (this.globalProxy) { this.globalProxy.setSpeed(speed); }; if (check) { if (speed.req === undefined && speed.res === undefined) { speed = { req: speed, res: speed }; }; if (this.httpProxy) { if (speed.req !== undefined) { expect(this.httpProxy.reqSpeed, "HTTP proxy requests speed is not limited") .be.equal(speed.req); }; if (speed.res !== undefined) { expect(this.httpProxy.resSpeed, "HTTP proxy responses speed is not limited") .be.equal(speed.res); }; }; if (this.globalProxy) { if (speed.req !== undefined) { expect(this.globalProxy.reqSpeed, "Global proxy requests speed is not limited") .be.equal(speed.req); }; if (speed.res !== undefined) { expect(this.globalProxy.resSpeed, "Global proxy responses speed is not limited") .be.equal(speed.res); }; }; }; LOG.info("Proxy speed is limited"); allure.pass(); return true; }, unlimitProxySpeed: function (opts) { /** * Step to unlimit proxy speed. * * @memberOf ProxySteps * @method unlimitProxySpeed * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that proxy speed * is unlimited. * @return {boolean} `true` if step is passed. * @throws {AssertionError} If proxy speed is still limited. * @example * * $.unlimitProxySpeed(); */ this._checkProxy(); opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Unlimit proxy speed"); LOG.info("Unlimiting proxy speed..."); if (this.httpProxy) { this.httpProxy.resetSpeed(); }; if (this.globalProxy) { this.globalProxy.resetSpeed(); }; if (check) { if (this.httpProxy) { expect(this.httpProxy.reqSpeed, "HTTP proxy requests speed still has limited value") .be.null; expect(this.httpProxy.resSpeed, "HTTP proxy responses speed still has limited value") .be.null; }; if (this.globalProxy) { expect(this.globalProxy.reqSpeed, "Global proxy requests speed still has limited value") .be.null; expect(this.globalProxy.resSpeed, "Global proxy responses speed still has limited value") .be.null; }; }; LOG.info("Proxy speed is unlimited"); allure.pass(); return true; }, measureResponses: function (opts) { /** * Step to start responses measurement. * * @memberOf ProxySteps * @method measureResponses * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that responses * measurement is launched. * @return {boolean} `true` if step is passed. * @throws {AssertionError} If responses measurement is not launched. * @example * * $.measureResponses(); */ this._checkProxy(); opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Start to measure proxy responses"); LOG.info("Starting to measure proxy responses..."); if (this.httpProxy) { this.httpProxy.measureResponses(); }; if (this.globalProxy) { this.globalProxy.measureResponses(); }; if (check) { if (this.httpProxy) { expect(this.httpProxy.getResponsesData(), "HTTP proxy responses measurement is not launched") .to.exist; }; if (this.globalProxy) { expect(this.globalProxy.getResponsesData(), "Global proxy responses measurement is not launched") .to.exist; }; }; LOG.info("Proxy responses are measuring"); allure.pass(); return true; }, getResponsesData: function (opts) { /** * Step to get measured responses data. * * @memberOf ProxySteps * @method getResponsesData * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that responses * data are present. * @throws {AssertionError} If responses data are absent. * @return {object[]} List of captured response data. * @example * * var responses = $.getResponsesData(); */ this._checkProxy(); opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); var data = []; allure.step("Get responses data"); LOG.info("Getting responses data..."); if (this.httpProxy && this.httpProxy.getResponsesData()) { data = data.concat(this.httpProxy.getResponsesData()); }; if (this.globalProxy && this.globalProxy.getResponsesData()) { data = data.concat(this.globalProxy.getResponsesData()); }; if (check) { expect(_.isEmpty(data), "Responses data are absent").be.false; }; LOG.info("Responses data is got"); allure.pass(); return data; }, unmeasureResponses: function (opts) { /** * Step to stop responses measurement. * * @memberOf ProxySteps * @method unmeasureResponses * @instance * @arg {object} [opts] - Step options. * @arg {boolean} [opts.check=true] - Flag to check that responses * measurement is stopped. * @return {boolean} `true` if step is passed. * @throws {AssertionError} If responses measurement is still running. * @example * * $.unmeasureResponses(); */ this._checkProxy(); opts = U.defVal(opts, {}); var check = U.defVal(opts.check, true); allure.step("Stop to measure proxy responses"); LOG.info("Stopping to measure proxy responses..."); if (this.httpProxy) { this.httpProxy.unmeasureResponses(); }; if (this.globalProxy) { this.globalProxy.unmeasureResponses(); }; if (check) { if (this.httpProxy) { expect(this.httpProxy.getResponsesData(), "HTTP proxy responses measurement is still running") .to.be.null; }; if (this.globalProxy) { expect(this.globalProxy.getResponsesData(), "Global proxy responses measurement is still running") .to.be.null; }; }; LOG.info("Proxy responses are not measured"); allure.pass(); return true; }, enableCache: function () { /** * Step to enable cache. * * @memberOf ProxySteps * @method enableCache * @instance * @return {boolean} `true` if step is passed. * @example * * $.enableCache(); */ allure.step("Enable proxy cache"); this._checkProxy(); LOG.info("Enabling proxy cache..."); if (this.httpProxy) this.httpProxy.useCache = true; if (this.globalProxy) this.globalProxy.useCache = true; LOG.info("Proxy cache is enabled"); allure.pass(); return true; }, disableCache: function () { /** * Step to disable cache. * * @memberOf ProxySteps * @method disableCache * @instance * @return {boolean} `true` if step is passed. * @example * * $.disableCache(); */ allure.step("Disable proxy cache"); this._checkProxy(); LOG.info("Disabling proxy cache..."); if (this.httpProxy) this.httpProxy.useCache = false; if (this.globalProxy) this.globalProxy.useCache = false; LOG.info("Proxy cache is disabled"); allure.pass(); return true; }, /** * Helper to check that proxy is launched. * * @ignore * @method * @protected * @instance * @throws {AssertionError} - If no one proxy is launched. */ _checkProxy: function () { expect( (this.httpProxy && this.httpProxy.isRunning) || (this.globalProxy && this.globalProxy.isRunning), "No one proxy is launched").to.be.true; }, }; module.exports = ProxySteps;