/**
* Replication Benchmarker
* https://github.com/score-team/replication-benchmarker/
* Copyright (C) 2013 LORIA / Inria / SCORE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package crdt.tree.wordtree;
import collect.HashTree;
import collect.Node;
import collect.Tree;
import collect.UnorderedNode;
import crdt.CRDTMessage;
import crdt.Factory;
import crdt.PreconditionException;
import crdt.set.CRDTSet;
import crdt.set.counter.CommutativeCounterSet;
import crdt.set.counter.ConvergentCounterSet;
import crdt.set.lastwriterwins.CommutativeLwwSet;
import crdt.set.lastwriterwins.ConvergentLwwSet;
import crdt.set.observedremove.CommutativeOrSet;
import crdt.set.observedremove.ConvergentOrSet;
import crdt.tree.CRDTUnorderedTree;
import crdt.tree.CrdtTreeGeneric;
import crdt.tree.wordtree.policy.WordCompact;
import crdt.tree.wordtree.policy.WordIncrementalCompact;
import crdt.tree.wordtree.policy.WordIncrementalReappear;
import crdt.tree.wordtree.policy.WordIncrementalRoot;
import crdt.tree.wordtree.policy.WordIncrementalSkip;
import crdt.tree.wordtree.policy.WordIncrementalSkipOpti;
import crdt.tree.wordtree.policy.WordReappear;
import crdt.tree.wordtree.policy.WordRoot;
import crdt.tree.wordtree.policy.WordSkip;
import jbenchmarker.ot.otset.AddWinTransformation;
import jbenchmarker.ot.otset.DelWinTransformation;
import jbenchmarker.ot.otset.OTSet;
import jbenchmarker.ot.soct2.SOCT2;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
/**
*
* @author urso
*/
public class WordTreeTest {
/**
*
*/
public WordTreeTest() {
}
/**
*
* @throws Exception
*/
@BeforeClass
public static void setUpClass() throws Exception {
}
/**
*
* @throws Exception
*/
@AfterClass
public static void tearDownClass() throws Exception {
}
/**
*
* @throws Exception
*/
@Test(expected = PreconditionException.class)
public void testNotIn() throws Exception {
WordTree t = new WordTree(new CommutativeCounterSet(), new WordSkip());
t.add(t.getRoot(), 'a');
UnorderedNode a = t.getRoot().getChild('a');
t.remove(a);
t.add(a, 'b');
}
/**
* Create test for wordtree
*
* @param sf setFactory
* @throws Exception
*/
public void testWordBasic(Factory<CRDTSet> sf) throws Exception {
CrdtTreeGeneric test = new CrdtTreeGeneric();
test.runAllBasic(new WordTree(sf.create(), new WordSkip()));
test.runAllBasic(new WordTree(sf.create(), new WordIncrementalSkip()));
test.runAllBasic(new WordTree(sf.create(), new WordIncrementalSkipOpti()));
test.runAllBasic(new WordTree(sf.create(), new WordReappear()));
test.runAllBasic(new WordTree(sf.create(), new WordIncrementalReappear()));
test.runAllBasic(new WordTree(sf.create(), new WordRoot()));
test.runAllBasic(new WordTree(sf.create(), new WordIncrementalRoot()));
test.runAllBasic(new WordTree(sf.create(), new WordCompact()));
test.runAllBasic(new WordTree(sf.create(), new WordIncrementalCompact()));
testRoot(sf, new WordRoot());
testRootDouble(sf, new WordRoot());
// testRoot(sf, new WordIncrementalRoot());
// testRootDouble(sf, new WordIncrementalRoot());
testCompact(sf, new WordCompact());
testCompact(sf, new WordIncrementalCompact());
}
/**
*
* @throws Exception
*/
@Test
public void testCmCWS() throws Exception {
Tree tr, resultTree;
Node a, b, c, x, y, z, k;
CrdtTreeGeneric test = new CrdtTreeGeneric();
Factory<CRDTUnorderedTree> tf = new WordTree(new CommutativeCounterSet(), new WordSkip());
test.testAdopt(tf.create(), tf.create());
tr = test.testConcurAddRmvFather(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
c = resultTree.add(null, 'c');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
tr = test.testConcurAddRmvSameElement(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(b, 'x');
y = resultTree.add(b, 'y');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
tr = test.testTwoPath(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(a, 'x');
y = resultTree.add(b, 'y');
z = resultTree.add(c, 'z');
resultTree.add(y, 'x');
assertEquals(resultTree, tr);
tr = test.testCycle(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(b, 'x');
y = resultTree.add(b, 'y');
resultTree.add(x, 'y');
resultTree.add(y, 'x');
assertEquals(resultTree, tr);
}
/**
*
* @throws Exception
*/
@Test
public void testCmOWS() throws Exception {
Tree tr, resultTree;
Node a, b, c, x, y, z, k;
CrdtTreeGeneric test = new CrdtTreeGeneric();
Factory<CRDTUnorderedTree> tf = new WordTree(new CommutativeOrSet(), new WordSkip());
test.testAdopt(tf.create(), tf.create());
tr = test.testConcurAddRmvFather(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
c = resultTree.add(null, 'c');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
tr = test.testConcurAddRmvSameElement(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(b, 'x');
y = resultTree.add(b, 'y');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
tr = test.testTwoPath(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(a, 'x');
y = resultTree.add(b, 'y');
z = resultTree.add(c, 'z');
resultTree.add(y, 'x');
assertEquals(resultTree, tr);
tr = test.testCycle(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(b, 'x');
y = resultTree.add(b, 'y');
resultTree.add(x, 'y');
resultTree.add(y, 'x');
assertEquals(resultTree, tr);
}
/*
* a = resultTree.innerAdd(null, 'a'); b = resultTree.innerAdd(null, 'b'); c
* = resultTree.innerAdd(null, 'c'); x = resultTree.innerAdd(b, 'x'); y =
* resultTree.innerAdd(b, 'y'); z = resultTree.innerAdd(c, 'z');
*/
/**
*
* @throws Exception
*/
@Test
public void testCmCWR() throws Exception {
Tree tr, resultTree;
Node a, b, c, x, y, z, k;
CrdtTreeGeneric test = new CrdtTreeGeneric();
CRDTSet s = new CommutativeCounterSet();
Factory<CRDTUnorderedTree> tf = new WordTree(s, new WordReappear());
tr = test.testConcurAddRmvFather(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
x = resultTree.add(b, 'x');
k = resultTree.add(x, 'k');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
}
/**
*
* @throws Exception
*/
@Test
public void testCmLWR() throws Exception {
Tree tr, resultTree;
Node a, b, c, x, y, z, k;
CrdtTreeGeneric test = new CrdtTreeGeneric();
Factory<CRDTUnorderedTree> tf = new WordTree(new CommutativeLwwSet(), new WordReappear());
tr = test.testConcurAddRmvSameElement(tf.create(), tf.create());
resultTree = new HashTree();
a = resultTree.add(null, 'a');
b = resultTree.add(null, 'b');
c = resultTree.add(null, 'c');
// x = resultTree.innerAdd(b, 'x');
y = resultTree.add(b, 'y');
z = resultTree.add(c, 'z');
assertEquals(resultTree, tr);
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCmCounter() throws Exception {
testWordBasic(new CommutativeCounterSet());
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCvCounter() throws Exception {
testWordBasic(new ConvergentCounterSet());
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCmLww() throws Exception {
testWordBasic(new CommutativeLwwSet());
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCvLww() throws Exception {
testWordBasic(new ConvergentLwwSet());
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCmOr() throws Exception {
testWordBasic(new CommutativeOrSet());
}
/**
*
* @throws Exception
*/
@Test
public void testBasicCvOr() throws Exception {
testWordBasic(new ConvergentOrSet());
}
/**
* test for wordTree with set OT with soct2 and addwin policy
*
* @throws Exception
*/
@Test
public void testBasicOtAddWin() throws Exception {
testWordBasic(new OTSet(new SOCT2(new AddWinTransformation(), null)));
}
/**
* test for wordTree with set OT with soct2 and delwin policy
*
* @throws Exception
*/
@Test
public void testBasicOtDelWin() throws Exception {
testWordBasic(new OTSet(new SOCT2(new DelWinTransformation(), null)));
}
private void testRoot(Factory<CRDTSet> sf, Factory<WordPolicy> rf) throws PreconditionException {
WordTree wt1 = new WordTree(sf.create(), rf.create()),
wt2 = new WordTree(sf.create(), rf.create());
CRDTMessage m1 = wt1.add(wt1.getRoot(), 'a');
m1=m1.concat(wt1.add(wt1.getRoot(), 'c'));
m1=m1.concat(wt1.add(wt1.getRoot().getChild('a'), 'b'));
wt2.applyRemote(m1);
CRDTMessage m2 = wt2.remove(wt2.getRoot().getChild('a').getChild('b'));
m1 = wt1.add(wt1.getRoot().getChild('a').getChild('b'), 'a');
wt1.applyRemote(m2);
wt2.applyRemote(m1);
Tree rt = new HashTree();
rt.add(null, 'a');
rt.add(null, 'c');
assertEquals(rt, wt1.lookup());
assertEquals(rt, wt2.lookup());
m1 = wt1.remove(wt1.getRoot().getChild('a'));
wt2.applyRemote(m1);
rt = new HashTree();
rt.add(null, 'c');
assertEquals(rt, wt1.lookup());
assertEquals(rt, wt2.lookup());
}
private void testRootDouble(Factory<CRDTSet> sf, Factory<WordPolicy> rf) throws PreconditionException {
WordTree wt1 = new WordTree(sf.create(), new WordRoot()),
wt2 = new WordTree(sf.create(), new WordRoot());
CRDTMessage m1 = wt1.add(wt1.getRoot(), 'a');
m1=m1.concat(wt1.add(wt1.getRoot(), 'c'));
m1=m1.concat(wt1.add(wt1.getRoot().getChild('a'), 'b'));
wt2.applyRemote(m1);
CRDTMessage m2 = wt2.remove(wt2.getRoot().getChild('a').getChild('b'));
m1 = wt1.add(wt1.getRoot().getChild('a').getChild('b'), 'a');
wt1.applyRemote(m2);
wt2.applyRemote(m1);
m1 = wt1.add(wt1.getRoot().getChild('a'), 'd');
m2 = wt2.add(wt2.getRoot().getChild('a'), 'b');
wt1.applyRemote(m2);
wt2.applyRemote(m1);
Tree rt = new HashTree();
Node a = rt.add(null, 'a'),
a2 = rt.add(rt.add(a, 'b'), 'a');
rt.add(null, 'c');
rt.add(a, 'd');
rt.add(a2, 'd');
rt.add(a2, 'b');
assertEquals(rt, wt1.lookup());
assertEquals(rt, wt2.lookup());
}
private void testCompact(Factory<CRDTSet> sf, Factory<WordPolicy> cf) throws PreconditionException {
WordTree wt1 = new WordTree(sf.create(), cf.create()),
wt2 = new WordTree(sf.create(), cf.create());
CRDTMessage m1 = wt1.add(wt1.getRoot(), 'a');
m1=m1.concat(wt1.add(wt1.getRoot(), 'c'));
m1=m1.concat(wt1.add(wt1.getRoot().getChild('a'), 'a'));
m1=m1.concat(wt1.add(wt1.getRoot().getChild('a'), 'b'));
wt2.applyRemote(m1);
CRDTMessage m2 = wt2.remove(wt2.getRoot().getChild('a').getChild('b'));
m1 = wt1.add(wt1.getRoot().getChild('a').getChild('b'), 'a');
wt1.applyRemote(m2);
wt2.applyRemote(m1);
Tree rt = new HashTree();
rt.add(rt.add(null, 'a'), 'a');
rt.add(null, 'c');
assertEquals(rt, wt1.lookup());
assertEquals(rt, wt2.lookup());
m1 = wt1.remove(wt1.getRoot().getChild('a').getChild('a'));
wt2.applyRemote(m1);
rt = new HashTree();
rt.add(null, 'a');
rt.add(null, 'c');
assertEquals(rt, wt1.lookup());
assertEquals(rt, wt2.lookup());
}
}