From 0a8af6fbb7416ab214bca6ceef16adcb1cbe5f19 Mon Sep 17 00:00:00 2001 From: Fredrik Teschke Date: Fri, 5 Dec 2014 20:18:37 +0100 Subject: [PATCH] first testing of regattalog replication --- .../test/AbstractLogReplicationTest.java | 120 ++++++++++++++++++ .../test/RaceLogReplicationTest.java | 103 +-------------- .../test/RegattaLogReplicationTest.java | 107 ++++++++++++++++ 3 files changed, 229 insertions(+), 101 deletions(-) create mode 100644 java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java create mode 100644 java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaLogReplicationTest.java diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java new file mode 100644 index 00000000000..f913d8cd1e6 --- /dev/null +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/AbstractLogReplicationTest.java @@ -0,0 +1,120 @@ +package com.sap.sailing.server.replication.test; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.UUID; + +import com.sap.sailing.domain.abstractlog.AbstractLog; +import com.sap.sailing.domain.abstractlog.AbstractLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLog; +import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; +import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.base.Series; +import com.sap.sailing.domain.common.Color; +import com.sap.sailing.domain.common.RegattaName; +import com.sap.sailing.domain.common.dto.FleetDTO; +import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; +import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO; +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; +import com.sap.sailing.domain.leaderboard.impl.LowPoint; +import com.sap.sailing.domain.persistence.MongoObjectFactory; +import com.sap.sailing.domain.persistence.PersistenceFactory; +import com.sap.sailing.domain.racelog.RaceLogIdentifier; +import com.sap.sailing.server.impl.RacingEventServiceImpl; +import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta; +import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard; +import com.sap.sse.common.Util; + +public abstract class AbstractLogReplicationTest, EventT extends AbstractLogEvent, VisitorT> + extends AbstractServerReplicationTest { + protected static final String BOAT_CLASS_NAME_49er = "49er"; + + /** + * Uses a new master that loads the existing regatta and race log to append an event to the race log. This will store it to the DB so that if the original + * master re-loads the race log it should see the new race log event. + */ + protected void addEventToDB(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent createRaceStatusEvent, String regattaName, String raceColumnName, String fleetName) { + final MongoObjectFactory defaultMongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(); + defaultMongoObjectFactory.getDatabase().getLastError(); // wait for regatta write operation to complete + final RacingEventServiceImpl temporaryMaster = createNewMaster(); + Regatta regatta = temporaryMaster.getRegatta(new RegattaName(regattaName+" ("+BOAT_CLASS_NAME_49er+")")); + Series series = regatta.getSeries().iterator().next(); + RaceLog masterLog = series.getRaceColumnByName(raceColumnName).getRaceLog(series.getFleetByName(fleetName)); + masterLog.add(createRaceStatusEvent); + defaultMongoObjectFactory.getDatabase().getLastError(); // wait for write operation to complete + } + + /** + * Validation is done based only on the identifier and type of the {@link RaceLogEvent}s. + */ + protected void addAndValidateEventIds(LogT masterLog, LogT replicaLog, @SuppressWarnings("unchecked") EventT... addedEvents) throws InterruptedException { + // 1. Check state of replica after initial load... + assertEqualsOnId(masterLog, replicaLog); + // 2. ... add all incoming events... + for (EventT event : addedEvents) { + masterLog.add(event); + } + // 3. ... and give replication some time to deliver messages. + Thread.sleep(3000); + assertEqualsOnId(masterLog, replicaLog); + } + + /** + * Equality of the events is done based only on the identifier and type. + */ + protected void assertEqualsOnId(LogT masterLog, LogT replicaLog) { + replicaLog.lockForRead(); + try { + masterLog.lockForRead(); + try { + assertEqualsOnId(masterLog.getRawFixes(), replicaLog.getRawFixes()); + } finally { + masterLog.unlockAfterRead(); + } + } finally { + replicaLog.unlockAfterRead(); + } + } + + /** + * Equality of the events is done based only on the {@link RaceLogEvent}'s identifier and type. + */ + private void assertEqualsOnId(Iterable expectedEvents, Iterable actualEvents) { + List expectedCollection = new ArrayList<>(); + Util.addAll(expectedEvents, expectedCollection); + List actualCollection = new ArrayList<>(); + Util.addAll(actualEvents, actualCollection); + assertEquals(Util.size(expectedEvents), Util.size(actualEvents)); + for (int i = 0; i < expectedCollection.size(); i++) { + assertEquals(expectedCollection.get(i).getClass(), actualCollection.get(i).getClass()); + assertEquals(expectedCollection.get(i).getId(), actualCollection.get(i).getId()); + } + } + + protected Regatta setupRegatta(final String regattaName, String seriesName, String fleetName, String boatClassName) { + LinkedHashMap seriesCreationParameters = new LinkedHashMap<>(); + SeriesCreationParametersDTO creationParametersForDefaultSeries = new SeriesCreationParametersDTO( + Arrays.asList(new FleetDTO[] { new FleetDTO(fleetName, 0, Color.BLACK), }), /* medal */false, /* startsWithZero */ + false, /* firstColumnIsNonDiscardableCarryForward */false, /* discardingThresholds */new int[0], /* hasSplitFleetContiguousScoring */ + false); + seriesCreationParameters.put(seriesName, creationParametersForDefaultSeries); + // 1. Install some race column on master... + RegattaCreationParametersDTO regattaCreationParams = new RegattaCreationParametersDTO(seriesCreationParameters); + AddSpecificRegatta addRegattaOperation = new AddSpecificRegatta(regattaName, boatClassName, + /*startDate*/ null, /*endDate*/ null, /* regatta ID */ UUID.randomUUID(), regattaCreationParams, /* persistent */ true, + new LowPoint(), /* default course area ID */ UUID.randomUUID(), /* useStartTimeInference */ true); + return master.apply(addRegattaOperation); + } + + protected FlexibleLeaderboard setupFlexibleLeaderboard(final String leaderboardName) { + CreateFlexibleLeaderboard createTestLeaderboard = new CreateFlexibleLeaderboard(leaderboardName, leaderboardName, new int[] { 19, 44 }, new LowPoint(), null); + FlexibleLeaderboard masterLeaderboard = master.apply(createTestLeaderboard); + return masterLeaderboard; + } + +} \ No newline at end of file diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java index 1be704d2b71..9660d8b92f3 100755 --- a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RaceLogReplicationTest.java @@ -4,10 +4,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; import java.util.UUID; import junit.framework.Assert; @@ -22,6 +18,7 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog; import com.sap.sailing.domain.abstractlog.race.RaceLogCourseDesignChangedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory; +import com.sap.sailing.domain.abstractlog.race.RaceLogEventVisitor; import com.sap.sailing.domain.abstractlog.race.RaceLogRaceStatusEvent; import com.sap.sailing.domain.base.ControlPointWithTwoMarks; import com.sap.sailing.domain.base.CourseBase; @@ -35,27 +32,15 @@ import com.sap.sailing.domain.base.impl.CourseDataImpl; import com.sap.sailing.domain.base.impl.MarkImpl; import com.sap.sailing.domain.base.impl.RegattaImpl; import com.sap.sailing.domain.base.impl.WaypointImpl; -import com.sap.sailing.domain.common.Color; import com.sap.sailing.domain.common.MarkType; import com.sap.sailing.domain.common.PassingInstruction; -import com.sap.sailing.domain.common.RegattaName; -import com.sap.sailing.domain.common.dto.FleetDTO; -import com.sap.sailing.domain.common.dto.RegattaCreationParametersDTO; -import com.sap.sailing.domain.common.dto.SeriesCreationParametersDTO; import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus; import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; -import com.sap.sailing.domain.leaderboard.impl.LowPoint; -import com.sap.sailing.domain.persistence.MongoObjectFactory; -import com.sap.sailing.domain.persistence.PersistenceFactory; -import com.sap.sailing.domain.racelog.RaceLogIdentifier; import com.sap.sailing.server.RacingEventService; -import com.sap.sailing.server.impl.RacingEventServiceImpl; import com.sap.sailing.server.operationaltransformation.AddColumnToLeaderboard; import com.sap.sailing.server.operationaltransformation.AddColumnToSeries; -import com.sap.sailing.server.operationaltransformation.AddSpecificRegatta; -import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard; import com.sap.sailing.server.operationaltransformation.CreateRegattaLeaderboard; import com.sap.sailing.server.operationaltransformation.RenameLeaderboard; import com.sap.sse.common.Util; @@ -63,8 +48,7 @@ import com.sap.sse.common.Util.Pair; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.replication.ReplicationMasterDescriptor; -public class RaceLogReplicationTest extends AbstractServerReplicationTest { - private static final String BOAT_CLASS_NAME_49er = "49er"; +public class RaceLogReplicationTest extends AbstractLogReplicationTest { private Pair, ReplicationMasterDescriptor> replicationDescriptorPair; @@ -259,68 +243,6 @@ public class RaceLogReplicationTest extends AbstractServerReplicationTest { assertNotNull(lastEventReadFromMasterLog); assertEqualsOnId(reloadedMasterLog, getReplicaLog(seriesName, fleetName, raceColumnName, masterRegatta)); } - - /** - * Uses a new master that loads the existing regatta and race log to append an event to the race log. This will store it to the DB so that if the original - * master re-loads the race log it should see the new race log event. - */ - private void addEventToDB(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent createRaceStatusEvent, String regattaName, String raceColumnName, String fleetName) { - final MongoObjectFactory defaultMongoObjectFactory = PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(); - defaultMongoObjectFactory.getDatabase().getLastError(); // wait for regatta write operation to complete - final RacingEventServiceImpl temporaryMaster = createNewMaster(); - Regatta regatta = temporaryMaster.getRegatta(new RegattaName(regattaName+" ("+BOAT_CLASS_NAME_49er+")")); - Series series = regatta.getSeries().iterator().next(); - RaceLog masterLog = series.getRaceColumnByName(raceColumnName).getRaceLog(series.getFleetByName(fleetName)); - masterLog.add(createRaceStatusEvent); - defaultMongoObjectFactory.getDatabase().getLastError(); // wait for write operation to complete - } - - /** - * Validation is done based only on the identifier and type of the {@link RaceLogEvent}s. - */ - private void addAndValidateEventIds(RaceLog masterLog, RaceLog replicaLog, RaceLogEvent... addedEvents) throws InterruptedException { - // 1. Check state of replica after initial load... - assertEqualsOnId(masterLog, replicaLog); - // 2. ... add all incoming events... - for (RaceLogEvent event : addedEvents) { - masterLog.add(event); - } - // 3. ... and give replication some time to deliver messages. - Thread.sleep(3000); - assertEqualsOnId(masterLog, replicaLog); - } - - /** - * Equality of the events is done based only on the identifier and type. - */ - private void assertEqualsOnId(RaceLog masterLog, RaceLog replicaLog) { - replicaLog.lockForRead(); - try { - masterLog.lockForRead(); - try { - assertEqualsOnId(masterLog.getRawFixes(), replicaLog.getRawFixes()); - } finally { - masterLog.unlockAfterRead(); - } - } finally { - replicaLog.unlockAfterRead(); - } - } - - /** - * Equality of the events is done based only on the {@link RaceLogEvent}'s identifier and type. - */ - private void assertEqualsOnId(Iterable expectedEvents, Iterable actualEvents) { - List expectedCollection = new ArrayList<>(); - Util.addAll(expectedEvents, expectedCollection); - List actualCollection = new ArrayList<>(); - Util.addAll(actualEvents, actualCollection); - assertEquals(Util.size(expectedEvents), Util.size(actualEvents)); - for (int i = 0; i < expectedCollection.size(); i++) { - assertEquals(expectedCollection.get(i).getClass(), actualCollection.get(i).getClass()); - assertEquals(expectedCollection.get(i).getId(), actualCollection.get(i).getId()); - } - } private RaceLog getReplicaLog(final String fleetName, final String raceColumnName, Leaderboard leaderboard) { Leaderboard replicaLeaderboard = replica.getLeaderboardByName(leaderboard.getName()); @@ -337,21 +259,6 @@ public class RaceLogReplicationTest extends AbstractServerReplicationTest { return replicaColumn.getRaceLog(replicaFleet); } - private Regatta setupRegatta(final String regattaName, String seriesName, String fleetName, String boatClassName) { - LinkedHashMap seriesCreationParameters = new LinkedHashMap<>(); - SeriesCreationParametersDTO creationParametersForDefaultSeries = new SeriesCreationParametersDTO( - Arrays.asList(new FleetDTO[] { new FleetDTO(fleetName, 0, Color.BLACK), }), /* medal */false, /* startsWithZero */ - false, /* firstColumnIsNonDiscardableCarryForward */false, /* discardingThresholds */new int[0], /* hasSplitFleetContiguousScoring */ - false); - seriesCreationParameters.put(seriesName, creationParametersForDefaultSeries); - // 1. Install some race column on master... - RegattaCreationParametersDTO regattaCreationParams = new RegattaCreationParametersDTO(seriesCreationParameters); - AddSpecificRegatta addRegattaOperation = new AddSpecificRegatta(regattaName, boatClassName, - /*startDate*/ null, /*endDate*/ null, /* regatta ID */ UUID.randomUUID(), regattaCreationParams, /* persistent */ true, - new LowPoint(), /* default course area ID */ UUID.randomUUID(), /* useStartTimeInference */ true); - return master.apply(addRegattaOperation); - } - private RaceLog setupRaceColumn(final Regatta regatta, final String seriesName, final String raceColumnName, final String fleetName) { AddColumnToSeries addColumnOperation = new AddColumnToSeries(regatta.getRegattaIdentifier(), seriesName, raceColumnName); @@ -360,12 +267,6 @@ public class RaceLogReplicationTest extends AbstractServerReplicationTest { return raceColumn.getRaceLog(masterFleet); } - private FlexibleLeaderboard setupFlexibleLeaderboard(final String leaderboardName) { - CreateFlexibleLeaderboard createTestLeaderboard = new CreateFlexibleLeaderboard(leaderboardName, leaderboardName, new int[] { 19, 44 }, new LowPoint(), null); - FlexibleLeaderboard masterLeaderboard = master.apply(createTestLeaderboard); - return masterLeaderboard; - } - private RaceLog setupRaceColumn(final String leaderboardName, final String fleetName, final String raceColumnName) { AddColumnToLeaderboard addColumnOperation = new AddColumnToLeaderboard(raceColumnName, leaderboardName, false); RaceColumn masterRaceColumn = master.apply(addColumnOperation); diff --git a/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaLogReplicationTest.java b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaLogReplicationTest.java new file mode 100644 index 00000000000..6cb31cbd304 --- /dev/null +++ b/java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/RegattaLogReplicationTest.java @@ -0,0 +1,107 @@ +package com.sap.sailing.server.replication.test; + +import java.io.IOException; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor; +import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLog; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEvent; +import com.sap.sailing.domain.abstractlog.regatta.RegattaLogEventVisitor; +import com.sap.sailing.domain.abstractlog.regatta.events.impl.RegattaLogRegisterCompetitorEventImpl; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.base.impl.RegattaImpl; +import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.common.TimePoint; +import com.sap.sse.common.Util.Pair; +import com.sap.sse.common.impl.MillisecondsTimePoint; +import com.sap.sse.replication.ReplicationMasterDescriptor; + +public class RegattaLogReplicationTest extends + AbstractLogReplicationTest { + + private Pair, ReplicationMasterDescriptor> replicationDescriptorPair; + + private RegattaLogEvent regattaLogEvent; +// private RegattaLogEvent anotherRegattaLogEvent; + private AbstractLogEventAuthor author = new LogEventAuthorImpl("Test Author", 1); + + private TimePoint t(long millis) { + return new MillisecondsTimePoint(millis); + } + + @Before + @Override + public void setUp() throws Exception { + regattaLogEvent = new RegattaLogRegisterCompetitorEventImpl(t(0), author, t(0), 0, null); +// anotherRegattaLogEvent = new RegattaLogRegisterCompetitorEventImpl(t(1), author, t(1), 1, null); + try { + replicationDescriptorPair = basicSetUp(/* dropDB */ true, null, null); + } catch (Exception e) { + e.printStackTrace(); + tearDown(); + } + } + + @Test + public void testRegattaLogEmptyOnInitialLoad() throws ClassNotFoundException, IOException, InterruptedException { + final String regattaName = "Test"; + final String seriesName = "Default"; + final String fleetName = "Default"; + Regatta regatta = setupRegatta(RegattaImpl.getDefaultName(regattaName, BOAT_CLASS_NAME_49er), seriesName, fleetName, BOAT_CLASS_NAME_49er); + RegattaLog masterLog = regatta.getRegattaLog(); + replicationDescriptorPair.getA().startToReplicateFrom(replicationDescriptorPair.getB()); + RegattaLog replicaLog = getReplicaLog(regatta); + addAndValidateEventIds(masterLog, replicaLog); + } + + @Test + public void testRegattaLogStateOnInitialLoad() throws InterruptedException, ClassNotFoundException, IOException { + final String regattaName = "Test"; + final String seriesName = "Default"; + final String fleetName = "Default"; + Regatta regatta = setupRegatta(RegattaImpl.getDefaultName(regattaName, BOAT_CLASS_NAME_49er), seriesName, fleetName, BOAT_CLASS_NAME_49er); + RegattaLog masterLog = regatta.getRegattaLog(); + masterLog.add(regattaLogEvent); + replicationDescriptorPair.getA().startToReplicateFrom(replicationDescriptorPair.getB()); + RegattaLog replicaLog = getReplicaLog(regatta); + addAndValidateEventIds(masterLog, replicaLog); + } + + @Test + public void testRaceEventReplicationOnEmptyRegatta() throws ClassNotFoundException, IOException, InterruptedException { + final String regattaName = "Test"; + final String seriesName = "Default"; + final String fleetName = "Default"; + Regatta masterRegatta = setupRegatta(RegattaImpl.getDefaultName(regattaName, BOAT_CLASS_NAME_49er), seriesName, fleetName, BOAT_CLASS_NAME_49er); + RegattaLog masterLog = masterRegatta.getRegattaLog(); + masterLog.add(regattaLogEvent); + replicationDescriptorPair.getA().startToReplicateFrom(replicationDescriptorPair.getB()); + RegattaLog replicaLog = getReplicaLog(masterRegatta); + addAndValidateEventIds(masterLog, replicaLog, regattaLogEvent); + } + + @Test + public void testRaceEventReplicationOnEmptyFlexibleLeaderboard() throws ClassNotFoundException, IOException, InterruptedException { + final String leaderboardName = "Test"; + FlexibleLeaderboard masterLeaderboard = setupFlexibleLeaderboard(leaderboardName); + RegattaLog masterLog = masterLeaderboard.getRegattaLog(); + masterLog.add(regattaLogEvent); + replicationDescriptorPair.getA().startToReplicateFrom(replicationDescriptorPair.getB()); + RegattaLog replicaLog = getReplicaLog(masterLeaderboard); + addAndValidateEventIds(masterLog, replicaLog, regattaLogEvent); + } + + + private RegattaLog getReplicaLog(Leaderboard leaderboard) { + return ((FlexibleLeaderboard) replica.getLeaderboardByName(leaderboard.getName())).getRegattaLog(); + } + + private RegattaLog getReplicaLog(Regatta masterRegatta) { + return replica.getRegatta(masterRegatta.getRegattaIdentifier()).getRegattaLog(); + } +}