This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-24823-infra-artemis-ports
in repository https://gitbox.apache.org/repos/asf/camel.git

commit d19a655e803112619fa2a2e007e742dcd2009d73
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Nov 12 19:45:37 2026 +0100

    CAMEL-24823: camel-jbang - camel infra run artemis maps MQTT and AMQP only 
on request, and a taken port is one line
    
    camel infra run artemis mapped 1883 and 5672 on the host, the ports of
    mosquitto and RabbitMQ, so it could not run next to them. It now maps
    the core acceptor and the web console, and MQTT and AMQP with
    --property artemis.ports=mqtt,amqp (or all).
    
    A service that does not start because a port it maps on the host is
    taken fails with one line naming the port and the infra service that
    has it, instead of the stack trace of the container runtime.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  10 ++
 .../ROOT/pages/camel-jbang-dev-services.adoc       |  18 ++++
 .../jbang/core/commands/infra/InfraPortInUse.java  | 106 +++++++++++++++++++++
 .../dsl/jbang/core/commands/infra/InfraRun.java    |  32 ++++++-
 .../core/commands/infra/InfraPortInUseTest.java    |  97 +++++++++++++++++++
 .../infra/artemis/common/ArtemisProperties.java    |   6 ++
 .../infra/artemis/services/ArtemisContainer.java   |  50 +++++++++-
 .../services/ArtemisContainerPortsTest.java        |  57 +++++++++++
 8 files changed, 371 insertions(+), 5 deletions(-)

diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 93adc90a66f1..f501728aad1d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -8263,3 +8263,13 @@ property of the bucket -- so `InfluxDb2Producer` never 
reads the option or the h
 Both are now deprecated with a note that says so. Remove `retentionPolicy` 
from the endpoint URI and stop setting the
 header: they are silently ignored. To control how long the data is kept, set 
the retention period on the bucket the
 endpoint writes to.
+
+=== camel-jbang - camel infra run artemis maps MQTT and AMQP only on request
+
+`camel infra run artemis` maps the core acceptor (61616) and the web console 
(8161) on the host, and no longer the
+MQTT (1883) and AMQP (5672) ports, which are the ports of mosquitto and 
RabbitMQ: Artemis failed to start next to
+`camel infra run mosquitto`. Map them with `--property 
artemis.ports=mqtt,amqp` (or `all`).
+The `withFixedPort()` container of `camel-test-infra-artemis` maps the same 
ports, and reads the same property.
+
+A service that does not start because a port it maps on the host is taken now 
fails with one line that names the port,
+and the infra service that has it, instead of the stack trace of the container 
runtime.
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-dev-services.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang-dev-services.adoc
index 616e9d307953..d85b3efc6007 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-dev-services.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-dev-services.adoc
@@ -85,6 +85,24 @@ container image, and the settings of every other service. 
The property names are
 `camel infra restart` takes the options again, the way it takes `--port`, so a 
restart keeps the
 model it was started with.
 
