/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * 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 com.hazelcast.internal.partition.impl; import com.hazelcast.cluster.ClusterState; import com.hazelcast.instance.Node; import com.hazelcast.internal.cluster.impl.ClusterServiceImpl; import com.hazelcast.internal.partition.InternalPartition; import com.hazelcast.logging.ILogger; import com.hazelcast.nio.Address; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import static com.hazelcast.internal.partition.impl.PartitionServiceState.MIGRATION_LOCAL; import static com.hazelcast.internal.partition.impl.PartitionServiceState.MIGRATION_ON_MASTER; import static com.hazelcast.internal.partition.impl.PartitionServiceState.REPLICA_NOT_OWNED; import static com.hazelcast.internal.partition.impl.PartitionServiceState.REPLICA_NOT_SYNC; import static com.hazelcast.internal.partition.impl.PartitionServiceState.SAFE; import static com.hazelcast.logging.Logger.getLogger; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class PartitionReplicaStateChecker_triggerAndWaitForReplicaSyncTest extends HazelcastTestSupport { private List<InternalPartition> partitions = new ArrayList<InternalPartition>(); private Node node; private PartitionStateManager partitionStateManager; private MigrationManager migrationManager; private PartitionReplicaStateChecker replicaStateChecker; @Before public void setUp() { ILogger logger = getLogger(PartitionReplicaStateChecker_triggerAndWaitForReplicaSyncTest.class); ClusterServiceImpl clusterService = mock(ClusterServiceImpl.class); when(clusterService.getClusterState()).thenReturn(ClusterState.ACTIVE); node = mock(Node.class); when(node.getLogger(any(Class.class))).thenReturn(logger); when(node.getClusterService()).thenReturn(clusterService); partitionStateManager = mock(PartitionStateManager.class); when(partitionStateManager.getPartitions()).thenAnswer(new Answer<InternalPartition[]>() { @Override public InternalPartition[] answer(InvocationOnMock invocationOnMock) throws Throwable { InternalPartition[] partitionsArray = new InternalPartition[partitions.size()]; return partitions.toArray(partitionsArray); } }); migrationManager = mock(MigrationManager.class); InternalPartitionServiceImpl partitionService = mock(InternalPartitionServiceImpl.class); when(partitionService.getPartitionStateManager()).thenReturn(partitionStateManager); when(partitionService.getMigrationManager()).thenReturn(migrationManager); replicaStateChecker = new PartitionReplicaStateChecker(node, partitionService); } @Test public void whenCalledWithZeroTimeout_thenDoNothing() { assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(0, TimeUnit.MILLISECONDS)); } @Test public void whenHasMissingReplicaOwners_withAddress_thenWaitForMissingReplicaOwners() throws Exception { configureNeedsReplicaStateCheckResponse(); Address address = new Address("127.0.0.1", 5701); InternalPartition partition = new DummyInternalPartition(new Address[]{address}, 1); partitions.add(partition); assertEquals(REPLICA_NOT_OWNED, replicaStateChecker.getPartitionServiceState()); assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenHasMissingReplicaOwners_withoutAddress_thenWaitForMissingReplicaOwners() { configureNeedsReplicaStateCheckResponse(); InternalPartition partition = new DummyInternalPartition(new Address[0], 1); partitions.add(partition); assertEquals(REPLICA_NOT_OWNED, replicaStateChecker.getPartitionServiceState()); assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenHasOngoingMigration_withLocalMigration_thenWaitForOngoingMigrations() { when(migrationManager.hasOnGoingMigration()).thenReturn(true); assertEquals(MIGRATION_LOCAL, replicaStateChecker.getPartitionServiceState()); assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenHasOngoingMigration_withMigrationOnMaster_thenWaitForOngoingMigrations() { when(node.getMasterAddress()).thenReturn(null); when(node.getClusterService().isJoined()).thenReturn(true); assertEquals(MIGRATION_ON_MASTER, replicaStateChecker.getPartitionServiceState()); assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenCheckAndTriggerReplicaSync() throws Exception { configureNeedsReplicaStateCheckResponseOnEachSecondCall(); InternalPartition partition = new DummyInternalPartition(new Address[]{null}, 1); partitions.add(partition); assertEquals(REPLICA_NOT_SYNC, replicaStateChecker.getPartitionServiceState()); assertFalse(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenCheckAndTriggerReplicaSync_withNeedsReplicaStateCheck_thenReturnTrue() { configureNeedsReplicaStateCheckResponseOnEachSecondCall(); assertEquals(SAFE, replicaStateChecker.getPartitionServiceState()); assertTrue(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } @Test public void whenCheckAndTriggerReplicaSync_withoutNeedsReplicaStateCheck_thenReturnTrue() { assertEquals(SAFE, replicaStateChecker.getPartitionServiceState()); assertTrue(replicaStateChecker.triggerAndWaitForReplicaSync(10, TimeUnit.MILLISECONDS, 5)); } private void configureNeedsReplicaStateCheckResponse() { when(partitionStateManager.isInitialized()).thenReturn(true); when(partitionStateManager.getMemberGroupsSize()).thenReturn(1); } private void configureNeedsReplicaStateCheckResponseOnEachSecondCall() { when(partitionStateManager.isInitialized()).thenAnswer(new AlternatingAnswer()); when(partitionStateManager.getMemberGroupsSize()).thenReturn(1); } /** * Alternately returns {@code true} and {@code false}, beginning with {@code false}. */ private static class AlternatingAnswer implements Answer<Boolean> { private boolean state = true; @Override public Boolean answer(InvocationOnMock invocationOnMock) throws Throwable { state = !state; return state; } } }