Merge pull request #13709 from rabbitmq/mergify/bp/v4.1.x/pr-13685

Upstream changes from Tanzu RabbitMQ's Selenium suite (backport #13685)
This commit is contained in:
Michael Klishin 2025-04-08 16:00:44 -04:00 committed by GitHub
commit 42deffd23f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 206 additions and 55 deletions

View File

@ -0,0 +1,46 @@
HTTPD_DOCKER_IMAGE=httpd:latest
ensure_devkeycloak-proxy() {
if docker ps | grep devkeycloak-proxy &> /dev/null; then
print "devkeycloak-proxy already running ..."
else
start_devkeycloak-proxy
fi
}
init_devkeycloak-proxy() {
HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/devkeycloak-proxy
PROXY_HOSTNAME=devkeycloak-proxy
PROXY_PORT=9092
print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}"
print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}"
print "> PROXY_PORT: ${PROXY_PORT}"
}
start_devkeycloak-proxy() {
begin "Starting devkeycloak-proxy ..."
init_devkeycloak-proxy
kill_container_if_exist devkeycloak-proxy
MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd
mkdir -p $MOUNT_HTTPD_CONFIG_DIR
${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf
print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf"
cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR
docker run \
--detach \
--name devkeycloak-proxy \
--net ${DOCKER_NETWORK} \
--publish 9092:9092 \
--mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \
${HTTPD_DOCKER_IMAGE}
#wait_for_url $OAUTH_PROVIDER_URL ${FORWARD_PROXY_URL}
wait_for_message devkeycloak-proxy "initializing worker proxy:forward local"
end "devkeycloak-proxy is ready"
}

View File

@ -0,0 +1,47 @@
HTTPD_DOCKER_IMAGE=httpd:latest
ensure_forward-proxy() {
if docker ps | grep forward-proxy &> /dev/null; then
print "forward-proxy already running ..."
else
start_forward-proxy
fi
}
init_forward-proxy() {
HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/forward-proxy
PROXY_HOSTNAME=forward-proxy
PROXY_PORT=9092
print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}"
print "> OAUTH_PROVIDER_URL: ${OAUTH_PROVIDER_URL}"
print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}"
print "> PROXY_PORT: ${PROXY_PORT}"
}
start_forward-proxy() {
begin "Starting forward-proxy ..."
init_forward-proxy
kill_container_if_exist forward-proxy
MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd
mkdir -p $MOUNT_HTTPD_CONFIG_DIR
${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf
print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf"
cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR
docker run \
--detach \
--name forward-proxy \
--net ${DOCKER_NETWORK} \
--publish 9092:9092 \
--mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \
${HTTPD_DOCKER_IMAGE}
#wait_for_url $OAUTH_PROVIDER_URL ${FORWARD_PROXY_URL}
wait_for_message forward-proxy "initializing worker proxy:forward local"
end "forward-proxy is ready"
}

View File

@ -12,7 +12,7 @@ ensure_keycloak() {
init_keycloak() {
KEYCLOAK_CONFIG_PATH=${KEYCLOAK_CONFIG_PATH:-oauth/keycloak}
KEYCLOAK_CONFIG_DIR=$(realpath ${TEST_DIR}/${KEYCLOAK_CONFIG_PATH})
KEYCLOAK_URL=${OAUTH_PROVIDER_URL}
KEYCLOAK_URL=${KEYCLOAK_URL:-OAUTH_PROVIDER_URL}
print "> KEYCLOAK_CONFIG_DIR: ${KEYCLOAK_CONFIG_DIR}"
print "> KEYCLOAK_URL: ${KEYCLOAK_URL}"
@ -42,8 +42,9 @@ start_keycloak() {
--publish 8443:8443 \
--env KEYCLOAK_ADMIN=admin \
--env KEYCLOAK_ADMIN_PASSWORD=admin \
--env QUARKUS_HTTP_ACCESS_LOG_ENABLED=true \
-v ${MOUNT_KEYCLOAK_CONF_DIR}:/opt/keycloak/data/import/ \
${KEYCLOAK_DOCKER_IMAGE} start-dev --import-realm \
${KEYCLOAK_DOCKER_IMAGE} start-dev --import-realm --log-level=INFO \
--https-certificate-file=/opt/keycloak/data/import/server_keycloak_certificate.pem \
--https-certificate-key-file=/opt/keycloak/data/import/server_keycloak_key.pem

View File

@ -0,0 +1,45 @@
HTTPD_DOCKER_IMAGE=httpd:latest
ensure_prodkeycloak-proxy() {
if docker ps | grep prodkeycloak-proxy &> /dev/null; then
print "prodkeycloak-proxy already running ..."
else
start_prodkeycloak-proxy
fi
}
init_prodkeycloak-proxy() {
HTTPD_CONFIG_DIR=${TEST_CONFIG_DIR}/prodkeycloak-proxy
PROXY_HOSTNAME=prodkeycloak-proxy
PROXY_PORT=9091
print "> HTTPD_CONFIG: ${HTTPD_CONFIG_DIR}"
print "> PROXY_HOSTNAME: ${PROXY_HOSTNAME}"
print "> PROXY_PORT: ${PROXY_PORT}"
}
start_prodkeycloak-proxy() {
begin "Starting prodkeycloak-proxy ..."
init_prodkeycloak-proxy
kill_container_if_exist prodkeycloak-proxy
MOUNT_HTTPD_CONFIG_DIR=$CONF_DIR/httpd
mkdir -p $MOUNT_HTTPD_CONFIG_DIR
${BIN_DIR}/gen-httpd-conf ${HTTPD_CONFIG_DIR} $ENV_FILE $MOUNT_HTTPD_CONFIG_DIR/httpd.conf
print "> EFFECTIVE HTTPD_CONFIG_FILE: $MOUNT_HTTPD_CONFIG_DIR/httpd.conf"
cp ${HTTPD_CONFIG_DIR}/.htpasswd $MOUNT_HTTPD_CONFIG_DIR
docker run \
--detach \
--name prodkeycloak-proxy \
--net ${DOCKER_NETWORK} \
--publish 9091:9091 \
--mount "type=bind,source=${MOUNT_HTTPD_CONFIG_DIR},target=/usr/local/apache2/conf" \
${HTTPD_DOCKER_IMAGE}
wait_for_message prodkeycloak-proxy "initializing worker proxy:forward local"
end "prodkeycloak-proxy is ready"
}

View File

@ -95,7 +95,7 @@ start_docker_cluster_rabbitmq() {
kill_container_if_exist rabbitmq1
kill_container_if_exist rabbitmq2
mkdir -p $CONF_DIR/rabbitmq
mkdir -pv $CONF_DIR/rabbitmq/conf.d/
RABBITMQ_TEST_DIR="/var/rabbitmq" ${BIN_DIR}/gen-rabbitmq-conf ${RABBITMQ_CONFIG_DIR} $ENV_FILE $CONF_DIR/rabbitmq/rabbitmq.conf
print "> EFFECTIVE RABBITMQ_CONFIG_FILE: $CONF_DIR/rabbitmq/rabbitmq.conf"
@ -109,7 +109,6 @@ start_docker_cluster_rabbitmq() {
fi
fi
if [ -f ${RABBITMQ_CONFIG_DIR}/logging.conf ]; then
mkdir -p $CONF_DIR/rabbitmq/conf.d/
cp ${RABBITMQ_CONFIG_DIR}/logging.conf $CONF_DIR/rabbitmq/conf.d/
fi
if [ -f ${RABBITMQ_CONFIG_DIR}/enabled_plugins ]; then
@ -187,7 +186,7 @@ start_docker_rabbitmq() {
-v $CONF_DIR/rabbitmq/imports:/var/rabbitmq/imports \
-v ${TEST_DIR}:/config \
${RABBITMQ_DOCKER_IMAGE}
wait_for_message rabbitmq "Server startup complete"
end "RabbitMQ ready"
}

View File

@ -218,20 +218,37 @@ wait_for_oidc_endpoint_docker() {
calculate_rabbitmq_url() {
echo "${RABBITMQ_SCHEME:-http}://$1${PUBLIC_RABBITMQ_PATH:-$RABBITMQ_PATH}"
}
calculate_forward_proxy_url() {
PROXIED_URL=$1
PROXY_HOSTNAME=$2
PROXY_PORT=$3
SCHEME=$(echo "$PROXIED_URL" | cut -d: -f1)
PATH=$(echo "$PROXIED_URL" | cut -d/ -f4-)
echo "$SCHEME://$PROXY_HOSTNAME:$PROXY_PORT/$PATH"
}
wait_for_url() {
BASE_URL=$1
if [[ $BASE_URL == *"localhost"** ]]; then
wait_for_url_local $BASE_URL
wait_for_url_local $@
else
wait_for_url_docker $BASE_URL
wait_for_url_docker $@
fi
}
wait_for_url_local() {
url=$1
proxy=${2:-none}
proxy_user=${3:-none}
proxy_pass=$4
curl_args="-L -f -v"
max_retry=10
counter=0
until (curl -L -f -v $url >/dev/null 2>&1)
if [[ "$proxy" != "none" && "$proxy" != "" ]]; then
curl_args="--proxy ${proxy} ${curl_args}"
fi
if [[ "$proxy_user" != "none" && "$proxy_user" != "" ]]; then
curl_args="--proxy-user ${proxy_user}:${proxy_pass} ${curl_args}"
fi
until (curl $curl_args $url >/dev/null 2>&1)
do
print "Waiting for $url to start (local)"
sleep 5
@ -242,9 +259,19 @@ wait_for_url_local() {
}
wait_for_url_docker() {
url=$1
proxy=${2:-none}
proxy_user=${3:-none}
proxy_pass=$4
max_retry=10
counter=0
until (docker run --net ${DOCKER_NETWORK} --rm curlimages/curl:7.85.0 -L -f -v $url >/dev/null 2>&1)
curl_args="-L -f -v"
if [[ "$proxy" != "none" && "$proxy" != "" ]]; then
curl_args="--proxy ${proxy} ${curl_args}"
fi
if [[ "$proxy_user" != "none" && "$proxy_user" != "" ]]; then
curl_args="--proxy-user ${proxy_user}:${proxy_pass} ${curl_args}"
fi
until (docker run --net ${DOCKER_NETWORK} --rm curlimages/curl:7.85.0 $curl_args $url >/dev/null 2>&1)
do
print "Waiting for $url to start (docker)"
sleep 5
@ -377,7 +404,8 @@ profiles_with_local_or_docker() {
generate_env_file() {
begin "Generating env file ..."
mkdir -p $CONF_DIR
${BIN_DIR}/gen-env-file $TEST_CONFIG_DIR $ENV_FILE
${BIN_DIR}/gen-env-file $TEST_CONFIG_DIR ${ENV_FILE}.tmp
grep -v '^#' ${ENV_FILE}.tmp > $ENV_FILE
source $ENV_FILE
end "Finished generating env file."
}
@ -560,7 +588,7 @@ run_on_docker_with() {
build_mocha_image
start_selenium
trap teardown_components EXIT
trap "teardown_components" EXIT
start_components
test
@ -641,7 +669,6 @@ start_components() {
$start
done
}
teardown_components() {
skip_rabbitmq=${1:-false}

View File

@ -27,35 +27,32 @@ describe('management user with vhosts permissions', function () {
it('can access overview tab', async function () {
await overview.clickOnOverviewTab()
await overview.waitForOverviewTab()
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('can access connections tab', async function () {
await overview.clickOnConnectionsTab()
await overview.waitForConnectionsTab()
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('can access channels tab', async function () {
await overview.clickOnChannelsTab()
await overview.waitForChannelsTab()
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('can access exchanges tab', async function () {
await overview.clickOnExchangesTab()
await overview.waitForExchangesTab()
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('can access queues and streams tab', async function () {
await overview.clickOnQueuesTab()
await overview.waitForQueuesTab()
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('can access limited options in admin tab', async function () {
console.log("before clickOnAdminTab")
await overview.clickOnAdminTab()
console.log("before waitForAdminTab")
await overview.waitForAdminTab()
console.log("after waitForAdminTab")
assert.ok(!await overview.isPopupWarningDisplayed())
assert.ok(await overview.isPopupWarningNotDisplayed())
})
it('cannot add/update user limits', async function () {

View File

@ -19,7 +19,6 @@ describe('An user without management tag', function () {
overview = new OverviewPage(driver)
captureScreen = captureScreensFor(driver, __filename)
//assert.ok(!await login.isPopupWarningDisplayed())
await login.login('rabbit_no_management', 'guest')
})
@ -44,9 +43,8 @@ describe('An user without management tag', function () {
})
it('should close popup warning', async function(){
await delay(1000)
const visible = await login.isPopupWarningDisplayed()
assert.ok(!visible)
await delay(1000)
assert.ok(await login.isPopupWarningNotDisplayed())
})
})

View File

@ -1,3 +1,2 @@
export KEYCLOAK_URL=https://keycloak:8443/realms/test
export OAUTH_PROVIDER_URL=https://keycloak:8443/realms/test
export OAUTH_PROVIDER_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem
export KEYCLOAK_CA_CERT=/config/oauth/keycloak/ca_keycloak_certificate.pem

View File

@ -1 +1,2 @@
# export OAUTH_PROVIDER_URL=${KEYCLOAK_URL}
export OAUTH_PROVIDER_URL=${KEYCLOAK_URL}
export OAUTH_PROVIDER_CA_CERT=${KEYCLOAK_CA_CERT}

View File

@ -1,3 +1,3 @@
export KEYCLOAK_URL=https://localhost:8443/realms/test
export OAUTH_PROVIDER_URL=https://localhost:8443/realms/test
export OAUTH_PROVIDER_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem
export OAUTH_PROVIDER_URL=${KEYCLOAK_URL}
export KEYCLOAK_CA_CERT=selenium/test/oauth/keycloak/ca_keycloak_certificate.pem

View File

@ -56,6 +56,9 @@
"vhosts": [
{
"name": "/"
},
{
"name": "other"
}
],
"permissions": [

View File

@ -1,3 +1,3 @@
# uaa requires a secret in order to renew tokens
management.oauth_provider_url = ${KEYCLOAK_URL}
#management.oauth_provider_url = ${KEYCLOAK_URL}
management.oauth_authorization_endpoint_params.resource = rabbitmq

View File

@ -1,2 +1,2 @@
auth_oauth2.issuer = ${OAUTH_PROVIDER_URL}
auth_oauth2.https.cacertfile = ${OAUTH_PROVIDER_CA_CERT}
auth_oauth2.issuer = ${KEYCLOAK_URL}
auth_oauth2.https.cacertfile = ${KEYCLOAK_CA_CERT}

View File

@ -1,2 +1,2 @@
auth_oauth2.issuer = ${OAUTH_PROVIDER_URL}
auth_oauth2.issuer = ${KEYCLOAK_URL}
auth_oauth2.https.peer_verification = verify_none

View File

@ -1,2 +1,5 @@
# uaa requires a secret in order to renew tokens
management.oauth_client_secret = ${OAUTH_CLIENT_SECRET}
# uaa requires a secret in order to renew tokens
management.oauth_provider_url = ${UAA_URL}

View File

@ -1,5 +1,3 @@
# uaa requires a secret in order to renew tokens
management.oauth_client_secret = ${OAUTH_CLIENT_SECRET}
# configure static signing keys and the oauth provider used by the plugin
auth_oauth2.default_key = ${OAUTH_SIGNING_KEY_ID}

View File

@ -26,14 +26,11 @@ describe('A user which accesses a protected URL without a session', function ()
it('redirect to previous accessed page after login ', async function () {
await homePage.clickToLogin()
await idpLogin.login('rabbit_admin', 'rabbit_admin')
if (!await exchanges.isLoaded()) {
throw new Error('Failed to login')
}
assert.equal("All exchanges (8)", await exchanges.getPagingSectionHeaderText())
await exchanges.getPagingSectionHeaderText()
})

View File

@ -29,8 +29,7 @@ describe('An user without management tag', function () {
if (!await homePage.isLoaded()) {
throw new Error('Failed to login')
}
const visible = await homePage.isWarningVisible()
assert.ok(visible)
assert.ok(await homePage.isWarningVisible())
})
it('should get "Not authorized" warning message and logout button but no login button', async function(){
@ -47,7 +46,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 driver.sleep(250)
const visible = await homePage.isWarningVisible()
assert.ok(!visible)
})

View File

@ -152,16 +152,6 @@ 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() {

View File

@ -3,15 +3,16 @@ const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
const fsp = fs.promises
const path = require('path')
const { By, Key, until, Builder, logging, Capabilities } = require('selenium-webdriver')
const proxy = require('selenium-webdriver/proxy')
require('chromedriver')
const UAALoginPage = require('./pageobjects/UAALoginPage')
const KeycloakLoginPage = require('./pageobjects/KeycloakLoginPage')
const assert = require('assert')
const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false'
const uaaUrl = process.env.UAA_URL || 'http://localhost:8080'
const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL) || 'http://localhost:15672/'
const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost'
const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false'
const seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444'
const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens'
const profiles = process.env.PROFILES || ''