FailoverMethodTest.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.server.failover;
022 
023 import junit.framework.TestCase;
024 import org.apache.qpid.AMQDisconnectedException;
025 import org.apache.qpid.AMQException;
026 import org.apache.qpid.client.AMQConnection;
027 import org.apache.qpid.client.AMQConnectionURL;
028 import org.apache.qpid.client.transport.TransportConnection;
029 import org.apache.qpid.client.vmbroker.AMQVMBrokerCreationException;
030 import org.apache.qpid.url.URLSyntaxException;
031 import org.slf4j.Logger;
032 import org.slf4j.LoggerFactory;
033 
034 import javax.jms.ExceptionListener;
035 import javax.jms.JMSException;
036 import java.util.concurrent.CountDownLatch;
037 
038 public class FailoverMethodTest extends TestCase implements ExceptionListener
039 {
040     private CountDownLatch _failoverComplete = new CountDownLatch(1);
041 
042     public void setUp() throws AMQVMBrokerCreationException
043     {
044         TransportConnection.createVMBroker(1);
045     }
046 
047     public void tearDown() throws AMQVMBrokerCreationException
048     {
049         TransportConnection.killAllVMBrokers();
050     }
051 
052     /**
053      * Test that the round robin method has the correct delays.
054      * The first connection to vm://:1 will work but the localhost connection should fail but the duration it takes
055      * to report the failure is what is being tested.
056      *
057      @throws URLSyntaxException
058      @throws InterruptedException
059      @throws JMSException
060      */
061     public void testFailoverRoundRobinDelay() throws URLSyntaxException, InterruptedException, JMSException
062     {
063         //note: The VM broker has no connect delay and the default 1 retry
064         //        while the tcp:localhost broker has 3 retries with a 2s connect delay
065         String connectionString = "amqp://guest:guest@/test?brokerlist=" +
066                                   "'vm://:1;tcp://localhost:5670?connectdelay='2000',retries='3''";
067 
068         AMQConnectionURL url = new AMQConnectionURL(connectionString);
069 
070         try
071         {
072             long start = System.currentTimeMillis();
073             AMQConnection connection = new AMQConnection(url, null);
074 
075             connection.setExceptionListener(this);
076 
077             TransportConnection.killAllVMBrokers();
078 
079             _failoverComplete.await();
080 
081             long end = System.currentTimeMillis();
082 
083             long duration = (end - start);
084 
085             //Failover should take more that 6 seconds.
086             // 3 Retires
087             // so VM Broker NoDelay 0 (Connect) NoDelay 0
088             // then TCP NoDelay 0 Delay 1 Delay 2 Delay  3
089             // so 3 delays of 2s in total for connection
090             // as this is a tcp connection it will take 1second per connection to fail
091             // so max time is 6seconds of delay plus 4 seconds of TCP Delay + 1 second of runtime. == 11 seconds 
092 
093             // Ensure we actually had the delay
094             assertTrue("Failover took less than 6 seconds", duration > 6000);
095 
096             // Ensure we don't have delays before initial connection and reconnection.
097             // We allow 1 second for initial connection and failover logic on top of 6s of sleep.
098             assertTrue("Failover took more than 11 seconds:(" + duration + ")", duration < 11000);
099         }
100         catch (AMQException e)
101         {
102             fail(e.getMessage());
103         }
104     }
105 
106     public void testFailoverSingleDelay() throws URLSyntaxException, AMQVMBrokerCreationException,
107                                                  InterruptedException, JMSException
108     {
109         String connectionString = "amqp://guest:guest@/test?brokerlist='vm://:1?connectdelay='2000',retries='3''";
110 
111         AMQConnectionURL url = new AMQConnectionURL(connectionString);
112 
113         try
114         {
115             long start = System.currentTimeMillis();
116             AMQConnection connection = new AMQConnection(url, null);
117 
118             connection.setExceptionListener(this);
119 
120             TransportConnection.killAllVMBrokers();
121 
122             _failoverComplete.await();
123 
124             long end = System.currentTimeMillis();
125 
126             long duration = (end - start);
127 
128             //Failover should take more that 6 seconds.
129             // 3 Retires
130             // so NoDelay 0 (Connect) NoDelay 0 Delay 1 Delay 2 Delay  3
131             // so 3 delays of 2s in total for connection
132             // so max time is 6 seconds of delay + 1 second of runtime. == 7 seconds
133 
134             // Ensure we actually had the delay
135             assertTrue("Failover took less than 6 seconds", duration > 6000);
136 
137             // Ensure we don't have delays before initial connection and reconnection.
138             // We allow 1 second for initial connection and failover logic on top of 6s of sleep.
139             assertTrue("Failover took more than 7 seconds:(" + duration + ")", duration < 7000);
140         }
141         catch (AMQException e)
142         {
143             fail(e.getMessage());
144         }
145     }
146 
147     public void onException(JMSException e)
148     {
149         if (e.getLinkedException() instanceof AMQDisconnectedException)
150         {
151             _failoverComplete.countDown();
152         }
153     }
154 }