+Artemis maps the core acceptor (61616) and the web console (8161) on the host. 
MQTT (1883) and AMQP
+(5672) are the ports of mosquitto and RabbitMQ, so Artemis maps them only when 
you ask:
+
+[source,bash]
+----
+camel infra run artemis --property artemis.ports=mqtt,amqp
+----
+
+`all` maps both. When a port a service maps is taken, it does not start, and 
says which port and
+which service has it:
+
+[source,bash]
+----
+$ camel infra run artemis --property artemis.ports=mqtt
+Starting service artemis (PID: 45390)
+ERROR: Cannot start artemis: port 1883 is in use by mosquitto (PID 45211), 
stop it first with: camel infra stop mosquitto
+----
+
 == Stopping a service
 
 [source,bash]
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUse.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUse.java
new file mode 100644
index 000000000000..e8962ae2519c
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUse.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.infra;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Why a service did not start when a port it maps on the host is taken: 
artemis maps 1883 when mosquitto has it, and
+ * Docker fails with "Bind for 0.0.0.0:1883 failed: port is already allocated" 
deep in a stack trace (CAMEL-24823).
+ */
+final class InfraPortInUse {
+
+    // Docker: "Bind for 0.0.0.0:1883 failed: port is already allocated"
+    // Podman: "rootlessport listen tcp 0.0.0.0:1883: bind: address already in 
use"
+    private static final String[] IN_USE = { "port is already allocated", 
"address already in use" };
+    private static final Pattern PORT = Pattern.compile(":(\\d{1,5})(?!\\d)");
+
+    private InfraPortInUse() {
+    }
+
+    /**
+     * The port on the host that a failure to start says is taken.
+     *
+     * @param  failure the failure of the start, with its causes
+     * @return         the port, or -1 when the failure is not about a port in 
use, or does not name it
+     */
+    static int port(Throwable failure) {
+        Set<Throwable> seen = Collections.newSetFromMap(new 
IdentityHashMap<>());
+        for (Throwable t = failure; t != null && seen.add(t); t = 
t.getCause()) {
+            int port = port(t.getMessage());
+            if (port > 0) {
+                return port;
+            }
+        }
+        return -1;
+    }
+
+    static int port(String message) {
+        if (message == null) {
+            return -1;
+        }
+        String lower = message.toLowerCase(Locale.ROOT);
+        for (String inUse : IN_USE) {
+            int end = lower.indexOf(inUse);
+            if (end > 0) {
+                // the last port before the complaint is the one on the host
+                Matcher m = PORT.matcher(message.substring(0, end));
+                int port = -1;
+                while (m.find()) {
+                    port = Integer.parseInt(m.group(1));
+                }
+                if (port > 0 && port <= 65535) {
+                    return port;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Whether the service data of a running service has the port: as a value 
({@code "port":1883}) or in an address
+     * ({@code "tcp://localhost:1883"}). Not a port that only starts the same 
({@code 18830}), nor a container id that
+     * starts with its digits.
+     */
+    static boolean hasPort(String serviceData, int port) {
+        if (serviceData == null) {
+            return false;
+        }
+        return Pattern.compile(":\\s*\"?" + port + 
"(?!\\w)").matcher(serviceData).find();
+    }
+
+    /**
+     * The one line that tells the user which port is taken, by what, and the 
way out.
+     *
+     * @param service the service that did not start
+     * @param port    the port that is taken
+     * @param holder  the running infra service that has the port, or {@code 
null} when it is another program
+     * @param pid     the pid of the holder
+     */
+    static String message(String service, int port, String holder, String pid) 
{
+        if (holder != null) {
+            return "Cannot start " + service + ": port " + port + " is in use 
by " + holder + " (PID " + pid
+                   + "), stop it first with: camel infra stop " + holder;
+        }
+        return "Cannot start " + service + ": port " + port + " is in use by 
another program";
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
index 913b3100ea01..ba2cfcbd977d 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraRun.java
@@ -18,6 +18,7 @@ package org.apache.camel.dsl.jbang.core.commands.infra;
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.URL;
 import java.nio.file.Files;
@@ -256,7 +257,15 @@ public class InfraRun extends InfraBaseCommand {
             printer().println("Starting service " + testService + prefix + " 
(PID: " + RuntimeUtil.getPid() + ")");
         }
 
-        actualService.getClass().getMethod("initialize").invoke(actualService);
+        try {
+            
actualService.getClass().getMethod("initialize").invoke(actualService);
+        } catch (InvocationTargetException e) {
+            String message = portInUseMessage(testService, e.getCause());
+            if (message != null) {
+                throw CliException.failure(message);
+            }
+            throw e;
+        }
 
         Method[] serviceMethods = 
cl.loadClass(serviceInterface).getDeclaredMethods();
         Map<String, Object> properties = new TreeMap<>();
@@ -359,6 +368,27 @@ public class InfraRun extends InfraBaseCommand {
         return 0;
     }
 
+    /**
+     * The one line for a service that did not start because a port it maps on 
the host is taken, naming the running
+     * infra service that has it, instead of the stack trace of the container 
runtime.
+     *
+     * @param  service the service that did not start
+     * @param  failure why it did not start
+     * @return         the line, or {@code null} when the failure is not about 
a port in use
+     */
+    String portInUseMessage(String service, Throwable failure) {
+        int port = InfraPortInUse.port(failure);
+        if (port < 0) {
+            return null;
+        }
+        for (RunningService running : findRunningServices(null)) {
+            if (InfraPortInUse.hasPort(readServiceData(running.pidFile()), 
port)) {
+                return InfraPortInUse.message(service, port, running.alias(), 
running.pid());
+            }
+        }
+        return InfraPortInUse.message(service, port, null, null);
+    }
+
     /**
      * Reads the --property options, which is how a service takes a setting 
the CLI has no flag of its own for, such as
      * the model of ollama. Only the pairs are read here, so that a malformed 
one is refused before anything is set and
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUseTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUseTest.java
new file mode 100644
index 000000000000..615f08e6f6a2
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/infra/InfraPortInUseTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.infra;
+
+import java.net.BindException;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * A service that does not start because a port it maps on the host is taken 
says so in one line, naming the infra
+ * service that has the port (CAMEL-24823).
+ */
+class InfraPortInUseTest extends InfraCommandTestSupport {
+
+    // as Docker and testcontainers report it, a few causes down
+    private static final RuntimeException DOCKER = new RuntimeException(
+            "Container startup failed for image artemis",
+            new RuntimeException(
+                    "Could not create/start container",
+                    new RuntimeException(
+                            "Status 500: {\"message\":\"failed to set up 
container networking: driver failed"
+                                         + " programming external connectivity 
on endpoint camel-artemis (3f2a9c1b7d4e):"
+                                         + " Bind for 0.0.0.0:1883 failed: 
port is already allocated\"}")));
+
+    @Test
+    void thePortDockerSaysIsTaken() {
+        assertThat(InfraPortInUse.port(DOCKER)).isEqualTo(1883);
+        assertThat(InfraPortInUse.port("Bind for [::]:5672 failed: port is 
already allocated")).isEqualTo(5672);
+    }
+
+    @Test
+    void thePortPodmanSaysIsTaken() {
+        assertThat(InfraPortInUse.port(
+                "rootlessport listen tcp 0.0.0.0:1883: bind: address already 
in use")).isEqualTo(1883);
+    }
+
+    @Test
+    void notAboutAPortInUse() {
+        assertThat(InfraPortInUse.port(new RuntimeException("Could not pull 
image: manifest unknown"))).isEqualTo(-1);
+        // an embedded service does not say which port
+        assertThat(InfraPortInUse.port(new BindException("Address already in 
use"))).isEqualTo(-1);
+        assertThat(InfraPortInUse.port((Throwable) null)).isEqualTo(-1);
+    }
+
+    @Test
+    void theServiceDataOfTheServiceThatHasThePort() {
+        assertThat(InfraPortInUse.hasPort("{\"port\":1883}", 1883)).isTrue();
+        
assertThat(InfraPortInUse.hasPort("{\"getServiceAddress\":\"tcp://localhost:1883\"}",
 1883)).isTrue();
+        assertThat(InfraPortInUse.hasPort("{\"port\":\"1883\"}", 
1883)).isTrue();
+        // not another port that starts the same, nor a container id
+        assertThat(InfraPortInUse.hasPort("{\"port\":18830}", 1883)).isFalse();
+        
assertThat(InfraPortInUse.hasPort("{\"containerId\":\"1883ab7d4e9f\"}", 
1883)).isFalse();
+        assertThat(InfraPortInUse.hasPort(null, 1883)).isFalse();
+    }
+
+    @Test
+    void aPortThatARunningInfraServiceHas() throws Exception {
+        writePidFile("mosquitto", 4321, 
"{\"getPort\":1883,\"serviceAddress\":\"tcp://localhost:1883\"}");
+        writePidFile("kafka", 1234, 
"{\"getBootstrapServers\":\"localhost:9092\"}");
+
+        assertThat(command().portInUseMessage("artemis", DOCKER)).isEqualTo(
+                "Cannot start artemis: port 1883 is in use by mosquitto (PID 
4321), stop it first with: camel infra stop mosquitto");
+    }
+
+    @Test
+    void aPortThatAnotherProgramHas() throws Exception {
+        writePidFile("kafka", 1234, 
"{\"getBootstrapServers\":\"localhost:9092\"}");
+
+        assertThat(command().portInUseMessage("artemis", DOCKER))
+                .isEqualTo("Cannot start artemis: port 1883 is in use by 
another program");
+        assertThat(command().portInUseMessage("artemis", new 
RuntimeException("Could not pull image"))).isNull();
+    }
+
+    private InfraRun command() {
+        InfraRun command = new InfraRun(new 
CamelJBangMain().withPrinter(printer));
+        // the pid files carry synthetic pids, so treat every pid as a live 
process
+        command.aliveCheck = pid -> true;
+        return command;
+    }
+}
diff --git 
a/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/common/ArtemisProperties.java
 
b/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/common/ArtemisProperties.java
index d48869238cdd..32a32c74a73a 100644
--- 
a/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/common/ArtemisProperties.java
+++ 
b/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/common/ArtemisProperties.java
@@ -29,6 +29,12 @@ public final class ArtemisProperties {
     public static final String ARTEMIS_SSL_KEYSTORE_PASSWORD = 
"artemis.ssl.keystore.password";
     public static final String ARTEMIS_SSL_TRUSTSTORE_PATH = 
"artemis.ssl.truststore.path";
     public static final String ARTEMIS_SSL_TRUSTSTORE_PASSWORD = 
"artemis.ssl.truststore.password";
+    /**
+     * The protocols whose ports {@code camel infra run artemis} maps on the 
host as well, comma separated: {@code mqtt}
+     * (1883), {@code amqp} (5672) or {@code all}. By default only the core 
acceptor (61616) and the web console (8161)
+     * are, as mosquitto and RabbitMQ use the others.
+     */
+    public static final String ARTEMIS_PORTS = "artemis.ports";
 
     private ArtemisProperties() {
 
diff --git 
a/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/services/ArtemisContainer.java
 
b/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/services/ArtemisContainer.java
index ee4c5f83fa34..3b181b66f11d 100644
--- 
a/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/services/ArtemisContainer.java
+++ 
b/test-infra/camel-test-infra-artemis/src/main/java/org/apache/camel/test/infra/artemis/services/ArtemisContainer.java
@@ -16,9 +16,16 @@
  */
 package org.apache.camel.test.infra.artemis.services;
 
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
 import org.apache.camel.test.infra.artemis.common.ArtemisProperties;
 import org.apache.camel.test.infra.common.LocalPropertyResolver;
 import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
+import 
org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil.PortConfig;
 import org.apache.camel.test.infra.messaging.services.MessagingContainer;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
@@ -48,17 +55,52 @@ public class ArtemisContainer extends 
GenericContainer<ArtemisContainer> impleme
                 .waitingFor(Wait.forListeningPort());
     }
 
+    /**
+     * A container with its ports on the same ports of the host, as {@code 
camel infra run artemis} runs it: the core
+     * acceptor (61616) and the web console (8161), and MQTT and AMQP only 
when {@link ArtemisProperties#ARTEMIS_PORTS}
+     * asks for them, as mosquitto (1883) and RabbitMQ (5672) use the same 
ports.
+     */
     public static ArtemisContainer withFixedPort() {
         ArtemisContainer container = new ArtemisContainer();
         ContainerEnvironmentUtil.configurePorts(container, true,
-                
ContainerEnvironmentUtil.PortConfig.primary(DEFAULT_ACCEPTOR_PORT),
-                
ContainerEnvironmentUtil.PortConfig.secondary(DEFAULT_MQTT_PORT),
-                
ContainerEnvironmentUtil.PortConfig.secondary(DEFAULT_AMQP_PORT),
-                
ContainerEnvironmentUtil.PortConfig.secondary(DEFAULT_ADMIN_PORT));
+                
fixedPorts(System.getProperty(ArtemisProperties.ARTEMIS_PORTS)).toArray(PortConfig[]::new));
 
         return container;
     }
 
+    /**
+     * The ports to map on the same ports of the host.
+     *
+     * @param  protocols                the protocols to map as well, comma 
separated ({@code mqtt}, {@code amqp},
+     *                                  {@code all}), or {@code null}
+     * @return                          the ports
+     * @throws IllegalArgumentException for a protocol that is not one of them
+     */
+    static List<PortConfig> fixedPorts(String protocols) {
+        Set<PortConfig> ports = new LinkedHashSet<>();
+        ports.add(PortConfig.primary(DEFAULT_ACCEPTOR_PORT));
+        ports.add(PortConfig.secondary(DEFAULT_ADMIN_PORT));
+        if (protocols != null) {
+            for (String protocol : protocols.split(",")) {
+                switch (protocol.trim().toLowerCase(Locale.ROOT)) {
+                    case "mqtt" -> 
ports.add(PortConfig.secondary(DEFAULT_MQTT_PORT));
+                    case "amqp" -> 
ports.add(PortConfig.secondary(DEFAULT_AMQP_PORT));
+                    case "all" -> {
+                        ports.add(PortConfig.secondary(DEFAULT_MQTT_PORT));
+                        ports.add(PortConfig.secondary(DEFAULT_AMQP_PORT));
+                    }
+                    case "" -> {
+                        // nothing between two commas
+                    }
+                    default -> throw new IllegalArgumentException(
+                            "Unknown protocol " + protocol.trim() + " in " + 
ArtemisProperties.ARTEMIS_PORTS
+                                                                  + ": use 
mqtt, amqp or all");
+                }
+            }
+        }
+        return new ArrayList<>(ports);
+    }
+
     /**
      * Gets the port number used for exchanging messages using the AMQP 
protocol
      *
diff --git 
a/test-infra/camel-test-infra-artemis/src/test/java/org/apache/camel/test/infra/artemis/services/ArtemisContainerPortsTest.java
 
b/test-infra/camel-test-infra-artemis/src/test/java/org/apache/camel/test/infra/artemis/services/ArtemisContainerPortsTest.java
new file mode 100644
index 000000000000..e323a9a4a670
--- /dev/null
+++ 
b/test-infra/camel-test-infra-artemis/src/test/java/org/apache/camel/test/infra/artemis/services/ArtemisContainerPortsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.artemis.services;
+
+import java.util.List;
+
+import 
org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil.PortConfig;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * camel infra run artemis maps the ports of MQTT and AMQP on the host only 
when asked, as mosquitto and RabbitMQ use
+ * the same ports (CAMEL-24823).
+ */
+class ArtemisContainerPortsTest {
+
+    @Test
+    void theCoreAcceptorAndTheWebConsoleByDefault() {
+        assertEquals(List.of(PortConfig.primary(61616), 
PortConfig.secondary(8161)), ArtemisContainer.fixedPorts(null));
+    }
+
+    @Test
+    void mqttAndAmqpOnRequest() {
+        assertEquals(List.of(PortConfig.primary(61616), 
PortConfig.secondary(8161), PortConfig.secondary(1883)),
+                ArtemisContainer.fixedPorts("mqtt"));
+        assertEquals(List.of(PortConfig.primary(61616), 
PortConfig.secondary(8161), PortConfig.secondary(5672),
+                PortConfig.secondary(1883)), ArtemisContainer.fixedPorts(" 
AMQP, mqtt,"));
+        assertEquals(List.of(PortConfig.primary(61616), 
PortConfig.secondary(8161), PortConfig.secondary(1883),
+                PortConfig.secondary(5672)), 
ArtemisContainer.fixedPorts("all,mqtt"));
+    }
+
+    @Test
+    void anUnknownProtocolIsRefused() {
+        IllegalArgumentException e
+                = assertThrows(IllegalArgumentException.class, () -> 
ArtemisContainer.fixedPorts("mqtt,stomp"));
+
+        assertTrue(e.getMessage().contains("stomp"), e.getMessage());
+        assertTrue(e.getMessage().contains("artemis.ports"), e.getMessage());
+    }
+}

Reply via email to