composite_delta.test.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import * as _ from "lodash";
  2. import {
  3. NodeCreation,
  4. NodeDeletion,
  5. EdgeCreation,
  6. EdgeUpdate,
  7. PrimitiveRegistry,
  8. } from "./primitive_delta";
  9. import {
  10. CompositeLevel,
  11. } from "./composite_delta";
  12. import {
  13. mockUuid,
  14. } from "./test_helpers";
  15. import {
  16. assert,
  17. assertThrows,
  18. } from "../util/assert";
  19. describe("Composite delta", () => {
  20. it("Dependency", () => {
  21. const registry = new PrimitiveRegistry();
  22. const getId = mockUuid();
  23. const level = new CompositeLevel();
  24. const nodeCreation = registry.newNodeCreation(getId());
  25. const composite1 = level.createComposite([nodeCreation]);
  26. assert(_.isEqual(composite1.getDependencies(), []), "expected composite1 to have no dependencies");
  27. const nodeDeletion = registry.newNodeDeletion(nodeCreation, [], []);
  28. const nodeCreation2 = registry.newNodeCreation(getId());
  29. const composite2 = level.createComposite([nodeDeletion, nodeCreation2]);
  30. assert(_.isEqual(composite2.getDependencies(), [composite1]), "expected composite2 to depend on composite 1");
  31. });
  32. it("Conflict", () => {
  33. const registry = new PrimitiveRegistry();
  34. const getId = mockUuid();
  35. const level = new CompositeLevel();
  36. const nodeCreation = registry.newNodeCreation(getId());
  37. const compositeCreate = level.createComposite([nodeCreation]);
  38. const edgeCreation = registry.newEdgeCreation(nodeCreation, "label", nodeCreation);
  39. const compositeEdgeCreation = level.createComposite([edgeCreation]);
  40. assert(_.isEqual(compositeEdgeCreation.getConflicts(), []), "there should not yet be a conflict")
  41. const nodeDeletion = registry.newNodeDeletion(nodeCreation, [], []);
  42. const compositeDelete = level.createComposite([nodeDeletion]);
  43. assert(_.isEqual(compositeEdgeCreation.getConflicts(), [compositeDelete]), "expected compositeDelete1 to conflict with compositeDelete2");
  44. assert(_.isEqual(compositeDelete.getConflicts(), [compositeEdgeCreation]), "expected compositeDelete1 to conflict with compositeDelete2");
  45. });
  46. it("Conflict, but no composite yet", () => {
  47. const registry = new PrimitiveRegistry();
  48. const getId = mockUuid();
  49. const level = new CompositeLevel();
  50. // Same as above, but now we first create all the L0 deltas:
  51. const nodeCreation = registry.newNodeCreation(getId());
  52. const edgeCreation = registry.newEdgeCreation(nodeCreation, "label", nodeCreation);
  53. const nodeDeletion = registry.newNodeDeletion(nodeCreation, [], []);
  54. // And then the L1 deltas:
  55. const compositeCreate = level.createComposite([nodeCreation]);
  56. const compositeEdgeCreation = level.createComposite([edgeCreation]);
  57. assert(_.isEqual(compositeEdgeCreation.getConflicts(), []), "there should not yet be a conflict")
  58. const compositeDelete = level.createComposite([nodeDeletion]);
  59. assert(_.isEqual(compositeEdgeCreation.getConflicts(), [compositeDelete]), "expected compositeDelete1 to conflict with compositeDelete2");
  60. assert(_.isEqual(compositeDelete.getConflicts(), [compositeEdgeCreation]), "expected compositeDelete1 to conflict with compositeDelete2");
  61. });
  62. it("Conflicting deltas cannot be part of the same composite", () => {
  63. const registry = new PrimitiveRegistry();
  64. const getId = mockUuid();
  65. const level = new CompositeLevel();
  66. const nodeCreation = registry.newNodeCreation(getId());
  67. const edgeCreation = registry.newEdgeCreation(nodeCreation, "label", nodeCreation);
  68. const nodeDeletion = registry.newNodeDeletion(nodeCreation, [], []);
  69. assertThrows(() => {
  70. level.createComposite([nodeCreation, edgeCreation, nodeDeletion]);
  71. }, "should not be able to create a composite consisting of conflicting deltas");
  72. })
  73. // This was added after I found a bug:
  74. it("Dependency within composite", () => {
  75. const registry = new PrimitiveRegistry();
  76. const getId = mockUuid();
  77. const level = new CompositeLevel();
  78. const nodeCreation = registry.newNodeCreation(getId());
  79. const nodeDeletion = registry.newNodeDeletion(nodeCreation, [], []);
  80. const composite = level.createComposite([nodeCreation, nodeDeletion]);
  81. assert(_.isEqual(composite.getDependencies(), []), "expected composite to have no dependencies");
  82. assert(_.isEqual(composite.getConflicts(), []), "expected composite to have no conflicts");
  83. });
  84. it("Multi-level", () => {
  85. const registry = new PrimitiveRegistry();
  86. const getId = mockUuid();
  87. const lvl1 = new CompositeLevel(); // transactions on CS or CORR
  88. const lvl2 = new CompositeLevel(); // transactions on CS+CORR
  89. // CS: a node is created, then deleted
  90. const csNode = registry.newNodeCreation(getId());
  91. const csDel = registry.newNodeDeletion(csNode, [], []);
  92. const csNodeLvl1 = lvl1.createComposite([csNode]);
  93. const csDelLvl1 = lvl1.createComposite([csDel]);
  94. assert(csNodeLvl1.getConflicts().length === 0, "did not expect any conflicts so far");
  95. assert(csDelLvl1.getConflicts().length === 0, "did not expect any conflicts so far");
  96. // CORR: a link is created from a corr-node to the cs-node, followed by the deletion of the corr-node
  97. // const corrLink = corrLvl.createComposite([csNode, registry.newNodeCreation(getId()), corrLink]);
  98. const corrNode = registry.newNodeCreation(getId());
  99. const corrLink = registry.newEdgeCreation(corrNode, "cs", csNode);
  100. const corrDel = registry.newNodeDeletion(corrNode, [corrLink], []);
  101. assert(_.isEqual(corrLink.getConflicts(), [csDel]), "expected corrLink to conflict with csDel");
  102. assert(_.isEqual(csDel.getConflicts(), [corrLink]), "expected csDel to conflict with corrLink");
  103. const corrLinkLvl1 = lvl1.createComposite([corrNode, corrLink]);
  104. assert(_.isEqual(corrLinkLvl1.getConflicts(), [csDelLvl1]), "expected corrLinkLvl1 to conflict with csDelLvl1");
  105. assert(_.isEqual(csDelLvl1.getConflicts(), [corrLinkLvl1]), "expected csDelLvl1 to conflict with corrLinkLvl1");
  106. const csCorrLinkLvl2 = lvl2.createComposite([csNodeLvl1, corrLinkLvl1]);
  107. assert(csCorrLinkLvl2.getConflicts().length === 0, "expected no conflicts here");
  108. // Patch: in order to avoid a conflict between csDel and corrLink, in corrV2, we override csDel by csDel1.
  109. const csDel1 = registry.newNodeDeletion(csNode, [], [corrDel]);
  110. assert(_.isEqual(csDel1.getConflicts(), [csDel]), "expected csDel1 to only conflict with csDel");
  111. const corrDelLvl1 = lvl1.createComposite([corrDel]);
  112. const csDel1Lvl1 = lvl1.createComposite([csDel1]);
  113. assert(_.isEqual(csDel1Lvl1.getConflicts(), [csDelLvl1]), "expected csDel1Lvl1 to conflict with csDelLvl1");
  114. const csCorrDelLvl2 = lvl2.createComposite([corrDelLvl1, csDel1Lvl1]);
  115. assert(csCorrDelLvl2.getConflicts().length === 0, "expected no conflicts here");
  116. });
  117. });