BUG 4017: Notification publish service is not available from provider context
[controller.git] / opendaylight / md-sal / sal-akka-raft / src / test / java / org / opendaylight / controller / cluster / raft / RaftActorTest.java
index c2ee4a26d14e040de00fed6acc0601232ff23cca..c47ca5cec1f93273a93c744125c12223d0fe39dd 100644 (file)
@@ -19,6 +19,7 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -36,6 +37,7 @@ import akka.persistence.SaveSnapshotFailure;
 import akka.persistence.SaveSnapshotSuccess;
 import akka.persistence.SnapshotMetadata;
 import akka.persistence.SnapshotOffer;
+import akka.persistence.SnapshotSelectionCriteria;
 import akka.testkit.JavaTestKit;
 import akka.testkit.TestActorRef;
 import com.google.common.base.Optional;
@@ -63,6 +65,7 @@ import org.opendaylight.controller.cluster.PersistentDataProvider;
 import org.opendaylight.controller.cluster.notifications.LeaderStateChanged;
 import org.opendaylight.controller.cluster.notifications.RoleChanged;
 import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
+import org.opendaylight.controller.cluster.raft.ServerConfigurationPayload.ServerInfo;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyJournalEntries;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplyLogEntries;
 import org.opendaylight.controller.cluster.raft.base.messages.ApplySnapshot;
@@ -70,6 +73,7 @@ import org.opendaylight.controller.cluster.raft.base.messages.ApplyState;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
 import org.opendaylight.controller.cluster.raft.base.messages.DeleteEntries;
+import org.opendaylight.controller.cluster.raft.base.messages.LeaderTransitioning;
 import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
 import org.opendaylight.controller.cluster.raft.base.messages.SwitchBehavior;
 import org.opendaylight.controller.cluster.raft.base.messages.UpdateElectionTerm;
@@ -100,6 +104,19 @@ public class RaftActorTest extends AbstractActorTest {
         factory = new TestActorFactory(getSystem());
     }
 
+    @SuppressWarnings("unchecked")
+    private static DataPersistenceProvider mockPersistenceProvider() {
+        final DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+        doReturn(false).when(dataPersistenceProvider).isRecoveryApplicable();
+        doReturn(0L).when(dataPersistenceProvider).getLastSequenceNumber();
+        doNothing().when(dataPersistenceProvider).saveSnapshot(any(Object.class));
+        doNothing().when(dataPersistenceProvider).persist(any(Object.class), any(Procedure.class));
+        doNothing().when(dataPersistenceProvider).deleteSnapshots(any(SnapshotSelectionCriteria.class));
+        doNothing().when(dataPersistenceProvider).deleteMessages(0L);
+
+        return dataPersistenceProvider;
+    }
+
     @After
     public void tearDown() throws Exception {
         factory.close();
@@ -293,7 +310,8 @@ public class RaftActorTest extends AbstractActorTest {
         mockRaftActor.waitForRecoveryComplete();
 
         RaftActorRecoverySupport mockSupport = mock(RaftActorRecoverySupport.class);
-        mockRaftActor.setRaftActorRecoverySupport(mockSupport );
+        doReturn(false).when(mockSupport).handleRecoveryMessage(any(Object.class), any(PersistentDataProvider.class));
+        mockRaftActor.setRaftActorRecoverySupport(mockSupport);
 
         Snapshot snapshot = Snapshot.create(new byte[]{1}, Collections.<ReplicatedLogEntry>emptyList(), 3, 1, 3, 1);
         SnapshotOffer snapshotOffer = new SnapshotOffer(new SnapshotMetadata("test", 6, 12345), snapshot);
@@ -398,7 +416,7 @@ public class RaftActorTest extends AbstractActorTest {
 
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+                DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
                 TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
                         Collections.<String, String>emptyMap(), config, dataPersistenceProvider), persistenceId);
@@ -429,7 +447,7 @@ public class RaftActorTest extends AbstractActorTest {
 
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+                DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
                 TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
                         Collections.<String, String>emptyMap(), config, dataPersistenceProvider), persistenceId);
