use of org.neo4j.kernel.ha.cluster.SwitchToMaster in project neo4j by neo4j.
the class HighAvailabilityModeSwitcherTest method shouldUseProperServerIdWhenDemotingFromMasterOnException.
@Test
public void shouldUseProperServerIdWhenDemotingFromMasterOnException() throws Throwable {
/*
* This a test that acts as a driver to prove a bug which had an instance send out a demote message
* with instance id -1, since it used HAMS#getServerId(URI) with a URI coming from the NetworkReceiver binding
* which did not contain the serverId URI argument. This has been fixed by explicitly adding the instanceid
* as a constructor argument of the HAMS.
*/
// Given
SwitchToSlaveCopyThenBranch sts = mock(SwitchToSlaveCopyThenBranch.class);
SwitchToMaster stm = mock(SwitchToMaster.class);
// this is necessary to trigger a revert which uses the serverId from the HAMS#me field
when(stm.switchToMaster(any(LifeSupport.class), any(URI.class))).thenThrow(new RuntimeException());
Election election = mock(Election.class);
ClusterMemberAvailability cma = mock(ClusterMemberAvailability.class);
InstanceId instanceId = new InstanceId(14);
HighAvailabilityModeSwitcher theSwitcher = new HighAvailabilityModeSwitcher(sts, stm, election, cma, mock(ClusterClient.class), storeSupplierMock(), instanceId, new ComponentSwitcherContainer(), neoStoreDataSourceSupplierMock(), NullLogService.getInstance());
theSwitcher.init();
theSwitcher.start();
/*
* This is the trick, kind of. NetworkReceiver creates this and passes it on to NetworkReceiver#getURI() and
* that
* is what HAMS uses as the HAMS#me field value. But we should not be using this to extract the instanceId.
* Note the lack of a serverId argument
*/
URI listeningAt = URI.create("ha://0.0.0.0:5001?name=someName");
theSwitcher.listeningAt(listeningAt);
// When
try {
// the instance fails to switch to master
theSwitcher.masterIsElected(new HighAvailabilityMemberChangeEvent(HighAvailabilityMemberState.PENDING, HighAvailabilityMemberState.TO_MASTER, instanceId, listeningAt));
} finally {
theSwitcher.stop();
theSwitcher.shutdown();
}
// Then
// The demotion message must have used the proper instance id
verify(election).demote(instanceId);
}
use of org.neo4j.kernel.ha.cluster.SwitchToMaster in project neo4j by neo4j.
the class HighAvailabilityModeSwitcherTest method shouldSwitchToSlaveForNullMasterAndBeSilentWhenMovingToDetached.
@Test
public void shouldSwitchToSlaveForNullMasterAndBeSilentWhenMovingToDetached() throws Throwable {
// Given
SwitchToSlaveCopyThenBranch sts = mock(SwitchToSlaveCopyThenBranch.class);
SwitchToMaster stm = mock(SwitchToMaster.class);
Election election = mock(Election.class);
ClusterMemberAvailability cma = mock(ClusterMemberAvailability.class);
InstanceId instanceId = new InstanceId(14);
ComponentSwitcher componentSwitcher = mock(ComponentSwitcher.class);
HighAvailabilityModeSwitcher theSwitcher = new HighAvailabilityModeSwitcher(sts, stm, election, cma, mock(ClusterClient.class), storeSupplierMock(), instanceId, componentSwitcher, neoStoreDataSourceSupplierMock(), NullLogService.getInstance());
// When
theSwitcher.init();
theSwitcher.start();
theSwitcher.instanceDetached(new HighAvailabilityMemberChangeEvent(HighAvailabilityMemberState.MASTER, HighAvailabilityMemberState.PENDING, null, null));
// Then
verify(componentSwitcher).switchToSlave();
verifyZeroInteractions(cma);
}
use of org.neo4j.kernel.ha.cluster.SwitchToMaster in project neo4j by neo4j.
the class HighAvailabilityModeSwitcherTest method shouldReswitchToSlaveIfNewMasterBecameElectedAndAvailableDuringSwitch.
@Test
public void shouldReswitchToSlaveIfNewMasterBecameElectedAndAvailableDuringSwitch() throws Throwable {
// Given
final CountDownLatch switching = new CountDownLatch(1);
final CountDownLatch slaveAvailable = new CountDownLatch(2);
final AtomicBoolean firstSwitch = new AtomicBoolean(true);
ClusterMemberAvailability availability = mock(ClusterMemberAvailability.class);
SwitchToSlaveCopyThenBranch switchToSlave = mock(SwitchToSlaveCopyThenBranch.class);
@SuppressWarnings("resource") SwitchToMaster switchToMaster = mock(SwitchToMaster.class);
when(switchToSlave.switchToSlave(any(LifeSupport.class), any(URI.class), any(URI.class), any(CancellationRequest.class))).thenAnswer(invocationOnMock -> {
switching.countDown();
CancellationRequest cancel = (CancellationRequest) invocationOnMock.getArguments()[3];
if (firstSwitch.get()) {
while (!cancel.cancellationRequested()) {
Thread.sleep(1);
}
firstSwitch.set(false);
}
slaveAvailable.countDown();
return URI.create("ha://slave");
});
HighAvailabilityModeSwitcher toTest = new HighAvailabilityModeSwitcher(switchToSlave, switchToMaster, mock(Election.class), availability, mock(ClusterClient.class), storeSupplierMock(), mock(InstanceId.class), new ComponentSwitcherContainer(), neoStoreDataSourceSupplierMock(), NullLogService.getInstance());
toTest.init();
toTest.start();
toTest.listeningAt(URI.create("ha://server3?serverId=3"));
// When
// This will start a switch to slave
toTest.masterIsAvailable(new HighAvailabilityMemberChangeEvent(PENDING, TO_SLAVE, mock(InstanceId.class), URI.create("ha://server1")));
// Wait until it starts and blocks on the cancellation request
switching.await();
// change the elected master, moving to pending, cancelling the previous change. This will block until the
// previous switch is aborted
toTest.masterIsElected(new HighAvailabilityMemberChangeEvent(TO_SLAVE, PENDING, new InstanceId(2), URI.create("ha://server2")));
// Now move to the new master by switching to TO_SLAVE
toTest.masterIsAvailable(new HighAvailabilityMemberChangeEvent(PENDING, TO_SLAVE, new InstanceId(2), URI.create("ha://server2")));
// Then
// The second switch must happen and this test won't block
slaveAvailable.await();
}
Aggregations