/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package jbenchmarker.ot.ttf; import collect.VectorClock; import crdt.CRDTMessage; import crdt.Operation; import crdt.simulator.IncorrectTraceException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import jbenchmarker.core.SequenceOperation; import jbenchmarker.core.SequenceOperation.OpType; import jbenchmarker.ot.soct2.OTMessage; import jbenchmarker.ot.ttf.MC.TTFMCMergeAlgorithm; import static org.junit.Assert.assertEquals; import org.junit.Test; /** * * @author mehdi */ public class TTFMCTest { @Test public void testSimpleMergeClean1() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(1, "x"), 1, vc(3, 1, 0)); site0.integrateRemote(op1); assertEquals("axbc", site0.lookup()); site0.integrateRemote(op2); assertEquals("axbc", site0.lookup()); } @Test public void testSimpleMergeClean2() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); site0.localInsert(insert(0, "abc")); //site0.generateLocal(insert(0, 1, "x")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(1, "x"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); site0.integrateRemote(op1); assertEquals("axbc", site0.lookup()); site0.integrateRemote(op3); assertEquals("axc", site0.lookup()); site0.integrateRemote(op2); assertEquals("axc", site0.lookup()); } @Test public void testSimpleMergeClean3() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); List<Operation> ops0 = duplicate(site0.localInsert(insert(0, "abc"))); assertEquals("abc", site0.lookup()); integrateSeqAtSite(ops0, site1); assertEquals("abc", site1.lookup()); //site0.generateLocal(insert(0, 1, "x")); List<Operation> ops00 = duplicate(site0.localInsert(insert(1, "xyz"))); assertEquals("axyzbc", site0.lookup()); List<Operation> ops1 = duplicate(site1.localInsert(insert(1, "xyz"))); assertEquals("axyzbc", site1.lookup()); integrateSeqAtSite(ops0, site2); assertEquals("abc", site2.lookup()); integrateSeqAtSite(ops00, site2); assertEquals("axyzbc", site2.lookup()); // integrateSeqAtSite(ops1, site2); // assertEquals("axyzbc", site2.lookup()); } @Test public void testPartialConcurrent() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); List<Operation> ops0 = duplicate(site0.localInsert(insert(0, "abc"))); assertEquals("abc", site0.lookup()); List<Operation> ops1 = duplicate(site1.localInsert(insert(0, "xyz"))); assertEquals("xyz", site1.lookup()); List<Operation> ops2 = duplicate(site2.localInsert(insert(0, "abc"))); assertEquals("abc", site2.lookup()); integrateSeqAtSite(ops1, site0); integrateSeqAtSite(ops2, site0); integrateSeqAtSite(ops0, site1); integrateSeqAtSite(ops2, site1); assertEquals(site1.lookup(), site1.lookup()); } //=======================Generic test==================== @Test public void testGenerateLocalInsertCharByChar() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); List<Operation> ops = merger.localInsert(insert(0, "b")); assertEquals(1, ops.size()); OTMessage<TTFOperation> opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(SequenceOperation.OpType.insert, opg.getOperation().getType()); assertEquals('b', opg.getOperation().getContent()); assertEquals(0, opg.getOperation().getPosition()); assertEquals("[<0,1>]", vcToString(opg.getClock())); assertEquals("b", merger.lookup()); ops = merger.localInsert(insert(0, "a")); assertEquals(1, ops.size()); opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals('a', opg.getOperation().getContent()); assertEquals(0, opg.getOperation().getPosition()); assertEquals("[<0,2>]", vcToString(opg.getClock())); assertEquals("ab", merger.lookup()); ops = merger.localInsert(insert(2, "c")); assertEquals(1, ops.size()); opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals('c', opg.getOperation().getContent()); assertEquals("[<0,3>]", vcToString(opg.getClock())); assertEquals(2, opg.getOperation().getPosition()); assertEquals("abc", merger.lookup()); } @Test public void testGenerateLocalInsertString() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); List<Operation> ops = merger.localInsert(insert(0, "abc")); assertEquals(3, ops.size()); OTMessage<TTFOperation> opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.insert, opg.getOperation().getType()); assertEquals('a', opg.getOperation().getContent()); assertEquals(0, opg.getOperation().getPosition()); assertEquals("[<0,1>]", vcToString(opg.getClock())); opg = ((TTFSequenceMessage) ops.get(1)).getSoct2Message(); assertEquals('b', opg.getOperation().getContent()); assertEquals(1, opg.getOperation().getPosition()); assertEquals("[<0,2>]", vcToString(opg.getClock())); opg = ((TTFSequenceMessage) ops.get(2)).getSoct2Message(); assertEquals('c', opg.getOperation().getContent()); assertEquals("[<0,3>]", vcToString(opg.getClock())); assertEquals(2, opg.getOperation().getPosition()); assertEquals("abc", merger.lookup()); } @Test public void testGenerateLocalDeleteCharByChar() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); merger.localInsert(insert(0, "abcd")); // remove 'a' List<Operation> ops = merger.localDelete(delete(0, 1)); assertEquals(1, ops.size()); OTMessage<TTFOperation> opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(0, opg.getOperation().getPosition()); assertEquals("[<0,5>]", vcToString(opg.getClock())); assertEquals("bcd", merger.lookup()); // remove 'd' ops = merger.localDelete(delete(2, 1)); assertEquals(1, ops.size()); opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(3, opg.getOperation().getPosition()); assertEquals("[<0,6>]", vcToString(opg.getClock())); assertEquals("bc", merger.lookup()); // remove 'c' ops = merger.localDelete(delete(1, 1)); assertEquals(1, ops.size()); opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(2, opg.getOperation().getPosition()); assertEquals("[<0,7>]", vcToString(opg.getClock())); assertEquals("b", merger.lookup()); // remove 'b' ops = merger.localDelete(delete(0, 1)); assertEquals(1, ops.size()); opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(1, opg.getOperation().getPosition()); assertEquals("[<0,8>]", vcToString(opg.getClock())); assertEquals("", merger.lookup()); } @Test public void testGenerateLocalDeleteString() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); merger.localInsert(insert(0, "abcd")); // remove "abcd" List<Operation> ops = merger.localDelete(delete(0, 4)); assertEquals(4, ops.size()); OTMessage<TTFOperation> opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(0, opg.getOperation().getPosition()); assertEquals("[<0,5>]", vcToString(opg.getClock())); opg = ((TTFSequenceMessage) ops.get(1)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(1, opg.getOperation().getPosition()); assertEquals("[<0,6>]", vcToString(opg.getClock())); opg = ((TTFSequenceMessage) ops.get(2)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(2, opg.getOperation().getPosition()); assertEquals("[<0,7>]", vcToString(opg.getClock())); opg = ((TTFSequenceMessage) ops.get(3)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(3, opg.getOperation().getPosition()); assertEquals("[<0,8>]", vcToString(opg.getClock())); assertEquals("", merger.lookup()); } @Test public void testGenerateLocalDeleteStringWhichContainsDeletedChars() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); merger.localInsert(insert(0, "abcdefg")); merger.localDelete(delete(2, 2)); assertEquals("abefg", merger.lookup()); // remove "bef" List<Operation> ops = merger.localDelete(delete(1, 3)); assertEquals(3, ops.size()); OTMessage<TTFOperation> opg = ((TTFSequenceMessage) ops.get(0)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(1, opg.getOperation().getPosition()); opg = ((TTFSequenceMessage) ops.get(1)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(4, opg.getOperation().getPosition()); opg = ((TTFSequenceMessage) ops.get(2)).getSoct2Message(); assertEquals(OpType.delete, opg.getOperation().getType()); assertEquals(5, opg.getOperation().getPosition()); assertEquals("ag", merger.lookup()); } @Test public void testVectorClockEvolution() throws IncorrectTraceException { int siteId = 0; TTFMCMergeAlgorithm merger = new TTFMCMergeAlgorithm(siteId); assertEquals(vc(0), merger.getClock()); OTMessage op1 = ((TTFSequenceMessage) merger.localInsert(insert(0, "a")).get(0)).getSoct2Message(); assertEquals(vc(1), merger.getClock()); OTMessage op2 = ((TTFSequenceMessage) merger.localInsert(insert(1, "b")).get(0)).getSoct2Message(); assertEquals(vc(2), merger.getClock()); assertEquals(vc(1), op1.getClock()); assertEquals(vc(2), op2.getClock()); } @Test public void testTP2PuzzleAtSite0() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); site0.localInsert(insert(0, "abc")); //site0.generateLocal(insert(0, 1, "x")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); site0.integrateRemote(op1); assertEquals("axbc", site0.lookup()); site0.integrateRemote(op2); assertEquals("axbyc", site0.lookup()); site0.integrateRemote(op3); assertEquals("axyc", site0.lookup()); } @Test public void testTP2PuzzleAtSite0bis() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); site0.integrateRemote(op1); assertEquals("axbc", site0.lookup()); site0.integrateRemote(op3); assertEquals("axc", site0.lookup()); site0.integrateRemote(op2); assertEquals("axyc", site0.lookup()); } @Test public void testTP2PuzzleAtSite1() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); List<Operation> ops = site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); for (Operation op : ops) { site1.integrateRemote(op); } site1.integrateRemote(op2); assertEquals("abyc", site1.lookup()); site1.integrateRemote(op1); assertEquals("axbyc", site1.lookup()); site1.integrateRemote(op3); assertEquals("axyc", site1.lookup()); } @Test public void testTP2PuzzleAtSite1bis() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); List<Operation> ops = site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); for (Operation op : ops) { site1.integrateRemote(op); } site1.integrateRemote(op2); assertEquals("abyc", site1.lookup()); site1.integrateRemote(op3); assertEquals("ayc", site1.lookup()); site1.integrateRemote(op1); assertEquals("axyc", site1.lookup()); } @Test public void testTP2PuzzleAtSite2() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); List<Operation> ops = site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); for (Operation op : ops) { site2.integrateRemote(op); } site2.integrateRemote(op3); assertEquals("ac", site2.lookup()); site2.integrateRemote(op1); assertEquals("axc", site2.lookup()); site2.integrateRemote(op2); assertEquals("axyc", site2.lookup()); } @Test public void testTP2PuzzleAtSite2bis() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); List<Operation> ops = site0.localInsert(insert(0, "abc")); TTFSequenceMessage op1 = TTFSequenceMessageFrom(insert(1, "x"), 0, vc(4, 0, 0)); TTFSequenceMessage op2 = TTFSequenceMessageFrom(insert(2, "y"), 1, vc(3, 1, 0)); TTFSequenceMessage op3 = TTFSequenceMessageFrom(delete(1, 1), 2, vc(3, 0, 1)); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); for (Operation op : ops) { site2.integrateRemote(op); } site2.integrateRemote(op3); assertEquals("ac", site2.lookup()); site2.integrateRemote(op2); assertEquals("ayc", site2.lookup()); site2.integrateRemote(op1); assertEquals("axyc", site2.lookup()); } @Test public void testTP2Puzzle() throws IncorrectTraceException { TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); TTFMCMergeAlgorithm site3 = new TTFMCMergeAlgorithm(3); List<Operation> ops0 = duplicate(site1.localInsert(insert(0, "abc"))); assertEquals("abc", site1.lookup()); integrateSeqAtSite(ops0, site2); assertEquals("abc", site2.lookup()); integrateSeqAtSite(ops0, site3); assertEquals("abc", site3.lookup()); List<Operation> ops1 = duplicate(site1.localInsert(insert(1, "x"))); assertEquals("axbc", site1.lookup()); List<Operation> ops2 = duplicate(site2.localInsert(insert(2, "y"))); assertEquals("abyc", site2.lookup()); List<Operation> ops3 = duplicate(site3.localDelete(delete(1, 1))); assertEquals("ac", site3.lookup()); integrateSeqAtSite(ops2, site1); assertEquals("axbyc", site1.lookup()); integrateSeqAtSite(ops3, site1); assertEquals("axyc", site1.lookup()); integrateSeqAtSite(ops3, site2); assertEquals("ayc", site2.lookup()); integrateSeqAtSite(ops1, site2); assertEquals("axyc", site2.lookup()); integrateSeqAtSite(ops2, site3); integrateSeqAtSite(ops1, site3); assertEquals("axyc", site3.lookup()); } @Test public void testBasicScenario() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); TTFMCMergeAlgorithm site4 = new TTFMCMergeAlgorithm(4); List<Operation> ops0 = duplicate(site0.localInsert(insert(0, "ABC"))); assertEquals("ABC", site0.lookup()); integrateSeqAtSite(ops0, site2); assertEquals("ABC", site2.lookup()); List<Operation> ops2 = duplicate(site2.localInsert(insert(2, "vw"))); assertEquals("ABvwC", site2.lookup()); List<Operation> ops2b = duplicate(site2.localInsert(insert(4, "xyz"))); assertEquals("ABvwxyzC", site2.lookup()); integrateSeqAtSite(ops0, site4); assertEquals("ABC", site4.lookup()); List<Operation> ops4 = duplicate(site4.localDelete(delete(1, 2))); assertEquals("A", site4.lookup()); integrateSeqAtSite(ops4, site2); assertEquals("Avwxyz", site2.lookup()); integrateSeqAtSite(ops2, site4); integrateSeqAtSite(ops2b, site4); assertEquals("Avwxyz", site4.lookup()); assertEquals("ABC", site0.lookup()); // integrateSeqAtSite(ops2, site0); assertEquals("ABvwC", site0.lookup()); // integrateSeqAtSite(ops2b, site0); assertEquals("ABvwxyzC", site0.lookup()); integrateSeqAtSite(ops4, site0); assertEquals("Avwxyz", site0.lookup()); } @Test public void testBasicScenario2() throws IncorrectTraceException { TTFMCMergeAlgorithm site0 = new TTFMCMergeAlgorithm(0); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); TTFMCMergeAlgorithm site4 = new TTFMCMergeAlgorithm(4); /* * Ins('Salut Monsieur \nFin', 0, 1297672411625, 1, 0, [<0,1>]) * Ins('Bonjour', 14, 1297672411625, 1, 2 [<2,1><0,1>]) Ins(' Mehdi', * 21, 1297672411625, 1, 2, [<2,2><0,1>]) Del(14, 3, 1297672512653, 1, * 4, [<0,1><4,1>]) */ List<Operation> ops0 = duplicate(site0.localInsert(insert(0, "Salut Monsieur \nFin"))); // [<0,1>] integrateSeqAtSite(ops0, site2); List<Operation> ops2 = site2.localInsert(insert(14, "Bonjour")); // [<2,1><0,1>] List<Operation> ops2b = site2.localInsert(insert(21, " Mehdi")); // [<2,2><0,1>] assertEquals("Salut MonsieurBonjour Mehdi \nFin", site2.lookup()); integrateSeqAtSite(ops0, site4); List<Operation> ops4 = duplicate(site4.localDelete(delete(14, 3))); // [<0,1><4,1>] integrateSeqAtSite(ops4, site2); assertEquals("Salut MonsieurBonjour MehdiFin", site2.lookup()); integrateSeqAtSite(ops2, site4); integrateSeqAtSite(ops2b, site4); assertEquals("Salut MonsieurBonjour MehdiFin", site4.lookup()); integrateSeqAtSite(ops2, site0); integrateSeqAtSite(ops2b, site0); integrateSeqAtSite(ops4, site0); assertEquals("Salut MonsieurBonjour MehdiFin", site0.lookup()); } @Test public void testPartialConcurrencyScenarioWith3Insert() throws IncorrectTraceException { TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); List<Operation> ops0 = duplicate(site1.localInsert(insert(0, "ABC"))); integrateSeqAtSite(ops0, site2); List<Operation> ops1 = duplicate(site1.localInsert(insert( 2, "X"))); assertEquals("ABXC", site1.lookup()); List<Operation> ops2 = duplicate(site2.localInsert(insert( 1, "12"))); List<Operation> ops2b = duplicate(site2.localInsert(insert( 3, "34"))); assertEquals("A1234BC", site2.lookup()); integrateSeqAtSite(ops1, site2); assertEquals("A1234BXC", site2.lookup()); integrateSeqAtSite(ops2, site1); assertEquals("A12BXC", site1.lookup()); integrateSeqAtSite(ops2b, site1); assertEquals("A1234BXC", site1.lookup()); } @Test public void testPartialConcurrencyScenarioWithDelInsert() throws IncorrectTraceException { TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); List<Operation> ops0 = duplicate(site1.localInsert(insert(0, "ABC"))); integrateSeqAtSite(ops0, site2); List<Operation> ops2 = duplicate(site2.localInsert(insert(1, "X"))); assertEquals("AXBC", site2.lookup()); List<Operation> ops22 = duplicate(site2.localInsert(insert(4, "Y"))); assertEquals("AXBCY", site2.lookup()); List<Operation> ops1 = duplicate(site1.localDelete(delete(1, 1))); assertEquals("AC", site1.lookup()); integrateSeqAtSite(ops2, site1); assertEquals("AXC", site1.lookup()); integrateSeqAtSite(ops22, site1); assertEquals("AXCY", site1.lookup()); integrateSeqAtSite(ops1, site2); assertEquals("AXCY", site2.lookup()); } @Test public void testConcurrencyScenarioWithDelInsert() throws IncorrectTraceException { TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); List<Operation> ops0 = duplicate(site1.localInsert(insert(0, "ABC"))); integrateSeqAtSite(ops0, site2); List<Operation> ops2 = duplicate(site2.localInsert(insert(2, "X"))); assertEquals("ABXC", site2.lookup()); List<Operation> ops22 = duplicate(site2.localDelete(delete(2, 1))); assertEquals("ABC", site2.lookup()); List<Operation> ops1 = duplicate(site1.localDelete(delete(0, 1))); assertEquals("BC", site1.lookup()); integrateSeqAtSite(ops2, site1); assertEquals("BXC", site1.lookup()); integrateSeqAtSite(ops22, site1); assertEquals("BC", site1.lookup()); integrateSeqAtSite(ops1, site2); assertEquals("BC", site2.lookup()); } @Test public void testTP() throws Exception { TTFMCMergeAlgorithm site1 = new TTFMCMergeAlgorithm(1); TTFMCMergeAlgorithm site2 = new TTFMCMergeAlgorithm(2); TTFMCMergeAlgorithm site3 = new TTFMCMergeAlgorithm(3); //TTFMCMergeAlgorithm site4 = new TTFMCMergeAlgorithm(4); CRDTMessage mess1 = site1.insert(0, "a").clone(); CRDTMessage mess2 = site1.remove(0, 1).clone(); CRDTMessage mess3 = site2.insert(0, "b").clone(); /* * site3.applyRemote(mess1); site3.applyRemote(mess2); site3.applyRemote(mess3); */ site1.applyRemote(mess3.clone()); site3.applyRemote(mess1.clone()); site3.applyRemote(mess3.clone()); site3.applyRemote(mess2.clone()); assertEquals(site1.lookup(), site3.lookup()); } //===========================Helpers======================================= private static SequenceOperation insert(int p, String s) { return SequenceOperation.insert(p, s); } private static SequenceOperation delete(int p, int o) { return SequenceOperation.delete(p, o); } private static VectorClock vc(int... v) { VectorClock vc = new VectorClock(); for (int i = 0; i < v.length; i++) { vc.put(i, v[i]); } return vc; } private static String vcToString(VectorClock vc) { StringBuilder sb = new StringBuilder(); sb.append("["); Iterator<Map.Entry<Integer, Integer>> it = vc.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> e = it.next(); sb.append("<"); sb.append(e.getKey()); sb.append(","); sb.append(e.getValue()); sb.append(">"); } sb.append("]"); return sb.toString(); } public static TTFSequenceMessage TTFSequenceMessageFrom(SequenceOperation opt, int rep, VectorClock vc) { TTFOperation op; if (opt.getType() == SequenceOperation.OpType.insert) { op = new TTFOperation(opt.getType(), opt.getPosition(), opt.getContent().get(0)); } else { op = new TTFOperation(opt.getType(), opt.getPosition(), null); } OTMessage smess = new OTMessage(vc, rep, op); TTFSequenceMessage mess = new TTFSequenceMessage(smess); return mess; } public static List<Operation> duplicate(List<Operation> list) { ArrayList<Operation> res = new ArrayList<Operation>(); for (Operation elt : list) { res.add(((TTFSequenceMessage) elt).clone()); } return res; } private static void integrateSeqAtSite(List<Operation> seq, TTFMCMergeAlgorithm site) throws IncorrectTraceException { for (Operation op : duplicate(seq)) { site.integrateRemote(op); } } }