@@ -597,7 +615,7 @@ public class RaftActorTest extends AbstractActorTest {
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
                 config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+                DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
                 Map<String, String> peerAddresses = new HashMap<>();
                 peerAddresses.put(follower1Id, followerActor1.path().toString());
@@ -694,7 +712,7 @@ public class RaftActorTest extends AbstractActorTest {
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
                 config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+                DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
                 Map<String, String> peerAddresses = new HashMap<>();
                 peerAddresses.put(leaderId, leaderActor1.path().toString());
@@ -801,7 +819,7 @@ public class RaftActorTest extends AbstractActorTest {
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
                 config.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+                DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
                 Map<String, String> peerAddresses = new HashMap<>();
                 peerAddresses.put(follower1Id, followerActor1.path().toString());
@@ -1061,7 +1079,7 @@ public class RaftActorTest extends AbstractActorTest {
         String persistenceId = factory.generateActorId("follower-");
         ImmutableMap<String, String> peerAddresses =
             ImmutableMap.<String, String>builder().put("member1", "address").build();
-        DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
+        DataPersistenceProvider dataPersistenceProvider = mockPersistenceProvider();
 
         TestActorRef<MockRaftActor> actorRef = factory.createTestActor(
                 MockRaftActor.props(persistenceId, peerAddresses, emptyConfig, dataPersistenceProvider), persistenceId);
@@ -1135,6 +1153,7 @@ public class RaftActorTest extends AbstractActorTest {
         verify(mockRaftActor.snapshotCohortDelegate, timeout(5000)).createSnapshot(any(ActorRef.class));
 
         mockRaftActor.snapshotCohortDelegate = mock(RaftActorSnapshotCohort.class);
+        doNothing().when(mockRaftActor.snapshotCohortDelegate).createSnapshot(any(ActorRef.class));
 
         raftActorRef.tell(GetSnapshot.INSTANCE, kit.getRef());
 
@@ -1162,6 +1181,7 @@ public class RaftActorTest extends AbstractActorTest {
 
         mockRaftActor.getSnapshotMessageSupport().setSnapshotReplyActorTimeout(Duration.create(200, TimeUnit.MILLISECONDS));
         reset(mockRaftActor.snapshotCohortDelegate);
+        doNothing().when(mockRaftActor.snapshotCohortDelegate).createSnapshot(any(ActorRef.class));
 
         raftActorRef.tell(GetSnapshot.INSTANCE, kit.getRef());
         Failure failure = kit.expectMsgClass(akka.actor.Status.Failure.class);
@@ -1173,6 +1193,7 @@ public class RaftActorTest extends AbstractActorTest {
 
         mockRaftActor.setPersistence(false);
         reset(mockRaftActor.snapshotCohortDelegate);
+        doNothing().when(mockRaftActor.snapshotCohortDelegate).createSnapshot(any(ActorRef.class));
 
         raftActorRef.tell(GetSnapshot.INSTANCE, kit.getRef());
         reply = kit.expectMsgClass(GetSnapshotReply.class);
@@ -1305,4 +1326,65 @@ public class RaftActorTest extends AbstractActorTest {
 
         TEST_LOG.info("testRestoreFromSnapshotWithRecoveredData ending");
     }
+
+    @Test
+    public void testNonVotingOnRecovery() throws Exception {
+        TEST_LOG.info("testNonVotingOnRecovery starting");
+
+        DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
+        config.setElectionTimeoutFactor(1);
+        config.setHeartBeatInterval(FiniteDuration.create(1, TimeUnit.MILLISECONDS));
+
+        String persistenceId = factory.generateActorId("test-actor-");
+        InMemoryJournal.addEntry(persistenceId, 1,  new MockRaftActorContext.MockReplicatedLogEntry(1, 0,
+                new ServerConfigurationPayload(Arrays.asList(new ServerInfo(persistenceId, false)))));
+
+        TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).
+                config(config).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
+        MockRaftActor mockRaftActor = raftActorRef.underlyingActor();
+
+        mockRaftActor.waitForInitializeBehaviorComplete();
+
+        // Sleep a bit and verify it didn't get an election timeout and schedule an election.
+
+        Uninterruptibles.sleepUninterruptibly(400, TimeUnit.MILLISECONDS);
+        assertEquals("getRaftState", RaftState.Follower, mockRaftActor.getRaftState());
+
+        TEST_LOG.info("testNonVotingOnRecovery ending");
+    }
+
+    @Test
+    public void testLeaderTransitioning() throws Exception {
+        TEST_LOG.info("testLeaderTransitioning starting");
+
+        TestActorRef<MessageCollectorActor> notifierActor = factory.createTestActor(
+                Props.create(MessageCollectorActor.class));
+
+        DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
+        config.setCustomRaftPolicyImplementationClass(DisableElectionsRaftPolicy.class.getName());
+
+        String persistenceId = factory.generateActorId("test-actor-");
+
+        TestActorRef<MockRaftActor> raftActorRef = factory.createTestActor(MockRaftActor.builder().id(persistenceId).
+                config(config).roleChangeNotifier(notifierActor).props().withDispatcher(Dispatchers.DefaultDispatcherId()), persistenceId);
+        MockRaftActor mockRaftActor = raftActorRef.underlyingActor();
+
+        mockRaftActor.waitForInitializeBehaviorComplete();
+
+        raftActorRef.tell(new AppendEntries(1L, "leader", 0L, 1L, Collections.<ReplicatedLogEntry>emptyList(),
+                0L, -1L, (short)1), ActorRef.noSender());
+        LeaderStateChanged leaderStateChange = MessageCollectorActor.expectFirstMatching(
+                notifierActor, LeaderStateChanged.class);
+        assertEquals("getLeaderId", "leader", leaderStateChange.getLeaderId());
+
+        MessageCollectorActor.clearMessages(notifierActor);
+
+        raftActorRef.tell(new LeaderTransitioning(), ActorRef.noSender());
+
+        leaderStateChange = MessageCollectorActor.expectFirstMatching(notifierActor, LeaderStateChanged.class);
+        assertEquals("getMemberId", persistenceId, leaderStateChange.getMemberId());
+        assertEquals("getLeaderId", null, leaderStateChange.getLeaderId());
+
+        TEST_LOG.info("testLeaderTransitioning ending");
+    }
 }