|
@@ -3,6 +3,8 @@ import * as _ from "lodash";
|
|
|
import {
|
|
|
NodeCreation,
|
|
|
NodeDeletion,
|
|
|
+ EdgeCreation,
|
|
|
+ EdgeUpdate,
|
|
|
} from "./primitive_delta";
|
|
|
|
|
|
import {
|
|
@@ -52,6 +54,46 @@ describe("Composite delta", () => {
|
|
|
assert(_.isEqual(compositeDelete2.getConflicts(), [compositeDelete1]), "expected compositeDelete1 to conflict with compositeDelete2");
|
|
|
});
|
|
|
|
|
|
+ it("Conflict, but no composite yet", () => {
|
|
|
+ const getId = mockUuid();
|
|
|
+ const level = new CompositeLevel();
|
|
|
+
|
|
|
+ // Same as above, but now we first create all the L0 deltas:
|
|
|
+ const nodeCreation = new NodeCreation(getId());
|
|
|
+ const nodeDeletion1 = new NodeDeletion(nodeCreation, [], []);
|
|
|
+ const nodeDeletion2 = new NodeDeletion(nodeCreation, [], []);
|
|
|
+
|
|
|
+ // And then the L1 deltas:
|
|
|
+ const compositeCreate = level.createComposite([nodeCreation]);
|
|
|
+ const compositeDelete1 = level.createComposite([nodeDeletion1]);
|
|
|
+ assert(_.isEqual(compositeDelete1.getConflicts(), []), "there should not yet be a conflict")
|
|
|
+ const compositeDelete2 = level.createComposite([nodeDeletion2]);
|
|
|
+
|
|
|
+ assert(_.isEqual(compositeDelete1.getConflicts(), [compositeDelete2]), "expected compositeDelete1 to conflict with compositeDelete2");
|
|
|
+ assert(_.isEqual(compositeDelete2.getConflicts(), [compositeDelete1]), "expected compositeDelete1 to conflict with compositeDelete2");
|
|
|
+ });
|
|
|
+
|
|
|
+ it("Conflicting deltas cannot be part of the same composite", () => {
|
|
|
+ const getId = mockUuid();
|
|
|
+ const level = new CompositeLevel();
|
|
|
+
|
|
|
+ const nodeCreation = new NodeCreation(getId());
|
|
|
+ const nodeDeletion1 = new NodeDeletion(nodeCreation, [], []);
|
|
|
+ const nodeDeletion2 = new NodeDeletion(nodeCreation, [], []);
|
|
|
+
|
|
|
+ let threw = false;
|
|
|
+ try {
|
|
|
+ level.createComposite([nodeCreation, nodeDeletion1, nodeDeletion2]); // should throw
|
|
|
+ } catch (e) {
|
|
|
+ threw = true;
|
|
|
+ assert(e.toString() === "Error: Cannot create a composite delta out of conflicting deltas.", "Wrong error thrown");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!threw) {
|
|
|
+ throw new Error("Failed!");
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
// This was added after I found a bug:
|
|
|
it("Dependency within composite", () => {
|
|
|
const getId = mockUuid();
|
|
@@ -65,4 +107,53 @@ describe("Composite delta", () => {
|
|
|
assert(_.isEqual(composite.getDependencies(), []), "expected composite to have no dependencies");
|
|
|
assert(_.isEqual(composite.getConflicts(), []), "expected composite to have no conflicts");
|
|
|
});
|
|
|
+
|
|
|
+ it("Multi-level", () => {
|
|
|
+ const getId = mockUuid();
|
|
|
+
|
|
|
+ const lvl1 = new CompositeLevel(); // transactions on CS or CORR
|
|
|
+ const lvl2 = new CompositeLevel(); // transactions on CS+CORR
|
|
|
+
|
|
|
+ // CS: a node is created, then deleted
|
|
|
+ const csNode = new NodeCreation(getId());
|
|
|
+ const csDel = new NodeDeletion(csNode, [], []);
|
|
|
+
|
|
|
+ const csNodeLvl1 = lvl1.createComposite([csNode]);
|
|
|
+ const csDelLvl1 = lvl1.createComposite([csDel]);
|
|
|
+
|
|
|
+ assert(csNodeLvl1.getConflicts().length === 0, "did not expect any conflicts so far");
|
|
|
+ assert(csDelLvl1.getConflicts().length === 0, "did not expect any conflicts so far");
|
|
|
+
|
|
|
+ // CORR: a link is created from a corr-node to the cs-node, followed by the deletion of the corr-node
|
|
|
+ // const corrLink = corrLvl.createComposite([csNode, new NodeCreation(getId()), corrLink]);
|
|
|
+ const corrNode = new NodeCreation(getId());
|
|
|
+ const corrLink = new EdgeCreation(corrNode, "cs", csNode);
|
|
|
+ const corrDel = new NodeDeletion(corrNode, [corrLink], []);
|
|
|
+
|
|
|
+ assert(_.isEqual(corrLink.getConflicts(), [csDel]), "expected corrLink to conflict with csDel");
|
|
|
+ assert(_.isEqual(csDel.getConflicts(), [corrLink]), "expected csDel to conflict with corrLink");
|
|
|
+
|
|
|
+ const corrLinkLvl1 = lvl1.createComposite([corrNode, corrLink]);
|
|
|
+
|
|
|
+ assert(_.isEqual(corrLinkLvl1.getConflicts(), [csDelLvl1]), "expected corrLinkLvl1 to conflict with csDelLvl1");
|
|
|
+ assert(_.isEqual(csDelLvl1.getConflicts(), [corrLinkLvl1]), "expected csDelLvl1 to conflict with corrLinkLvl1");
|
|
|
+
|
|
|
+ const csCorrLinkLvl2 = lvl2.createComposite([csNodeLvl1, corrLinkLvl1]);
|
|
|
+
|
|
|
+ assert(csCorrLinkLvl2.getConflicts().length === 0, "expected no conflicts here");
|
|
|
+
|
|
|
+ // Patch: in order to avoid a conflict between csDel and corrLink, in corrV2, we override csDel by csDel1.
|
|
|
+ const csDel1 = new NodeDeletion(csNode, [], [corrDel]);
|
|
|
+
|
|
|
+ assert(_.isEqual(csDel1.getConflicts(), [csDel]), "expected csDel1 to only conflict with csDel");
|
|
|
+
|
|
|
+ const corrDelLvl1 = lvl1.createComposite([corrDel]);
|
|
|
+ const csDel1Lvl1 = lvl1.createComposite([csDel1]);
|
|
|
+
|
|
|
+ assert(_.isEqual(csDel1Lvl1.getConflicts(), [csDelLvl1]), "expected csDel1Lvl1 to conflict with csDelLvl1");
|
|
|
+
|
|
|
+ const csCorrDelLvl2 = lvl2.createComposite([corrDelLvl1, csDel1Lvl1]);
|
|
|
+
|
|
|
+ assert(csCorrDelLvl2.getConflicts().length === 0, "expected no conflicts here");
|
|
|
+ });
|
|
|
});
|