/* * 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.qpid.jms.provider.failover; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import org.apache.qpid.jms.JmsConnectionFactory; import org.apache.qpid.jms.meta.JmsConnectionInfo; import org.apache.qpid.jms.meta.JmsConsumerInfo; import org.apache.qpid.jms.meta.JmsProducerInfo; import org.apache.qpid.jms.meta.JmsSessionInfo; import org.apache.qpid.jms.provider.DefaultProviderListener; import org.apache.qpid.jms.provider.ProviderFuture; import org.apache.qpid.jms.test.Wait; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Test behavior of the FailoverProvider */ public class FailoverProviderTest extends FailoverProviderTestSupport { private static final Logger LOG = LoggerFactory.getLogger(FailoverProviderTest.class); private List<URI> uris; private FailoverProvider provider; private JmsConnectionInfo connection; @Override @Before public void setUp() throws Exception { uris = new ArrayList<URI>(); uris.add(new URI("mock://192.168.2.1:5672")); uris.add(new URI("mock://192.168.2.2:5672")); uris.add(new URI("mock://192.168.2.3:5672")); uris.add(new URI("mock://192.168.2.4:5672")); connection = createConnectionInfo(); super.setUp(); } @Override @After public void tearDown() throws Exception { if (provider != null) { provider.close(); } super.tearDown(); } @Test(timeout = 30000) public void testCreateProviderOnlyUris() { provider = new FailoverProvider(uris); assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, provider.isRandomize()); assertNull(provider.getRemoteURI()); assertNotNull(provider.getNestedOptions()); assertTrue(provider.getNestedOptions().isEmpty()); } @Test(timeout = 30000) public void testCreateProviderOnlyNestedOptions() { Map<String, String> options = new HashMap<String, String>(); options.put("transport.tcpNoDelay", "true"); provider = new FailoverProvider(options); assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, provider.isRandomize()); assertNull(provider.getRemoteURI()); assertNotNull(provider.getNestedOptions()); assertFalse(provider.getNestedOptions().isEmpty()); assertTrue(provider.getNestedOptions().containsKey("transport.tcpNoDelay")); } @Test(timeout = 30000) public void testCreateProviderWithNestedOptions() { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, provider.isRandomize()); assertNull(provider.getRemoteURI()); assertNotNull(provider.getNestedOptions()); assertTrue(provider.getNestedOptions().isEmpty()); } @Test(timeout = 30000) public void testProviderListener() { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertNull(provider.getProviderListener()); provider.setProviderListener(new DefaultProviderListener()); assertNotNull(provider.getProviderListener()); } @Test(timeout = 30000) public void testGetRemoteURI() throws Exception { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertNull(provider.getRemoteURI()); provider.connect(connection); assertTrue("Should have a remote URI after connect", Wait.waitFor(new Wait.Condition() { @Override public boolean isSatisified() throws Exception { return provider.getRemoteURI() != null; } }, TimeUnit.SECONDS.toMillis(20), 10)); } @Test(timeout = 30000) public void testToString() throws Exception { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertNotNull(provider.toString()); provider.connect(connection); assertTrue("Should have a mock scheme after connect", Wait.waitFor(new Wait.Condition() { @Override public boolean isSatisified() throws Exception { LOG.info("FailoverProvider: toString = {}", provider.toString()); return provider.toString().contains("mock://"); } }, TimeUnit.SECONDS.toMillis(20), 10)); } @Test(timeout = 30000) public void testConnectToMock() throws Exception { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, provider.isRandomize()); assertNull(provider.getRemoteURI()); final CountDownLatch connected = new CountDownLatch(1); provider.setProviderListener(new DefaultProviderListener() { @Override public void onConnectionEstablished(URI remoteURI) { connected.countDown(); } }); provider.connect(connection); ProviderFuture request = new ProviderFuture(); provider.create(createConnectionInfo(), request); request.sync(10, TimeUnit.SECONDS); assertTrue(request.isComplete()); provider.close(); assertEquals(1, mockPeer.getContextStats().getProvidersCreated()); assertEquals(1, mockPeer.getContextStats().getConnectionAttempts()); } @Test(timeout = 30000) public void testCannotStartWithoutListener() throws Exception { provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, provider.isRandomize()); assertNull(provider.getRemoteURI()); provider.connect(connection); try { provider.start(); fail("Should not allow a start if no listener added yet."); } catch (IllegalStateException ex) { } provider.close(); } @Test(timeout = 30000) public void testStartupMaxReconnectAttempts() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost?mock.failOnConnect=true)" + "?failover.startupMaxReconnectAttempts=5" + "&failover.useReconnectBackOff=false"); Connection connection = null; try { connection = factory.createConnection(); connection.start(); fail("Should have stopped after five retries."); } catch (JMSException ex) { } finally { if (connection != null) { connection.close(); } } assertEquals(5, mockPeer.getContextStats().getProvidersCreated()); assertEquals(5, mockPeer.getContextStats().getConnectionAttempts()); assertEquals(5, mockPeer.getContextStats().getCloseAttempts()); } @Test(timeout = 30000) public void testMaxReconnectAttempts() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost?mock.failOnConnect=true)" + "?failover.maxReconnectAttempts=5" + "&failover.useReconnectBackOff=false"); Connection connection = null; try { connection = factory.createConnection(); connection.start(); fail("Should have stopped after five retries."); } catch (JMSException ex) { } finally { if (connection != null) { connection.close(); } } assertEquals(5, mockPeer.getContextStats().getProvidersCreated()); assertEquals(5, mockPeer.getContextStats().getConnectionAttempts()); assertEquals(5, mockPeer.getContextStats().getCloseAttempts()); } @Test(timeout = 30000) public void testMaxReconnectAttemptsWithBackOff() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost?mock.failOnConnect=true)" + "?failover.maxReconnectAttempts=5" + "&failover.maxReconnectDelay=60" + "&failover.reconnectDelay=10" + "&failover.useReconnectBackOff=true"); Connection connection = null; try { connection = factory.createConnection(); connection.start(); fail("Should have stopped after five retries."); } catch (JMSException ex) { } finally { if (connection != null) { connection.close(); } } assertEquals(5, mockPeer.getContextStats().getProvidersCreated()); assertEquals(5, mockPeer.getContextStats().getConnectionAttempts()); assertEquals(5, mockPeer.getContextStats().getCloseAttempts()); } @Test(timeout = 30000) public void testFailureOnCloseIsSwallowed() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost?mock.failOnClose=true)"); Connection connection = factory.createConnection(); connection.start(); connection.close(); assertEquals(1, mockPeer.getContextStats().getProvidersCreated()); assertEquals(1, mockPeer.getContextStats().getConnectionAttempts()); assertEquals(1, mockPeer.getContextStats().getCloseAttempts()); } @Test(timeout = 30000) public void testSessionLifeCyclePassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); connection.createSession(false, Session.AUTO_ACKNOWLEDGE).close(); connection.close(); assertEquals(1, mockPeer.getContextStats().getCreateResourceCalls(JmsSessionInfo.class)); assertEquals(1, mockPeer.getContextStats().getDestroyResourceCalls(JmsSessionInfo.class)); } @Test(timeout = 30000) public void testConsumerLifeCyclePassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = session.createTopic(_testName.getMethodName()); session.createConsumer(destination).close(); connection.close(); assertEquals(1, mockPeer.getContextStats().getCreateResourceCalls(JmsConsumerInfo.class)); assertEquals(1, mockPeer.getContextStats().getStartResourceCalls(JmsConsumerInfo.class)); assertEquals(1, mockPeer.getContextStats().getDestroyResourceCalls(JmsConsumerInfo.class)); } @Test(timeout = 30000) public void testProducerLifeCyclePassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = session.createTopic(_testName.getMethodName()); session.createProducer(destination).close(); connection.close(); assertEquals(1, mockPeer.getContextStats().getCreateResourceCalls(JmsProducerInfo.class)); assertEquals(1, mockPeer.getContextStats().getDestroyResourceCalls(JmsProducerInfo.class)); } @Test(timeout = 30000) public void testSessionRecoverPassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); session.recover(); connection.close(); assertEquals(1, mockPeer.getContextStats().getRecoverCalls()); } @Test(timeout = 30000) public void testSessionUnsubscribePassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); session.unsubscribe("some-subscription"); connection.close(); assertEquals(1, mockPeer.getContextStats().getUnsubscribeCalls()); } @Test(timeout = 30000) public void testSendMessagePassthrough() throws Exception { JmsConnectionFactory factory = new JmsConnectionFactory( "failover:(mock://localhost)"); Connection connection = factory.createConnection(); connection.start(); Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); Queue queue = session.createQueue(getTestName()); MessageProducer producer = session.createProducer(queue); producer.send(session.createMessage()); connection.close(); assertEquals(1, mockPeer.getContextStats().getSendCalls()); } @Test(timeout=10000) public void testTimeoutsSetFromConnectionInfo() throws IOException, JMSException { final long CONNECT_TIMEOUT = TimeUnit.SECONDS.toMillis(4); final long CLOSE_TIMEOUT = TimeUnit.SECONDS.toMillis(5); final long SEND_TIMEOUT = TimeUnit.SECONDS.toMillis(6); final long REQUEST_TIMEOUT = TimeUnit.SECONDS.toMillis(7); provider = new FailoverProvider(uris, Collections.<String, String>emptyMap()); provider.setProviderListener(new DefaultProviderListener() { @Override public void onConnectionEstablished(URI remoteURI) { } }); provider.connect(connection); provider.start(); JmsConnectionInfo connectionInfo = createConnectionInfo(); connectionInfo.setConnectTimeout(CONNECT_TIMEOUT); connectionInfo.setCloseTimeout(CLOSE_TIMEOUT); connectionInfo.setSendTimeout(SEND_TIMEOUT); connectionInfo.setRequestTimeout(REQUEST_TIMEOUT); ProviderFuture request = new ProviderFuture(); provider.create(connectionInfo, request); request.sync(); assertEquals(CLOSE_TIMEOUT, provider.getCloseTimeout()); assertEquals(SEND_TIMEOUT, provider.getSendTimeout()); assertEquals(REQUEST_TIMEOUT, provider.getRequestTimeout()); } @Test(timeout = 30000) public void testAmqpOpenServerListActionDefault() { provider = new FailoverProvider(uris); assertEquals("REPLACE", provider.getAmqpOpenServerListAction()); } @Test(timeout = 30000) public void testSetGetAmqpOpenServerListAction() { provider = new FailoverProvider(uris); String action = "ADD"; assertFalse(action.equals(provider.getAmqpOpenServerListAction())); provider.setAmqpOpenServerListAction(action); assertEquals(action, provider.getAmqpOpenServerListAction()); } @Test(timeout = 30000) public void testSetInvalidAmqpOpenServerListActionThrowsIAE() { provider = new FailoverProvider(uris); try { provider.setAmqpOpenServerListAction("invalid"); fail("no exception was thrown"); } catch (IllegalArgumentException iae) { // Expected } } }