diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java new file mode 100755 index 00000000000..9b67319827f --- /dev/null +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/PrematureOperationReceiptTest.java @@ -0,0 +1,64 @@ +package com.sap.sailing.server.replication.test; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard; +import com.sap.sailing.server.replication.ReplicationMasterDescriptor; +import com.sap.sailing.server.replication.impl.Replicator; + +public class PrematureOperationReceiptTest extends AbstractServerReplicationTest { + private Replicator replicator; + private ReplicationServiceTestImpl replicationService; + + /** + * Drops the test DB. Sets up master and replica, starts the JMS message broker and registers the replica with the master. + */ + @Before + @Override + public void setUp() throws Exception { + Pair result = basicSetUp(true, /* master=null means create a new one */ null, + /* replica=null means create a new one */ null); + replicationService = result.getA(); + replicator = replicationService.startToReplicateFromButDontYetFetchInitialLoad(result.getB(), /* startReplicatorSuspended */ true); + } + + /** + * If JMS replication starts and the initial load hasn't yet been fully received and installed into the server, + * the JMS-transported operations may not yet be applicable on the replica's side. This test forces such a situation + * by first creating a leaderboard, then starting the replication but holding back the fetching of the initial load, + * then creates a race column in this leaderboard which will be sent as an operation through JMS to the replica which + * hasn't yet received the initial load with the leaderboard. Trying to apply will fail unless the replicator is + * started in suspended mode and resumed only after the initial load was successfully installed. + */ + @Test + public void testRaceColumnInLeaderboardReplicationAfterInitialLoad() throws InterruptedException, ClassNotFoundException, IOException { + final String leaderboardName = "My new leaderboard"; + final int[] discardThresholds = new int[] { 17, 23 }; + CreateFlexibleLeaderboard createTestLeaderboard = new CreateFlexibleLeaderboard(leaderboardName, discardThresholds); + assertNull(master.getLeaderboardByName(leaderboardName)); + master.apply(createTestLeaderboard); + final Leaderboard masterLeaderboard = master.getLeaderboardByName(leaderboardName); + assertNotNull(masterLeaderboard); + Thread.sleep(1000); // wait 1s for JMS to deliver the message and the message to be applied + final Leaderboard nonExistingReplicaLeaderboard = replica.getLeaderboardByName(leaderboardName); + assertNull(nonExistingReplicaLeaderboard); // because replicator is still suspended + replicationService.initialLoad(); + replicator.setSuspended(false); + synchronized (replicator) { + while (!replicator.isQueueEmpty()) { + replicator.wait(); + } + } + final Leaderboard replicaLeaderboard = replica.getLeaderboardByName(leaderboardName); + assertNotNull(replicaLeaderboard); + } + +}