/*
* 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.assertNotEquals;
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 static org.junit.Assume.assumeFalse;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.qpid.jms.test.QpidJmsTestCase;
import org.apache.qpid.jms.util.URISupport;
import org.junit.Before;
import org.junit.Test;
/**
* Test for the behavior of the FailoverUriPool
*/
public class FailoverUriPoolTest extends QpidJmsTestCase {
private List<URI> uris;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
uris = new ArrayList<URI>();
uris.add(new URI("tcp://192.168.2.1:5672"));
uris.add(new URI("tcp://192.168.2.2:5672"));
uris.add(new URI("tcp://192.168.2.3:5672"));
uris.add(new URI("tcp://192.168.2.4:5672"));
}
@Test
public void testCreateEmptyPool() {
FailoverUriPool pool = new FailoverUriPool();
assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, pool.isRandomize());
assertTrue(pool.isEmpty());
assertEquals(0, pool.size());
assertNotNull(pool.getNestedOptions());
assertTrue(pool.getNestedOptions().isEmpty());
}
@Test
public void testCreateEmptyPoolFromNullUris() {
FailoverUriPool pool = new FailoverUriPool(null, null);
assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, pool.isRandomize());
assertNotNull(pool.getNestedOptions());
assertTrue(pool.getNestedOptions().isEmpty());
}
@Test
public void testCreateEmptyPoolWithURIs() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, pool.isRandomize());
assertNotNull(pool.getNestedOptions());
assertTrue(pool.getNestedOptions().isEmpty());
}
@Test
public void testGetNextFromEmptyPool() {
FailoverUriPool pool = new FailoverUriPool();
assertEquals(FailoverUriPool.DEFAULT_RANDOMIZE_ENABLED, pool.isRandomize());
assertNull(pool.getNext());
}
@Test
public void testGetNextFromSingleValuePool() {
FailoverUriPool pool = new FailoverUriPool(uris.subList(0, 1), null);
assertEquals(uris.get(0), pool.getNext());
assertEquals(uris.get(0), pool.getNext());
assertEquals(uris.get(0), pool.getNext());
}
@Test
public void testAddUriToEmptyPool() {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(uris.get(0));
assertFalse(pool.isEmpty());
assertEquals(uris.get(0), pool.getNext());
}
@Test
public void testGetSetRandomize() {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertFalse(pool.isEmpty());
assertFalse(pool.isRandomize());
pool.setRandomize(true);
assertTrue(pool.isRandomize());
pool.setRandomize(false);
assertFalse(pool.isRandomize());
}
@Test
public void testDuplicatesNotAdded() {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertEquals(uris.size(), pool.size());
pool.add(uris.get(0));
assertEquals(uris.size(), pool.size());
pool.add(uris.get(1));
assertEquals(uris.size(), pool.size());
}
@Test
public void testDuplicatesNotAddedByAddFirst() {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertEquals(uris.size(), pool.size());
pool.addFirst(uris.get(0));
assertEquals(uris.size(), pool.size());
pool.addFirst(uris.get(1));
assertEquals(uris.size(), pool.size());
}
@Test
public void testDuplicatesNotAddedWhenQueryPresent() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
assertEquals(1, pool.size());
pool.add(new URI("tcp://localhost:5672?transport.tcpNoDelay=true"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://localhost:5672?transport.tcpNoDelay=false"));
assertEquals(1, pool.size());
}
@Test
public void testDuplicatesNotAddedWithHostResolution() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672"));
assertFalse(pool.isEmpty());
assertEquals(1, pool.size());
pool.add(new URI("tcp://localhost:5672"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://localhost:5673"));
assertEquals(2, pool.size());
}
@Test
public void testDuplicatesNotAddedUnresolvable() throws Exception {
assumeFalse("Host resolution works when not expected", checkIfResolutionWorks());
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672"));
assertFalse(pool.isEmpty());
assertEquals(1, pool.size());
pool.add(new URI("tcp://shouldbeunresolvable:5672"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://SHOULDBEUNRESOLVABLE:5672"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://SHOULDBEUNRESOLVABLE2:5672"));
assertEquals(2, pool.size());
}
@Test
public void testDuplicatesNotAddedWhenQueryPresentAndUnresolveable() throws URISyntaxException {
assumeFalse("Host resolution works when not expected", checkIfResolutionWorks());
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
assertEquals(1, pool.size());
pool.add(new URI("tcp://shouldbeunresolvable:5672?transport.tcpNoDelay=false"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://SHOULDBEUNRESOLVABLE:5672?transport.tcpNoDelay=true"));
assertEquals(1, pool.size());
assertEquals(1, pool.size());
pool.add(new URI("tcp://SHOULDBEUNRESOLVABLE2:5672?transport.tcpNoDelay=true"));
assertEquals(2, pool.size());
}
@Test
public void testAddUriToPoolRandomized() throws URISyntaxException {
URI newUri = new URI("tcp://192.168.2." + (uris.size() + 1) + ":5672");
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(true);
pool.add(newUri);
URI found = null;
for (int i = 0; i < uris.size() + 1; ++i) {
URI next = pool.getNext();
if (newUri.equals(next)) {
found = next;
}
}
if (found == null) {
fail("URI added was not retrieved from the pool");
}
}
@Test
public void testAddUriToPoolNotRandomized() throws URISyntaxException {
URI newUri = new URI("tcp://192.168.2." + (uris.size() + 1) + ":5672");
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
pool.add(newUri);
for (int i = 0; i < uris.size(); ++i) {
assertNotEquals(newUri, pool.getNext());
}
assertEquals(newUri, pool.getNext());
}
@Test
public void testAddFirst() throws URISyntaxException {
URI newUri = new URI("tcp://192.168.2." + (uris.size() + 1) + ":5672");
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
pool.addFirst(newUri);
assertEquals(newUri, pool.getNext());
for (int i = 0; i < uris.size(); ++i) {
assertNotEquals(newUri, pool.getNext());
}
assertEquals(newUri, pool.getNext());
}
@Test
public void testAddFirstHandlesNulls() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
pool.addFirst(null);
assertEquals(uris.size(), pool.size());
}
@Test
public void testAddFirstToEmptyPool() {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.addFirst(uris.get(0));
assertFalse(pool.isEmpty());
assertEquals(uris.get(0), pool.getNext());
}
@Test
public void testAddAllHandlesNulls() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
pool.addAll(null);
assertEquals(uris.size(), pool.size());
}
@Test
public void testAddAllHandlesEmpty() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
pool.addAll(Collections.emptyList());
assertEquals(uris.size(), pool.size());
}
@Test
public void testAddAll() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(null, null);
pool.setRandomize(false);
assertEquals(0, pool.size());
assertFalse(uris.isEmpty());
pool.addAll(uris);
assertEquals(uris.size(), pool.size());
}
@Test
public void testRemoveURIFromPool() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(false);
URI removed = uris.get(0);
pool.remove(removed);
for (int i = 0; i < uris.size() + 1; ++i) {
if (removed.equals(pool.getNext())) {
fail("URI was not removed from the pool");
}
}
}
@Test
public void testRemovedWhenQueryPresent() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://localhost:5672?transport.tcpNoDelay=true"));
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://localhost:5672?transport.tcpNoDelay=false"));
assertTrue(pool.isEmpty());
}
@Test
public void testRemoveWithHostResolution() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://localhost:5672"));
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://127.0.0.1:5672"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://localhost:5673"));
assertFalse(pool.isEmpty());
}
@Test
public void testRemoveWhenUnresolvable() throws URISyntaxException {
assumeFalse("Host resolution works when not expected", checkIfResolutionWorks());
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://SHOULDBEUNRESOLVABLE:5672"));
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://shouldbeunresolvable:5673"));
assertFalse(pool.isEmpty());
}
@Test
public void testRemoveWhenQueryPresentAndUnresolveable() throws URISyntaxException {
assumeFalse("Host resolution works when not expected", checkIfResolutionWorks());
FailoverUriPool pool = new FailoverUriPool();
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://SHOULDBEUNRESOLVABLE:5672?transport.tcpNoDelay=true"));
assertTrue(pool.isEmpty());
pool.add(new URI("tcp://shouldbeunresolvable:5672?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
pool.remove(new URI("tcp://shouldbeunresolvable:5673?transport.tcpNoDelay=true"));
assertFalse(pool.isEmpty());
}
@Test
public void testConnectedShufflesWhenRandomizing() {
assertConnectedEffectOnPool(true, true);
}
@Test
public void testConnectedDoesNotShufflesWhenNoRandomizing() {
assertConnectedEffectOnPool(false, false);
}
private void assertConnectedEffectOnPool(boolean randomize, boolean shouldShuffle) {
FailoverUriPool pool = new FailoverUriPool(uris, null);
pool.setRandomize(randomize);
List<URI> current = new ArrayList<URI>();
List<URI> previous = new ArrayList<URI>();
boolean shuffled = false;
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < uris.size(); ++j) {
current.add(pool.getNext());
}
pool.connected();
if (!previous.isEmpty() && !previous.equals(current)) {
shuffled = true;
break;
}
previous.clear();
previous.addAll(current);
current.clear();
}
if (shouldShuffle) {
assertTrue("URIs did not get randomized", shuffled);
} else {
assertFalse("URIs should not get randomized", shuffled);
}
}
@Test
public void testAddOrRemoveNullHasNoAffect() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertEquals(uris.size(), pool.size());
pool.add(null);
assertEquals(uris.size(), pool.size());
pool.remove(null);
assertEquals(uris.size(), pool.size());
}
@Test
public void testNestedOptionsAreApplied() throws URISyntaxException {
Map<String, String> nested = new HashMap<String, String>();
nested.put("transport.tcpNoDelay", "true");
nested.put("transport.tcpKeepAlive", "false");
FailoverUriPool pool = new FailoverUriPool(uris, nested);
assertNotNull(pool.getNestedOptions());
assertFalse(pool.getNestedOptions().isEmpty());
for (int i = 0; i < uris.size(); ++i) {
URI next = pool.getNext();
assertNotNull(next);
String query = next.getQuery();
assertNotNull(query);
assertFalse(query.isEmpty());
Map<String, String> options = URISupport.parseParameters(next);
assertFalse(options.isEmpty());
assertTrue(options.containsKey("transport.tcpNoDelay"));
assertTrue(options.containsKey("transport.tcpKeepAlive"));
assertEquals("true", options.get("transport.tcpNoDelay"));
assertEquals("false", options.get("transport.tcpKeepAlive"));
}
}
@Test
public void testRemoveURIWhenNestedOptionsSet() throws URISyntaxException {
Map<String, String> nested = new HashMap<String, String>();
nested.put("transport.tcpNoDelay", "true");
nested.put("transport.tcpKeepAlive", "false");
FailoverUriPool pool = new FailoverUriPool(uris, nested);
assertNotNull(pool.getNestedOptions());
assertFalse(pool.getNestedOptions().isEmpty());
for (int i = 0; i < uris.size(); ++i) {
assertTrue(pool.remove(uris.get(i)));
assertEquals(uris.size() - (i + 1), pool.size());
}
}
@Test
public void testAddURIWhenNestedOptionsSet() throws URISyntaxException {
Map<String, String> nested = new HashMap<String, String>();
nested.put("transport.tcpNoDelay", "true");
nested.put("transport.tcpKeepAlive", "false");
FailoverUriPool pool = new FailoverUriPool(null, nested);
assertNotNull(pool.getNestedOptions());
assertFalse(pool.getNestedOptions().isEmpty());
assertTrue(pool.isEmpty());
pool.add(uris.get(0));
assertFalse(pool.isEmpty());
assertEquals(uris.get(0).getHost(), pool.getNext().getHost());
}
@Test
public void testAddFirstURIWhenNestedOptionsSet() throws URISyntaxException {
Map<String, String> nested = new HashMap<String, String>();
nested.put("transport.tcpNoDelay", "true");
nested.put("transport.tcpKeepAlive", "false");
FailoverUriPool pool = new FailoverUriPool(null, nested);
assertNotNull(pool.getNestedOptions());
assertFalse(pool.getNestedOptions().isEmpty());
assertTrue(pool.isEmpty());
pool.addFirst(uris.get(0));
assertFalse(pool.isEmpty());
assertEquals(uris.get(0).getHost(), pool.getNext().getHost());
}
private boolean checkIfResolutionWorks() {
boolean resolutionWorks = false;
try {
resolutionWorks = InetAddress.getByName("shouldbeunresolvable") != null;
resolutionWorks = InetAddress.getByName("SHOULDBEUNRESOLVABLE") != null;
resolutionWorks = InetAddress.getByName("SHOULDBEUNRESOLVABLE2") != null;
} catch (Exception e) {
}
return resolutionWorks;
}
@Test
public void testRemoveAll() throws URISyntaxException {
FailoverUriPool pool = new FailoverUriPool(uris, null);
assertEquals(uris.size(), pool.size());
pool.removeAll();
assertTrue(pool.isEmpty());
assertEquals(0, pool.size());
pool.removeAll();
}
}