This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 8f5f59f5dcb8ffa1547afb20cd63bfadaeba365b Author: Guillaume Nodet <gno...@gmail.com> AuthorDate: Tue May 28 11:36:30 2019 +0200 Use custom ports for management tests --- .../camel/management/ManagedComponentTest.java | 3 +- .../camel/management/ManagementTestSupport.java | 19 +++ .../camel/management/util/AvailablePortFinder.java | 167 +++++++++++++++++++++ 3 files changed, 187 insertions(+), 2 deletions(-) diff --git a/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagedComponentTest.java b/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagedComponentTest.java index acbea64..b78f6c4 100644 --- a/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagedComponentTest.java +++ b/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagedComponentTest.java @@ -80,8 +80,7 @@ public class ManagedComponentTest extends ManagementTestSupport { return; } - JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi/camel")); - MBeanServerConnection mbeanServer = connector.getMBeanServerConnection(); + MBeanServerConnection mbeanServer = getMBeanServer(); ObjectName on = ObjectName.getInstance("org.apache.camel:context=camel-1,type=components,name=\"my-verifiable-component\""); assertTrue(mbeanServer.isRegistered(on)); diff --git a/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagementTestSupport.java b/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagementTestSupport.java index 2965622..a4057bd 100644 --- a/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagementTestSupport.java +++ b/core/camel-management-impl/src/test/java/org/apache/camel/management/ManagementTestSupport.java @@ -17,6 +17,7 @@ package org.apache.camel.management; import java.io.IOException; +import java.util.Random; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; @@ -26,17 +27,35 @@ import javax.management.ObjectName; import javax.management.ReflectionException; import org.apache.camel.ContextTestSupport; +import org.apache.camel.api.management.JmxSystemPropertyKeys; +import org.apache.camel.management.util.AvailablePortFinder; +import org.junit.Before; /** * Base class for JMX tests. */ public abstract class ManagementTestSupport extends ContextTestSupport { + protected int registryPort; + protected String url; + @Override protected boolean useJmx() { return true; } + @Override + @Before + public void setUp() throws Exception { + registryPort = AvailablePortFinder.getNextAvailable(); + log.info("Using port " + registryPort); + + // need to explicit set it to false to use non-platform mbs + System.setProperty(JmxSystemPropertyKeys.CREATE_CONNECTOR, "true"); + System.setProperty(JmxSystemPropertyKeys.REGISTRY_PORT, "" + registryPort); + super.setUp(); + } + protected MBeanServer getMBeanServer() { return context.getManagementStrategy().getManagementAgent().getMBeanServer(); } diff --git a/core/camel-management-impl/src/test/java/org/apache/camel/management/util/AvailablePortFinder.java b/core/camel-management-impl/src/test/java/org/apache/camel/management/util/AvailablePortFinder.java new file mode 100644 index 0000000..04a14b2 --- /dev/null +++ b/core/camel-management-impl/src/test/java/org/apache/camel/management/util/AvailablePortFinder.java @@ -0,0 +1,167 @@ +/* + * 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.management.util; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.ServerSocket; +import java.util.NoSuchElementException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Finds currently available server ports. + */ +public final class AvailablePortFinder { + + /** + * The minimum server currentMinPort number for IPv4. + * Set at 1100 to avoid returning privileged currentMinPort numbers. + */ + public static final int MIN_PORT_NUMBER = 1100; + + /** + * The maximum server currentMinPort number for IPv4. + */ + public static final int MAX_PORT_NUMBER = 65535; + + private static final Logger LOG = LoggerFactory.getLogger(AvailablePortFinder.class); + + /** + * We'll hold open the lowest port in this process + * so parallel processes won't use the same block + * of ports. They'll go up to the next block. + */ + private static final ServerSocket LOCK; + + /** + * Incremented to the next lowest available port when getNextAvailable() is called. + */ + private static AtomicInteger currentMinPort = new AtomicInteger(MIN_PORT_NUMBER); + + /** + * Creates a new instance. + */ + private AvailablePortFinder() { + // Do nothing + } + + static { + int port = MIN_PORT_NUMBER; + ServerSocket ss = null; + + while (ss == null) { + try { + ss = new ServerSocket(port); + } catch (Exception e) { + ss = null; + port += 200; + } + } + LOCK = ss; + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + try { + LOCK.close(); + } catch (Exception ex) { + //ignore + } + } + }); + currentMinPort.set(port + 1); + } + + /** + * Gets the next available port starting at the lowest number. This is the preferred + * method to use. The port return is immediately marked in use and doesn't rely on the caller actually opening + * the port. + * + * @throws IllegalArgumentException is thrown if the port number is out of range + * @throws NoSuchElementException if there are no ports available + * @return the available port + */ + public static synchronized int getNextAvailable() { + int next = getNextAvailable(currentMinPort.get()); + currentMinPort.set(next + 1); + return next; + } + + /** + * Gets the next available port starting at a given from port. + * + * @param fromPort the from port to scan for availability + * @throws IllegalArgumentException is thrown if the port number is out of range + * @throws NoSuchElementException if there are no ports available + * @return the available port + */ + public static synchronized int getNextAvailable(int fromPort) { + if (fromPort < currentMinPort.get() || fromPort > MAX_PORT_NUMBER) { + throw new IllegalArgumentException("From port number not in valid range: " + fromPort); + } + + for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) { + if (available(i)) { + LOG.info("getNextAvailable({}) -> {}", fromPort, i); + return i; + } + } + + throw new NoSuchElementException("Could not find an available port above " + fromPort); + } + + /** + * Checks to see if a specific port is available. + * + * @param port the port number to check for availability + * @return <tt>true</tt> if the port is available, or <tt>false</tt> if not + * @throws IllegalArgumentException is thrown if the port number is out of range + */ + public static boolean available(int port) throws IllegalArgumentException { + if (port < currentMinPort.get() || port > MAX_PORT_NUMBER) { + throw new IllegalArgumentException("Invalid start currentMinPort: " + port); + } + + ServerSocket ss = null; + DatagramSocket ds = null; + try { + ss = new ServerSocket(port); + ss.setReuseAddress(true); + ds = new DatagramSocket(port); + ds.setReuseAddress(true); + return true; + } catch (IOException e) { + // Do nothing + } finally { + if (ds != null) { + ds.close(); + } + + if (ss != null) { + try { + ss.close(); + } catch (IOException e) { + /* should not be thrown */ + } + } + } + + return false; + } + +}