/**
* Tests that a follower takes a snapshot of its state machine and compacts its log.
*/
public void testFollowerTakesSnapshotAndCompactsLog() {
Protocol<Member> protocol = new LocalProtocol();
TestCluster cluster = new TestCluster();
TestNode node1 = new TestNode()
.withCluster("foo", "bar", "baz")
.withProtocol(protocol)
.withConfig(new CopycatConfig().withMaxLogSize(512))
.withTerm(3)
.withLeader("baz")
.withStateMachine(new TestStateMachine())
.withLog(new TestLog()
.withEntry(new ConfigurationEntry(1, new ClusterConfig()
.withLocalMember(new Member("foo"))
.withRemoteMembers(new Member("bar"), new Member("baz"))))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz"))))
.withState(CopycatState.FOLLOWER)
.withCommitIndex(6)
.withLastApplied(6);
cluster.addNode(node1);
TestNode node2 = new TestNode()
.withCluster("bar", "foo", "baz")
.withProtocol(protocol)
.withConfig(new CopycatConfig().withMaxLogSize(512))
.withTerm(3)
.withLeader("baz")
.withStateMachine(new TestStateMachine())
.withLog(new TestLog()
.withEntry(new ConfigurationEntry(1, new ClusterConfig()
.withLocalMember(new Member("bar"))
.withRemoteMembers(new Member("foo"), new Member("baz"))))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz"))))
.withState(CopycatState.FOLLOWER)
.withCommitIndex(6)
.withLastApplied(6);
cluster.addNode(node2);
TestNode node3 = new TestNode()
.withCluster("baz", "bar", "foo")
.withProtocol(protocol)
.withConfig(new CopycatConfig().withMaxLogSize(512))
.withTerm(3)
.withLeader("baz")
.withStateMachine(new TestStateMachine())
.withLog(new TestLog()
.withEntry(new ConfigurationEntry(1, new ClusterConfig()
.withLocalMember(new Member("baz"))
.withRemoteMembers(new Member("foo"), new Member("bar"))))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(1, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz")))
.withEntry(new OperationEntry(2, "foo", Arrays.asList("bar", "baz"))))
.withState(CopycatState.LEADER)
.withCommitIndex(6)
.withLastApplied(6);
cluster.addNode(node3);
cluster.start();
node1.stateMachine().data("Hello world!");
AtomicBoolean compacted = new AtomicBoolean();
node1.log().on().compacted(() -> compacted.set(true));
node1.instance().submit("command", "Hello world!").thenRun(() -> {
node1.instance().submit("command", "Hello world!").thenRun(() -> {
node1.instance().submit("command", "Hello world!").thenRun(() -> {
node1.instance().submit("command", "Hello world!").thenRun(() -> {
node1.instance().submit("command", "Hello world!").thenRun(() -> {
});
});
});
});
});
Assert.assertTrue(compacted.get());
Entry firstEntry = node1.log().firstEntry();
Assert.assertTrue(firstEntry instanceof SnapshotEntry);
Assert.assertEquals("Hello world!", new String(((SnapshotEntry) firstEntry).data()));
cluster.stop();
}