/* * Copyright (c) 2002-2017 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Licensed 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.neo4j.driver.internal.cluster; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import org.junit.Test; import org.neo4j.driver.internal.net.BoltServerAddress; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; public class RoundRobinAddressSetTest { @Test public void shouldReturnNullWhenEmpty() throws Exception { // given RoundRobinAddressSet set = new RoundRobinAddressSet(); // then assertNull( set.next() ); } @Test public void shouldReturnRoundRobin() throws Exception { // given RoundRobinAddressSet set = new RoundRobinAddressSet(); set.update( new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "tre" ) ) ), new HashSet<BoltServerAddress>() ); // when BoltServerAddress a = set.next(); BoltServerAddress b = set.next(); BoltServerAddress c = set.next(); // then assertEquals( a, set.next() ); assertEquals( b, set.next() ); assertEquals( c, set.next() ); assertEquals( a, set.next() ); assertEquals( b, set.next() ); assertEquals( c, set.next() ); assertNotEquals( a, c ); assertNotEquals( b, a ); assertNotEquals( c, b ); } @Test public void shouldPreserveOrderWhenAdding() throws Exception { // given HashSet<BoltServerAddress> servers = new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "tre" ) ) ); RoundRobinAddressSet set = new RoundRobinAddressSet(); set.update( servers, new HashSet<BoltServerAddress>() ); List<BoltServerAddress> order = new ArrayList<>(); for ( int i = 3 * 4 + 1; i-- > 0; ) { BoltServerAddress server = set.next(); if ( !order.contains( server ) ) { order.add( server ); } } assertEquals( 3, order.size() ); // when servers.add( new BoltServerAddress( "fyr" ) ); set.update( servers, new HashSet<BoltServerAddress>() ); // then assertEquals( order.get( 1 ), set.next() ); assertEquals( order.get( 2 ), set.next() ); BoltServerAddress next = set.next(); assertNotEquals( order.get( 0 ), next ); assertNotEquals( order.get( 1 ), next ); assertNotEquals( order.get( 2 ), next ); assertEquals( order.get( 0 ), set.next() ); // ... and once more assertEquals( order.get( 1 ), set.next() ); assertEquals( order.get( 2 ), set.next() ); assertEquals( next, set.next() ); assertEquals( order.get( 0 ), set.next() ); } @Test public void shouldPreserveOrderWhenRemoving() throws Exception { // given HashSet<BoltServerAddress> servers = new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "tre" ) ) ); RoundRobinAddressSet set = new RoundRobinAddressSet(); set.update( servers, new HashSet<BoltServerAddress>() ); List<BoltServerAddress> order = new ArrayList<>(); for ( int i = 3 * 2 + 1; i-- > 0; ) { BoltServerAddress server = set.next(); if ( !order.contains( server ) ) { order.add( server ); } } assertEquals( 3, order.size() ); // when set.remove( order.get( 1 ) ); // then assertEquals( order.get( 2 ), set.next() ); assertEquals( order.get( 0 ), set.next() ); assertEquals( order.get( 2 ), set.next() ); assertEquals( order.get( 0 ), set.next() ); } @Test public void shouldPreserveOrderWhenRemovingThroughUpdate() throws Exception { // given HashSet<BoltServerAddress> servers = new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "tre" ) ) ); RoundRobinAddressSet set = new RoundRobinAddressSet(); set.update( servers, new HashSet<BoltServerAddress>() ); List<BoltServerAddress> order = new ArrayList<>(); for ( int i = 3 * 2 + 1; i-- > 0; ) { BoltServerAddress server = set.next(); if ( !order.contains( server ) ) { order.add( server ); } } assertEquals( 3, order.size() ); // when servers.remove( order.get( 1 ) ); set.update( servers, new HashSet<BoltServerAddress>() ); // then assertEquals( order.get( 2 ), set.next() ); assertEquals( order.get( 0 ), set.next() ); assertEquals( order.get( 2 ), set.next() ); assertEquals( order.get( 0 ), set.next() ); } @Test public void shouldRecordRemovedAddressesWhenUpdating() throws Exception { // given RoundRobinAddressSet set = new RoundRobinAddressSet(); set.update( new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "tre" ) ) ), new HashSet<BoltServerAddress>() ); // when HashSet<BoltServerAddress> removed = new HashSet<>(); set.update( new HashSet<>( asList( new BoltServerAddress( "one" ), new BoltServerAddress( "two" ), new BoltServerAddress( "fyr" ) ) ), removed ); // then assertEquals( singleton( new BoltServerAddress( "tre" ) ), removed ); } @Test public void shouldPreserveOrderEvenWhenIntegerOverflows() throws Exception { // given RoundRobinAddressSet set = new RoundRobinAddressSet(); for ( int div = 1; div <= 1024; div++ ) { // when - white box testing! set.setOffset( Integer.MAX_VALUE - 1 ); int a = set.next( div ); int b = set.next( div ); // then if ( b != (a + 1) % div ) { fail( String.format( "a=%d, b=%d, div=%d, (a+1)%%div=%d", a, b, div, (a + 1) % div ) ); } } } }