diff --git a/selenium/.node-xmlhttprequest-sync-88011 b/selenium/.node-xmlhttprequest-sync-88011 deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/selenium/bin/components/other-rabbitmq b/selenium/bin/components/other-rabbitmq index c0b711f59e9b..473071cca4f1 100644 --- a/selenium/bin/components/other-rabbitmq +++ b/selenium/bin/components/other-rabbitmq @@ -28,14 +28,14 @@ start_other_rabbitmq() { if [[ "$PROFILES_FOR_OTHER" == *"docker"* ]]; then start_docker_other_rabbitmq else - start_local_rabbitmq + start_local_other_rabbitmq fi } stop_other_rabbitmq() { if [[ "$PROFILES_FOR_OTHER" == *"docker"* ]]; then - kill_container_if_exist "$component" + kill_container_if_exist "${OTHER_RABBITMQ_HOSTNAME}" else - stop_local_rabbitmq + stop_local_other_rabbitmq fi } @@ -44,7 +44,7 @@ save_logs_other_rabbitmq() { if [[ "$PROFILES_FOR_OTHER" == *"cluster"* ]]; then docker compose -f $CONF_DIR/rabbitmq/other-compose.yml logs > $LOGS/other-rabbitmq.log else - save_container_logs "other-rabbitmq" + save_container_logs "${OTHER_RABBITMQ_HOSTNAME}" fi fi } @@ -129,13 +129,15 @@ start_docker_other_rabbitmq() { print "> RABBITMQ_TEST_DIR: /var/rabbitmq" docker run \ + --rm \ --detach \ --name ${OTHER_RABBITMQ_HOSTNAME} \ --net ${DOCKER_NETWORK} \ -p 5674:5672 \ -p 5673:5671 \ -p 15674:15672 \ - -p 15673:15671 \ + -p 15675:15675 \ + -p 5552:5552 \ -v $CONF_DIR/other-rabbitmq/:/etc/rabbitmq \ -v $CONF_DIR/other-rabbitmq/imports:/var/rabbitmq/imports \ -v ${TEST_DIR}:/config \ diff --git a/selenium/bin/components/rabbitmq b/selenium/bin/components/rabbitmq index 7350f0205fe8..9cf16d495cbe 100644 --- a/selenium/bin/components/rabbitmq +++ b/selenium/bin/components/rabbitmq @@ -188,6 +188,7 @@ start_docker_rabbitmq() { -p 5671:5671 \ -p 15672:15672 \ -p 15671:15671 \ + -p 5551:5551 \ -v $CONF_DIR/rabbitmq/:/etc/rabbitmq \ -v $CONF_DIR/rabbitmq/imports:/var/rabbitmq/imports \ -v ${TEST_DIR}:/config \ diff --git a/selenium/bin/suite_template b/selenium/bin/suite_template index efe99343c6eb..c1e64653ebe3 100644 --- a/selenium/bin/suite_template +++ b/selenium/bin/suite_template @@ -355,8 +355,8 @@ _test() { print "> FAKEPORTAL_URL: ${FAKEPORTAL_URL}" mocha_test_tag=($(md5sum $SELENIUM_ROOT_FOLDER/package.json)) - print "> OAUTH_NODE_EXTRA_CA_CERTS: ${OAUTH_NODE_EXTRA_CA_CERTS}" - MOUNT_NODE_EXTRA_CA_CERTS=${TEST_DIR}/${OAUTH_NODE_EXTRA_CA_CERTS} + generate_node_extra_ca_cert + MOUNT_NODE_EXTRA_CA_CERTS=${CONF_DIR}/node_ca_certs.pem print "> MOUNT_NODE_EXTRA_CA_CERTS: ${MOUNT_NODE_EXTRA_CA_CERTS}" docker run \ @@ -417,7 +417,7 @@ other_profiles_with_local_or_docker() { fi } generate_env_file() { - begin "Generating env file from profiles ${PROFILES} ..." + begin "Generating env file from profiles: [${PROFILES}] ..." mkdir -p $CONF_DIR ${BIN_DIR}/gen-env-file "${PROFILES}" $TEST_CONFIG_DIR ${ENV_FILE}.tmp grep -v '^#' ${ENV_FILE}.tmp > $ENV_FILE @@ -425,7 +425,7 @@ generate_env_file() { end "Finished generating env file." } generate_other_env_file() { - begin "Generating other env file from profiles ${PROFILES_FOR_OTHER} " + begin "Generating other env file from profiles: [${PROFILES_FOR_OTHER}] " mkdir -p $CONF_DIR ${BIN_DIR}/gen-env-file "${PROFILES_FOR_OTHER}" $TEST_CONFIG_DIR ${OTHER_ENV_FILE}.tmp grep -v '^#' ${OTHER_ENV_FILE}.tmp > $OTHER_ENV_FILE @@ -674,7 +674,7 @@ test_local() { export SELENIUM_POLLING=${SELENIUM_POLLING:-500} generate_node_extra_ca_cert - MOUNT_NODE_EXTRA_CA_CERTS=${RABBITMQ_CERTS}/node_ca_certs.pem + MOUNT_NODE_EXTRA_CA_CERTS=${CONF_DIR}/node_ca_certs.pem print "> SELENIUM_TIMEOUT: ${SELENIUM_TIMEOUT}" print "> SELENIUM_POLLING: ${SELENIUM_POLLING}" @@ -738,14 +738,16 @@ save_components_logs() { end "Finished saving logs" } generate_node_extra_ca_cert() { - echo "Generating $RABBITMQ_CERTS/node_ca_certs.pem ..." - rm -f $RABBITMQ_CERTS/node_ca_certs.pem + echo "Generating ${CONF_DIR}/node_ca_certs.pem ..." + rm -f ${CONF_DIR}/node_ca_certs.pem env | while IFS= read -r line; do value=${line#*=} name=${line%%=*} + if [[ $name == *NODE_EXTRA_CA_CERTS ]] then - cat ${TEST_DIR}/${value} >> $RABBITMQ_CERTS/node_ca_certs.pem + echo "Adding ${TEST_DIR}/${value} to ${CONF_DIR}/node_ca_certs.pem ..." + cat ${TEST_DIR}/${value} >> ${CONF_DIR}/node_ca_certs.pem fi done } \ No newline at end of file diff --git a/selenium/fakeportal/proxy.js b/selenium/fakeportal/proxy.js index 884c02e4d0da..8bcdd217f304 100644 --- a/selenium/fakeportal/proxy.js +++ b/selenium/fakeportal/proxy.js @@ -1,5 +1,6 @@ var http = require('http'), httpProxy = require('http-proxy'); +const {log, error} = require('./utils.js') const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest const rabbitmq_url = process.env.RABBITMQ_URL || 'http://0.0.0.0:15672/'; @@ -14,7 +15,7 @@ const port = process.env.PORT; var proxy = httpProxy.createProxyServer({}); proxy.on('proxyReq', function(proxyReq, req, res, options) { - console.log("proxing " + req.url) + log("proxing " + req.url) if (req.url.endsWith("bootstrap.js")) { proxyReq.setHeader('Authorization', 'Bearer ' + access_token(client_id, client_secret)); } @@ -30,7 +31,7 @@ var server = http.createServer(function(req, res) { target: rabbitmq_url }); }); -console.log("fakeproxy listening on port " + port + ". RABBITMQ_URL=" + rabbitmq_url) +log("fakeproxy listening on port " + port + ". RABBITMQ_URL=" + rabbitmq_url) server.listen(port); @@ -51,18 +52,19 @@ function access_token(id, secret) { '&token_format=jwt' + '&response_type=token'; - console.debug("Sending " + url + " with params "+ params); + log("Sending " + url + " with params "+ params); req.open('POST', url, false); req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); req.setRequestHeader('Accept', 'application/json'); req.send(params); - console.log("Ret " + req.status) + log("Ret " + req.status) if (req.status == 200) { const token = JSON.parse(req.responseText).access_token; - console.log("Token => " + token) + log("Token => " + token) return token; } else { + error("Failed to get access token due to " + req.responseText) throw new Error(req.status + " : " + req.responseText); } } diff --git a/selenium/test/amqp.js b/selenium/test/amqp.js index 799e97fa43dc..920dd682c098 100644 --- a/selenium/test/amqp.js +++ b/selenium/test/amqp.js @@ -1,6 +1,8 @@ var container = require('rhea') // https://github.com/amqp/rhea var fs = require('fs'); var path = require('path'); +const {log, error} = require('./utils.js') + var connectionOptions = getConnectionOptions() function getAmqpConnectionOptions() { @@ -28,7 +30,7 @@ function getAmqpsConnectionOptions() { } function getConnectionOptions() { let scheme = process.env.RABBITMQ_AMQP_SCHEME || 'amqp' - console.log("Using AMQP protocol: " + scheme) + log("Using AMQP protocol: " + scheme) switch(scheme){ case "amqp": return getAmqpConnectionOptions() diff --git a/selenium/test/authnz-msg-protocols/amqp10.js b/selenium/test/authnz-msg-protocols/amqp10.js index 048349ed9d15..714389bcb73f 100644 --- a/selenium/test/authnz-msg-protocols/amqp10.js +++ b/selenium/test/authnz-msg-protocols/amqp10.js @@ -1,5 +1,5 @@ const assert = require('assert') -const { tokenFor, openIdConfiguration } = require('../utils') +const { log, tokenFor, openIdConfiguration } = require('../utils') const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend') const { open: openAmqp, once: onceAmqp, on: onAmqp, close: closeAmqp } = require('../amqp') @@ -48,11 +48,11 @@ describe('Having AMQP 1.0 protocol enabled and the following auth_backends: ' + let oauthProviderUrl = process.env.OAUTH_PROVIDER_URL let oauthClientId = process.env.OAUTH_CLIENT_ID let oauthClientSecret = process.env.OAUTH_CLIENT_SECRET - console.log("oauthProviderUrl : " + oauthProviderUrl) + log("oauthProviderUrl : " + oauthProviderUrl) let openIdConfig = openIdConfiguration(oauthProviderUrl) - console.log("Obtained token_endpoint : " + openIdConfig.token_endpoint) + log("Obtained token_endpoint : " + openIdConfig.token_endpoint) password = tokenFor(oauthClientId, oauthClientSecret, openIdConfig.token_endpoint) - console.log("Obtained access token : " + password) + log("Obtained access token : " + password) } }) @@ -78,7 +78,7 @@ describe('Having AMQP 1.0 protocol enabled and the following auth_backends: ' + closeAmqp(amqp.connection) } } catch (error) { - console.error("Failed to close amqp10 connection due to " + error); + error("Failed to close amqp10 connection due to " + error); } }) }) diff --git a/selenium/test/authnz-msg-protocols/mqtt.js b/selenium/test/authnz-msg-protocols/mqtt.js index cce856fcf6c6..c6466a919d5a 100644 --- a/selenium/test/authnz-msg-protocols/mqtt.js +++ b/selenium/test/authnz-msg-protocols/mqtt.js @@ -1,6 +1,6 @@ const fs = require('fs') const assert = require('assert') -const { tokenFor, openIdConfiguration } = require('../utils') +const { tokenFor, openIdConfiguration, log } = require('../utils') const { reset, expectUser, expectVhost, expectResource, allow, verifyAll } = require('../mock_http_backend') const mqtt = require('mqtt'); @@ -45,9 +45,9 @@ describe('Having MQTT protocol enbled and the following auth_backends: ' + backe let oauthClientId = process.env.OAUTH_CLIENT_ID let oauthClientSecret = process.env.OAUTH_CLIENT_SECRET let openIdConfig = openIdConfiguration(oauthProviderUrl) - console.log("Obtained token_endpoint : " + openIdConfig.token_endpoint) + log("Obtained token_endpoint : " + openIdConfig.token_endpoint) password = tokenFor(oauthClientId, oauthClientSecret, openIdConfig.token_endpoint) - console.log("Obtained access token : " + password) + log("Obtained access token : " + password) } mqttOptions = { clientId: client_id, diff --git a/selenium/test/exchanges/management.js b/selenium/test/exchanges/management.js index 0e47868f7181..5f6830a52f37 100644 --- a/selenium/test/exchanges/management.js +++ b/selenium/test/exchanges/management.js @@ -1,7 +1,7 @@ const { By, Key, until, Builder } = require('selenium-webdriver') require('chromedriver') const assert = require('assert') -const { buildDriver, goToHome, captureScreensFor, teardown, doWhile } = require('../utils') +const { buildDriver, goToHome, captureScreensFor, teardown, doWhile, log } = require('../utils') const LoginPage = require('../pageobjects/LoginPage') const OverviewPage = require('../pageobjects/OverviewPage') @@ -56,7 +56,6 @@ describe('Exchange management', function () { ["other", "amq.topic", "topic"] ] - console.log("e :" + actual_table) assert.deepEqual(actual_table, expected_table) }) diff --git a/selenium/test/mgt-api.js b/selenium/test/mgt-api.js index 2ff69328a690..305e896c33be 100644 --- a/selenium/test/mgt-api.js +++ b/selenium/test/mgt-api.js @@ -1,4 +1,5 @@ const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest +const { escapeCss } = require('selenium-webdriver') const {log, error} = require('./utils.js') const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL || 'http://localhost:15672/') @@ -20,10 +21,56 @@ module.exports = { return baseUrl }, - geOtherManagementUrl: () => { + getOtherManagementUrl: () => { return otherBaseUrl }, + basicAuthorization: (username, password) => { + return "Basic " + btoa(username + ":" + password) + }, + publish: (url, authorization, vhost, exchange, routingKey, payload) => { + const req = new XMLHttpRequest() + + let body = { + "properties" : {}, + "routing_key" : routingKey, + "payload" : payload, + "payload_encoding" : "string" + } + log("Publish message to vhost " + vhost + " with exchnage " + exchange + " : " + JSON.stringify(body)) + + let finalUrl = url + "/api/exchanges/" + encodeURIComponent(vhost) + "/" + + encodeURIComponent(exchange) + "/publish" + req.open('POST', finalUrl, false) + req.setRequestHeader("Authorization", authorization) + req.setRequestHeader('Content-Type', 'application/json') + + req.send(JSON.stringify(body)) + if (req.status == 200 || req.status == 204 || req.status == 201) { + log("Succesfully published message") + return + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + }, + getNodes: (url) => { + log("Getting rabbitmq nodes ...") + const req = new XMLHttpRequest() + let base64Credentials = btoa('administrator-only' + ":" + 'guest') + let finalUrl = url + "/api/nodes?columns=name" + req.open('GET', finalUrl, false) + req.setRequestHeader("Authorization", "Basic " + base64Credentials) + + req.send() + if (req.status == 200 || req.status == 204 || req.status == 201) { + log("Succesfully got nodes ") + return JSON.parse(req.responseText) + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + }, setPolicy: (url, vhost, name, pattern, definition, appliedTo = "queues") => { let policy = { "pattern": pattern, @@ -90,6 +137,27 @@ module.exports = { throw new Error(req.responseText) } }, + grantPermissions: (url, vhost, user, permissions) => { + log("Granting permissions [" + JSON.stringify(permissions) + + "] for user " + user + " on vhost " + vhost + " on " + url) + + const req = new XMLHttpRequest() + let base64Credentials = btoa('administrator-only' + ":" + 'guest') + let finalUrl = url + "/api/permissions/" + encodeURIComponent(vhost) + "/" + + encodeURIComponent(user) + req.open('PUT', finalUrl, false) + req.setRequestHeader("Authorization", "Basic " + base64Credentials) + req.setRequestHeader('Content-Type', 'application/json') + + req.send(JSON.stringify(permissions)) + if (req.status == 200 || req.status == 204 || req.status == 201) { + log("Succesfully granted permissions") + return + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + }, deleteVhost: (url, vhost) => { log("Deleting vhost " + vhost) const req = new XMLHttpRequest() @@ -106,7 +174,68 @@ module.exports = { error("status:" + req.status + " : " + req.responseText) throw new Error(req.responseText) } - } + }, + getQueue: (url, name, vhost) => { + log("Getting queue " + name + " on vhost " + vhost) + const req = new XMLHttpRequest() + let base64Credentials = btoa('administrator-only' + ":" + 'guest') + let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/" + + encodeURIComponent(name) + req.open('GET', finalUrl, false) + req.setRequestHeader("Authorization", "Basic " + base64Credentials) + + req.send() + if (req.status == 200 || req.status == 204 || req.status == 201) { + log("Succesfully got queue ") + return JSON.parse(req.responseText) + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + }, + createQueue: (url, name, vhost, queueType = "quorum") => { + log("Create queue " + JSON.stringify(name) + + " in vhost " + vhost + " on " + url) + const req = new XMLHttpRequest() + let base64Credentials = btoa('administrator-only' + ":" + 'guest') + let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/" + + encodeURIComponent(name) + req.open('PUT', finalUrl, false) + req.setRequestHeader("Authorization", "Basic " + base64Credentials) + req.setRequestHeader('Content-Type', 'application/json') + let payload = { + "durable": true, + "arguments":{ + "x-queue-type" : queueType + } + } + req.send(JSON.stringify(payload)) + if (req.status == 200 || req.status == 204 || req.status == 201) { + log("Succesfully created queue " + name) + return + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + }, + deleteQueue: (url, name, vhost) => { + log("Deleting queue " + name + " on vhost " + vhost) + const req = new XMLHttpRequest() + let base64Credentials = btoa('administrator-only' + ":" + 'guest') + let finalUrl = url + "/api/queues/" + encodeURIComponent(vhost) + "/" + + encodeURIComponent(name) + req.open('DELETE', finalUrl, false) + req.setRequestHeader("Authorization", "Basic " + base64Credentials) + + req.send() + if (req.status == 200 || req.status == 204) { + log("Succesfully deleted queue " + vhost) + return + }else { + error("status:" + req.status + " : " + req.responseText) + throw new Error(req.responseText) + } + } } diff --git a/selenium/test/oauth/with-idp-initiated/happy-login.js b/selenium/test/oauth/with-idp-initiated/happy-login.js index e5f726f25cf0..ae668653d792 100644 --- a/selenium/test/oauth/with-idp-initiated/happy-login.js +++ b/selenium/test/oauth/with-idp-initiated/happy-login.js @@ -11,6 +11,7 @@ describe('A user with a JWT token', function () { let captureScreen let token let fakePortal + let driver before(async function () { driver = buildDriver() diff --git a/selenium/test/oauth/with-sp-initiated/happy-login.js b/selenium/test/oauth/with-sp-initiated/happy-login.js index 763c22202ac1..c792ff339bd7 100644 --- a/selenium/test/oauth/with-sp-initiated/happy-login.js +++ b/selenium/test/oauth/with-sp-initiated/happy-login.js @@ -11,6 +11,7 @@ describe('An user with administrator tag', function () { let idpLogin let overview let captureScreen + var driver before(async function () { driver = buildDriver() diff --git a/selenium/test/oauth/with-sp-initiated/landing.js b/selenium/test/oauth/with-sp-initiated/landing.js index 6a600a74770d..93861080a1b3 100644 --- a/selenium/test/oauth/with-sp-initiated/landing.js +++ b/selenium/test/oauth/with-sp-initiated/landing.js @@ -8,6 +8,7 @@ const SSOHomePage = require('../../pageobjects/SSOHomePage') describe('A user which accesses any protected URL without a session', function () { let homePage let captureScreen + let driver before(async function () { driver = buildDriver() diff --git a/selenium/test/oauth/with-sp-initiated/logout.js b/selenium/test/oauth/with-sp-initiated/logout.js index f8b40fe0abe2..c811bcea0160 100644 --- a/selenium/test/oauth/with-sp-initiated/logout.js +++ b/selenium/test/oauth/with-sp-initiated/logout.js @@ -11,6 +11,7 @@ describe('When a logged in user', function () { let homePage let captureScreen let idpLogin + let driver before(async function () { driver = buildDriver() diff --git a/selenium/test/oauth/with-sp-initiated/token-refresh.js b/selenium/test/oauth/with-sp-initiated/token-refresh.js index d14e009c1e8f..6f475082be2d 100644 --- a/selenium/test/oauth/with-sp-initiated/token-refresh.js +++ b/selenium/test/oauth/with-sp-initiated/token-refresh.js @@ -13,6 +13,7 @@ describe('Once user is logged in', function () { let idpLogin let overview let captureScreen + let driver this.timeout(45000) // hard-coded to 25secs because this test requires 35sec to run before(async function () { diff --git a/selenium/test/oauth/with-sp-initiated/unauthorized.js b/selenium/test/oauth/with-sp-initiated/unauthorized.js index 798f600a30db..d920607fd978 100644 --- a/selenium/test/oauth/with-sp-initiated/unauthorized.js +++ b/selenium/test/oauth/with-sp-initiated/unauthorized.js @@ -1,7 +1,7 @@ const { By, Key, until, Builder } = require('selenium-webdriver') require('chromedriver') const assert = require('assert') -const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage } = require('../../utils') +const { buildDriver, goToHome, captureScreensFor, teardown, idpLoginPage, delay } = require('../../utils') const SSOHomePage = require('../../pageobjects/SSOHomePage') const OverviewPage = require('../../pageobjects/OverviewPage') @@ -11,6 +11,7 @@ describe('An user without management tag', function () { let idpLogin let overview let captureScreen + let driver before(async function () { driver = buildDriver() @@ -46,7 +47,7 @@ describe('An user without management tag', function () { }) it('should get redirected to home page again without error message', async function(){ - await driver.sleep(250) + await delay(250) const visible = await homePage.isWarningVisible() assert.ok(!visible) }) diff --git a/selenium/test/pageobjects/BasePage.js b/selenium/test/pageobjects/BasePage.js index 2b4f40ba476f..e52e4eb2facc 100644 --- a/selenium/test/pageobjects/BasePage.js +++ b/selenium/test/pageobjects/BasePage.js @@ -28,7 +28,7 @@ module.exports = class BasePage { interactionDelay constructor (webdriver) { - this.driver = webdriver + this.driver = webdriver.driver this.timeout = parseInt(process.env.SELENIUM_TIMEOUT) || 1000 // max time waiting to locate an element. Should be less that test timeout this.polling = parseInt(process.env.SELENIUM_POLLING) || 500 // how frequent selenium searches for an element this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy) @@ -50,13 +50,17 @@ module.exports = class BasePage { return this.selectOption(SELECT_REFRESH, option) } + async selectRefreshOptionByValue(option) { + return this.selectOptionByValue(SELECT_REFRESH, option) + } + async waitForOverviewTab() { await this.driver.sleep(250) return this.waitForDisplayed(OVERVIEW_TAB) } async clickOnOverviewTab () { - return this.click(CONNECTIONS_TAB) + return this.click(OVERVIEW_TAB) } async clickOnConnectionsTab () { @@ -130,7 +134,6 @@ module.exports = class BasePage { const select = await new Select(selectable) return select.selectByValue(value) } - async getSelectableVhosts() { const table_model = await this.getSelectableOptions(SELECT_VHOSTS) let new_table_model = [] @@ -139,9 +142,11 @@ module.exports = class BasePage { } return new_table_model } - - - + async selectVhost(vhost) { + let selectable = await this.waitForDisplayed(SELECT_VHOSTS) + const select = await new Select(selectable) + return select.selectByValue(vhost) + } async getTable(tableLocator, firstNColumns, rowClass) { const table = await this.waitForDisplayed(tableLocator) const rows = await table.findElements(rowClass == undefined ? @@ -166,16 +171,7 @@ module.exports = class BasePage { } catch(e) { return Promise.resolve(false) } - /* - let element = await driver.findElement(FORM_POPUP) - return this.driver.wait(until.elementIsVisible(element), this.timeout / 2, - 'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element, - this.polling / 2).then(function onWarningVisible(e) { - return Promise.resolve(true) - }, function onError(e) { - return Promise.resolve(false) - }) - */ + } async isPopupWarningNotDisplayed() { @@ -199,7 +195,7 @@ module.exports = class BasePage { } } async getPopupWarning() { - let element = await driver.findElement(FORM_POPUP_WARNING) + let element = await this.driver.findElement(FORM_POPUP_WARNING) return this.driver.wait(until.elementIsVisible(element), this.timeout, 'Timed out after [timeout=' + this.timeout + ';polling=' + this.polling + '] awaiting till visible ' + element, this.polling).getText().then((value) => value.substring(0, value.search('\n\nClose'))) @@ -363,9 +359,6 @@ module.exports = class BasePage { await this.driver.sleep(250) return alert.accept(); } - log(message) { - console.log(new Date() + " " + message) - } capture () { this.driver.takeScreenshot().then( diff --git a/selenium/test/pageobjects/LimitsAdminTab.js b/selenium/test/pageobjects/LimitsAdminTab.js index 09ddbf9c5807..f87a45c6e58a 100644 --- a/selenium/test/pageobjects/LimitsAdminTab.js +++ b/selenium/test/pageobjects/LimitsAdminTab.js @@ -19,7 +19,7 @@ module.exports = class LimitsAdminTab extends AdminTab { await this.click(VIRTUAL_HOST_LIMITS_SECTION) try { - return driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS) + return this.driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS) } catch (NoSuchElement) { return Promise.resolve([]) } @@ -28,7 +28,7 @@ module.exports = class LimitsAdminTab extends AdminTab { await this.click(USER_LIMITS_SECTION) try { - return driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS) + return this.driver.findElements(VIRTUAL_HOST_LIMITS_TABLE_ROWS) } catch (NoSuchElement) { return Promise.resolve([]) } diff --git a/selenium/test/pageobjects/LoginPage.js b/selenium/test/pageobjects/LoginPage.js index 5e69e15dfbd6..cfb2a0ebf1c6 100644 --- a/selenium/test/pageobjects/LoginPage.js +++ b/selenium/test/pageobjects/LoginPage.js @@ -36,7 +36,7 @@ module.exports = class LoginPage extends BasePage { async getWarnings() { try { - return driver.findElements(WARNING) + return this.driver.findElements(WARNING) } catch (NoSuchElement) { return Promise.resolve([]) } diff --git a/selenium/test/pageobjects/QueuePage.js b/selenium/test/pageobjects/QueuePage.js index e160e969fb38..0746d564baf5 100644 --- a/selenium/test/pageobjects/QueuePage.js +++ b/selenium/test/pageobjects/QueuePage.js @@ -17,7 +17,7 @@ module.exports = class QueuePage extends BasePage { } async ensureDeleteQueueSectionIsVisible() { await this.click(DELETE_SECTION) - return driver.findElement(DELETE_SECTION).isDisplayed() + return this.driver.findElement(DELETE_SECTION).isDisplayed() } async deleteQueue() { await this.click(DELETE_BUTTON) diff --git a/selenium/test/pageobjects/QueuesAndStreamsPage.js b/selenium/test/pageobjects/QueuesAndStreamsPage.js index a326e8056cef..eb11bace37b0 100644 --- a/selenium/test/pageobjects/QueuesAndStreamsPage.js +++ b/selenium/test/pageobjects/QueuesAndStreamsPage.js @@ -31,11 +31,11 @@ module.exports = class QueuesAndStreamsPage extends BasePage { } async ensureAddQueueSectionIsVisible() { await this.click(ADD_NEW_QUEUE_SECTION) - return driver.findElement(ADD_NEW_QUEUE_SECTION).isDisplayed() + return this.driver.findElement(ADD_NEW_QUEUE_SECTION).isDisplayed() } async ensureAllQueuesSectionIsVisible() { await this.click(PAGING_SECTION) - return driver.findElement(PAGING_SECTION).isDisplayed() + return this.driver.findElement(PAGING_SECTION).isDisplayed() } async fillInAddNewQueue(queueDetails) { await this.selectOptionByValue(FORM_QUEUE_TYPE, queueDetails.type) diff --git a/selenium/test/pageobjects/SSOHomePage.js b/selenium/test/pageobjects/SSOHomePage.js index 9b22aea3087d..44f771bc54e2 100644 --- a/selenium/test/pageobjects/SSOHomePage.js +++ b/selenium/test/pageobjects/SSOHomePage.js @@ -110,7 +110,7 @@ module.exports = class SSOHomePage extends BasePage { async getWarnings() { try { - return driver.findElements(WARNING) + return this.driver.findElements(WARNING) } catch (NoSuchElement) { return Promise.resolve([]) } diff --git a/selenium/test/pageobjects/StreamPage.js b/selenium/test/pageobjects/StreamPage.js index 506c0b5c50e5..c1c7ab71631e 100644 --- a/selenium/test/pageobjects/StreamPage.js +++ b/selenium/test/pageobjects/StreamPage.js @@ -17,7 +17,7 @@ module.exports = class StreamPage extends BasePage { } async ensureDeleteQueueSectionIsVisible() { await this.click(DELETE_SECTION) - return driver.findElement(DELETE_SECTION).isDisplayed() + return this.driver.findElement(DELETE_SECTION).isDisplayed() } async deleteStream() { await this.click(DELETE_BUTTON) diff --git a/selenium/test/utils.js b/selenium/test/utils.js index 3068f68240a7..f192cc3b9ced 100644 --- a/selenium/test/utils.js +++ b/selenium/test/utils.js @@ -17,6 +17,7 @@ const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost' const seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444' const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens' const profiles = process.env.PROFILES || '' +const debug = process.env.SELENIUM_DEBUG || false function randomly_pick_baseurl(baseUrl) { urls = baseUrl.split(",") @@ -34,7 +35,7 @@ class CaptureScreenshot { } async shot (name) { - const image = await driver.takeScreenshot() + const image = await this.driver.takeScreenshot() const screenshotsSubDir = path.join(screenshotsDir, this.test) if (!fs.existsSync(screenshotsSubDir)) { await fsp.mkdir(screenshotsSubDir) @@ -46,7 +47,7 @@ class CaptureScreenshot { module.exports = { log: (message) => { - console.log(new Date() + " " + message) + if (debug) console.log(new Date() + " " + message) }, error: (message) => { console.error(new Date() + " " + message) @@ -55,7 +56,7 @@ module.exports = { return profiles.includes(profile) }, - buildDriver: (caps) => { + buildDriver: (url = baseUrl) => { builder = new Builder() if (!runLocal) { builder = builder.usingServer(seleniumUrl) @@ -86,15 +87,23 @@ module.exports = { "profile.password_manager_leak_detection=false" ] }); - driver = builder + let driver = builder .forBrowser('chrome') //.setChromeOptions(options.excludeSwitches("disable-popup-blocking", "enable-automation")) .withCapabilities(chromeCapabilities) .build() driver.manage().setTimeouts( { pageLoad: 35000 } ) - return driver + return { + "driver": driver, + "baseUrl": url + } + }, + updateDriver: (d, url) => { + return { + "driver" : d.driver, + "baseUrl" : url + } }, - getURLForProtocol: (protocol) => { switch(protocol) { @@ -103,20 +112,21 @@ module.exports = { } }, - goToHome: (driver) => { - return driver.get(baseUrl) + goToHome: (d) => { + module.exports.log("goToHome on " + d.baseUrl) + return d.driver.get(d.baseUrl) }, - goToLogin: (driver, token) => { - return driver.get(baseUrl + '#/login?access_token=' + token) + goToLogin: (d, token) => { + return d.driver.get(d.baseUrl + '#/login?access_token=' + token) }, - goToExchanges: (driver) => { - return driver.get(baseUrl + '#/exchanges') + goToExchanges: (d) => { + return d.driver.get(d.baseUrl + '#/exchanges') }, - goTo: (driver, address) => { - return driver.get(address) + goTo: (d, address) => { + return d.get(address) }, delay: async (msec, ref) => { @@ -125,8 +135,8 @@ module.exports = { }) }, - captureScreensFor: (driver, test) => { - return new CaptureScreenshot(driver, require('path').basename(test)) + captureScreensFor: (d, test) => { + return new CaptureScreenshot(d.driver, require('path').basename(test)) }, doWhile: async (doCallback, booleanCallback, delayMs = 1000, message = "doWhile failed") => { @@ -135,16 +145,45 @@ module.exports = { let ret do { try { - //console.log("Calling doCallback (attempts:" + attempts + ") ... ") + module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ") ret = await doCallback() - //console.log("Calling booleanCallback (attempts:" + attempts + ") with arg " + ret + " ... ") + module.exports.log("Calling booleanCallback (attempts:" + attempts + + ") with arg " + JSON.stringify(ret) + " ... ") + done = booleanCallback(ret) + }catch(error) { + module.exports.error("Caught " + error + " on doWhile callback...") + + }finally { + if (!done) { + module.exports.log("Waiting until next attempt") + await module.exports.delay(delayMs) + } + } + attempts-- + } while (attempts > 0 && !done) + if (!done) { + throw new Error(message) + }else { + return ret + } + }, + retry: async (doCallback, booleanCallback, delayMs = 1000, message = "retry failed") => { + let done = false + let attempts = 10 + let ret + do { + try { + module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ") + ret = doCallback() + module.exports.log("Calling booleanCallback (attempts:" + attempts + + ") with arg " + JSON.stringify(ret) + " ... ") done = booleanCallback(ret) }catch(error) { - console.log("Caught " + error + " on doWhile callback...") + module.exports.error("Caught " + error + " on doWhile callback...") }finally { if (!done) { - //console.log("Waiting until next attempt") + module.exports.log("Waiting until next attempt") await module.exports.delay(delayMs) } } @@ -157,7 +196,7 @@ module.exports = { } }, - idpLoginPage: (driver, preferredIdp) => { + idpLoginPage: (d, preferredIdp) => { if (!preferredIdp) { if (process.env.PROFILES.includes("uaa")) { preferredIdp = "uaa" @@ -168,8 +207,8 @@ module.exports = { } } switch(preferredIdp) { - case "uaa": return new UAALoginPage(driver) - case "keycloak": return new KeycloakLoginPage(driver) + case "uaa": return new UAALoginPage(d) + case "keycloak": return new KeycloakLoginPage(d) default: new Error("Unsupported ipd " + preferredIdp) } }, @@ -179,7 +218,7 @@ module.exports = { req.send() if (req.status == 200) return JSON.parse(req.responseText) else { - console.error(req.responseText) + module.exports.error(req.responseText) throw new Error(req.responseText) } }, @@ -198,7 +237,7 @@ module.exports = { req.send(params) if (req.status == 200) return JSON.parse(req.responseText).access_token else { - console.error(req.responseText) + module.exports.error(req.responseText) throw new Error(req.responseText) } }, @@ -212,10 +251,11 @@ module.exports = { } }, - teardown: async (driver, test, captureScreen = null) => { + teardown: async (d, test, captureScreen = null) => { + driver = d.driver driver.manage().logs().get(logging.Type.BROWSER).then(function(entries) { entries.forEach(function(entry) { - console.log('[%s] %s', entry.level.name, entry.message); + module.exports.log('[%s] %s', entry.level.name, entry.message); }) }) if (test.currentTest) { @@ -227,6 +267,14 @@ module.exports = { } } await driver.quit() + }, + + findTableRow: (table, booleanCallback) => { + if (!table) return false + + let i = 0 + while (i < table.length && !booleanCallback(table[i])) i++; + return i < table.length ? table[i] : undefined } }