X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-akka-raft%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fcluster%2Fraft%2FRaftActorRecoverySupportTest.java;h=0d29c31ee4b3b1d5f9e879c3a014317fa188e850;hp=7420fc4e6cb6e82e4612adaefc33ebd9e35a2209;hb=33877f41ffc3f8eb36ad8490315419b90817d26e;hpb=e1e2b8993826feb599a77a3464d8f46a6c7897ca diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorRecoverySupportTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorRecoverySupportTest.java index 7420fc4e6c..0d29c31ee4 100644 --- a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorRecoverySupportTest.java +++ b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorRecoverySupportTest.java @@ -8,27 +8,58 @@ package org.opendaylight.controller.cluster.raft; import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.anyInt; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; + +import akka.actor.ActorRef; +import akka.actor.ActorSystem; +import akka.actor.Props; import akka.persistence.RecoveryCompleted; import akka.persistence.SnapshotMetadata; import akka.persistence.SnapshotOffer; +import com.google.common.collect.Sets; +import com.google.common.util.concurrent.MoreExecutors; +import java.io.OutputStream; import java.util.Arrays; import java.util.Collections; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.cluster.DataPersistenceProvider; -import org.opendaylight.controller.cluster.raft.RaftActor.UpdateElectionTerm; -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.DeleteEntries; -import org.opendaylight.controller.cluster.raft.behaviors.RaftActorBehavior; +import org.opendaylight.controller.cluster.PersistentDataProvider; +import org.opendaylight.controller.cluster.raft.MockRaftActor.MockSnapshotState; +import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload; +import org.opendaylight.controller.cluster.raft.persisted.ApplyJournalEntries; +import org.opendaylight.controller.cluster.raft.persisted.DeleteEntries; +import org.opendaylight.controller.cluster.raft.persisted.ServerConfigurationPayload; +import org.opendaylight.controller.cluster.raft.persisted.ServerInfo; +import org.opendaylight.controller.cluster.raft.persisted.SimpleReplicatedLogEntry; +import org.opendaylight.controller.cluster.raft.persisted.Snapshot; +import org.opendaylight.controller.cluster.raft.persisted.UpdateElectionTerm; +import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload; +import org.opendaylight.controller.cluster.raft.utils.DoNothingActor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,43 +76,50 @@ public class RaftActorRecoverySupportTest { private DataPersistenceProvider mockPersistence; @Mock - private RaftActorBehavior mockBehavior; + private RaftActorRecoveryCohort mockCohort; @Mock - private RaftActorRecoveryCohort mockCohort; + PersistentDataProvider mockPersistentProvider; + + ActorRef mockActorRef; + + ActorSystem mockActorSystem; private RaftActorRecoverySupport support; private RaftActorContext context; private final DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl(); + private final String localId = "leader"; @Before public void setup() { MockitoAnnotations.initMocks(this); + mockActorSystem = ActorSystem.create(); + mockActorRef = mockActorSystem.actorOf(Props.create(DoNothingActor.class)); + context = new RaftActorContextImpl(mockActorRef, null, localId, + new ElectionTermImpl(mockPersistentProvider, "test", LOG), -1, -1, + Collections.emptyMap(), configParams, mockPersistence, applyState -> { + }, LOG, MoreExecutors.directExecutor()); - context = new RaftActorContextImpl(null, null, "test", new ElectionTermImpl(mockPersistence, "test", LOG), - -1, -1, Collections.emptyMap(), configParams, LOG); - - support = new RaftActorRecoverySupport(mockPersistence, context , mockBehavior, mockCohort); + support = new RaftActorRecoverySupport(context, mockCohort); doReturn(true).when(mockPersistence).isRecoveryApplicable(); - context.setReplicatedLog(ReplicatedLogImpl.newInstance(context, mockPersistence, mockBehavior)); + context.setReplicatedLog(ReplicatedLogImpl.newInstance(context)); } - private void sendMessageToSupport(Object message) { + private void sendMessageToSupport(final Object message) { sendMessageToSupport(message, false); } - private void sendMessageToSupport(Object message, boolean expComplete) { - boolean complete = support.handleRecoveryMessage(message); + private void sendMessageToSupport(final Object message, final boolean expComplete) { + boolean complete = support.handleRecoveryMessage(message, mockPersistentProvider); assertEquals("complete", expComplete, complete); } @Test public void testOnReplicatedLogEntry() { - MockRaftActorContext.MockReplicatedLogEntry logEntry = new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1", 5)); + ReplicatedLogEntry logEntry = new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1", 5)); sendMessageToSupport(logEntry); @@ -99,18 +137,12 @@ public class RaftActorRecoverySupportTest { configParams.setJournalRecoveryLogBatchSize(5); ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 0, new MockRaftActorContext.MockPayload("0"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 2, new MockRaftActorContext.MockPayload("2"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 3, new MockRaftActorContext.MockPayload("3"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 4, new MockRaftActorContext.MockPayload("4"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 5, new MockRaftActorContext.MockPayload("5"))); + replicatedLog.append(new SimpleReplicatedLogEntry(0, 1, new MockRaftActorContext.MockPayload("0"))); + replicatedLog.append(new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1"))); + replicatedLog.append(new SimpleReplicatedLogEntry(2, 1, new MockRaftActorContext.MockPayload("2"))); + replicatedLog.append(new SimpleReplicatedLogEntry(3, 1, new MockRaftActorContext.MockPayload("3"))); + replicatedLog.append(new SimpleReplicatedLogEntry(4, 1, new MockRaftActorContext.MockPayload("4"))); + replicatedLog.append(new SimpleReplicatedLogEntry(5, 1, new MockRaftActorContext.MockPayload("5"))); sendMessageToSupport(new ApplyJournalEntries(2)); @@ -133,7 +165,7 @@ public class RaftActorRecoverySupportTest { InOrder inOrder = Mockito.inOrder(mockCohort); inOrder.verify(mockCohort).startLogRecoveryBatch(5); - for(int i = 0; i < replicatedLog.size() - 1; i++) { + for (int i = 0; i < replicatedLog.size() - 1; i++) { inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData()); } @@ -145,44 +177,65 @@ public class RaftActorRecoverySupportTest { } @Test - public void testOnApplyLogEntries() { + public void testIncrementalRecovery() { + int recoverySnapshotInterval = 3; + int numberOfEntries = 5; + configParams.setRecoverySnapshotIntervalSeconds(recoverySnapshotInterval); + Consumer> mockSnapshotConsumer = mock(Consumer.class); + context.getSnapshotManager().setCreateSnapshotConsumer(mockSnapshotConsumer); + + ScheduledExecutorService applyEntriesExecutor = Executors.newSingleThreadScheduledExecutor(); ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 0, new MockRaftActorContext.MockPayload("0"))); - sendMessageToSupport(new ApplyLogEntries(0)); + for (int i = 0; i <= numberOfEntries; i++) { + replicatedLog.append(new SimpleReplicatedLogEntry(i, 1, + new MockRaftActorContext.MockPayload(String.valueOf(i)))); + } - assertEquals("Last applied", 0, context.getLastApplied()); - assertEquals("Commit index", 0, context.getCommitIndex()); + AtomicInteger entryCount = new AtomicInteger(); + ScheduledFuture applyEntriesFuture = applyEntriesExecutor.scheduleAtFixedRate(() -> { + int run = entryCount.getAndIncrement(); + LOG.info("Sending entry number {}", run); + sendMessageToSupport(new ApplyJournalEntries(run)); + }, 0, 1, TimeUnit.SECONDS); + + ScheduledFuture canceller = applyEntriesExecutor.schedule(() -> applyEntriesFuture.cancel(false), + numberOfEntries, TimeUnit.SECONDS); + try { + canceller.get(); + verify(mockSnapshotConsumer, times(1)).accept(any()); + applyEntriesExecutor.shutdown(); + } catch (InterruptedException | ExecutionException e) { + Assert.fail(); + } } @Test public void testOnSnapshotOffer() { ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 2, new MockRaftActorContext.MockPayload("2"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 3, new MockRaftActorContext.MockPayload("3"))); + replicatedLog.append(new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1"))); + replicatedLog.append(new SimpleReplicatedLogEntry(2, 1, new MockRaftActorContext.MockPayload("2"))); + replicatedLog.append(new SimpleReplicatedLogEntry(3, 1, new MockRaftActorContext.MockPayload("3"))); - byte[] snapshotBytes = {1,2,3,4,5}; + ReplicatedLogEntry unAppliedEntry1 = new SimpleReplicatedLogEntry(4, 1, + new MockRaftActorContext.MockPayload("4", 4)); - ReplicatedLogEntry unAppliedEntry1 = new MockRaftActorContext.MockReplicatedLogEntry(1, - 4, new MockRaftActorContext.MockPayload("4", 4)); + ReplicatedLogEntry unAppliedEntry2 = new SimpleReplicatedLogEntry(5, 1, + new MockRaftActorContext.MockPayload("5", 5)); - ReplicatedLogEntry unAppliedEntry2 = new MockRaftActorContext.MockReplicatedLogEntry(1, - 5, new MockRaftActorContext.MockPayload("5", 5)); + long lastAppliedDuringSnapshotCapture = 3; + long lastIndexDuringSnapshotCapture = 5; + long electionTerm = 2; + String electionVotedFor = "member-2"; - int lastAppliedDuringSnapshotCapture = 3; - int lastIndexDuringSnapshotCapture = 5; - - Snapshot snapshot = Snapshot.create(snapshotBytes, Arrays.asList(unAppliedEntry1, unAppliedEntry2), - lastIndexDuringSnapshotCapture, 1, lastAppliedDuringSnapshotCapture, 1); + MockSnapshotState snapshotState = new MockSnapshotState(Arrays.asList(new MockPayload("1"))); + Snapshot snapshot = Snapshot.create(snapshotState, + Arrays.asList(unAppliedEntry1, unAppliedEntry2), lastIndexDuringSnapshotCapture, 1, + lastAppliedDuringSnapshotCapture, 1, electionTerm, electionVotedFor, null); SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345); - SnapshotOffer snapshotOffer = new SnapshotOffer(metadata , snapshot); + SnapshotOffer snapshotOffer = new SnapshotOffer(metadata, snapshot); sendMessageToSupport(snapshotOffer); @@ -193,17 +246,18 @@ public class RaftActorRecoverySupportTest { assertEquals("Commit index", lastAppliedDuringSnapshotCapture, context.getCommitIndex()); assertEquals("Snapshot term", 1, context.getReplicatedLog().getSnapshotTerm()); assertEquals("Snapshot index", lastAppliedDuringSnapshotCapture, context.getReplicatedLog().getSnapshotIndex()); + assertEquals("Election term", electionTerm, context.getTermInformation().getCurrentTerm()); + assertEquals("Election votedFor", electionVotedFor, context.getTermInformation().getVotedFor()); + assertFalse("Dynamic server configuration", context.isDynamicServerConfigurationInUse()); - verify(mockCohort).applyRecoverySnapshot(snapshotBytes); + verify(mockCohort).applyRecoverySnapshot(snapshotState); } @Test public void testOnRecoveryCompletedWithRemainingBatch() { ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 0, new MockRaftActorContext.MockPayload("0"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1"))); + replicatedLog.append(new SimpleReplicatedLogEntry(0, 1, new MockRaftActorContext.MockPayload("0"))); + replicatedLog.append(new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1"))); sendMessageToSupport(new ApplyJournalEntries(1)); @@ -215,12 +269,12 @@ public class RaftActorRecoverySupportTest { InOrder inOrder = Mockito.inOrder(mockCohort); inOrder.verify(mockCohort).startLogRecoveryBatch(anyInt()); - for(int i = 0; i < replicatedLog.size(); i++) { + for (int i = 0; i < replicatedLog.size(); i++) { inOrder.verify(mockCohort).appendRecoveredLogEntry(replicatedLog.get(i).getData()); } inOrder.verify(mockCohort).applyCurrentLogRecoveryBatch(); - + inOrder.verify(mockCohort).getRestoreFromSnapshot(); inOrder.verifyNoMoreInteractions(); } @@ -228,34 +282,16 @@ public class RaftActorRecoverySupportTest { public void testOnRecoveryCompletedWithNoRemainingBatch() { sendMessageToSupport(RecoveryCompleted.getInstance(), true); + verify(mockCohort).getRestoreFromSnapshot(); verifyNoMoreInteractions(mockCohort); } - @Test - public void testOnDeprecatedDeleteEntries() { - ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 0, new MockRaftActorContext.MockPayload("0"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 2, new MockRaftActorContext.MockPayload("2"))); - - sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(1)); - - assertEquals("Journal log size", 1, context.getReplicatedLog().size()); - assertEquals("Last index", 0, context.getReplicatedLog().lastIndex()); - } - @Test public void testOnDeleteEntries() { ReplicatedLog replicatedLog = context.getReplicatedLog(); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 0, new MockRaftActorContext.MockPayload("0"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 1, new MockRaftActorContext.MockPayload("1"))); - replicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, - 2, new MockRaftActorContext.MockPayload("2"))); + replicatedLog.append(new SimpleReplicatedLogEntry(0, 1, new MockRaftActorContext.MockPayload("0"))); + replicatedLog.append(new SimpleReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("1"))); + replicatedLog.append(new SimpleReplicatedLogEntry(2, 1, new MockRaftActorContext.MockPayload("2"))); sendMessageToSupport(new DeleteEntries(1)); @@ -273,25 +309,26 @@ public class RaftActorRecoverySupportTest { } @Test - public void testRecoveryWithPersistenceDisabled() { + public void testDataRecoveredWithPersistenceDisabled() { + doNothing().when(mockCohort).applyRecoverySnapshot(any()); doReturn(false).when(mockPersistence).isRecoveryApplicable(); + doReturn(10L).when(mockPersistentProvider).getLastSequenceNumber(); - Snapshot snapshot = Snapshot.create(new byte[]{1}, Collections.emptyList(), 3, 1, 3, 1); + Snapshot snapshot = Snapshot.create(new MockSnapshotState(Arrays.asList(new MockPayload("1"))), + Collections.emptyList(), 3, 1, 3, 1, -1, null, null); SnapshotOffer snapshotOffer = new SnapshotOffer(new SnapshotMetadata("test", 6, 12345), snapshot); sendMessageToSupport(snapshotOffer); - sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1, - 4, new MockRaftActorContext.MockPayload("4"))); - sendMessageToSupport(new MockRaftActorContext.MockReplicatedLogEntry(1, - 5, new MockRaftActorContext.MockPayload("5"))); + sendMessageToSupport(new UpdateElectionTerm(5, "member2")); + + sendMessageToSupport(new SimpleReplicatedLogEntry(4, 1, new MockRaftActorContext.MockPayload("4"))); + sendMessageToSupport(new SimpleReplicatedLogEntry(5, 1, new MockRaftActorContext.MockPayload("5"))); sendMessageToSupport(new ApplyJournalEntries(4)); sendMessageToSupport(new DeleteEntries(5)); - sendMessageToSupport(new org.opendaylight.controller.cluster.raft.RaftActor.DeleteEntries(5)); - assertEquals("Journal log size", 0, context.getReplicatedLog().size()); assertEquals("Last index", -1, context.getReplicatedLog().lastIndex()); assertEquals("Last applied", -1, context.getLastApplied()); @@ -299,13 +336,119 @@ public class RaftActorRecoverySupportTest { assertEquals("Snapshot term", -1, context.getReplicatedLog().getSnapshotTerm()); assertEquals("Snapshot index", -1, context.getReplicatedLog().getSnapshotIndex()); + assertEquals("Current term", 5, context.getTermInformation().getCurrentTerm()); + assertEquals("Voted For", "member2", context.getTermInformation().getVotedFor()); + + sendMessageToSupport(RecoveryCompleted.getInstance(), true); + + verify(mockCohort, never()).applyRecoverySnapshot(any()); + verify(mockCohort, never()).getRestoreFromSnapshot(); + verifyNoMoreInteractions(mockCohort); + + verify(mockPersistentProvider).deleteMessages(10L); + } + + static UpdateElectionTerm updateElectionTerm(final long term, final String votedFor) { + return ArgumentMatchers.argThat(other -> + term == other.getCurrentTerm() && votedFor.equals(other.getVotedFor())); + } + + @Test + public void testNoDataRecoveredWithPersistenceDisabled() { + doReturn(false).when(mockPersistence).isRecoveryApplicable(); + sendMessageToSupport(new UpdateElectionTerm(5, "member2")); - assertEquals("Current term", 0, context.getTermInformation().getCurrentTerm()); - assertEquals("Voted For", null, context.getTermInformation().getVotedFor()); + assertEquals("Current term", 5, context.getTermInformation().getCurrentTerm()); + assertEquals("Voted For", "member2", context.getTermInformation().getVotedFor()); sendMessageToSupport(RecoveryCompleted.getInstance(), true); - verifyNoMoreInteractions(mockCohort); + verify(mockCohort).getRestoreFromSnapshot(); + verifyNoMoreInteractions(mockCohort, mockPersistentProvider); + } + + @Test + public void testServerConfigurationPayloadApplied() { + String follower1 = "follower1"; + String follower2 = "follower2"; + String follower3 = "follower3"; + + context.addToPeers(follower1, null, VotingState.VOTING); + context.addToPeers(follower2, null, VotingState.VOTING); + + //add new Server + ServerConfigurationPayload obj = new ServerConfigurationPayload(Arrays.asList( + new ServerInfo(localId, true), + new ServerInfo(follower1, true), + new ServerInfo(follower2, false), + new ServerInfo(follower3, true))); + + sendMessageToSupport(new SimpleReplicatedLogEntry(0, 1, obj)); + + //verify new peers + assertTrue("Dynamic server configuration", context.isDynamicServerConfigurationInUse()); + assertEquals("New peer Ids", Sets.newHashSet(follower1, follower2, follower3), + Sets.newHashSet(context.getPeerIds())); + assertEquals("follower1 isVoting", true, context.getPeerInfo(follower1).isVoting()); + assertEquals("follower2 isVoting", false, context.getPeerInfo(follower2).isVoting()); + assertEquals("follower3 isVoting", true, context.getPeerInfo(follower3).isVoting()); + + sendMessageToSupport(new ApplyJournalEntries(0)); + + verify(mockCohort, never()).startLogRecoveryBatch(anyInt()); + verify(mockCohort, never()).appendRecoveredLogEntry(any(Payload.class)); + + //remove existing follower1 + obj = new ServerConfigurationPayload(Arrays.asList( + new ServerInfo(localId, true), + new ServerInfo("follower2", true), + new ServerInfo("follower3", true))); + + sendMessageToSupport(new SimpleReplicatedLogEntry(1, 1, obj)); + + //verify new peers + assertTrue("Dynamic server configuration", context.isDynamicServerConfigurationInUse()); + assertEquals("New peer Ids", Sets.newHashSet(follower2, follower3), Sets.newHashSet(context.getPeerIds())); + } + + @Test + public void testServerConfigurationPayloadAppliedWithPersistenceDisabled() { + doReturn(false).when(mockPersistence).isRecoveryApplicable(); + + String follower = "follower"; + ServerConfigurationPayload obj = new ServerConfigurationPayload(Arrays.asList( + new ServerInfo(localId, true), new ServerInfo(follower, true))); + + sendMessageToSupport(new SimpleReplicatedLogEntry(0, 1, obj)); + + //verify new peers + assertEquals("New peer Ids", Sets.newHashSet(follower), Sets.newHashSet(context.getPeerIds())); + } + + @Test + public void testOnSnapshotOfferWithServerConfiguration() { + long electionTerm = 2; + String electionVotedFor = "member-2"; + ServerConfigurationPayload serverPayload = new ServerConfigurationPayload(Arrays.asList( + new ServerInfo(localId, true), + new ServerInfo("follower1", true), + new ServerInfo("follower2", true))); + + MockSnapshotState snapshotState = new MockSnapshotState(Arrays.asList(new MockPayload("1"))); + Snapshot snapshot = Snapshot.create(snapshotState, Collections.emptyList(), + -1, -1, -1, -1, electionTerm, electionVotedFor, serverPayload); + + SnapshotMetadata metadata = new SnapshotMetadata("test", 6, 12345); + SnapshotOffer snapshotOffer = new SnapshotOffer(metadata, snapshot); + + sendMessageToSupport(snapshotOffer); + + assertEquals("Journal log size", 0, context.getReplicatedLog().size()); + assertEquals("Election term", electionTerm, context.getTermInformation().getCurrentTerm()); + assertEquals("Election votedFor", electionVotedFor, context.getTermInformation().getVotedFor()); + assertTrue("Dynamic server configuration", context.isDynamicServerConfigurationInUse()); + assertEquals("Peer List", Sets.newHashSet("follower1", "follower2"), + Sets.newHashSet(context.getPeerIds())); } -} +} \ No newline at end of file