diff --git a/deps/rabbit/src/rabbit_fifo.erl b/deps/rabbit/src/rabbit_fifo.erl index 29740cc325da..2f841c8f804e 100644 --- a/deps/rabbit/src/rabbit_fifo.erl +++ b/deps/rabbit/src/rabbit_fifo.erl @@ -1529,9 +1529,12 @@ activate_next_consumer(#?STATE{consumers = Cons0, State = State0#?STATE{consumers = Cons, service_queue = ServiceQueue1, waiting_consumers = Waiting}, + Effects1 = consumer_update_active_effects(State, Active, + false, waiting, + Effects0), Effects = consumer_update_active_effects(State, Consumer, true, single_active, - Effects0), + Effects1), {State, Effects}; {{ActiveCKey, ?CONSUMER_PRIORITY(ActivePriority) = Active}, {_NextCKey, ?CONSUMER_PRIORITY(WaitingPriority)}} @@ -1829,8 +1832,22 @@ complete_and_checkout(#{} = Meta, MsgIds, ConsumerKey, Effects0, State0) -> State1 = complete(Meta, ConsumerKey, MsgIds, Con0, State0), %% a completion could have removed the active/quiescing consumer - {State2, Effects1} = activate_next_consumer(State1, Effects0), - checkout(Meta, State0, State2, Effects1). + Effects1 = add_active_effect(Con0, State1, Effects0), + {State2, Effects2} = activate_next_consumer(State1, Effects1), + checkout(Meta, State0, State2, Effects2). + +add_active_effect(#consumer{status = quiescing} = Consumer, + #?STATE{cfg = #cfg{consumer_strategy = single_active}, + consumers = Consumers} = State, + Effects) -> + case active_consumer(Consumers) of + undefined -> + consumer_update_active_effects(State, Consumer, false, waiting, Effects); + _ -> + Effects + end; +add_active_effect(_, _, Effects) -> + Effects. cancel_consumer_effects(ConsumerId, #?STATE{cfg = #cfg{resource = QName}}, diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs index de73eb0dcf90..df697b4c6727 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs @@ -1,5 +1,5 @@ <% if (consumers.length > 0) { %> - +
<% if (mode == 'queue') { %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs index c4bed04b9c9b..b50b47484955 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs @@ -11,10 +11,10 @@ <% } %>

Details

-
+
- + <% if(!disable_stats) { %> @@ -76,7 +76,7 @@
Features<%= fmt_features(queue) %><%= fmt_features(queue) %>
<% if(!disable_stats) { %> - +
@@ -84,12 +84,12 @@ <% if(queue.consumers) { %> - + <% } else if(queue.hasOwnProperty('consumer_details')) { %> - + <% } %> <% if (is_classic(queue)) { %> @@ -277,7 +277,7 @@ <% } %> <% if(!disable_stats) { %> -
+

Consumers (<%=(queue.consumer_details.length)%>)

<%= format('consumers', {'mode': 'queue', 'consumers': queue.consumer_details}) %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/quorum-queue-stats.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/quorum-queue-stats.ejs new file mode 100644 index 000000000000..98d266ef5306 --- /dev/null +++ b/deps/rabbitmq_management/priv/www/js/tmpl/quorum-queue-stats.ejs @@ -0,0 +1,108 @@ +
State <%= fmt_object_state(queue) %>
Consumers<%= fmt_string(queue.consumers) %><%= fmt_string(queue.consumers) %>
Consumers<%= fmt_string(queue.consumer_details.length) %><%= fmt_string(queue.consumer_details.length) %>
+ + + + + + <% if(queue.consumers) { %> + + + + + <% } else if(queue.hasOwnProperty('consumer_details')) { %> + + + + + <% } %> + <% if(queue.hasOwnProperty('publishers')) { %> + + + + + <% } %> + + + + + <% if (queue.hasOwnProperty('delivery_limit')) { %> + + + + + <% } %> + +
State<%= fmt_object_state(queue) %>
Consumers<%= fmt_string(queue.consumers) %>
Consumers<%= fmt_string(queue.consumer_details.length) %>
Publishers<%= fmt_string(queue.publishers) %>
Open files<%= fmt_table_short(queue.open_files) %>
Delivery limit <%= fmt_string(queue.delivery_limit) %>
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TotalReadyUnackedHigh priorityNormal priorityReturnedDead-lettered + +
+ Messages + + + <%= fmt_num_thousands(queue.messages) %> + + <%= fmt_num_thousands(queue.messages_ready) %> + + <%= fmt_num_thousands(queue.messages_unacknowledged) %> + + <%= fmt_num_thousands(queue.messages_ready_high) %> + + <%= fmt_num_thousands(queue.messages_ready_normal) %> + + <%= fmt_num_thousands(queue.messages_ready_returned) %> + + <%= fmt_num_thousands(queue.messages_dlx) %> +
+ Message body bytes + + + <%= fmt_bytes(queue.message_bytes) %> + + <%= fmt_bytes(queue.message_bytes_ready) %> + + <%= fmt_bytes(queue.message_bytes_unacknowledged) %> + + + + + <%= fmt_bytes(queue.message_bytes_dlx) %> +
+ Process memory + + <%= fmt_bytes(queue.memory) %>
\ No newline at end of file diff --git a/selenium/Dockerfile b/selenium/Dockerfile index ce100de43725..ee580b544a21 100644 --- a/selenium/Dockerfile +++ b/selenium/Dockerfile @@ -1,5 +1,4 @@ -# syntax=docker/dockerfile:1 -FROM atools/jdk-maven-node:mvn3-jdk11-node16 as base +FROM node:18 as base WORKDIR /code diff --git a/selenium/package.json b/selenium/package.json index f8f1402b6ce7..c84f5668ff73 100644 --- a/selenium/package.json +++ b/selenium/package.json @@ -22,7 +22,8 @@ "proxy": "^1.0.2", "rhea": "^3.0.3", "selenium-webdriver": "^4.26.0", - "xmlhttprequest": "^1.8.0" + "xmlhttprequest": "^1.8.0", + "amqplib": "0.8.0" }, "devDependencies": { "chai": "^4.3.6", diff --git a/selenium/test/amqp.js b/selenium/test/amqp.js index 920dd682c098..cb94bfdfc983 100644 --- a/selenium/test/amqp.js +++ b/selenium/test/amqp.js @@ -7,6 +7,7 @@ var connectionOptions = getConnectionOptions() function getAmqpConnectionOptions() { return { + 'scheme': process.env.RABBITMQ_AMQP_SCHEME || 'amqp', 'host': process.env.RABBITMQ_HOSTNAME || 'rabbitmq', 'port': process.env.RABBITMQ_AMQP_PORT || 5672, 'username' : process.env.RABBITMQ_AMQP_USERNAME || 'guest', @@ -39,21 +40,28 @@ function getConnectionOptions() { } } module.exports = { - - open: () => { + getAmqpConnectionOptions: () => { return connectionOptions }, + getAmqpUrl: () => { + return connectionOptions.scheme + '://' + + connectionOptions.username + ":" + connectionOptions.password + "@" + + connectionOptions.host + ":" + connectionOptions.port + }, + open: (queueName = "my-queue") => { let promise = new Promise((resolve, reject) => { container.on('connection_open', function(context) { resolve() }) }) + console.log("Opening amqp connection using " + JSON.stringify(connectionOptions)) + let connection = container.connect(connectionOptions) let receiver = connection.open_receiver({ - source: 'my-queue', + source: queueName, target: 'receiver-target', name: 'receiver-link' }) let sender = connection.open_sender({ - target: 'my-queue', + target: queueName, source: 'sender-source', name: 'sender-link' }) @@ -64,6 +72,13 @@ module.exports = { 'sender' : sender } }, + openReceiver: (handler, queueName = "my-queue") => { + return handler.connection.open_receiver({ + source: queueName, + target: 'receiver-target', + name: 'receiver-link' + }) + }, close: (connection) => { if (connection != null) { connection.close() diff --git a/selenium/test/exchanges/management.js b/selenium/test/exchanges/management.js index 5919c9771668..1e7654aa353d 100644 --- a/selenium/test/exchanges/management.js +++ b/selenium/test/exchanges/management.js @@ -30,7 +30,8 @@ describe('Exchange management', function () { if (!await overview.isLoaded()) { throw new Error('Failed to login') } - overview.clickOnExchangesTab() + await overview.selectRefreshOption("Do not refresh") + await overview.clickOnExchangesTab() }) it('display summary of exchanges', async function () { diff --git a/selenium/test/mgt-api.js b/selenium/test/mgt-api.js index 305e896c33be..eb0876837028 100644 --- a/selenium/test/mgt-api.js +++ b/selenium/test/mgt-api.js @@ -114,7 +114,7 @@ module.exports = { throw new Error(req.responseText) } }, - createVhost: (url, name, description = "", tags = []) => { + createVhost: (url, authorization, name, description = "", tags = []) => { let vhost = { "description": description, "tags": tags @@ -122,10 +122,9 @@ module.exports = { log("Create vhost " + JSON.stringify(vhost) + " with name " + name + " on " + url) const req = new XMLHttpRequest() - let base64Credentials = btoa('administrator-only' + ":" + 'guest') let finalUrl = url + "/api/vhosts/" + encodeURIComponent(name) req.open('PUT', finalUrl, false) - req.setRequestHeader("Authorization", "Basic " + base64Credentials) + req.setRequestHeader("Authorization", authorization) req.setRequestHeader('Content-Type', 'application/json') req.send(JSON.stringify(vhost)) @@ -158,13 +157,12 @@ module.exports = { throw new Error(req.responseText) } }, - deleteVhost: (url, vhost) => { + deleteVhost: (url, authorization, vhost) => { log("Deleting vhost " + vhost) const req = new XMLHttpRequest() - let base64Credentials = btoa('administrator-only' + ":" + 'guest') let finalUrl = url + "/api/vhosts/" + encodeURIComponent(vhost) req.open('DELETE', finalUrl, false) - req.setRequestHeader("Authorization", "Basic " + base64Credentials) + req.setRequestHeader("Authorization", authorization) req.send() if (req.status == 200 || req.status == 204) { @@ -194,21 +192,18 @@ module.exports = { throw new Error(req.responseText) } }, - createQueue: (url, name, vhost, queueType = "quorum") => { + createQueue: (url, authorization, vhost, name, arguments = {}) => { 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("Authorization", authorization) req.setRequestHeader('Content-Type', 'application/json') let payload = { "durable": true, - "arguments":{ - "x-queue-type" : queueType - } + "arguments": arguments } req.send(JSON.stringify(payload)) if (req.status == 200 || req.status == 204 || req.status == 201) { @@ -219,14 +214,13 @@ module.exports = { throw new Error(req.responseText) } }, - deleteQueue: (url, name, vhost) => { + deleteQueue: (url, authorization, vhost, name) => { 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.setRequestHeader("Authorization", authorization) req.send() if (req.status == 200 || req.status == 204) { diff --git a/selenium/test/pageobjects/BasePage.js b/selenium/test/pageobjects/BasePage.js index d810ca7cd2be..36bad7c4e0b4 100644 --- a/selenium/test/pageobjects/BasePage.js +++ b/selenium/test/pageobjects/BasePage.js @@ -34,7 +34,12 @@ module.exports = class BasePage { this.interactionDelay = parseInt(process.env.SELENIUM_INTERACTION_DELAY) || 0 // slow down interactions (when rabbit is behind a http proxy) } - + async goTo(path) { + return driver.get(d.baseUrl + path) + } + async refresh() { + return this.driver.navigate().refresh() + } async isLoaded () { return this.waitForDisplayed(MENU_TABS) } @@ -147,11 +152,63 @@ module.exports = class BasePage { const select = await new Select(selectable) return select.selectByValue(vhost) } + async getTableMini(tableLocator) { + const table = await this.waitForDisplayed(tableLocator) + return this.getTableMiniUsingTableElement(table) + } + async getTableMiniUsingTableElement(table) { + let tbody = await table.findElement(By.css('tbody')) + let rows = await tbody.findElements(By.xpath("./child::*")) + + let table_model = [] + for (let row of rows) { + let columnName = await row.findElement(By.css('th')).getText() + + let columnValue = await row.findElement(By.css('td')) + let columnContent = await columnValue.findElement(By.xpath("./child::*")) + + let columnType = await columnContent.getTagName() + + switch (columnType) { + case "table": + table_model.push({ + "name": columnName, + "value" : await this.getTableMiniUsingTableElement(columnValue) + }) + break + default: + table_model.push({ + "name" : columnName, + "value" : await columnContent.getText() + }) + } + } + return table_model + } async getTable(tableLocator, firstNColumns, rowClass) { const table = await this.waitForDisplayed(tableLocator) const rows = await table.findElements(rowClass == undefined ? - By.css('tbody tr') : By.css('tbody tr.' + rowClass)) + By.css('tbody tr') : By.css('tbody tr.' + rowClass)) + let table_model = [] + + for (let row of rows) { + let columns = await row.findElements(By.css('td')) + let table_row = [] + for (let column of columns) { + if (firstNColumns == undefined || table_row.length < firstNColumns) { + table_row.push(await column.getText()) + } + } + table_model.push(table_row) + } + return table_model + } + async getPlainTable(tableLocator, firstNColumns) { + const table = await this.waitForDisplayed(tableLocator) + let tbody = await table.findElement(By.css('tbody')) + let rows = await tbody.findElements(By.xpath("./child::*")) let table_model = [] + for (let row of rows) { let columns = await row.findElements(By.css('td')) let table_row = [] diff --git a/selenium/test/pageobjects/QueuePage.js b/selenium/test/pageobjects/QueuePage.js index 0746d564baf5..642d6c79f319 100644 --- a/selenium/test/pageobjects/QueuePage.js +++ b/selenium/test/pageobjects/QueuePage.js @@ -7,14 +7,36 @@ const QUEUE_NAME = By.css('div#main h1 b') const DELETE_SECTION = By.css('div#main div#delete') const DELETE_BUTTON = By.css('div#main div#delete input[type=submit]') +const FEATURES_TABLE = By.css('table#details-queue-table td#details-queue-features table.mini') +const STATS_CONSUMER_COUNT = By.css('table#details-queue-stats-table td#consumers') + +const CONSUMERS_SECTION = By.css('div#queue-consumers-section') +const CONSUMERS_SECTION_TITLE = By.css('div#queue-consumers-section h2') +const CONSUMERS_TABLE = By.css('div#queue-consumers-section table.list#consumers') module.exports = class QueuePage extends BasePage { async isLoaded() { return this.waitForDisplayed(QUEUE_NAME) } + async getName() { return this.getText(QUEUE_NAME) } + async getConsumerCount() { + return this.getText(STATS_CONSUMER_COUNT) + } + async getFeatures() { + return this.getTableMini(FEATURES_TABLE) + } + async getConsumersSectionTitle() { + return this.getText(CONSUMERS_SECTION_TITLE) + } + async clickOnConsumerSection() { + return this.click(CONSUMERS_SECTION) + } + async getConsumersTable() { + return this.getPlainTable(CONSUMERS_TABLE) + } async ensureDeleteQueueSectionIsVisible() { await this.click(DELETE_SECTION) return this.driver.findElement(DELETE_SECTION).isDisplayed() diff --git a/selenium/test/queuesAndStreams/view-qq-consumers.js b/selenium/test/queuesAndStreams/view-qq-consumers.js new file mode 100644 index 000000000000..652d2d299ae7 --- /dev/null +++ b/selenium/test/queuesAndStreams/view-qq-consumers.js @@ -0,0 +1,256 @@ +const { By, Key, until, Builder } = require('selenium-webdriver') +require('chromedriver') +const assert = require('assert') +const { buildDriver, goToHome, captureScreensFor, teardown, doWhile, goToQueue,delay } = require('../utils') +const { createQueue, deleteQueue, getManagementUrl, basicAuthorization } = require('../mgt-api') +const { getAmqpUrl : getAmqpUrl } = require('../amqp') +const amqplib = require('amqplib'); + +const LoginPage = require('../pageobjects/LoginPage') +const OverviewPage = require('../pageobjects/OverviewPage') +const QueuesAndStreamsPage = require('../pageobjects/QueuesAndStreamsPage') +const QueuePage = require('../pageobjects/QueuePage') +const StreamPage = require('../pageobjects/StreamPage') + + +describe('Given a quorum queue configured with SAC', function () { + let login + let queuesAndStreams + let queuePage + let queueName + let stream + let overview + let captureScreen + + before(async function () { + driver = buildDriver() + await goToHome(driver) + login = new LoginPage(driver) + overview = new OverviewPage(driver) + queuesAndStreams = new QueuesAndStreamsPage(driver) + queuePage = new QueuePage(driver) + stream = new StreamPage(driver) + captureScreen = captureScreensFor(driver, __filename) + + await login.login('management', 'guest') + if (!await overview.isLoaded()) { + throw new Error('Failed to login') + } + await overview.selectRefreshOption("Do not refresh") + queueName = "test_" + Math.floor(Math.random() * 1000) + + createQueue(getManagementUrl(), basicAuthorization("management", "guest"), + "/", queueName, { + "x-queue-type": "quorum", + "x-single-active-consumer": true + }) + + await goToQueue(driver, "/", queueName) + await queuePage.isLoaded() + assert.equal(queueName, await queuePage.getName()) + + }) + + it('it must display its queue-type and durability', async function () { + let table = await queuePage.getFeatures() + assert.equal(table[0].name, "arguments:") + let expectedArguments = [ + {"name":"x-queue-type:", "value":"quorum"} + ] + assert.equal(JSON.stringify(table[0].value), JSON.stringify(expectedArguments)) + assert.equal(table[1].name, "x-single-active-consumer:") + assert.equal(table[1].value, "true") + assert.equal(table[2].name, "durable:") + assert.equal(table[2].value, "true") + }) + + it('it should not have any consumers', async function() { + assert.equal("0", await queuePage.getConsumerCount()) + assert.equal("Consumers (0)", await queuePage.getConsumersSectionTitle()) + }) + + describe("given there is a consumer (without priority) attached to the queue", function () { + let amqp091conn + let ch1 + let ch1Consumer + let ch2 + let ch2Consumer + + before(async function() { + let amqpUrl = getAmqpUrl() + "?frameMax=0" + amqp091conn = await amqplib.connect(amqpUrl) + ch1 = await amqp091conn.createChannel() + ch1Consumer = ch1.consume(queueName, (msg) => {}, {consumerTag: "one"}) + }) + + it('it should have one consumer as active', async function() { + await doWhile(async function() { + await queuePage.refresh() + await queuePage.isLoaded() + return queuePage.getConsumerCount() + }, function(count) { + return count.localeCompare("0") == 1 + }, 5000) + assert.equal("1", await queuePage.getConsumerCount()) + assert.equal("Consumers (1)", await queuePage.getConsumersSectionTitle()) + await queuePage.clickOnConsumerSection() + let consumerTable = await doWhile(async function() { + return queuePage.getConsumersTable() + }, function(table) { + return table[0][6].localeCompare("single active") == 0 && + table[0][1].localeCompare("one") == 0 + }) + assert.equal("single active", consumerTable[0][6]) + assert.equal("one", consumerTable[0][1]) + + }) + + describe("given another consumer is added with priority", function () { + before(async function() { + ch2 = await amqp091conn.createChannel() + ch2Consumer = ch2.consume(queueName, (msg) => {}, {consumerTag: "two", priority: 10}) + }) + + it('the latter consumer should be active and the former waiting', async function() { + + await doWhile(async function() { + await queuePage.refresh() + await queuePage.isLoaded() + return queuePage.getConsumerCount() + }, function(count) { + return count.localeCompare("2") == 0 + }, 5000) + + assert.equal("2", await queuePage.getConsumerCount()) + assert.equal("Consumers (2)", await queuePage.getConsumersSectionTitle()) + await queuePage.clickOnConsumerSection() + let consumerTable = await doWhile(async function() { + return queuePage.getConsumersTable() + }, function(table) { + return table.length == 2 && table[0][1] != "" && table[1][1] != "" + }, 5000) + + let activeConsumer = consumerTable[1][6].localeCompare("single active") == 0 ? + 1 : 0 + let nonActiveConsumer = activeConsumer == 1 ? 0 : 1 + + assert.equal("waiting", consumerTable[nonActiveConsumer][6]) + assert.equal("one", consumerTable[nonActiveConsumer][1]) + assert.equal("single active", consumerTable[activeConsumer][6]) + assert.equal("two", consumerTable[activeConsumer][1]) + await delay(5000) + }) + }) + + after(async function() { + try { + if (amqp091conn != null) { + amqp091conn.close() + } + } catch (error) { + error("Failed to close amqp091 connection due to " + error); + } + // ensure there are no more consumers + await doWhile(async function() { + await queuePage.refresh() + await queuePage.isLoaded() + return queuePage.getConsumerCount() + }, function(count) { + return count.localeCompare("0") == 0 + }, 5000) + + + }) + }) + + describe("given there is a consumer (with priority) attached to the queue", function () { + let amqp091conn + let ch1 + let ch1Consumer + let ch2 + let ch2Consumer + + before(async function() { + let amqpUrl = getAmqpUrl() + "?frameMax=0" + amqp091conn = await amqplib.connect(amqpUrl) + ch1 = await amqp091conn.createChannel() + ch1Consumer = ch1.consume(queueName, (msg) => {}, {consumerTag: "one", priority: 10}) + }) + + it('it should have one consumer as active', async function() { + await doWhile(async function() { + await queuePage.refresh() + await queuePage.isLoaded() + return queuePage.getConsumerCount() + }, function(count) { + return count.localeCompare("0") == 1 + }, 5000) + assert.equal("1", await queuePage.getConsumerCount()) + assert.equal("Consumers (1)", await queuePage.getConsumersSectionTitle()) + await queuePage.clickOnConsumerSection() + let consumerTable = await doWhile(async function() { + return queuePage.getConsumersTable() + }, function(table) { + return table[0][6].localeCompare("single active") == 0 && + table[0][1].localeCompare("one") == 0 + }) + assert.equal("single active", consumerTable[0][6]) + assert.equal("one", consumerTable[0][1]) + + }) + + describe("given another consumer is added without priority", function () { + before(async function() { + ch2 = await amqp091conn.createChannel() + ch2Consumer = ch2.consume(queueName, (msg) => {}, {consumerTag: "two"}) + }) + + it('the former consumer should still be active and the latter be waiting', async function() { + + await doWhile(async function() { + await queuePage.refresh() + await queuePage.isLoaded() + return queuePage.getConsumerCount() + }, function(count) { + return count.localeCompare("2") == 0 + }, 5000) + + assert.equal("2", await queuePage.getConsumerCount()) + assert.equal("Consumers (2)", await queuePage.getConsumersSectionTitle()) + await queuePage.clickOnConsumerSection() + let consumerTable = await doWhile(async function() { + return queuePage.getConsumersTable() + }, function(table) { + return table.length == 2 && table[0][1] != "" && table[1][1] != "" + }, 5000) + + let activeConsumer = consumerTable[1][6].localeCompare("single active") == 0 ? + 1 : 0 + let nonActiveConsumer = activeConsumer == 1 ? 0 : 1 + + assert.equal("waiting", consumerTable[nonActiveConsumer][6]) + assert.equal("two", consumerTable[nonActiveConsumer][1]) + assert.equal("single active", consumerTable[activeConsumer][6]) + assert.equal("one", consumerTable[activeConsumer][1]) + await delay(5000) + }) + }) + + after(function() { + try { + if (amqp091conn != null) { + amqp091conn.close() + } + } catch (error) { + error("Failed to close amqp091 connection due to " + error); + } + + }) + }) + + after(async function () { + await teardown(driver, this, captureScreen) + deleteQueue(getManagementUrl(), basicAuthorization("management", "guest"), + "/", queueName) + }) +}) diff --git a/selenium/test/utils.js b/selenium/test/utils.js index 8c29fef64bc2..19987356beb1 100644 --- a/selenium/test/utils.js +++ b/selenium/test/utils.js @@ -129,9 +129,9 @@ module.exports = { goToExchanges: (d) => { return d.driver.get(d.baseUrl + '#/exchanges') }, - - goTo: (d, address) => { - return d.get(address) + + goToQueue(d, vhost, queue) { + return d.driver.get(d.baseUrl + '#/queues/' + encodeURIComponent(vhost) + '/' + encodeURIComponent(queue)) }, delay: async (msec, ref) => { diff --git a/selenium/test/vhosts/admin-vhosts.js b/selenium/test/vhosts/admin-vhosts.js index 2e51157b6eea..932d480d8263 100644 --- a/selenium/test/vhosts/admin-vhosts.js +++ b/selenium/test/vhosts/admin-vhosts.js @@ -2,7 +2,7 @@ const { By, Key, until, Builder } = require('selenium-webdriver') require('chromedriver') const assert = require('assert') const { buildDriver, goToHome, captureScreensFor, teardown, doWhile, log, delay } = require('../utils') -const { getManagementUrl, createVhost, deleteVhost } = require('../mgt-api') +const { getManagementUrl, basicAuthorization, createVhost, deleteVhost } = require('../mgt-api') const LoginPage = require('../pageobjects/LoginPage') const OverviewPage = require('../pageobjects/OverviewPage') @@ -107,7 +107,8 @@ describe('Virtual Hosts in Admin tab', function () { let vhost = "test_" + Math.floor(Math.random() * 1000) before(async function() { log("Creating vhost") - createVhost(getManagementUrl(), vhost, "selenium", "selenium-tag") + createVhost(getManagementUrl(), basicAuthorization('administrator-only', 'guest'), + vhost, "selenium", "selenium-tag") // await overview.clickOnOverviewTab() await overview.clickOnAdminTab() await adminTab.clickOnVhosts() @@ -131,7 +132,8 @@ describe('Virtual Hosts in Admin tab', function () { }) after(async function () { log("Deleting vhost") - deleteVhost(getManagementUrl(), vhost) + deleteVhost(getManagementUrl(), basicAuthorization("administrator-only", "guest"), + vhost) }) })