Skip to content

Commit

Permalink
Converted most of HaBeanIT to unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
tinwelint committed Sep 19, 2016
1 parent ec498f3 commit 213dea9
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 240 deletions.
Expand Up @@ -30,7 +30,7 @@ public final class ManagementData extends DependencyResolver.Adapter
private final ManagementSupport support;
final ManagementBeanProvider provider;

ManagementData( ManagementBeanProvider provider, KernelData kernel, ManagementSupport support )
public ManagementData( ManagementBeanProvider provider, KernelData kernel, ManagementSupport support )
{
this.provider = provider;
this.kernel = kernel;
Expand Down
Expand Up @@ -35,7 +35,7 @@

public class ManagementSupport
{
static final ManagementSupport load()
public static final ManagementSupport load()
{
ManagementSupport support = new ManagementSupport();
for ( ManagementSupport candidate : Service.load( ManagementSupport.class ) )
Expand Down Expand Up @@ -66,7 +66,7 @@ protected <T> T makeProxy( KernelBean kernel, ObjectName name, Class<T> beanInte

final <T> Collection<T> getProxiesFor( Class<T> beanInterface, KernelBean kernel )
{
Collection<T> result = new ArrayList<T>();
Collection<T> result = new ArrayList<>();
ObjectName query = createObjectNameQuery( kernel.getInstanceId(), beanInterface );
for ( ObjectName name : getMBeanServer().queryNames( query, null ) )
{
Expand Down Expand Up @@ -115,7 +115,7 @@ protected String getBeanName( Class<?> beanInterface )

protected ObjectName createObjectName( String instanceId, String beanName, boolean query, String... extraNaming )
{
Hashtable<String, String> properties = new Hashtable<String, String>();
Hashtable<String, String> properties = new Hashtable<>();
properties.put( "instance", "kernel#" + instanceId );
properties.put( "name", beanName );
for ( int i = 0; i < extraNaming.length; i++ )
Expand Down
Expand Up @@ -42,7 +42,7 @@ public ClusterMember( InstanceId instanceId )
this( instanceId, Collections.<String,URI>emptyMap(), StoreId.DEFAULT, true );
}

ClusterMember( InstanceId instanceId, Map<String,URI> roles, StoreId storeId, boolean alive )
public ClusterMember( InstanceId instanceId, Map<String,URI> roles, StoreId storeId, boolean alive )
{
this.instanceId = instanceId;
this.roles = roles;
Expand Down
247 changes: 12 additions & 235 deletions enterprise/ha/src/test/java/jmx/HaBeanIT.java
Expand Up @@ -23,30 +23,21 @@
import org.junit.Test;

import java.net.URI;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.function.Predicate;

import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.jmx.Kernel;
import org.neo4j.jmx.impl.JmxKernelExtension;
import org.neo4j.kernel.ha.HaSettings;
import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase;
import org.neo4j.kernel.ha.cluster.HighAvailabilityMemberState;
import org.neo4j.kernel.ha.cluster.modeswitch.HighAvailabilityModeSwitcher;
import org.neo4j.kernel.impl.ha.ClusterManager;
import org.neo4j.kernel.impl.ha.ClusterManager.ManagedCluster;
import org.neo4j.kernel.impl.ha.ClusterManager.RepairKit;
import org.neo4j.management.BranchedStore;
import org.neo4j.management.ClusterMemberInfo;
import org.neo4j.management.HighAvailability;
import org.neo4j.management.Neo4jManager;
import org.neo4j.test.ha.ClusterRule;

import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
Expand All @@ -55,232 +46,42 @@
import static org.neo4j.helpers.collection.Iterables.firstOrNull;
import static org.neo4j.kernel.configuration.Settings.STRING;
import static org.neo4j.kernel.configuration.Settings.setting;
import static org.neo4j.kernel.impl.ha.ClusterManager.instanceEvicted;
import static org.neo4j.kernel.impl.ha.ClusterManager.masterAvailable;
import static org.neo4j.kernel.impl.ha.ClusterManager.masterSeesMembers;
import static org.neo4j.kernel.impl.ha.ClusterManager.masterSeesSlavesAsAvailable;
import static org.neo4j.test.ha.ClusterRule.intBase;
import static org.neo4j.test.ha.ClusterRule.stringWithIntBase;

public class HaBeanIT
{
@Rule
public final ClusterRule clusterRule = new ClusterRule( getClass() )
public final ClusterRule clusterRule = new ClusterRule( HaBeanIT.class )
.withInstanceSetting( setting( "jmx.port", STRING, (String) null ), intBase( 9912 ) )
.withInstanceSetting( HaSettings.ha_server, stringWithIntBase( ":", 1136 ) )
.withInstanceSetting( GraphDatabaseSettings.forced_kernel_id, stringWithIntBase( "kernel", 0 ) );

@Test
public void canGetHaBean() throws Throwable
public void shouldAccessHaBeans() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();

// High Availability bean
HighAvailability ha = ha( cluster.getMaster() );
assertNotNull( "could not get ha bean", ha );
assertMasterInformation( ha );
}

private void assertMasterInformation( HighAvailability ha )
{
assertTrue( "should be available", ha.isAvailable() );
assertEquals( "should be master", HighAvailabilityModeSwitcher.MASTER, ha.getRole() );
}

@Test
public void testLatestTxInfoIsCorrect() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();
HighlyAvailableGraphDatabase db = cluster.getMaster();
HighAvailability masterHa = ha( db );
long lastCommitted = masterHa.getLastCommittedTxId();
try ( Transaction tx = db.beginTx() )
{
db.createNode();
tx.success();
}
assertEquals( lastCommitted + 1, masterHa.getLastCommittedTxId() );
}

@Test
public void testUpdatePullWorksAndUpdatesLastUpdateTime() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();
HighlyAvailableGraphDatabase master = cluster.getMaster();
HighlyAvailableGraphDatabase slave = cluster.getAnySlave();
try (Transaction tx = master.beginTx())
{
master.createNode();
tx.success();
}
HighAvailability slaveBean = ha( slave );
DateFormat format = new SimpleDateFormat( "yyyy-MM-DD kk:mm:ss.SSSZZZZ" );
// To begin with, no updates
slaveBean.update();
long timeUpdated = format.parse( slaveBean.getLastUpdateTime() ).getTime();
assertTrue( timeUpdated > 0 );
}

@Test
public void testAfterGentleMasterSwitchClusterInfoIsCorrect() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();
HighlyAvailableGraphDatabase master = cluster.getMaster();
RepairKit masterShutdown = cluster.shutdown( master );

cluster.await( masterAvailable( master ) );
cluster.await( masterSeesSlavesAsAvailable( 1 ) );

for ( HighlyAvailableGraphDatabase db : cluster.getAllMembers() )
{
assertEquals( 2, ha( db ).getInstancesInCluster().length );
}

masterShutdown.repair();

cluster.await( ClusterManager.allSeesAllAsAvailable() );

for ( HighlyAvailableGraphDatabase db : cluster.getAllMembers() )
{
HighAvailability bean = ha( db );

assertEquals( 3, bean.getInstancesInCluster().length );
for ( ClusterMemberInfo info : bean.getInstancesInCluster() )
{
assertTrue( "every instance should be available", info.isAvailable() );
assertTrue( "every instances should have at least one role", info.getRoles().length > 0 );
if ( HighAvailabilityModeSwitcher.MASTER.equals( info.getRoles()[0] ) )
{
assertEquals( "coordinator should be master",
HighAvailabilityModeSwitcher.MASTER, info.getHaRole() );
}
else
{
assertEquals( "Either master or slave, no other way",
HighAvailabilityModeSwitcher.SLAVE, info.getRoles()[0] );
assertEquals( "instance " + info.getInstanceId() + " is cluster slave but HA master",
HighAvailabilityModeSwitcher.SLAVE, info.getHaRole() );
}
for ( String uri : info.getUris() )
{
assertTrue( "roles should contain URIs",
uri.startsWith( "ha://" ) || uri.startsWith( "backup://" ) );
}
}
}
}

@Test
public void testAfterHardMasterSwitchClusterInfoIsCorrect() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();

cluster.await( masterSeesSlavesAsAvailable( 2 ) );

HighlyAvailableGraphDatabase master = cluster.getMaster();
RepairKit masterShutdown = cluster.fail( master );

cluster.await( instanceEvicted( master ) );

for ( HighlyAvailableGraphDatabase db : cluster.getAllMembers() )
{
if ( db.getInstanceState() == HighAvailabilityMemberState.PENDING )
{
continue;
}
// Instance that was hard killed will still be in the cluster
assertEquals( 3, ha( db ).getInstancesInCluster().length );
}

masterShutdown.repair();

cluster.await( ClusterManager.allSeesAllAsAvailable(), 180 );

for ( HighlyAvailableGraphDatabase db : cluster.getAllMembers() )
assertMasterAndSlaveInformation( ha.getInstancesInCluster() );
for ( ClusterMemberInfo info : ha.getInstancesInCluster() )
{
int mastersFound = 0;
HighAvailability bean = ha( db );

assertEquals( 3, bean.getInstancesInCluster().length );
for ( ClusterMemberInfo info : bean.getInstancesInCluster() )
{
assertTrue( bean.getInstanceId() + ": every instance should be available: " + info.getInstanceId(),
info.isAvailable() );
for ( String role : info.getRoles() )
{
if ( role.equals( HighAvailabilityModeSwitcher.MASTER ) )
{
mastersFound++;
}
}
}
assertEquals( 1, mastersFound );
assertTrue( info.isAlive() );
assertTrue( info.isAvailable() );
}
}

@Test
public void canGetBranchedStoreBean() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();
// Branched data bean
BranchedStore bs = beans( cluster.getMaster() ).getBranchedStoreBean();
assertNotNull( "could not get branched store bean", bs );
}

@Test
public void joinedInstanceShowsUpAsSlave() throws Throwable
{
ManagedCluster cluster = clusterRule.startCluster();
ClusterMemberInfo[] instancesInCluster = ha( cluster.getMaster() ).getInstancesInCluster();
assertEquals( 3, instancesInCluster.length );
ClusterMemberInfo[] secondInstancesInCluster = ha( cluster.getAnySlave() ).getInstancesInCluster();
assertEquals( 3, secondInstancesInCluster.length );
assertMasterAndSlaveInformation( instancesInCluster );
assertMasterAndSlaveInformation( secondInstancesInCluster );
}

@Test
public void leftInstanceDisappearsFromMemberList() throws Throwable
{
// Start the cluster and make sure it's up.
// Then shut down one of the slaves to see if it disappears from the member list.
ManagedCluster cluster = clusterRule.startCluster();
assertEquals( 3, ha( cluster.getAnySlave() ).getInstancesInCluster().length );
RepairKit repair = cluster.shutdown( cluster.getAnySlave() );

try
{
cluster.await( masterSeesMembers( 2 ) );
HighAvailability haMaster = ha( cluster.getMaster() );
assertEquals( 2, haMaster.getInstancesInCluster().length );
}
finally
{
repair.repair();
}
}

@Test
public void failedMemberIsStillInMemberListAlthoughFailed() throws Throwable
private void assertMasterInformation( HighAvailability ha )
{
ManagedCluster cluster = clusterRule.startCluster();
assertEquals( 3, ha( cluster.getAnySlave() ).getInstancesInCluster().length );

// Fail the instance
HighlyAvailableGraphDatabase failedDb = cluster.getAnySlave();
RepairKit dbFailure = cluster.fail( failedDb );
try
{
await( ha( cluster.getMaster() ), dbAlive( false ) );
await( ha( cluster.getAnySlave( failedDb ) ), dbAlive( false ) );
}
finally
{
// Repair the failure and come back
dbFailure.repair();
}
for ( HighlyAvailableGraphDatabase db : cluster.getAllMembers() )
{
await( ha( db ), dbAvailability( true ) );
await( ha( db ), dbAlive( true ) );
}
assertTrue( "should be available", ha.isAvailable() );
assertEquals( "should be master", HighAvailabilityModeSwitcher.MASTER, ha.getRole() );
}

private Neo4jManager beans( HighlyAvailableGraphDatabase db )
Expand Down Expand Up @@ -324,28 +125,4 @@ private ClusterMemberInfo member( ClusterMemberInfo[] members, int instanceId )
members ) );
return null; // it will never get here.
}

private void await( HighAvailability ha, Predicate<ClusterMemberInfo> predicate ) throws InterruptedException
{
long end = System.currentTimeMillis() + SECONDS.toMillis( 300 );
while ( System.currentTimeMillis() < end )
{
if ( predicate.test( member( ha.getInstancesInCluster(), 2 ) ) )
{
return;
}
Thread.sleep( 500 );
}
fail( "Failed instance didn't show up as such in JMX" );
}

private Predicate<ClusterMemberInfo> dbAvailability( final boolean available )
{
return item -> item.isAvailable() == available;
}

private Predicate<ClusterMemberInfo> dbAlive( final boolean alive )
{
return item -> item.isAlive() == alive;
}
}

0 comments on commit 213dea9

Please sign in to comment.