ARTEMIS-2858 DNS Tests on reconnects and backups

There are no fixes as part of this test addition.  As I wrote this test as I was debugging DNS issues.
This commit is contained in:
Clebert Suconic 2020-07-29 11:33:22 -04:00
parent 3d86d78828
commit c00b210629
17 changed files with 1847 additions and 44 deletions

View File

@ -48,6 +48,30 @@ public class ServerUtil {
* @throws Exception * @throws Exception
*/ */
public static Process startServer(String artemisInstance, String serverName, int id, int timeout) throws Exception { public static Process startServer(String artemisInstance, String serverName, int id, int timeout) throws Exception {
final Process process = internalStartServer(artemisInstance, serverName);
// wait for start
if (timeout != 0) {
waitForServerToStart(id, timeout);
}
return process;
}
public static Process startServer(String artemisInstance, String serverName, String uri, int timeout) throws Exception {
final Process process = internalStartServer(artemisInstance, serverName);
// wait for start
if (timeout != 0) {
waitForServerToStart(uri, timeout);
}
return process;
}
private static Process internalStartServer(String artemisInstance,
String serverName) throws IOException, ClassNotFoundException {
try {
boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().trim().startsWith("win"); boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().trim().startsWith("win");
ProcessBuilder builder = null; ProcessBuilder builder = null;
@ -74,13 +98,10 @@ public class ServerUtil {
// http://www.jboss.org/index.html?module=bb&op=viewtopic&t=151815 // http://www.jboss.org/index.html?module=bb&op=viewtopic&t=151815
ProcessLogger errorLogger = new ProcessLogger(true, process.getErrorStream(), serverName, true); ProcessLogger errorLogger = new ProcessLogger(true, process.getErrorStream(), serverName, true);
errorLogger.start(); errorLogger.start();
// wait for start
if (timeout != 0) {
waitForServerToStart(id, timeout);
}
return process; return process;
} catch (IOException e) {
throw new IOException("Cannot start server at " + artemisInstance, e);
}
} }
public static boolean waitForServerToStart(int id, int timeout) throws InterruptedException { public static boolean waitForServerToStart(int id, int timeout) throws InterruptedException {
@ -119,9 +140,11 @@ public class ServerUtil {
server.destroy(); server.destroy();
} }
server.waitFor(); server.waitFor();
if (!forcibly) {
Thread.sleep(1000); Thread.sleep(1000);
} }
} }
}
public static int getServer(Connection connection) { public static int getServer(Connection connection) {
ClientSession session = ((ActiveMQConnection) connection).getInitialSession(); ClientSession session = ((ActiveMQConnection) connection).getInitialSession();

View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.apache.activemq.artemis.tests.util.network; package org.apache.activemq.artemis.utils.network;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -100,7 +100,7 @@ public class NetUtil {
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next(); Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next();
try { try {
netDown(entry.getKey(), entry.getValue()); netDown(entry.getKey(), entry.getValue(), true);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -125,21 +125,32 @@ public class NetUtil {
} }
public static void netDown(String ip) throws Exception { public static void netDown(String ip) throws Exception {
String device = networks.remove(ip); netDown(ip, false);
Assert.assertNotNull("ip " + ip + "wasn't set up before", device);
netDown(ip, device);
} }
private static void netDown(String ip, String device) throws Exception {
public static void netDown(String ip, boolean force) throws Exception {
String device = networks.remove(ip);
if (!force) {
// in case the netDown is coming from a different VM (spawned tests)
Assert.assertNotNull("ip " + ip + "wasn't set up before", device);
}
netDown(ip, device, force);
}
private static void netDown(String ip, String device, boolean force) throws Exception {
if (osUsed == OS.MAC) { if (osUsed == OS.MAC) {
if (runCommand("sudo", "-n", "ifconfig", "lo0", "-alias", ip) != 0) { if (runCommand("sudo", "-n", "ifconfig", "lo0", "-alias", ip) != 0) {
if (!force) {
Assert.fail("Cannot sudo ifconfig for ip " + ip); Assert.fail("Cannot sudo ifconfig for ip " + ip);
} }
}
} else if (osUsed == OS.LINUX) { } else if (osUsed == OS.LINUX) {
if (runCommand("sudo", "-n", "ifconfig", device, "down") != 0) { if (runCommand("sudo", "-n", "ifconfig", device, "down") != 0) {
if (!force) {
Assert.fail("Cannot sudo ifconfig for ip " + ip); Assert.fail("Cannot sudo ifconfig for ip " + ip);
} }
}
} else { } else {
Assert.fail("OS not supported"); Assert.fail("OS not supported");
} }

View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.apache.activemq.artemis.tests.util.network; package org.apache.activemq.artemis.utils.network;
import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;

View File

@ -1127,24 +1127,22 @@ public abstract class ActiveMQTestBase extends Assert {
assertFalse(store.isPaging()); assertFalse(store.isPaging());
} }
protected Topology waitForTopology(final ActiveMQServer server, final int nodes) throws Exception { protected static Topology waitForTopology(final ActiveMQServer server, final int nodes) throws Exception {
return waitForTopology(server, nodes, -1, WAIT_TIMEOUT); return waitForTopology(server, nodes, -1, WAIT_TIMEOUT);
} }
protected Topology waitForTopology(final ActiveMQServer server, protected static Topology waitForTopology(final ActiveMQServer server,
final int nodes, final int nodes,
final int backups) throws Exception { final int backups) throws Exception {
return waitForTopology(server, nodes, backups, WAIT_TIMEOUT); return waitForTopology(server, nodes, backups, WAIT_TIMEOUT);
} }
protected Topology waitForTopology(final ActiveMQServer server, protected static Topology waitForTopology(final ActiveMQServer server,
final int liveNodes, final int liveNodes,
final int backupNodes, final int backupNodes,
final long timeout) throws Exception { final long timeout) throws Exception {
logger.debug("waiting for " + liveNodes + " on the topology for server = " + server); logger.debug("waiting for " + liveNodes + " on the topology for server = " + server);
long start = System.currentTimeMillis();
Set<ClusterConnection> ccs = server.getClusterManager().getClusterConnections(); Set<ClusterConnection> ccs = server.getClusterManager().getClusterConnections();
if (ccs.size() != 1) { if (ccs.size() != 1) {
@ -1153,6 +1151,15 @@ public abstract class ActiveMQTestBase extends Assert {
Topology topology = server.getClusterManager().getDefaultConnection(null).getTopology(); Topology topology = server.getClusterManager().getDefaultConnection(null).getTopology();
return waitForTopology(topology, timeout, liveNodes, backupNodes);
}
protected static Topology waitForTopology(Topology topology,
long timeout,
int liveNodes,
int backupNodes) throws Exception {
final long start = System.currentTimeMillis();
int liveNodesCount = 0; int liveNodesCount = 0;
int backupNodesCount = 0; int backupNodesCount = 0;

View File

@ -45,8 +45,8 @@ import org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants;
import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType; import org.apache.activemq.artemis.core.server.cluster.impl.MessageLoadBalancingType;
import org.apache.activemq.artemis.tests.util.Wait; import org.apache.activemq.artemis.tests.util.Wait;
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection; import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
import org.apache.activemq.artemis.tests.util.network.NetUtil; import org.apache.activemq.artemis.utils.network.NetUtil;
import org.apache.activemq.artemis.tests.util.network.NetUtilResource; import org.apache.activemq.artemis.utils.network.NetUtilResource;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Rule; import org.junit.Rule;

View File

@ -120,6 +120,11 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes
proxy.invokeOperation("createQueue", address, name); proxy.invokeOperation("createQueue", address, name);
} }
@Override
public boolean isActive() {
return (Boolean) proxy.retrieveAttributeValue("active");
}
@Override @Override
public String createQueue(String address, public String createQueue(String address,
String routingType, String routingType,

View File

@ -219,6 +219,97 @@
<instance>${basedir}/target/standard</instance> <instance>${basedir}/target/standard</instance>
</configuration> </configuration>
</execution> </execution>
<execution>
<phase>test-compile</phase>
<id>create-dnsswitch</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<configuration>${basedir}/target/classes/servers/dnsswitch</configuration>
<allowAnonymous>true</allowAnonymous>
<user>admin</user>
<password>admin</password>
<instance>${basedir}/target/dnsswitch</instance>
</configuration>
</execution>
<execution>
<phase>test-compile</phase>
<id>create-dnsswitch2</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<configuration>${basedir}/target/classes/servers/dnsswitch2</configuration>
<allowAnonymous>true</allowAnonymous>
<user>admin</user>
<password>admin</password>
<instance>${basedir}/target/dnsswitch2</instance>
</configuration>
</execution>
<execution>
<phase>test-compile</phase>
<id>create-dnsswitch-main</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<configuration>${basedir}/target/classes/servers/dnsswitch-replicated-main</configuration>
<allowAnonymous>true</allowAnonymous>
<user>admin</user>
<password>admin</password>
<noWeb>true</noWeb>
<instance>${basedir}/target/dnsswitch-replicated-main</instance>
<args>
<arg>--java-options</arg>
<!-- notice these files are only available on dnsswitch, so this is not a copy and paste error
where I really meant dnsswitch here -->
<arg>-Djdk.net.hosts.file=${basedir}/target/dnsswitch/etc/hosts.conf -Djava.security.properties=${basedir}/target/dnsswitch/etc/zerocache.security -Djava.rmi.server.hostname=localhost</arg>
</args>
</configuration>
</execution>
<execution>
<phase>test-compile</phase>
<id>create-dnsswitch-main-noretrydns</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<configuration>${basedir}/target/classes/servers/dnsswitch-replicated-main-noretrydns</configuration>
<allowAnonymous>true</allowAnonymous>
<user>admin</user>
<password>admin</password>
<noWeb>true</noWeb>
<instance>${basedir}/target/dnsswitch-replicated-main-noretrydns</instance>
<args>
<arg>--java-options</arg>
<!-- notice these files are only available on dnsswitch, so this is not a copy and paste error
where I really meant dnsswitch here -->
<arg>-Djdk.net.hosts.file=${basedir}/target/dnsswitch/etc/hosts.conf -Djava.security.properties=${basedir}/target/dnsswitch/etc/noretrydns.security -Djava.rmi.server.hostname=localhost</arg>
</args>
</configuration>
</execution>
<execution>
<phase>test-compile</phase>
<id>create-dnsswitch-backup</id>
<goals>
<goal>create</goal>
</goals>
<configuration>
<configuration>${basedir}/target/classes/servers/dnsswitch-replicated-backup</configuration>
<allowAnonymous>true</allowAnonymous>
<user>admin</user>
<password>admin</password>
<noWeb>true</noWeb>
<instance>${basedir}/target/dnsswitch-replicated-backup</instance>
<args>
<arg>--java-options</arg>
<!-- notice these files are only available on dnsswitch, so this is not a copy and paste error
where I really meant dnsswitch here -->
<arg>-Djdk.net.hosts.file=${basedir}/target/dnsswitch/etc/hosts.conf -Djava.security.properties=${basedir}/target/dnsswitch/etc/zerocache.security -Djava.rmi.server.hostname=localhost</arg>
</args>
</configuration>
</execution>
<execution> <execution>
<phase>test-compile</phase> <phase>test-compile</phase>
<id>create-maxConsumers</id> <id>create-maxConsumers</id>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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.
--><configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd">
<core xmlns="urn:activemq:core">
<name>backup</name>
<bindings-directory>./data/bindings</bindings-directory>
<journal-directory>./data/journal</journal-directory>
<large-messages-directory>./data/largemessages</large-messages-directory>
<paging-directory>./data/paging</paging-directory>
<ha-policy>
<replication>
<slave>
<group-name>a</group-name>
<allow-failback>true</allow-failback>
</slave>
</replication>
</ha-policy>
<connectors>
<!-- Connector used to be announced through cluster connections and notifications -->
<connector name="artemis">tcp://SECOND:61616</connector>
<connector name="main">tcp://FIRST:61616</connector>
</connectors>
<!-- Acceptors -->
<acceptors>
<acceptor name="artemis">tcp://SECOND:61616</acceptor>
</acceptors>
<cluster-user>admin</cluster-user>
<cluster-password>password</cluster-password>
<cluster-connections>
<cluster-connection name="my-cluster">
<connector-ref>artemis</connector-ref>
<message-load-balancing>OFF</message-load-balancing>
<max-hops>1</max-hops>
<static-connectors>
<connector-ref>main</connector-ref>
</static-connectors>
</cluster-connection>
</cluster-connections>
<!-- Other config -->
<security-settings>
<!--security for example queue-->
<security-setting match="#">
<permission type="createNonDurableQueue" roles="amq, guest"/>
<permission type="deleteNonDurableQueue" roles="amq, guest"/>
<permission type="createDurableQueue" roles="amq, guest"/>
<permission type="deleteDurableQueue" roles="amq, guest"/>
<permission type="createAddress" roles="amq, guest"/>
<permission type="deleteAddress" roles="amq, guest"/>
<permission type="consume" roles="amq, guest"/>
<permission type="browse" roles="amq, guest"/>
<permission type="send" roles="amq, guest"/>
<!-- we need this otherwise ./artemis data imp wouldn't work -->
<permission type="manage" roles="amq"/>
</security-setting>
</security-settings>
<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>10MB</max-size-bytes>
<page-size-bytes>1MB</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
</address-settings>
<addresses>
<address name="exampleTopic">
<multicast>
</multicast>
</address>
<address name="exampleQueue">
<anycast>
<queue name="exampleQueue"/>
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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.
-->
<management-context xmlns="http://activemq.org/schema">
<connector connector-port="10199" connector-host="localhost"/>
</management-context>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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.
--><configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd">
<core xmlns="urn:activemq:core">
<name>live</name>
<bindings-directory>./data/bindings</bindings-directory>
<journal-directory>./data/journal</journal-directory>
<large-messages-directory>./data/largemessages</large-messages-directory>
<paging-directory>./data/paging</paging-directory>
<ha-policy>
<replication>
<master>
<group-name>a</group-name>
<check-for-live-server>true</check-for-live-server>
<vote-on-replication-failure>true</vote-on-replication-failure>
</master>
</replication>
</ha-policy>
<connectors>
<!-- Connector used to be announced through cluster connections and notifications -->
<connector name="artemis">tcp://FIRST:61616</connector>
<connector name="backup">tcp://SECOND:61616</connector>
</connectors>
<!-- Acceptors -->
<acceptors>
<acceptor name="artemis">tcp://FIRST:61616</acceptor>
</acceptors>
<cluster-user>admin</cluster-user>
<cluster-password>password</cluster-password>
<cluster-connections>
<cluster-connection name="my-cluster">
<connector-ref>artemis</connector-ref>
<message-load-balancing>OFF</message-load-balancing>
<max-hops>1</max-hops>
<static-connectors>
<connector-ref>backup</connector-ref>
</static-connectors>
</cluster-connection>
</cluster-connections>
<!-- Other config -->
<security-settings>
<!--security for example queue-->
<security-setting match="#">
<permission type="createNonDurableQueue" roles="amq, guest"/>
<permission type="deleteNonDurableQueue" roles="amq, guest"/>
<permission type="createDurableQueue" roles="amq, guest"/>
<permission type="deleteDurableQueue" roles="amq, guest"/>
<permission type="createAddress" roles="amq, guest"/>
<permission type="deleteAddress" roles="amq, guest"/>
<permission type="consume" roles="amq, guest"/>
<permission type="browse" roles="amq, guest"/>
<permission type="send" roles="amq, guest"/>
<!-- we need this otherwise ./artemis data imp wouldn't work -->
<permission type="manage" roles="amq"/>
</security-setting>
</security-settings>
<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>10MB</max-size-bytes>
<page-size-bytes>1MB</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
</address-settings>
<addresses>
<address name="exampleTopic">
<multicast>
</multicast>
</address>
<address name="exampleQueue">
<anycast>
<queue name="exampleQueue"/>
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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.
-->
<management-context xmlns="http://activemq.org/schema">
<connector connector-port="10099" connector-host="localhost"/>
</management-context>

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
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.
--><configuration xmlns="urn:activemq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd">
<core xmlns="urn:activemq:core">
<name>live</name>
<bindings-directory>./data/bindings</bindings-directory>
<journal-directory>./data/journal</journal-directory>
<large-messages-directory>./data/largemessages</large-messages-directory>
<paging-directory>./data/paging</paging-directory>
<ha-policy>
<replication>
<master>
<group-name>a</group-name>
<check-for-live-server>true</check-for-live-server>
<vote-on-replication-failure>true</vote-on-replication-failure>
</master>
</replication>
</ha-policy>
<connectors>
<!-- Connector used to be announced through cluster connections and notifications -->
<connector name="artemis">tcp://FIRST:61616</connector>
<connector name="backup">tcp://SECOND:61616</connector>
</connectors>
<!-- Acceptors -->
<acceptors>
<acceptor name="artemis">tcp://FIRST:61616</acceptor>
</acceptors>
<cluster-user>admin</cluster-user>
<cluster-password>password</cluster-password>
<cluster-connections>
<cluster-connection name="my-cluster">
<connector-ref>artemis</connector-ref>
<message-load-balancing>OFF</message-load-balancing>
<max-hops>1</max-hops>
<static-connectors>
<connector-ref>backup</connector-ref>
</static-connectors>
</cluster-connection>
</cluster-connections>
<!-- Other config -->
<security-settings>
<!--security for example queue-->
<security-setting match="#">
<permission type="createNonDurableQueue" roles="amq, guest"/>
<permission type="deleteNonDurableQueue" roles="amq, guest"/>
<permission type="createDurableQueue" roles="amq, guest"/>
<permission type="deleteDurableQueue" roles="amq, guest"/>
<permission type="createAddress" roles="amq, guest"/>
<permission type="deleteAddress" roles="amq, guest"/>
<permission type="consume" roles="amq, guest"/>
<permission type="browse" roles="amq, guest"/>
<permission type="send" roles="amq, guest"/>
<!-- we need this otherwise ./artemis data imp wouldn't work -->
<permission type="manage" roles="amq"/>
</security-setting>
</security-settings>
<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>-1</max-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<max-size-bytes>10MB</max-size-bytes>
<page-size-bytes>1MB</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
</address-settings>
<addresses>
<address name="exampleTopic">
<multicast>
</multicast>
</address>
<address name="exampleQueue">
<anycast>
<queue name="exampleQueue"/>
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
~ 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.
-->
<management-context xmlns="http://activemq.org/schema">
<connector connector-port="10099" connector-host="localhost"/>
</management-context>

View File

@ -0,0 +1,182 @@
<?xml version='1.0'?>
<!--
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.
-->
<configuration xmlns="urn:activemq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq:core ">
<name>0.0.0.0</name>
<persistence-enabled>true</persistence-enabled>
<!-- this could be ASYNCIO, MAPPED, NIO
ASYNCIO: Linux Libaio
MAPPED: mmap files
NIO: Plain Java Files
-->
<journal-type>NIO</journal-type>
<paging-directory>./data/paging</paging-directory>
<bindings-directory>./data/bindings</bindings-directory>
<journal-directory>./data/journal</journal-directory>
<large-messages-directory>./data/large-messages</large-messages-directory>
<journal-datasync>true</journal-datasync>
<journal-min-files>2</journal-min-files>
<journal-pool-files>-1</journal-pool-files>
<journal-buffer-size>10485760</journal-buffer-size>
<!--
You can specify the NIC you want to use to verify if the network
<network-check-NIC>theNickName</network-check-NIC>
-->
<!--
Use this to use an HTTP server to validate the network
<network-check-URL-list>http://www.apache.org</network-check-URL-list> -->
<!-- <network-check-period>10000</network-check-period> -->
<!-- <network-check-timeout>1000</network-check-timeout> -->
<!-- this is a comma separated list, no spaces, just DNS or IPs
it should accept IPV6
Warning: Make sure you understand your network topology as this is meant to validate if your network is valid.
Using IPs that could eventually disappear or be partially visible may defeat the purpose.
You can use a list of multiple IPs, and if any successful ping will make the server OK to continue running -->
<!-- <network-check-list>10.0.0.1</network-check-list> -->
<!-- use this to customize the ping used for ipv4 addresses -->
<!-- <network-check-ping-command>ping -c 1 -t %d %s</network-check-ping-command> -->
<!-- use this to customize the ping used for ipv6 addresses -->
<!-- <network-check-ping6-command>ping6 -c 1 %2$s</network-check-ping6-command> -->
<!--
This value was determined through a calculation.
Your system could perform 0.15 writes per millisecond
on the current journal configuration.
That translates as a sync write every 6488000 nanoseconds
-->
<journal-buffer-timeout>6488000</journal-buffer-timeout>
<!-- how often we are looking for how many bytes are being used on the disk in ms -->
<disk-scan-period>5000</disk-scan-period>
<!-- once the disk hits this limit the system will block, or close the connection in certain protocols
that won't support flow control. -->
<max-disk-usage>90</max-disk-usage>
<!-- the system will enter into page mode once you hit this limit.
This is an estimate in bytes of how much the messages are using in memory
The system will use half of the available memory (-Xmx) by default for the global-max-size.
You may specify a different value here if you need to customize it to your needs.
<global-max-size>100Mb</global-max-size>
-->
<global-max-size>100Mb</global-max-size>
<acceptors>
<!-- Acceptor for every supported protocol -->
<acceptor name="artemis">tcp://192.0.2.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>
</acceptors>
<security-settings>
<security-setting match="#">
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
<permission type="createDurableQueue" roles="guest"/>
<permission type="deleteDurableQueue" roles="guest"/>
<permission type="createAddress" roles="guest"/>
<permission type="deleteAddress" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="browse" roles="guest"/>
<permission type="send" roles="guest"/>
<!-- we need this otherwise ./artemis data imp wouldn't work -->
<permission type="manage" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<!-- <max-size-bytes>-1</max-size-bytes> -->
<max-size-bytes>1M</max-size-bytes>
<page-size-bytes>50000</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<!-- <max-size-bytes>-1</max-size-bytes> -->
<page-size-bytes>50000</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
</address-settings>
<addresses>
<address name="DLQ">
<anycast>
<queue name="DLQ" />
</anycast>
</address>
<address name="ExpiryQueue">
<anycast>
<queue name="ExpiryQueue" />
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -0,0 +1,182 @@
<?xml version='1.0'?>
<!--
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.
-->
<configuration xmlns="urn:activemq"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
<core xmlns="urn:activemq:core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:activemq:core ">
<name>0.0.0.0</name>
<persistence-enabled>true</persistence-enabled>
<!-- this could be ASYNCIO, MAPPED, NIO
ASYNCIO: Linux Libaio
MAPPED: mmap files
NIO: Plain Java Files
-->
<journal-type>NIO</journal-type>
<paging-directory>./data/paging</paging-directory>
<bindings-directory>./data/bindings</bindings-directory>
<journal-directory>./data/journal</journal-directory>
<large-messages-directory>./data/large-messages</large-messages-directory>
<journal-datasync>true</journal-datasync>
<journal-min-files>2</journal-min-files>
<journal-pool-files>-1</journal-pool-files>
<journal-buffer-size>10485760</journal-buffer-size>
<!--
You can specify the NIC you want to use to verify if the network
<network-check-NIC>theNickName</network-check-NIC>
-->
<!--
Use this to use an HTTP server to validate the network
<network-check-URL-list>http://www.apache.org</network-check-URL-list> -->
<!-- <network-check-period>10000</network-check-period> -->
<!-- <network-check-timeout>1000</network-check-timeout> -->
<!-- this is a comma separated list, no spaces, just DNS or IPs
it should accept IPV6
Warning: Make sure you understand your network topology as this is meant to validate if your network is valid.
Using IPs that could eventually disappear or be partially visible may defeat the purpose.
You can use a list of multiple IPs, and if any successful ping will make the server OK to continue running -->
<!-- <network-check-list>10.0.0.1</network-check-list> -->
<!-- use this to customize the ping used for ipv4 addresses -->
<!-- <network-check-ping-command>ping -c 1 -t %d %s</network-check-ping-command> -->
<!-- use this to customize the ping used for ipv6 addresses -->
<!-- <network-check-ping6-command>ping6 -c 1 %2$s</network-check-ping6-command> -->
<!--
This value was determined through a calculation.
Your system could perform 0.15 writes per millisecond
on the current journal configuration.
That translates as a sync write every 6488000 nanoseconds
-->
<journal-buffer-timeout>6488000</journal-buffer-timeout>
<!-- how often we are looking for how many bytes are being used on the disk in ms -->
<disk-scan-period>5000</disk-scan-period>
<!-- once the disk hits this limit the system will block, or close the connection in certain protocols
that won't support flow control. -->
<max-disk-usage>90</max-disk-usage>
<!-- the system will enter into page mode once you hit this limit.
This is an estimate in bytes of how much the messages are using in memory
The system will use half of the available memory (-Xmx) by default for the global-max-size.
You may specify a different value here if you need to customize it to your needs.
<global-max-size>100Mb</global-max-size>
-->
<global-max-size>100Mb</global-max-size>
<acceptors>
<!-- Acceptor for every supported protocol -->
<acceptor name="artemis">tcp://192.0.3.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>
</acceptors>
<security-settings>
<security-setting match="#">
<permission type="createNonDurableQueue" roles="guest"/>
<permission type="deleteNonDurableQueue" roles="guest"/>
<permission type="createDurableQueue" roles="guest"/>
<permission type="deleteDurableQueue" roles="guest"/>
<permission type="createAddress" roles="guest"/>
<permission type="deleteAddress" roles="guest"/>
<permission type="consume" roles="guest"/>
<permission type="browse" roles="guest"/>
<permission type="send" roles="guest"/>
<!-- we need this otherwise ./artemis data imp wouldn't work -->
<permission type="manage" roles="guest"/>
</security-setting>
</security-settings>
<address-settings>
<!-- if you define auto-create on certain queues, management has to be auto-create -->
<address-setting match="activemq.management#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<!-- <max-size-bytes>-1</max-size-bytes> -->
<max-size-bytes>1M</max-size-bytes>
<page-size-bytes>50000</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
<!--default for catch all-->
<address-setting match="#">
<dead-letter-address>DLQ</dead-letter-address>
<expiry-address>ExpiryQueue</expiry-address>
<redelivery-delay>0</redelivery-delay>
<!-- with -1 only the global-max-size is in use for limiting -->
<!-- <max-size-bytes>-1</max-size-bytes> -->
<page-size-bytes>50000</page-size-bytes>
<message-counter-history-day-limit>10</message-counter-history-day-limit>
<address-full-policy>PAGE</address-full-policy>
<auto-create-queues>true</auto-create-queues>
<auto-create-addresses>true</auto-create-addresses>
<auto-create-jms-queues>true</auto-create-jms-queues>
<auto-create-jms-topics>true</auto-create-jms-topics>
</address-setting>
</address-settings>
<addresses>
<address name="DLQ">
<anycast>
<queue name="DLQ" />
</anycast>
</address>
<address name="ExpiryQueue">
<anycast>
<queue name="ExpiryQueue" />
</anycast>
</address>
</addresses>
</core>
</configuration>

View File

@ -70,4 +70,10 @@ public class SmokeTestBase extends ActiveMQTestBase {
return process; return process;
} }
public Process startServer(String serverName, String uri, int timeout) throws Exception {
Process process = ServerUtil.startServer(getServerLocation(serverName), serverName, uri, timeout);
addProcess(process);
return process;
}
} }

View File

@ -0,0 +1,837 @@
/*
* 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.activemq.artemis.tests.smoke.dnsswitch;
import javax.jms.Connection;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.management.MBeanServerInvocationHandler;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
import org.apache.activemq.artemis.api.core.management.ActiveMQServerControl;
import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.tests.smoke.common.SmokeTestBase;
import org.apache.activemq.artemis.util.ServerUtil;
import org.apache.activemq.artemis.utils.SpawnedVMSupport;
import org.apache.activemq.artemis.utils.Wait;
import org.apache.activemq.artemis.utils.network.NetUtil;
import org.apache.activemq.artemis.utils.network.NetUtilResource;
import org.jboss.logging.Logger;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
/**
* Validating connection retry scenarios where the DNS had changes
*/
public class DNSSwitchTest extends SmokeTestBase {
private static boolean USING_SPAWN = true;
public static final File ETC_HOSTS = new File("/etc/hosts");
private static File ETC_BACKUP;
private static final String JMX_SERVER_HOSTNAME = "localhost";
private static final int JMX_SERVER_PORT_0 = 10099;
private static final int JMX_SERVER_PORT_1 = 10199;
static String liveURI = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT_0 + "/jmxrmi";
static String backupURI = "service:jmx:rmi:///jndi/rmi://" + JMX_SERVER_HOSTNAME + ":" + JMX_SERVER_PORT_1 + "/jmxrmi";
static ObjectNameBuilder liveNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), "live", true);
static ObjectNameBuilder backupNameBuilder = ObjectNameBuilder.create(ActiveMQDefaultConfiguration.getDefaultJmxDomain(), "backup", true);
// This is a more intrusive option to use with JDK 8
// Instead of using a separate jdk hsots, which is not supported on jdk8,
// with this option set to true we would use the original /etc/hosts
private static boolean USE_ETC_HOSTS = System.getProperty("java.version").startsWith("1.8");
private static final Logger logger = Logger.getLogger(DNSSwitchTest.class);
private static final String SERVER_NAME_0 = "dnsswitch";
private static final String SERVER_NAME_1 = "dnsswitch2";
private static final String SERVER_STANDARD = "standard";
private static final String SERVER_LIVE = "dnsswitch-replicated-main";
private static final String SERVER_LIVE_NORETRYDNS = "dnsswitch-replicated-main-noretrydns";
private static final String SERVER_BACKUP = "dnsswitch-replicated-backup";
// 192.0.2.0 is reserved for documentation (and testing on this case).
private static final String FIRST_IP = "192.0.2.0";
private static final String SECOND_IP = "192.0.3.0";
private static final String THIRD_IP = "192.0.3.0";
private static final String FOURTH_IP = "192.0.4.0";
private static String serverLocation;
@Rule
public NetUtilResource netUtilResource = new NetUtilResource();
private static JMXConnector newJMXFactory(String uri) throws Throwable {
return JMXConnectorFactory.connect(new JMXServiceURL(uri));
}
private static ActiveMQServerControl getServerControl(String uri,
ObjectNameBuilder builder,
long timeout) throws Throwable {
long expireLoop = System.currentTimeMillis() + timeout;
Throwable lastException = null;
do {
try {
JMXConnector connector = newJMXFactory(uri);
ActiveMQServerControl serverControl = MBeanServerInvocationHandler.newProxyInstance(connector.getMBeanServerConnection(), builder.getActiveMQServerObjectName(), ActiveMQServerControl.class, false);
serverControl.isActive(); // making one call to make sure it's working
return serverControl;
} catch (Throwable e) {
System.err.println("Retrying error : " + e.getMessage());
lastException = e;
Thread.sleep(500);
}
}
while (expireLoop > System.currentTimeMillis());
throw lastException;
}
@BeforeClass
public static void beforeClassMethod() throws Exception {
serverLocation = getServerLocation(SERVER_NAME_0);
// Before anything we must copy the jave security and change what we need for no cache
// this will be used to spawn new tests
generateNoCacheSecurity(serverLocation);
generateNoRetrySecurity(serverLocation);
if (USE_ETC_HOSTS) {
Assert.assertTrue("If you want to run this test, you must do 'sudo chmod 666 " + ETC_HOSTS + "'", ETC_HOSTS.canWrite());
File tmpDirectory = new File(System.getProperty("java.io.tmpdir"));
ETC_BACKUP = new File(tmpDirectory, "etcHostsBackup");
if (!ETC_BACKUP.exists()) {
Files.copy(ETC_HOSTS.toPath(), ETC_BACKUP.toPath(), StandardCopyOption.COPY_ATTRIBUTES);
}
}
NetUtil.failIfNotSudo();
}
private static File getETCBackup() {
if (ETC_BACKUP == null) {
File tmpDirectory = new File(System.getProperty("java.io.tmpdir"));
ETC_BACKUP = new File(tmpDirectory, "etcHostsBackup");
}
Assert.assertTrue(ETC_BACKUP.exists());
return ETC_BACKUP;
}
@AfterClass
public static void afterClassMethod() throws Exception {
if (USE_ETC_HOSTS && ETC_BACKUP != null) {
Assert.assertTrue(ETC_BACKUP.exists());
try {
recoverETCHosts();
} finally {
ETC_BACKUP.delete();
ETC_BACKUP = null;
}
}
}
private static void recoverETCHosts() throws IOException {
// it seems silly to use a FileInputStream / FileOutputStream to copy
// a file these days, but on this case we have authorization to write on the file
// but not to replace the file in any way.
// So, Files.copy is not acceptable.
// I could use a library that was doing the same here
// but I didn't bother about it and simply went to the simplest way possible
FileInputStream inputStream = new FileInputStream(getETCBackup());
FileOutputStream outputStream = new FileOutputStream(ETC_HOSTS);
byte[] buffer = new byte[4 * 1024];
int bytes;
try {
while ((bytes = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, bytes);
}
} finally {
inputStream.close();
outputStream.close();
}
}
private static void generateNoCacheSecurity(String serverLocation) throws Exception {
File outputSecurity = new File(serverLocation + File.separator + "etc" + File.separator + "zerocache.security");
generateSecurity(outputSecurity, "networkaddress.cache.ttl", "0", "networkaddress.cache.negative.ttl", "0");
}
private static void generateNoRetrySecurity(String serverLocation) throws Exception {
File outputSecurity = new File(serverLocation + File.separator + "etc" + File.separator + "noretrydns.security");
generateSecurity(outputSecurity, "networkaddress.cache.ttl", "-1", "networkaddress.cache.negative.ttl", "-1");
}
private static void generateSecurity(File outputSecurity, String... overrideParameters) throws IOException {
Assert.assertTrue("You must send pairs as overrideParameters", overrideParameters.length % 2 == 0);
File security = new File(System.getProperty("java.home") + File.separator + "lib" + File.separator + "security" + File.separator + "java.security");
Properties securityProperties = new Properties();
securityProperties.load(new FileInputStream(security));
for (int i = 0; i < overrideParameters.length; i += 2) {
securityProperties.setProperty(overrideParameters[i], overrideParameters[i + 1]);
}
securityProperties.store(new FileOutputStream(outputSecurity), "# generated by DNSSwitchTest");
}
private static final String hostsFile = System.getProperty("jdk.net.hosts.file");
@Before
public void before() throws Exception {
cleanupData(SERVER_NAME_0);
cleanupData(SERVER_NAME_1);
cleanupData(SERVER_STANDARD);
cleanupData(SERVER_LIVE);
cleanupData(SERVER_LIVE_NORETRYDNS);
cleanupData(SERVER_BACKUP);
}
@Test
public void testBackupRedefinition() throws Throwable {
System.out.println(System.getProperty("java.security.properties"));
spawnRun(serverLocation, "testBackupRedefinition", getServerLocation(SERVER_LIVE), getServerLocation(SERVER_BACKUP));
}
public static void testBackupRedefinition(String[] args) throws Throwable {
NetUtil.netUp(FIRST_IP);
NetUtil.netUp(SECOND_IP);
// NetUtil.netUp(THIRD_IP);
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
//System.out.println("Waiting here");
//Thread.sleep(300_000);
Process serverLive = null;
Process serverBackup = null;
try {
serverLive = ServerUtil.startServer(args[1], "live", "tcp://FIRST:61616", 30_000);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
connectAndWaitBackup();
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
NetUtil.netDown(SECOND_IP, true);
serverBackup.destroyForcibly();
Thread.sleep(1000); // wait some time at least until a reconnection is in place
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
// waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 0);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
ActiveMQServerControl backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
connectAndWaitBackup();
//waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
//System.out.println("I'm here!!!");
//Thread.sleep(300_000);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://FIRST:61616?ha=true");
Assert.assertTrue(connectionFactory.getServerLocator().isHA());
Connection connection = connectionFactory.createConnection();
waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Queue queue = session.createQueue("test");
MessageProducer producer = session.createProducer(queue);
producer.send(session.createTextMessage("hello"));
session.commit();
NetUtil.netUp(THIRD_IP);
serverLive.destroyForcibly();
Wait.assertTrue(backupControl::isActive);
MessageConsumer consumer = null;
int errors = 0;
while (true) {
try {
consumer = session.createConsumer(queue);
connection.start();
TextMessage message = (TextMessage) consumer.receive(5000);
Assert.assertNotNull(message);
Assert.assertEquals("hello", message.getText());
session.commit();
break;
} catch (Exception e) {
e.printStackTrace();
errors++;
Assert.assertTrue(errors < 20); // I would accept one or two errors, but the code must connect itself
connection.close();
connectionFactory = new ActiveMQConnectionFactory("tcp://SECOND:61616?ha=true");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
}
}
} finally {
if (serverLive != null) {
serverLive.destroyForcibly();
}
if (serverBackup != null) {
serverBackup.destroyForcibly();
}
}
}
@Test
public void testBackupRedefinition2() throws Throwable {
System.out.println(System.getProperty("java.security.properties"));
spawnRun(serverLocation, "testBackupRedefinition2", getServerLocation(SERVER_LIVE), getServerLocation(SERVER_BACKUP));
}
public static void testBackupRedefinition2(String[] args) throws Throwable {
NetUtil.netUp(FIRST_IP);
NetUtil.netUp(SECOND_IP);
NetUtil.netUp(THIRD_IP);
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
//System.out.println("Waiting here");
//Thread.sleep(300_000);
Process serverLive = null;
Process serverBackup = null;
try {
serverLive = ServerUtil.startServer(args[1], "live", "tcp://FIRST:61616", 30_000);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
connectAndWaitBackup();
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
NetUtil.netDown(SECOND_IP, true);
serverBackup.destroyForcibly();
Thread.sleep(1000); // wait some time at least until a reconnection is in place
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
// waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 0);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
ActiveMQServerControl backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
serverBackup.destroyForcibly();
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
connectAndWaitBackup();
backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
//waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
//System.out.println("I'm here!!!");
//Thread.sleep(300_000);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://FIRST:61616?ha=true");
Assert.assertTrue(connectionFactory.getServerLocator().isHA());
Connection connection = connectionFactory.createConnection();
waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Queue queue = session.createQueue("test");
MessageProducer producer = session.createProducer(queue);
producer.send(session.createTextMessage("hello"));
session.commit();
NetUtil.netUp(THIRD_IP);
serverLive.destroyForcibly();
Wait.assertTrue(backupControl::isActive);
MessageConsumer consumer = null;
int errors = 0;
while (true) {
try {
consumer = session.createConsumer(queue);
connection.start();
TextMessage message = (TextMessage) consumer.receive(5000);
Assert.assertNotNull(message);
Assert.assertEquals("hello", message.getText());
session.commit();
break;
} catch (Exception e) {
e.printStackTrace();
errors++;
Assert.assertTrue(errors < 20); // I would accept one or two errors, but the code must connect itself
connection.close();
connectionFactory = new ActiveMQConnectionFactory("tcp://SECOND:61616?ha=true");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
}
}
} finally {
if (serverBackup != null) {
serverBackup.destroyForcibly();
}
if (serverLive != null) {
serverLive.destroyForcibly();
}
}
}
@Test
public void testBackupRedefinition3() throws Throwable {
System.out.println(System.getProperty("java.security.properties"));
spawnRun(serverLocation, "testBackupRedefinition2", getServerLocation(SERVER_LIVE), getServerLocation(SERVER_BACKUP));
}
public static void testBackupRedefinition3(String[] args) throws Throwable {
NetUtil.netUp(FIRST_IP);
NetUtil.netUp(SECOND_IP);
NetUtil.netUp(THIRD_IP);
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
//System.out.println("Waiting here");
//Thread.sleep(300_000);
Process serverLive = null;
Process serverBackup = null;
try {
serverLive = ServerUtil.startServer(args[1], "live", "tcp://FIRST:61616", 30_000);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
connectAndWaitBackup();
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
NetUtil.netDown(SECOND_IP, true);
serverBackup.destroyForcibly();
Thread.sleep(1000); // wait some time at least until a reconnection is in place
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
// waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 0);
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
ActiveMQServerControl backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
serverBackup.destroyForcibly();
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
connectAndWaitBackup();
backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
//waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
//System.out.println("I'm here!!!");
//Thread.sleep(300_000);
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://FIRST:61616?ha=true");
Assert.assertTrue(connectionFactory.getServerLocator().isHA());
Connection connection = connectionFactory.createConnection();
waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
Queue queue = session.createQueue("test");
MessageProducer producer = session.createProducer(queue);
producer.send(session.createTextMessage("hello"));
session.commit();
NetUtil.netUp(THIRD_IP);
serverLive.destroyForcibly();
Wait.assertTrue(backupControl::isActive);
MessageConsumer consumer = null;
int errors = 0;
while (true) {
try {
consumer = session.createConsumer(queue);
connection.start();
TextMessage message = (TextMessage) consumer.receive(5000);
Assert.assertNotNull(message);
Assert.assertEquals("hello", message.getText());
session.commit();
break;
} catch (Exception e) {
e.printStackTrace();
errors++;
Assert.assertTrue(errors < 20); // I would accept one or two errors, but the code must connect itself
connection.close();
connectionFactory = new ActiveMQConnectionFactory("tcp://SECOND:61616?ha=true");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(true, Session.SESSION_TRANSACTED);
}
}
} finally {
if (serverBackup != null) {
serverBackup.destroyForcibly();
}
if (serverLive != null) {
serverLive.destroyForcibly();
}
}
}
@Test
public void testCantReachBack() throws Throwable {
System.out.println(System.getProperty("java.security.properties"));
spawnRun(serverLocation, "testCantReachBack", getServerLocation(SERVER_LIVE_NORETRYDNS), getServerLocation(SERVER_BACKUP));
}
public static void testCantReachBack(String[] args) throws Throwable {
NetUtil.netUp(FIRST_IP);
NetUtil.netUp(SECOND_IP);
// notice there's no THIRD_IP anywhere
saveConf(hostsFile, FIRST_IP, "FIRST", THIRD_IP, "SECOND");
Process serverLive = null;
Process serverBackup = null;
try {
serverLive = ServerUtil.startServer(args[1], "live", "tcp://FIRST:61616", 30_000);
ActiveMQServerControl liveControl = getServerControl(liveURI, liveNameBuilder, 20_000);
Wait.assertTrue(liveControl::isStarted);
// notice the first server does not know about this server at all
saveConf(hostsFile, FIRST_IP, "FIRST", SECOND_IP, "SECOND");
serverBackup = ServerUtil.startServer(args[2], "backup", "tcp://SECOND:61716", 0);
ActiveMQServerControl backupControl = getServerControl(backupURI, backupNameBuilder, 20_000);
Wait.assertTrue(backupControl::isStarted);
Wait.assertTrue(backupControl::isReplicaSync);
connectAndWaitBackup();
} finally {
if (serverBackup != null) {
serverBackup.destroyForcibly();
}
if (serverLive != null) {
serverLive.destroyForcibly();
}
}
}
private static void connectAndWaitBackup() throws Exception {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://FIRST:61616?ha=true");
Assert.assertTrue(connectionFactory.getServerLocator().isHA());
Connection connection = connectionFactory.createConnection();
waitForTopology(connectionFactory.getServerLocator().getTopology(), 60_000, 1, 1);
connection.close();
}
@Test
public void testFailoverDifferentIPRedefinition() throws Throwable {
spawnRun(serverLocation, "testFailoverDifferentIPRedefinition", serverLocation, getServerLocation(SERVER_NAME_1));
}
public static void testFailoverDifferentIPRedefinition(String[] arg) throws Throwable {
NetUtil.netUp(FIRST_IP);
NetUtil.netUp(SECOND_IP);
saveConf(hostsFile, FIRST_IP, "test");
Process server = null;
Process server2 = null;
try {
server = ServerUtil.startServer(arg[1], "original-server", "tcp://test:61616", 5000);
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://test:61616?initialConnectAttempts=500&retryInterval=100&connect-timeout-millis=100&reconnectAttempts=500&connectionTTL=1000");
Connection connection = factory.createConnection();
server.destroyForcibly();
NetUtil.netDown(FIRST_IP, true);
CountDownLatch latchConnect = new CountDownLatch(1);
AtomicInteger errors = new AtomicInteger(0);
Thread connecting = new Thread(() -> {
try {
latchConnect.countDown();
Connection connection2 = factory.createConnection();
connection2.close();
} catch (Exception e) {
e.printStackTrace();
errors.incrementAndGet();
}
});
connecting.start();
Assert.assertTrue(latchConnect.await(5, TimeUnit.SECONDS));
Thread.sleep(500);
server = ServerUtil.startServer(arg[2], "new-server", "tcp://" + SECOND_IP + ":61616", 5000);
saveConf(hostsFile, SECOND_IP, "test");
connecting.join(5000);
Assert.assertFalse(connecting.isAlive());
Assert.assertEquals(0, errors.get());
} finally {
if (server != null)
server.destroyForcibly();
if (server2 != null)
server2.destroyForcibly();
}
}
@Test
public void testInitialConnector() throws Throwable {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://test:61616?initialConnectAttempts=500&retryInterval=100&connect-timeout-millis=100");
startServer(SERVER_STANDARD, 0, 30000);
String location = getServerLocation(SERVER_NAME_0);
spawnRun(location, "testInitialConnector");
// If you eed to debug the test, comment out spawnRun, and call the method directly
// you will need to add roperties on the JDK for that
// Add the properties you need
// testInitialConnector("testInitialConnector", location);
}
// called with reflection
public static void testInitialConnector(String... arg) throws Throwable {
saveConf(hostsFile, "192.0.0.3", "test");
validateIP("test", "192.0.0.3");
AtomicInteger errors = new AtomicInteger(0);
CountDownLatch initialConnectTried = new CountDownLatch(1);
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://test:61616?initialConnectAttempts=500&retryInterval=100&connect-timeout-millis=100");
Thread connecting = new Thread(() -> {
try {
initialConnectTried.countDown();
Connection connection = factory.createConnection();
connection.close();
} catch (Exception e) {
e.printStackTrace();
errors.incrementAndGet();
}
});
connecting.start();
Assert.assertTrue(initialConnectTried.await(10, TimeUnit.SECONDS));
Thread.sleep(1000);
saveConf(hostsFile, "127.0.0.1", "test");
validateIP("test", "127.0.0.1");
connecting.join(10_000);
Connection connection = factory.createConnection();
connection.close();
Assert.assertEquals(0, errors.get());
Assert.assertFalse(connecting.isAlive());
}
// This test is just validating the DNS is not being cached on the separte VM
@Test
public void testSimpleResolution() throws Throwable {
spawnRun(serverLocation, "testSimpleResolution");
}
// called with reflection
public static void testSimpleResolution(String[] arg) throws Throwable {
// This is just to validate the DNS hosts is picking up the right host
saveConf(hostsFile, "192.0.0.1", "test");
validateIP("test", "192.0.0.1");
// and it should not cache anything if the right properties are in place
saveConf(hostsFile, "192.0.0.3", "test");
validateIP("test", "192.0.0.3");
}
/**
* it will continue the test on a spwned VM with the properties we need for this test
*/
private void spawnRun(String location, String... args) throws Throwable {
// We have to run part of the test on a separate VM, as we need VM settings to tweak the DNS
String securityProperties = System.getProperty("java.security.properties");
if (securityProperties != null && securityProperties.equals(location + "/etc/zerocache.security3")) {
System.out.println("No need to spawn a VM, the zerocache is already in place");
System.setProperty("artemis.config.location", location);
USING_SPAWN = false;
main(args);
} else {
securityProperties = "-Djava.security.properties=" + location + "/etc/zerocache.security";
String hostProperties = "-Djdk.net.hosts.file=" + location + "/etc/hosts.conf";
String configLocation = "-Dartemis.config.location=" + location;
String temporaryLocation = "-Djava.io.tmpdir=" + System.getProperty("java.io.tmpdir");
logger.info("if you would like to run without Spawn for debugging purposes, add these properties to your VM arguments on this test: " + securityProperties + " " + hostProperties);
Process p = SpawnedVMSupport.spawnVM(DNSSwitchTest.class.getName(), new String[]{securityProperties, hostProperties, configLocation, temporaryLocation}, args);
addProcess(p);
Assert.assertEquals(1, p.waitFor());
}
}
public static void saveConf(String fileName, String... hostDefinition) throws Exception {
if (USE_ETC_HOSTS) {
recoverETCHosts();
saveConf(ETC_HOSTS, true, hostDefinition);
} else {
saveConf(new File(fileName), false, hostDefinition);
}
}
public static void saveConf(File fileName, boolean append, String... hostDefinition) throws Exception {
PrintWriter writer = new PrintWriter(new FileOutputStream(fileName, append));
Assert.assertTrue("you must send pairs", hostDefinition.length % 2 == 0);
if (USE_ETC_HOSTS) {
writer.println();
writer.println("# this was generated by DNSSwitchTest. Make sure you recover from your backup");
}
for (int i = 0; i < hostDefinition.length; i += 2) {
writer.println(hostDefinition[i] + " " + hostDefinition[i + 1]);
}
writer.close();
}
private static void validateIP(String host, String ip) {
InetSocketAddress inetSocketAddress;
inetSocketAddress = new InetSocketAddress(host, 8080);
// And this is to validate no cache
Assert.assertEquals(ip, inetSocketAddress.getAddress().getHostAddress());
}
// This main method will be used with spawnRun to continue the test on a separate VM
public static void main(String[] arg) throws Throwable {
try {
String methodName = arg[0];
Method methodReflection = DNSSwitchTest.class.getMethod(methodName, arg.getClass());
methodReflection.invoke(null, new Object[]{arg});
if (USING_SPAWN) {
NetUtil.cleanup();
System.exit(1);
}
} catch (InvocationTargetException e) {
e.getCause().printStackTrace();
if (USING_SPAWN) {
NetUtil.cleanup();
System.exit(2);
} else {
throw e;
}
} catch (Throwable e) {
e.printStackTrace();
if (USING_SPAWN) {
NetUtil.cleanup();
System.exit(2);
} else {
throw e;
}
}
}
}