added a second OT test which folds a leaderboard column addition with a leaderboard removal

This commit is contained in:
Axel Uhl
2012-03-28 15:42:33 +02:00
parent 2e603bc6e3
commit ff23e68c9f
14 changed files with 171 additions and 114 deletions
@@ -9,8 +9,8 @@ public interface Transformer<O extends Operation<?>> {
* again.<p>
*
* If a resulting operation is supposed to not have any effects, return the
* {@link ClientServerOperationPair#getNoOp()} operation, but never <code>null</code>
* {@link AbstractRacingEventServiceOperation#getNoOp()} operation, but never <code>null</code>
* as any of the operations in the resulting pair.
*/
ClientServerOperationPair<O> transform(O clientOp, O serverOp);
ClientServerOperationPair<O> transform(O transformedOp, O unconfirmedOperation);
}
@@ -48,8 +48,8 @@ public class UnmergedOperationsQueue<O extends Operation<S>, S> {
*
* @param localOperationNumber starts with 0
*/
public synchronized void updateWithTransformed(int localOperationNumber, O transformedOperation) {
unmergedOperations.set(localOperationNumber-numberOfFirstInList, transformedOperation);
public synchronized void updateWithTransformed(int localOperationNumber, O operation) {
unmergedOperations.set(localOperationNumber-numberOfFirstInList, operation);
}
/**
@@ -76,7 +76,7 @@ public class UnmergedOperationsQueue<O extends Operation<S>, S> {
StringBuilder result = new StringBuilder();
result.append('[');
boolean first = true;
for (O op : unmergedOperations) {
for (Operation<S> op : unmergedOperations) {
if (!first) {
result.append(", ");
} else {
@@ -17,9 +17,11 @@ import com.sap.sailing.operationaltransformation.Peer.Role;
import com.sap.sailing.operationaltransformation.PeerImpl;
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.AddLeaderboard;
import com.sap.sailing.server.operationaltransformation.OperationalTransformer;
import com.sap.sailing.server.operationaltransformation.RacingEventServiceOperation;
import com.sap.sailing.server.operationaltransformation.RemoveLeaderboard;
public class OperationalTransformationTest {
private static final String LEADERBOARDNAME = "TESTBOARD";
@@ -48,9 +50,24 @@ public class OperationalTransformationTest {
RacingEventServiceOperation addLeaderboardOp = new AddLeaderboard(LEADERBOARDNAME, new int[] { 5 });
server.apply(addLeaderboardOp);
server.waitForNotRunning();
replica.waitForNotRunning();
Map<String, Leaderboard> replicaLeaderboards = racingEventServiceReplica.getLeaderboards();
assertEquals(2, replicaLeaderboards.size()); // expected to include the default leaderboard
assertEquals(new HashSet<String>(Arrays.asList(new String[] { DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, LEADERBOARDNAME })),
replicaLeaderboards.keySet());
assertEquals(racingEventServiceServer.getLeaderboards().keySet(), replicaLeaderboards.keySet());
}
@Test
public void testAddColumnToLeaderboardOnClientAndRemoveLeaderboardOnServer() {
RacingEventServiceOperation addLeaderboardColumn = new AddColumnToLeaderboard(
"newColumn", DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME, /* medalRace */ true);
server.apply(addLeaderboardColumn);
RacingEventServiceOperation removeDefaultLeaderboard = new RemoveLeaderboard(DefaultLeaderboardName.DEFAULT_LEADERBOARD_NAME);
replica.apply(removeDefaultLeaderboard);
server.waitForNotRunning();
replica.waitForNotRunning();
assertEquals(0, racingEventServiceReplica.getLeaderboards().size());
assertEquals(0, racingEventServiceServer.getLeaderboards().size());
}
}
@@ -1,25 +1,43 @@
package com.sap.sailing.server.operationaltransformation;
public abstract class AbstractLeaderboardColumnOperation extends AbstractRacingEventServiceOperation {
private final String leaderboardName;
public abstract class AbstractLeaderboardColumnOperation extends AbstractLeaderboardOperation {
private final String columnName;
public AbstractLeaderboardColumnOperation(String leaderboardName, String columnName) {
super();
this.leaderboardName = leaderboardName;
super(leaderboardName);
this.columnName = columnName;
}
public String getLeaderboardName() {
return leaderboardName;
}
public String getColumnName() {
return columnName;
}
protected boolean affectsSameColumn(AbstractLeaderboardColumnOperation other) {
return getLeaderboardName().equals(other.getLeaderboardName()) && getColumnName().equals(other.getColumnName());
return affectsSameLeaderboard(other) && getColumnName().equals(other.getColumnName());
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
// skip server's remove and hence only apply the client's remove operation
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
// skip client's remove and hence only apply the server's remove operation
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
}
@@ -0,0 +1,40 @@
package com.sap.sailing.server.operationaltransformation;
public abstract class AbstractLeaderboardOperation extends AbstractRacingEventServiceOperation {
private final String leaderboardName;
public AbstractLeaderboardOperation(String leaderboardName) {
super();
this.leaderboardName = leaderboardName;
}
protected String getLeaderboardName() {
return leaderboardName;
}
protected boolean affectsSameLeaderboard(AbstractLeaderboardOperation other) {
return getLeaderboardName().equals(other.getLeaderboardName());
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard) {
if (affectsSameLeaderboard(removeLeaderboard)) {
return AbstractRacingEventServiceOperation.getNoOp();
} else {
return this;
}
}
}
@@ -1,5 +1,8 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.server.RacingEventService;
/**
* Performs identical transformations for all operation types by simply returning the operation passed. Subclasses need
@@ -9,6 +12,26 @@ package com.sap.sailing.server.operationaltransformation;
*
*/
public abstract class AbstractRacingEventServiceOperation implements RacingEventServiceOperation {
@Override
public RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard) {
return removeLeaderboard;
}
@Override
public RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard) {
return removeLeaderboard;
}
@Override
public RacingEventServiceOperation transformAddLeaderboardClientOp(AddLeaderboard addLeaderboard) {
return addLeaderboard;
}
@Override
public RacingEventServiceOperation transformAddLeaderboardServerOp(AddLeaderboard addLeaderboard) {
return addLeaderboard;
}
@Override
public RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(
RenameLeaderboardColumn renameLeaderboardColumnClientOp) {
@@ -30,4 +53,23 @@ public abstract class AbstractRacingEventServiceOperation implements RacingEvent
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
return removeColumnFromLeaderboardClientOp;
}
public static RacingEventServiceOperation getNoOp() {
return new AbstractRacingEventServiceOperation() {
@Override
public RacingEventService applyTo(RacingEventService toState) {
return toState;
}
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp;
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp;
}
};
}
}
@@ -2,32 +2,28 @@ package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.server.RacingEventService;
public class AddLeaderboard extends AbstractRacingEventServiceOperation {
private final String leaderboardName;
public class AddLeaderboard extends AbstractLeaderboardOperation {
private final int[] discardThresholds;
public AddLeaderboard(String leaderboardName, int[] discardThresholds) {
super();
this.leaderboardName = leaderboardName;
super(leaderboardName);
this.discardThresholds = discardThresholds;
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.addLeaderboard(leaderboardName, discardThresholds);
toState.addLeaderboard(getLeaderboardName(), discardThresholds);
return toState;
}
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
// TODO Auto-generated method stub
return null;
return serverOp.transformAddLeaderboardClientOp(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
// TODO Auto-generated method stub
return null;
return clientOp.transformAddLeaderboardServerOp(this);
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class MoveLeaderboardColumnDown extends AbstractLeaderboardColumnOperation {
@@ -30,26 +29,4 @@ public class MoveLeaderboardColumnDown extends AbstractLeaderboardColumnOperatio
return null;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class MoveLeaderboardColumnUp extends AbstractLeaderboardColumnOperation {
@@ -30,26 +29,4 @@ public class MoveLeaderboardColumnUp extends AbstractLeaderboardColumnOperation
return null;
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -36,4 +36,12 @@ public interface RacingEventServiceOperation extends Operation<RacingEventServic
RacingEventServiceOperation transformClientRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnClientOp);
RacingEventServiceOperation transformServerRenameLeaderboardColumnOp(RenameLeaderboardColumn renameLeaderboardColumnServerOp);
RacingEventServiceOperation transformAddLeaderboardClientOp(AddLeaderboard addLeaderboard);
RacingEventServiceOperation transformAddLeaderboardServerOp(AddLeaderboard addLeaderboard);
RacingEventServiceOperation transformRemoveLeaderboardClientOp(RemoveLeaderboard removeLeaderboard);
RacingEventServiceOperation transformRemoveLeaderboardServerOp(RemoveLeaderboard removeLeaderboard);
}
@@ -1,6 +1,5 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class RemoveColumnFromLeaderboard extends AbstractLeaderboardColumnOperation {
@@ -26,26 +25,4 @@ public class RemoveColumnFromLeaderboard extends AbstractLeaderboardColumnOperat
return clientOp.transformServerRemoveColumnFromLeaderboard(this);
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
// skip server's remove and hence only apply the client's remove operation
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
// skip client's remove and hence only apply the server's remove operation
return ClientServerOperationPair.getNoOp();
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}
@@ -0,0 +1,26 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.server.RacingEventService;
public class RemoveLeaderboard extends AbstractLeaderboardOperation {
public RemoveLeaderboard(String leaderboardName) {
super(leaderboardName);
}
@Override
public RacingEventServiceOperation transformClientOp(RacingEventServiceOperation serverOp) {
return serverOp.transformRemoveLeaderboardClientOp(this);
}
@Override
public RacingEventServiceOperation transformServerOp(RacingEventServiceOperation clientOp) {
return clientOp.transformRemoveLeaderboardServerOp(this);
}
@Override
public RacingEventService applyTo(RacingEventService toState) {
toState.removeLeaderboard(getLeaderboardName());
return toState;
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.server.operationaltransformation;
import com.sap.sailing.operationaltransformation.ClientServerOperationPair;
import com.sap.sailing.server.RacingEventService;
public class RenameLeaderboardColumn extends AbstractLeaderboardColumnOperation {
@@ -29,24 +28,4 @@ public class RenameLeaderboardColumn extends AbstractLeaderboardColumnOperation
return clientOp.transformServerRenameLeaderboardColumnOp(this);
}
@Override
public RacingEventServiceOperation transformServerRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardServerOp) {
if (affectsSameColumn(removeColumnFromLeaderboardServerOp)) {
return ClientServerOperationPair.getNoOp(); // don't need the rename anymore when column is removed
} else {
return removeColumnFromLeaderboardServerOp;
}
}
@Override
public RacingEventServiceOperation transformClientRemoveColumnFromLeaderboard(
RemoveColumnFromLeaderboard removeColumnFromLeaderboardClientOp) {
if (affectsSameColumn(removeColumnFromLeaderboardClientOp)) {
return ClientServerOperationPair.getNoOp(); // don't need the rename anymore when column is removed
} else {
return removeColumnFromLeaderboardClientOp;
}
}
}