@fluidframework/merge-tree 2.41.0 → 2.43.0-343119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/client.d.ts +9 -6
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +79 -36
  5. package/dist/client.js.map +1 -1
  6. package/dist/collections/list.d.ts +95 -5
  7. package/dist/collections/list.d.ts.map +1 -1
  8. package/dist/collections/list.js +67 -5
  9. package/dist/collections/list.js.map +1 -1
  10. package/dist/constants.d.ts +5 -0
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/constants.js +6 -1
  13. package/dist/constants.js.map +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/mergeTree.d.ts +9 -9
  19. package/dist/mergeTree.d.ts.map +1 -1
  20. package/dist/mergeTree.js +15 -7
  21. package/dist/mergeTree.js.map +1 -1
  22. package/dist/perspective.d.ts +15 -0
  23. package/dist/perspective.d.ts.map +1 -1
  24. package/dist/perspective.js +25 -1
  25. package/dist/perspective.js.map +1 -1
  26. package/dist/revertibles.js +1 -1
  27. package/dist/revertibles.js.map +1 -1
  28. package/dist/stamps.d.ts +1 -0
  29. package/dist/stamps.d.ts.map +1 -1
  30. package/dist/stamps.js +5 -1
  31. package/dist/stamps.js.map +1 -1
  32. package/dist/test/beastTest.spec.js +1 -1
  33. package/dist/test/beastTest.spec.js.map +1 -1
  34. package/dist/test/client.annotateMarker.spec.js +1 -1
  35. package/dist/test/client.annotateMarker.spec.js.map +1 -1
  36. package/dist/test/client.applyMsg.spec.js +25 -25
  37. package/dist/test/client.applyMsg.spec.js.map +1 -1
  38. package/dist/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  39. package/dist/test/client.applyStashedOpFarm.spec.js +3 -3
  40. package/dist/test/client.applyStashedOpFarm.spec.js.map +1 -1
  41. package/dist/test/client.attributionFarm.spec.js +1 -1
  42. package/dist/test/client.attributionFarm.spec.js.map +1 -1
  43. package/dist/test/client.getPosition.spec.js +1 -0
  44. package/dist/test/client.getPosition.spec.js.map +1 -1
  45. package/dist/test/client.localReference.spec.js +62 -48
  46. package/dist/test/client.localReference.spec.js.map +1 -1
  47. package/dist/test/client.localReferenceFarm.spec.js +1 -0
  48. package/dist/test/client.localReferenceFarm.spec.js.map +1 -1
  49. package/dist/test/client.reconnectFarm.spec.js +1 -1
  50. package/dist/test/client.reconnectFarm.spec.js.map +1 -1
  51. package/dist/test/client.rollback.spec.js +8 -6
  52. package/dist/test/client.rollback.spec.js.map +1 -1
  53. package/dist/test/client.searchForMarker.spec.js +2 -2
  54. package/dist/test/client.searchForMarker.spec.js.map +1 -1
  55. package/dist/test/clientTestHelper.js +1 -1
  56. package/dist/test/clientTestHelper.js.map +1 -1
  57. package/dist/test/mergeTree.annotate.spec.js +25 -25
  58. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  59. package/dist/test/mergeTree.markRangeRemoved.spec.js +1 -1
  60. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  61. package/dist/test/obliterate.spec.js +4 -4
  62. package/dist/test/obliterate.spec.js.map +1 -1
  63. package/dist/test/resetPendingSegmentsToOp.spec.js +14 -14
  64. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  65. package/dist/test/snapshot.utils.js +1 -1
  66. package/dist/test/snapshot.utils.js.map +1 -1
  67. package/dist/test/sortedSegmentSet.spec.js +3 -3
  68. package/dist/test/sortedSegmentSet.spec.js.map +1 -1
  69. package/dist/test/testClient.js +3 -3
  70. package/dist/test/testClient.js.map +1 -1
  71. package/dist/test/tracking.spec.js +7 -7
  72. package/dist/test/tracking.spec.js.map +1 -1
  73. package/dist/test/wordUnitTests.spec.js.map +1 -1
  74. package/lib/client.d.ts +9 -6
  75. package/lib/client.d.ts.map +1 -1
  76. package/lib/client.js +81 -38
  77. package/lib/client.js.map +1 -1
  78. package/lib/collections/list.d.ts +95 -5
  79. package/lib/collections/list.d.ts.map +1 -1
  80. package/lib/collections/list.js +67 -5
  81. package/lib/collections/list.js.map +1 -1
  82. package/lib/constants.d.ts +5 -0
  83. package/lib/constants.d.ts.map +1 -1
  84. package/lib/constants.js +5 -0
  85. package/lib/constants.js.map +1 -1
  86. package/lib/index.d.ts +1 -1
  87. package/lib/index.d.ts.map +1 -1
  88. package/lib/index.js +1 -1
  89. package/lib/index.js.map +1 -1
  90. package/lib/mergeTree.d.ts +9 -9
  91. package/lib/mergeTree.d.ts.map +1 -1
  92. package/lib/mergeTree.js +15 -7
  93. package/lib/mergeTree.js.map +1 -1
  94. package/lib/perspective.d.ts +15 -0
  95. package/lib/perspective.d.ts.map +1 -1
  96. package/lib/perspective.js +23 -0
  97. package/lib/perspective.js.map +1 -1
  98. package/lib/revertibles.js +1 -1
  99. package/lib/revertibles.js.map +1 -1
  100. package/lib/stamps.d.ts +1 -0
  101. package/lib/stamps.d.ts.map +1 -1
  102. package/lib/stamps.js +4 -1
  103. package/lib/stamps.js.map +1 -1
  104. package/lib/test/beastTest.spec.js +1 -1
  105. package/lib/test/beastTest.spec.js.map +1 -1
  106. package/lib/test/client.annotateMarker.spec.js +1 -1
  107. package/lib/test/client.annotateMarker.spec.js.map +1 -1
  108. package/lib/test/client.applyMsg.spec.js +25 -25
  109. package/lib/test/client.applyMsg.spec.js.map +1 -1
  110. package/lib/test/client.applyStashedOpFarm.spec.d.ts.map +1 -1
  111. package/lib/test/client.applyStashedOpFarm.spec.js +3 -3
  112. package/lib/test/client.applyStashedOpFarm.spec.js.map +1 -1
  113. package/lib/test/client.attributionFarm.spec.js +1 -1
  114. package/lib/test/client.attributionFarm.spec.js.map +1 -1
  115. package/lib/test/client.getPosition.spec.js +1 -0
  116. package/lib/test/client.getPosition.spec.js.map +1 -1
  117. package/lib/test/client.localReference.spec.js +62 -48
  118. package/lib/test/client.localReference.spec.js.map +1 -1
  119. package/lib/test/client.localReferenceFarm.spec.js +1 -0
  120. package/lib/test/client.localReferenceFarm.spec.js.map +1 -1
  121. package/lib/test/client.reconnectFarm.spec.js +1 -1
  122. package/lib/test/client.reconnectFarm.spec.js.map +1 -1
  123. package/lib/test/client.rollback.spec.js +8 -6
  124. package/lib/test/client.rollback.spec.js.map +1 -1
  125. package/lib/test/client.searchForMarker.spec.js +2 -2
  126. package/lib/test/client.searchForMarker.spec.js.map +1 -1
  127. package/lib/test/clientTestHelper.js +1 -1
  128. package/lib/test/clientTestHelper.js.map +1 -1
  129. package/lib/test/mergeTree.annotate.spec.js +25 -25
  130. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  131. package/lib/test/mergeTree.markRangeRemoved.spec.js +1 -1
  132. package/lib/test/mergeTree.markRangeRemoved.spec.js.map +1 -1
  133. package/lib/test/obliterate.spec.js +4 -4
  134. package/lib/test/obliterate.spec.js.map +1 -1
  135. package/lib/test/resetPendingSegmentsToOp.spec.js +14 -14
  136. package/lib/test/resetPendingSegmentsToOp.spec.js.map +1 -1
  137. package/lib/test/snapshot.utils.js +1 -1
  138. package/lib/test/snapshot.utils.js.map +1 -1
  139. package/lib/test/sortedSegmentSet.spec.js +3 -3
  140. package/lib/test/sortedSegmentSet.spec.js.map +1 -1
  141. package/lib/test/testClient.js +3 -3
  142. package/lib/test/testClient.js.map +1 -1
  143. package/lib/test/tracking.spec.js +7 -7
  144. package/lib/test/tracking.spec.js.map +1 -1
  145. package/lib/test/wordUnitTests.spec.js.map +1 -1
  146. package/package.json +16 -16
  147. package/src/client.ts +117 -50
  148. package/src/collections/list.ts +101 -5
  149. package/src/constants.ts +6 -0
  150. package/src/index.ts +3 -0
  151. package/src/mergeTree.ts +30 -24
  152. package/src/perspective.ts +26 -0
  153. package/src/revertibles.ts +1 -1
  154. package/src/stamps.ts +9 -1
@@ -1 +1 @@
1
- {"version":3,"file":"client.applyStashedOpFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.applyStashedOpFarm.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { describeFuzz, makeRandom } from \"@fluid-private/stochastic-test-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\n\nimport { SegmentGroup } from \"../mergeTreeNodes.js\";\nimport { IMergeTreeOp, MergeTreeDeltaType } from \"../ops.js\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tannotateRange,\n\tdoOverRange,\n\tgenerateClientNames,\n\tinsert,\n\tremoveRange,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport { TestClient } from \"./testClient.js\";\nimport { TestClientLogger } from \"./testClientLogger.js\";\n\nfunction applyMessagesWithReconnect(\n\tstartingSeq: number,\n\tmessageDatas: [ISequencedDocumentMessage, SegmentGroup | SegmentGroup[]][],\n\tclients: readonly TestClient[],\n\tstashClients: readonly TestClient[],\n): number {\n\tlet seq = startingSeq;\n\tconst reconnectClientMsgs: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] = [];\n\tlet minSeq = 0;\n\n\t// apply ops as stashed ops except for client #1\n\tconst stashedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[], number][] = [];\n\tfor (const messageData of messageDatas) {\n\t\tif (messageData[0].clientId !== clients[1].longClientId) {\n\t\t\tconst index = clients\n\t\t\t\t.map((c) => c.longClientId)\n\t\t\t\t.indexOf(messageData[0].clientId as string);\n\t\t\tconst op = messageData[0].contents as IMergeTreeOp;\n\t\t\tstashClients[index].applyStashedOp(op);\n\t\t\tstashedOps.push([\n\t\t\t\top,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tstashClients[index].peekPendingSegmentGroups(\n\t\t\t\t\top.type === MergeTreeDeltaType.GROUP ? op.ops.length : 1,\n\t\t\t\t)!,\n\t\t\t\tindex,\n\t\t\t]);\n\t\t}\n\t}\n\t// this should put all stash clients (except #1) in the same state as the\n\t// respective normal clients, having local changes only.\n\tfor (let i = 0; i < clients.length; ++i) {\n\t\tif (i !== 1) {\n\t\t\tTestClientLogger.validate([clients[i], stashClients[i]]);\n\t\t}\n\t}\n\tTestClientLogger.validate([clients[0], stashClients[1]]);\n\n\t// apply the ops to the normal clients. they will all be the same now,\n\t// except #1 which has local changes other clients haven't seen yet\n\tfor (const [message, sg] of messageDatas) {\n\t\tif (message.clientId === clients[1].longClientId) {\n\t\t\treconnectClientMsgs.push([message.contents as IMergeTreeOp, sg]);\n\t\t} else {\n\t\t\tmessage.sequenceNumber = ++seq;\n\t\t\tfor (const c of clients) c.applyMsg(message);\n\t\t\tminSeq = message.minimumSequenceNumber;\n\t\t}\n\t}\n\n\t// regenerate the ops that were applied as stashed ops. this simulates resubmit()\n\tconst regeneratedStashedOps = stashedOps.map((op) =>\n\t\tstashClients[op[2]].makeOpMessage(stashClients[op[2]].regeneratePendingOp(op[0], op[1])),\n\t);\n\n\t// apply the regenerated stashed ops\n\tlet stashedOpSeq = startingSeq;\n\tfor (const msg of regeneratedStashedOps) {\n\t\tmsg.sequenceNumber = ++stashedOpSeq;\n\t\tfor (const c of stashClients) c.applyMsg(msg);\n\t}\n\t// all stash and normal clients should now be in the same state,\n\t// except #1 (normal) which still has local changes\n\tTestClientLogger.validate([...clients.filter((_, i) => i !== 1), ...stashClients]);\n\n\t// regenerate ops for client #1\n\tconst reconnectMsgs: ISequencedDocumentMessage[] = [];\n\tfor (const opData of reconnectClientMsgs) {\n\t\tconst newMsg = clients[1].makeOpMessage(\n\t\t\tclients[1].regeneratePendingOp(opData[0], opData[1]),\n\t\t);\n\t\tnewMsg.minimumSequenceNumber = minSeq;\n\t\treconnectMsgs.push(newMsg);\n\t}\n\n\t// apply regenerated ops as stashed ops for client #1\n\tconst stashedRegeneratedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] =\n\t\treconnectMsgs.map((message) => {\n\t\t\tconst op = message.contents as IMergeTreeOp;\n\t\t\tstashClients[1].applyStashedOp(op);\n\t\t\treturn [\n\t\t\t\top,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tstashClients[1].peekPendingSegmentGroups(\n\t\t\t\t\top.type === MergeTreeDeltaType.GROUP ? op.ops.length : 1,\n\t\t\t\t)!,\n\t\t\t];\n\t\t});\n\t// now both clients at index 1 should be the same\n\tTestClientLogger.validate([clients[1], stashClients[1]]);\n\n\t// apply the regenerated ops from client #1\n\tfor (const message of reconnectMsgs) {\n\t\tmessage.sequenceNumber = ++seq;\n\t\tfor (const c of clients) c.applyMsg(message);\n\t}\n\n\t// resubmit regenerated stashed ops\n\tconst reRegeneratedStashedMessages = stashedRegeneratedOps.map((stashedOp) =>\n\t\tstashClients[1].makeOpMessage(\n\t\t\tstashClients[1].regeneratePendingOp(stashedOp[0], stashedOp[1]),\n\t\t),\n\t);\n\n\tfor (const reRegeneratedStashedOp of reRegeneratedStashedMessages) {\n\t\treRegeneratedStashedOp.sequenceNumber = ++stashedOpSeq;\n\t\tfor (const c of stashClients) c.applyMsg(reRegeneratedStashedOp);\n\t}\n\n\t// all clients should now be the same\n\tTestClientLogger.validate([...clients, ...stashClients]);\n\n\treturn seq;\n}\n\ninterface IApplyStashedOpFarmConfig extends IMergeTreeOperationRunnerConfig {\n\tminLength: number;\n\tclients: IConfigRange;\n}\n\nexport const defaultOptions: IApplyStashedOpFarmConfig = {\n\tminLength: 16,\n\tclients: { min: 3, max: 12 },\n\topsPerRoundRange: { min: 40, max: 120 },\n\trounds: 3,\n\toperations: [annotateRange, removeRange, insert],\n\tgrowthFunc: (input: number) => input * 2,\n};\n\n// Generate a list of single character client names, support up to 69 clients\nconst clientNames = generateClientNames();\n\nfunction runApplyStashedOpFarmTests(\n\topts: IApplyStashedOpFarmConfig,\n\textraSeed?: number,\n): void {\n\tdoOverRange(opts.clients, opts.growthFunc.bind(opts), (clientCount) => {\n\t\tit(`applyStashedOpFarm_${clientCount}`, async () => {\n\t\t\tconst random = makeRandom(0xdeadbeef, 0xfeedbed, clientCount, extraSeed ?? 0);\n\t\t\tconst testOpts = { ...opts };\n\t\t\tif (extraSeed) {\n\t\t\t\ttestOpts.resultsFilePostfix ??= \"\";\n\t\t\t\ttestOpts.resultsFilePostfix += extraSeed;\n\t\t\t}\n\n\t\t\tconst clients: TestClient[] = [new TestClient({ mergeTreeEnableAnnotateAdjust: true })];\n\t\t\t// This test is based on reconnectFarm, but we keep a second set of clients. For\n\t\t\t// these clients, we apply the generated ops as stashed ops, then regenerate\n\t\t\t// them to simulate resubmit(), then apply them. In the end, they should arrive\n\t\t\t// at the same state as the \"normal\" set of clients\n\t\t\tlet stashClients: TestClient[] = [];\n\n\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\t\t\tstashClients = [new TestClient({ mergeTreeEnableAnnotateAdjust: true })];\n\t\t\tfor (const [i, c] of stashClients.entries())\n\t\t\t\tc.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\tlet seq = 0;\n\t\t\tfor (const c of clients) c.updateMinSeq(seq);\n\t\t\tfor (const c of stashClients) c.updateMinSeq(seq);\n\n\t\t\t// Add double the number of clients each iteration\n\t\t\tconst targetClients = Math.max(opts.clients.min, clientCount);\n\t\t\tfor (let cc = clients.length; cc < targetClients; cc++) {\n\t\t\t\tconst newClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\tclients[0],\n\t\t\t\t\tclientNames[cc],\n\t\t\t\t);\n\t\t\t\tclients.push(newClient);\n\t\t\t\t// add 1 stash client per normal client\n\t\t\t\tconst anotherNewClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\tclients[0],\n\t\t\t\t\tclientNames[cc],\n\t\t\t\t);\n\t\t\t\tstashClients.push(anotherNewClient);\n\t\t\t}\n\n\t\t\tseq = runMergeTreeOperationRunner(\n\t\t\t\trandom,\n\t\t\t\tseq,\n\t\t\t\tclients,\n\t\t\t\topts.minLength,\n\t\t\t\topts,\n\t\t\t\t(s, m, c) => applyMessagesWithReconnect(s, m, c, stashClients),\n\t\t\t);\n\t\t}).timeout(30 * 1000);\n\t});\n}\n\ndescribeFuzz(\"MergeTree.Client\", ({ testCount }) => {\n\tconst opts = defaultOptions;\n\n\tif (testCount > 1) {\n\t\tdoOverRange(\n\t\t\t{ min: 0, max: testCount - 1 },\n\t\t\t(x) => x + 1,\n\t\t\t(seed) => {\n\t\t\t\tdescribe(`with seed ${seed}`, () => {\n\t\t\t\t\trunApplyStashedOpFarmTests(opts, seed);\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t} else {\n\t\trunApplyStashedOpFarmTests(opts);\n\t}\n});\n"]}
1
+ {"version":3,"file":"client.applyStashedOpFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.applyStashedOpFarm.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { describeFuzz, makeRandom } from \"@fluid-private/stochastic-test-utils\";\nimport { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\n\nimport { SegmentGroup } from \"../mergeTreeNodes.js\";\nimport { IMergeTreeOp, MergeTreeDeltaType } from \"../ops.js\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tannotateRange,\n\tdoOverRange,\n\tgenerateClientNames,\n\tinsert,\n\tremoveRange,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport { TestClient } from \"./testClient.js\";\nimport { TestClientLogger } from \"./testClientLogger.js\";\n\nfunction applyMessagesWithReconnect(\n\tstartingSeq: number,\n\tmessageDatas: [ISequencedDocumentMessage, SegmentGroup | SegmentGroup[]][],\n\tclients: readonly TestClient[],\n\tstashClients: readonly TestClient[],\n): number {\n\tlet seq = startingSeq;\n\tconst reconnectClientMsgs: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] = [];\n\tlet minSeq = 0;\n\n\t// apply ops as stashed ops except for client #1\n\tconst stashedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[], number][] = [];\n\tfor (const messageData of messageDatas) {\n\t\tif (messageData[0].clientId !== clients[1].longClientId) {\n\t\t\tconst index = clients\n\t\t\t\t.map((c) => c.longClientId)\n\t\t\t\t.indexOf(messageData[0].clientId as string);\n\t\t\tconst op = messageData[0].contents as IMergeTreeOp;\n\t\t\tstashClients[index].applyStashedOp(op);\n\t\t\tstashedOps.push([\n\t\t\t\top,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tstashClients[index].peekPendingSegmentGroups(\n\t\t\t\t\top.type === MergeTreeDeltaType.GROUP ? op.ops.length : 1,\n\t\t\t\t)!,\n\t\t\t\tindex,\n\t\t\t]);\n\t\t}\n\t}\n\t// this should put all stash clients (except #1) in the same state as the\n\t// respective normal clients, having local changes only.\n\tfor (let i = 0; i < clients.length; ++i) {\n\t\tif (i !== 1) {\n\t\t\tTestClientLogger.validate([clients[i], stashClients[i]]);\n\t\t}\n\t}\n\tTestClientLogger.validate([clients[0], stashClients[1]]);\n\n\t// apply the ops to the normal clients. they will all be the same now,\n\t// except #1 which has local changes other clients haven't seen yet\n\tfor (const [message, sg] of messageDatas) {\n\t\tif (message.clientId === clients[1].longClientId) {\n\t\t\treconnectClientMsgs.push([message.contents as IMergeTreeOp, sg]);\n\t\t} else {\n\t\t\tmessage.sequenceNumber = ++seq;\n\t\t\tfor (const c of clients) c.applyMsg(message);\n\t\t\tminSeq = message.minimumSequenceNumber;\n\t\t}\n\t}\n\n\t// regenerate the ops that were applied as stashed ops. this simulates resubmit()\n\tconst regeneratedStashedOps = stashedOps.map((op) =>\n\t\tstashClients[op[2]].makeOpMessage(\n\t\t\tstashClients[op[2]].regeneratePendingOp(op[0], op[1], false),\n\t\t),\n\t);\n\n\t// apply the regenerated stashed ops\n\tlet stashedOpSeq = startingSeq;\n\tfor (const msg of regeneratedStashedOps) {\n\t\tmsg.sequenceNumber = ++stashedOpSeq;\n\t\tfor (const c of stashClients) c.applyMsg(msg);\n\t}\n\t// all stash and normal clients should now be in the same state,\n\t// except #1 (normal) which still has local changes\n\tTestClientLogger.validate([...clients.filter((_, i) => i !== 1), ...stashClients]);\n\n\t// regenerate ops for client #1\n\tconst reconnectMsgs: ISequencedDocumentMessage[] = [];\n\tfor (const opData of reconnectClientMsgs) {\n\t\tconst newMsg = clients[1].makeOpMessage(\n\t\t\tclients[1].regeneratePendingOp(opData[0], opData[1], false),\n\t\t);\n\t\tnewMsg.minimumSequenceNumber = minSeq;\n\t\treconnectMsgs.push(newMsg);\n\t}\n\n\t// apply regenerated ops as stashed ops for client #1\n\tconst stashedRegeneratedOps: [IMergeTreeOp, SegmentGroup | SegmentGroup[]][] =\n\t\treconnectMsgs.map((message) => {\n\t\t\tconst op = message.contents as IMergeTreeOp;\n\t\t\tstashClients[1].applyStashedOp(op);\n\t\t\treturn [\n\t\t\t\top,\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\tstashClients[1].peekPendingSegmentGroups(\n\t\t\t\t\top.type === MergeTreeDeltaType.GROUP ? op.ops.length : 1,\n\t\t\t\t)!,\n\t\t\t];\n\t\t});\n\t// now both clients at index 1 should be the same\n\tTestClientLogger.validate([clients[1], stashClients[1]]);\n\n\t// apply the regenerated ops from client #1\n\tfor (const message of reconnectMsgs) {\n\t\tmessage.sequenceNumber = ++seq;\n\t\tfor (const c of clients) c.applyMsg(message);\n\t}\n\n\t// resubmit regenerated stashed ops\n\tconst reRegeneratedStashedMessages = stashedRegeneratedOps.map((stashedOp) =>\n\t\tstashClients[1].makeOpMessage(\n\t\t\tstashClients[1].regeneratePendingOp(stashedOp[0], stashedOp[1], false),\n\t\t),\n\t);\n\n\tfor (const reRegeneratedStashedOp of reRegeneratedStashedMessages) {\n\t\treRegeneratedStashedOp.sequenceNumber = ++stashedOpSeq;\n\t\tfor (const c of stashClients) c.applyMsg(reRegeneratedStashedOp);\n\t}\n\n\t// all clients should now be the same\n\tTestClientLogger.validate([...clients, ...stashClients]);\n\n\treturn seq;\n}\n\ninterface IApplyStashedOpFarmConfig extends IMergeTreeOperationRunnerConfig {\n\tminLength: number;\n\tclients: IConfigRange;\n}\n\nexport const defaultOptions: IApplyStashedOpFarmConfig = {\n\tminLength: 16,\n\tclients: { min: 3, max: 12 },\n\topsPerRoundRange: { min: 40, max: 120 },\n\trounds: 3,\n\toperations: [annotateRange, removeRange, insert],\n\tgrowthFunc: (input: number) => input * 2,\n};\n\n// Generate a list of single character client names, support up to 69 clients\nconst clientNames = generateClientNames();\n\nfunction runApplyStashedOpFarmTests(\n\topts: IApplyStashedOpFarmConfig,\n\textraSeed?: number,\n): void {\n\tdoOverRange(opts.clients, opts.growthFunc.bind(opts), (clientCount) => {\n\t\tit(`applyStashedOpFarm_${clientCount}`, async () => {\n\t\t\tconst random = makeRandom(0xdeadbeef, 0xfeedbed, clientCount, extraSeed ?? 0);\n\t\t\tconst testOpts = { ...opts };\n\t\t\tif (extraSeed) {\n\t\t\t\ttestOpts.resultsFilePostfix ??= \"\";\n\t\t\t\ttestOpts.resultsFilePostfix += extraSeed;\n\t\t\t}\n\n\t\t\tconst clients: TestClient[] = [new TestClient({ mergeTreeEnableAnnotateAdjust: true })];\n\t\t\t// This test is based on reconnectFarm, but we keep a second set of clients. For\n\t\t\t// these clients, we apply the generated ops as stashed ops, then regenerate\n\t\t\t// them to simulate resubmit(), then apply them. In the end, they should arrive\n\t\t\t// at the same state as the \"normal\" set of clients\n\t\t\tlet stashClients: TestClient[] = [];\n\n\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\t\t\tstashClients = [new TestClient({ mergeTreeEnableAnnotateAdjust: true })];\n\t\t\tfor (const [i, c] of stashClients.entries())\n\t\t\t\tc.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\tlet seq = 0;\n\t\t\tfor (const c of clients) c.updateMinSeq(seq);\n\t\t\tfor (const c of stashClients) c.updateMinSeq(seq);\n\n\t\t\t// Add double the number of clients each iteration\n\t\t\tconst targetClients = Math.max(opts.clients.min, clientCount);\n\t\t\tfor (let cc = clients.length; cc < targetClients; cc++) {\n\t\t\t\tconst newClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\tclients[0],\n\t\t\t\t\tclientNames[cc],\n\t\t\t\t);\n\t\t\t\tclients.push(newClient);\n\t\t\t\t// add 1 stash client per normal client\n\t\t\t\tconst anotherNewClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\tclients[0],\n\t\t\t\t\tclientNames[cc],\n\t\t\t\t);\n\t\t\t\tstashClients.push(anotherNewClient);\n\t\t\t}\n\n\t\t\tseq = runMergeTreeOperationRunner(\n\t\t\t\trandom,\n\t\t\t\tseq,\n\t\t\t\tclients,\n\t\t\t\topts.minLength,\n\t\t\t\topts,\n\t\t\t\t(s, m, c) => applyMessagesWithReconnect(s, m, c, stashClients),\n\t\t\t);\n\t\t}).timeout(30 * 1000);\n\t});\n}\n\ndescribeFuzz(\"MergeTree.Client\", ({ testCount }) => {\n\tconst opts = defaultOptions;\n\n\tif (testCount > 1) {\n\t\tdoOverRange(\n\t\t\t{ min: 0, max: testCount - 1 },\n\t\t\t(x) => x + 1,\n\t\t\t(seed) => {\n\t\t\t\tdescribe(`with seed ${seed}`, () => {\n\t\t\t\t\trunApplyStashedOpFarmTests(opts, seed);\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t} else {\n\t\trunApplyStashedOpFarmTests(opts);\n\t}\n});\n"]}
@@ -37,7 +37,7 @@ describeFuzz("MergeTree.Attribution", ({ testCount }) => {
37
37
  for (const [i, c] of clients.entries())
38
38
  c.startOrUpdateCollaboration(clientNames[i]);
39
39
  const getAttributionAtPosition = (client, pos) => {
40
- const { segment, offset } = client.getContainingSegment(pos);
40
+ const { segment, offset } = client.getContainingSegment(pos) ?? {};
41
41
  if (segment?.attribution === undefined || offset === undefined) {
42
42
  return undefined;
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.attributionFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.attributionFarm.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { describeFuzz, makeRandom } from \"@fluid-private/stochastic-test-utils\";\nimport { generatePairwiseOptions } from \"@fluid-private/test-pairwise-generator\";\nimport { AttributionKey } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { createPropertyTrackingAndInsertionAttributionPolicyFactory } from \"../attributionPolicy.js\";\nimport type { ISegmentPrivate } from \"../mergeTreeNodes.js\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tTestOperation,\n\tgenerateClientNames,\n\tinsert,\n\tremoveRange,\n\tresolveRanges,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport { TestClient } from \"./testClient.js\";\nimport { TestClientLogger } from \"./testClientLogger.js\";\n\nexport const annotateRange: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n) => client.annotateRangeLocal(opStart, opEnd, { trackedProp: client.longClientId });\n\nconst defaultOptions: Record<\"initLen\" | \"modLen\", IConfigRange> &\n\tIMergeTreeOperationRunnerConfig = {\n\tinitLen: { min: 2, max: 4 },\n\tmodLen: { min: 1, max: 8 },\n\topsPerRoundRange: { min: 10, max: 40 },\n\trounds: 10,\n\toperations: [removeRange, annotateRange, insert],\n\tgrowthFunc: (input: number) => input * 2,\n};\n\ndescribeFuzz(\"MergeTree.Attribution\", ({ testCount }) => {\n\t// Generate a list of single character client names, support up to 69 clients\n\tconst clientNames = generateClientNames();\n\tconst rangeOptions = resolveRanges(defaultOptions, defaultOptions.growthFunc);\n\tfor (let extraSeed = 0; extraSeed < testCount; extraSeed++) {\n\t\tfor (const { initLen, modLen, opsPerRoundRange } of generatePairwiseOptions(\n\t\t\trangeOptions,\n\t\t)) {\n\t\t\tit(`AttributionFarm_${initLen}_${modLen}_${opsPerRoundRange}`, async () => {\n\t\t\t\tconst random = makeRandom(0xdeadbeef, initLen, modLen, extraSeed ?? 0);\n\n\t\t\t\tconst clients: TestClient[] = Array.from({ length: 3 })\n\t\t\t\t\t.fill(0)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\tnew TestClient({\n\t\t\t\t\t\t\t\tattribution: {\n\t\t\t\t\t\t\t\t\ttrack: true,\n\t\t\t\t\t\t\t\t\tpolicyFactory:\n\t\t\t\t\t\t\t\t\t\tcreatePropertyTrackingAndInsertionAttributionPolicyFactory(\"trackedProp\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\t\tconst getAttributionAtPosition = (\n\t\t\t\t\tclient: TestClient,\n\t\t\t\t\tpos: number,\n\t\t\t\t):\n\t\t\t\t\t| {\n\t\t\t\t\t\t\t[name: string]: AttributionKey | undefined;\n\t\t\t\t\t }\n\t\t\t\t\t| undefined => {\n\t\t\t\t\tconst { segment, offset } = client.getContainingSegment<ISegmentPrivate>(pos);\n\t\t\t\t\tif (segment?.attribution === undefined || offset === undefined) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tconst { attribution } = segment;\n\t\t\t\t\tlet channels: { [name: string]: AttributionKey | undefined } | undefined;\n\t\t\t\t\tconst result: {\n\t\t\t\t\t\troot: AttributionKey | undefined;\n\t\t\t\t\t\tchannels?: { [name: string]: AttributionKey | undefined };\n\t\t\t\t\t} = {\n\t\t\t\t\t\troot: attribution.getAtOffset(offset),\n\t\t\t\t\t};\n\t\t\t\t\tfor (const name of attribution.channelNames) {\n\t\t\t\t\t\t(channels ??= {})[name] = attribution.getAtOffset(offset, name);\n\t\t\t\t\t\tresult.channels = channels;\n\t\t\t\t\t}\n\t\t\t\t\treturn channels;\n\t\t\t\t};\n\n\t\t\t\tconst validateAnnotation = (reason: string, workload: () => void): void => {\n\t\t\t\t\tconst preWorkload = TestClientLogger.toString(clients);\n\t\t\t\t\tworkload();\n\t\t\t\t\tconst attributions = Array.from({ length: clients[0].getLength() }).map((_, i) =>\n\t\t\t\t\t\tgetAttributionAtPosition(clients[0], i),\n\t\t\t\t\t);\n\t\t\t\t\tfor (let c = 1; c < clients.length; c++) {\n\t\t\t\t\t\tfor (let i = 0; i < clients[c].getLength(); i++) {\n\t\t\t\t\t\t\tconst attribution0 = attributions[i];\n\t\t\t\t\t\t\tconst attributionC = getAttributionAtPosition(clients[c], i);\n\t\t\t\t\t\t\tif (attribution0 !== attributionC) {\n\t\t\t\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\t\t\t\tattribution0,\n\t\t\t\t\t\t\t\t\tattributionC,\n\t\t\t\t\t\t\t\t\t`${reason}:\\n${preWorkload}\\n${TestClientLogger.toString([\n\t\t\t\t\t\t\t\t\t\tclients[0],\n\t\t\t\t\t\t\t\t\t\tclients[c],\n\t\t\t\t\t\t\t\t\t])}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tlet seq = 0;\n\n\t\t\t\tvalidateAnnotation(\"Initialize\", () => {\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, initLen, defaultOptions);\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After Init Zamboni\", () => {\n\t\t\t\t\t// trigger zamboni multiple times as it is incremental\n\t\t\t\t\tfor (let i = clients[0].getCollabWindow().minSeq; i <= seq; i++) {\n\t\t\t\t\t\tfor (const c of clients) c.updateMinSeq(i);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After More Ops\", () => {\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, modLen, defaultOptions);\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After Final Zamboni\", () => {\n\t\t\t\t\t// trigger zamboni multiple times as it is incremental\n\t\t\t\t\tfor (let i = clients[0].getCollabWindow().minSeq; i <= seq; i++) {\n\t\t\t\t\t\tfor (const c of clients) c.updateMinSeq(i);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n});\n"]}
1
+ {"version":3,"file":"client.attributionFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.attributionFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,wCAAwC,CAAC;AAGjF,OAAO,EAAE,0DAA0D,EAAE,MAAM,yBAAyB,CAAC;AAGrG,OAAO,EAIN,mBAAmB,EACnB,MAAM,EACN,WAAW,EACX,aAAa,EACb,2BAA2B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,CAAC,MAAM,aAAa,GAAkB,CAC3C,MAAkB,EAClB,OAAe,EACf,KAAa,EACZ,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;AAErF,MAAM,cAAc,GACe;IAClC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;IAC3B,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;IAC1B,gBAAgB,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;IACtC,MAAM,EAAE,EAAE;IACV,UAAU,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,MAAM,CAAC;IAChD,UAAU,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC;CACxC,CAAC;AAEF,YAAY,CAAC,uBAAuB,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;IACvD,6EAA6E;IAC7E,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAC;IAC1C,MAAM,YAAY,GAAG,aAAa,CAAC,cAAc,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAC9E,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,EAAE,CAAC;QAC5D,KAAK,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,IAAI,uBAAuB,CAC1E,YAAY,CACZ,EAAE,CAAC;YACH,EAAE,CAAC,mBAAmB,OAAO,IAAI,MAAM,IAAI,gBAAgB,EAAE,EAAE,KAAK,IAAI,EAAE;gBACzE,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC;gBAEvE,MAAM,OAAO,GAAiB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;qBACrD,IAAI,CAAC,CAAC,CAAC;qBACP,GAAG,CACH,GAAG,EAAE,CACJ,IAAI,UAAU,CAAC;oBACd,WAAW,EAAE;wBACZ,KAAK,EAAE,IAAI;wBACX,aAAa,EACZ,0DAA0D,CAAC,aAAa,CAAC;qBAC1E;iBACD,CAAC,CACH,CAAC;gBACH,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE;oBAAE,CAAC,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;gBAErF,MAAM,wBAAwB,GAAG,CAChC,MAAkB,EAClB,GAAW,EAKC,EAAE;oBACd,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,oBAAoB,CAAkB,GAAG,CAAC,IAAI,EAAE,CAAC;oBACpF,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBAChE,OAAO,SAAS,CAAC;oBAClB,CAAC;oBACD,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;oBAChC,IAAI,QAAoE,CAAC;oBACzE,MAAM,MAAM,GAGR;wBACH,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC;qBACrC,CAAC;oBACF,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,YAAY,EAAE,CAAC;wBAC7C,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;wBAChE,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;oBAC5B,CAAC;oBACD,OAAO,QAAQ,CAAC;gBACjB,CAAC,CAAC;gBAEF,MAAM,kBAAkB,GAAG,CAAC,MAAc,EAAE,QAAoB,EAAQ,EAAE;oBACzE,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;oBACvD,QAAQ,EAAE,CAAC;oBACX,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAChF,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACvC,CAAC;oBACF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;4BACjD,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;4BACrC,MAAM,YAAY,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;4BAC7D,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;gCACnC,MAAM,CAAC,SAAS,CACf,YAAY,EACZ,YAAY,EACZ,GAAG,MAAM,MAAM,WAAW,KAAK,gBAAgB,CAAC,QAAQ,CAAC;oCACxD,OAAO,CAAC,CAAC,CAAC;oCACV,OAAO,CAAC,CAAC,CAAC;iCACV,CAAC,EAAE,CACJ,CAAC;4BACH,CAAC;wBACF,CAAC;oBACF,CAAC;gBACF,CAAC,CAAC;gBAEF,IAAI,GAAG,GAAG,CAAC,CAAC;gBAEZ,kBAAkB,CAAC,YAAY,EAAE,GAAG,EAAE;oBACrC,GAAG,GAAG,2BAA2B,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;gBAClF,CAAC,CAAC,CAAC;gBAEH,kBAAkB,CAAC,oBAAoB,EAAE,GAAG,EAAE;oBAC7C,sDAAsD;oBACtD,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;wBACjE,KAAK,MAAM,CAAC,IAAI,OAAO;4BAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;oBAC5C,CAAC;gBACF,CAAC,CAAC,CAAC;gBAEH,kBAAkB,CAAC,gBAAgB,EAAE,GAAG,EAAE;oBACzC,GAAG,GAAG,2BAA2B,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;gBACjF,CAAC,CAAC,CAAC;gBAEH,kBAAkB,CAAC,qBAAqB,EAAE,GAAG,EAAE;oBAC9C,sDAAsD;oBACtD,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;wBACjE,KAAK,MAAM,CAAC,IAAI,OAAO;4BAAE,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;oBAC5C,CAAC;gBACF,CAAC,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;AACF,CAAC,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { describeFuzz, makeRandom } from \"@fluid-private/stochastic-test-utils\";\nimport { generatePairwiseOptions } from \"@fluid-private/test-pairwise-generator\";\nimport { AttributionKey } from \"@fluidframework/runtime-definitions/internal\";\n\nimport { createPropertyTrackingAndInsertionAttributionPolicyFactory } from \"../attributionPolicy.js\";\nimport type { ISegmentPrivate } from \"../mergeTreeNodes.js\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tTestOperation,\n\tgenerateClientNames,\n\tinsert,\n\tremoveRange,\n\tresolveRanges,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport { TestClient } from \"./testClient.js\";\nimport { TestClientLogger } from \"./testClientLogger.js\";\n\nexport const annotateRange: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n) => client.annotateRangeLocal(opStart, opEnd, { trackedProp: client.longClientId });\n\nconst defaultOptions: Record<\"initLen\" | \"modLen\", IConfigRange> &\n\tIMergeTreeOperationRunnerConfig = {\n\tinitLen: { min: 2, max: 4 },\n\tmodLen: { min: 1, max: 8 },\n\topsPerRoundRange: { min: 10, max: 40 },\n\trounds: 10,\n\toperations: [removeRange, annotateRange, insert],\n\tgrowthFunc: (input: number) => input * 2,\n};\n\ndescribeFuzz(\"MergeTree.Attribution\", ({ testCount }) => {\n\t// Generate a list of single character client names, support up to 69 clients\n\tconst clientNames = generateClientNames();\n\tconst rangeOptions = resolveRanges(defaultOptions, defaultOptions.growthFunc);\n\tfor (let extraSeed = 0; extraSeed < testCount; extraSeed++) {\n\t\tfor (const { initLen, modLen, opsPerRoundRange } of generatePairwiseOptions(\n\t\t\trangeOptions,\n\t\t)) {\n\t\t\tit(`AttributionFarm_${initLen}_${modLen}_${opsPerRoundRange}`, async () => {\n\t\t\t\tconst random = makeRandom(0xdeadbeef, initLen, modLen, extraSeed ?? 0);\n\n\t\t\t\tconst clients: TestClient[] = Array.from({ length: 3 })\n\t\t\t\t\t.fill(0)\n\t\t\t\t\t.map(\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\tnew TestClient({\n\t\t\t\t\t\t\t\tattribution: {\n\t\t\t\t\t\t\t\t\ttrack: true,\n\t\t\t\t\t\t\t\t\tpolicyFactory:\n\t\t\t\t\t\t\t\t\t\tcreatePropertyTrackingAndInsertionAttributionPolicyFactory(\"trackedProp\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\t\tconst getAttributionAtPosition = (\n\t\t\t\t\tclient: TestClient,\n\t\t\t\t\tpos: number,\n\t\t\t\t):\n\t\t\t\t\t| {\n\t\t\t\t\t\t\t[name: string]: AttributionKey | undefined;\n\t\t\t\t\t }\n\t\t\t\t\t| undefined => {\n\t\t\t\t\tconst { segment, offset } = client.getContainingSegment<ISegmentPrivate>(pos) ?? {};\n\t\t\t\t\tif (segment?.attribution === undefined || offset === undefined) {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t\tconst { attribution } = segment;\n\t\t\t\t\tlet channels: { [name: string]: AttributionKey | undefined } | undefined;\n\t\t\t\t\tconst result: {\n\t\t\t\t\t\troot: AttributionKey | undefined;\n\t\t\t\t\t\tchannels?: { [name: string]: AttributionKey | undefined };\n\t\t\t\t\t} = {\n\t\t\t\t\t\troot: attribution.getAtOffset(offset),\n\t\t\t\t\t};\n\t\t\t\t\tfor (const name of attribution.channelNames) {\n\t\t\t\t\t\t(channels ??= {})[name] = attribution.getAtOffset(offset, name);\n\t\t\t\t\t\tresult.channels = channels;\n\t\t\t\t\t}\n\t\t\t\t\treturn channels;\n\t\t\t\t};\n\n\t\t\t\tconst validateAnnotation = (reason: string, workload: () => void): void => {\n\t\t\t\t\tconst preWorkload = TestClientLogger.toString(clients);\n\t\t\t\t\tworkload();\n\t\t\t\t\tconst attributions = Array.from({ length: clients[0].getLength() }).map((_, i) =>\n\t\t\t\t\t\tgetAttributionAtPosition(clients[0], i),\n\t\t\t\t\t);\n\t\t\t\t\tfor (let c = 1; c < clients.length; c++) {\n\t\t\t\t\t\tfor (let i = 0; i < clients[c].getLength(); i++) {\n\t\t\t\t\t\t\tconst attribution0 = attributions[i];\n\t\t\t\t\t\t\tconst attributionC = getAttributionAtPosition(clients[c], i);\n\t\t\t\t\t\t\tif (attribution0 !== attributionC) {\n\t\t\t\t\t\t\t\tassert.deepEqual(\n\t\t\t\t\t\t\t\t\tattribution0,\n\t\t\t\t\t\t\t\t\tattributionC,\n\t\t\t\t\t\t\t\t\t`${reason}:\\n${preWorkload}\\n${TestClientLogger.toString([\n\t\t\t\t\t\t\t\t\t\tclients[0],\n\t\t\t\t\t\t\t\t\t\tclients[c],\n\t\t\t\t\t\t\t\t\t])}`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tlet seq = 0;\n\n\t\t\t\tvalidateAnnotation(\"Initialize\", () => {\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, initLen, defaultOptions);\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After Init Zamboni\", () => {\n\t\t\t\t\t// trigger zamboni multiple times as it is incremental\n\t\t\t\t\tfor (let i = clients[0].getCollabWindow().minSeq; i <= seq; i++) {\n\t\t\t\t\t\tfor (const c of clients) c.updateMinSeq(i);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After More Ops\", () => {\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, modLen, defaultOptions);\n\t\t\t\t});\n\n\t\t\t\tvalidateAnnotation(\"After Final Zamboni\", () => {\n\t\t\t\t\t// trigger zamboni multiple times as it is incremental\n\t\t\t\t\tfor (let i = clients[0].getCollabWindow().minSeq; i <= seq; i++) {\n\t\t\t\t\t\tfor (const c of clients) c.updateMinSeq(i);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t}\n});\n"]}
@@ -19,6 +19,7 @@ describe("client.getPosition", () => {
19
19
  }
20
20
  client.startOrUpdateCollaboration(localUserLongId);
21
21
  const segOff = client.getContainingSegment(segPos);
22
+ assert(segOff);
22
23
  assert(TextSegment.is(segOff.segment));
23
24
  assert.strictEqual(segOff.offset, 0);
24
25
  assert.strictEqual(segOff.segment.text, "o");
@@ -1 +1 @@
1
- {"version":3,"file":"client.getPosition.spec.js","sourceRoot":"","sources":["../../src/test/client.getPosition.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { segmentIsRemoved, type ISegmentPrivate } from \"../mergeTreeNodes.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { TestClient } from \"./testClient.js\";\n\ndescribe(\"client.getPosition\", () => {\n\tconst localUserLongId = \"localUser\";\n\tlet client: TestClient;\n\tlet segment: TextSegment;\n\tconst segPos = 4;\n\tbeforeEach(() => {\n\t\tclient = new TestClient();\n\t\tfor (const c of \"hello world\") {\n\t\t\tclient.insertTextLocal(client.getLength(), c);\n\t\t}\n\t\tclient.startOrUpdateCollaboration(localUserLongId);\n\n\t\tconst segOff = client.getContainingSegment<ISegmentPrivate>(segPos);\n\t\tassert(TextSegment.is(segOff.segment!));\n\t\tassert.strictEqual(segOff.offset, 0);\n\t\tassert.strictEqual(segOff.segment.text, \"o\");\n\t\tsegment = segOff.segment;\n\t});\n\n\tit(\"Existing Segment\", () => {\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos);\n\t});\n\n\tit(\"Deleted Segment\", () => {\n\t\tclient.removeRangeLocal(segPos, segPos + 1);\n\t\tassert.strictEqual(segmentIsRemoved(segment), true);\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos);\n\t});\n\n\tit(\"Detached Segment\", () => {\n\t\tclient.applyMsg(client.makeOpMessage(client.removeRangeLocal(segPos, segPos + 1), 1));\n\t\t// do some work and move the client's min seq forward, so zamboni runs\n\t\tfor (const c of \"hello world\") {\n\t\t\tclient.applyMsg(\n\t\t\t\tclient.makeOpMessage(\n\t\t\t\t\tclient.insertTextLocal(client.getLength(), c),\n\t\t\t\t\tclient.getCurrentSeq() + 1,\n\t\t\t\t\tclient.getCurrentSeq(),\n\t\t\t\t\tundefined,\n\t\t\t\t\tclient.getCurrentSeq(),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tassert.strictEqual(segmentIsRemoved(segment), true);\n\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, -1);\n\t});\n\n\tit(\"Removed Segment\", () => {\n\t\tclient.removeRangeLocal(segPos - 1, segPos);\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos - 1);\n\t});\n});\n"]}
1
+ {"version":3,"file":"client.getPosition.spec.js","sourceRoot":"","sources":["../../src/test/client.getPosition.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { segmentIsRemoved, type ISegmentPrivate } from \"../mergeTreeNodes.js\";\nimport { TextSegment } from \"../textSegment.js\";\n\nimport { TestClient } from \"./testClient.js\";\n\ndescribe(\"client.getPosition\", () => {\n\tconst localUserLongId = \"localUser\";\n\tlet client: TestClient;\n\tlet segment: TextSegment;\n\tconst segPos = 4;\n\tbeforeEach(() => {\n\t\tclient = new TestClient();\n\t\tfor (const c of \"hello world\") {\n\t\t\tclient.insertTextLocal(client.getLength(), c);\n\t\t}\n\t\tclient.startOrUpdateCollaboration(localUserLongId);\n\n\t\tconst segOff = client.getContainingSegment<ISegmentPrivate>(segPos);\n\t\tassert(segOff);\n\t\tassert(TextSegment.is(segOff.segment));\n\t\tassert.strictEqual(segOff.offset, 0);\n\t\tassert.strictEqual(segOff.segment.text, \"o\");\n\t\tsegment = segOff.segment;\n\t});\n\n\tit(\"Existing Segment\", () => {\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos);\n\t});\n\n\tit(\"Deleted Segment\", () => {\n\t\tclient.removeRangeLocal(segPos, segPos + 1);\n\t\tassert.strictEqual(segmentIsRemoved(segment), true);\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos);\n\t});\n\n\tit(\"Detached Segment\", () => {\n\t\tclient.applyMsg(client.makeOpMessage(client.removeRangeLocal(segPos, segPos + 1), 1));\n\t\t// do some work and move the client's min seq forward, so zamboni runs\n\t\tfor (const c of \"hello world\") {\n\t\t\tclient.applyMsg(\n\t\t\t\tclient.makeOpMessage(\n\t\t\t\t\tclient.insertTextLocal(client.getLength(), c),\n\t\t\t\t\tclient.getCurrentSeq() + 1,\n\t\t\t\t\tclient.getCurrentSeq(),\n\t\t\t\t\tundefined,\n\t\t\t\t\tclient.getCurrentSeq(),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tassert.strictEqual(segmentIsRemoved(segment), true);\n\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, -1);\n\t});\n\n\tit(\"Removed Segment\", () => {\n\t\tclient.removeRangeLocal(segPos - 1, segPos);\n\t\tconst pos = client.getPosition(segment);\n\t\tassert.strictEqual(pos, segPos - 1);\n\t});\n});\n"]}
@@ -45,7 +45,8 @@ describe("MergeTree.Client", () => {
45
45
  client2.applyMsg(insert);
46
46
  }
47
47
  const segInfo = client1.getContainingSegment(2);
48
- const c1LocalRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.Simple, undefined);
48
+ assert(segInfo);
49
+ const c1LocalRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.Simple, undefined);
49
50
  assert.equal(client1.localReferencePositionToPosition(c1LocalRef), 2, "create position");
50
51
  const remove = client2.makeOpMessage(client2.removeRangeLocal(2, 3), ++seq);
51
52
  remove.minimumSequenceNumber = seq - 1;
@@ -75,7 +76,8 @@ describe("MergeTree.Client", () => {
75
76
  client2.applyMsg(insert);
76
77
  }
77
78
  const segInfo = client1.getContainingSegment(2);
78
- const c1LocalRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
79
+ assert(segInfo);
80
+ const c1LocalRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
79
81
  assert.equal(client1.localReferencePositionToPosition(c1LocalRef), 2);
80
82
  const remove = client2.makeOpMessage(client2.removeRangeLocal(2, 3), ++seq);
81
83
  remove.minimumSequenceNumber = seq - 1;
@@ -103,7 +105,8 @@ describe("MergeTree.Client", () => {
103
105
  client2.applyMsg(insert);
104
106
  }
105
107
  const segInfo = client1.getContainingSegment(2);
106
- const c1LocalRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
108
+ assert(segInfo);
109
+ const c1LocalRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
107
110
  assert.equal(client1.localReferencePositionToPosition(c1LocalRef), 2);
108
111
  const remove = client2.makeOpMessage(client2.removeRangeLocal(2, client2.getLength()), ++seq);
109
112
  remove.minimumSequenceNumber = seq - 1;
@@ -124,7 +127,7 @@ describe("MergeTree.Client", () => {
124
127
  helper.insertText("A", 0, "AxxC");
125
128
  helper.processAllOps();
126
129
  const [localRefA, localRefB] = [A, B].map((client) => {
127
- const { segment, offset } = client.getContainingSegment(2);
130
+ const { segment, offset } = client.getContainingSegment(2) ?? {};
128
131
  assert(segment !== undefined && offset !== undefined);
129
132
  return client.createLocalReferencePosition(segment, offset, ReferenceType.SlideOnRemove, undefined, SlidingPreference.BACKWARD);
130
133
  });
@@ -144,7 +147,7 @@ describe("MergeTree.Client", () => {
144
147
  helper.insertText("A", 0, "AxxC");
145
148
  helper.processAllOps();
146
149
  const [localRefA, localRefB] = [A, B].map((client) => {
147
- const { segment, offset } = client.getContainingSegment(2);
150
+ const { segment, offset } = client.getContainingSegment(2) ?? {};
148
151
  assert(segment !== undefined && offset !== undefined);
149
152
  return client.createLocalReferencePosition(segment, offset, ReferenceType.SlideOnRemove, undefined, SlidingPreference.BACKWARD);
150
153
  });
@@ -165,7 +168,8 @@ describe("MergeTree.Client", () => {
165
168
  insert.minimumSequenceNumber = seq - 1;
166
169
  client1.applyMsg(insert);
167
170
  const segInfo = client1.getContainingSegment(3);
168
- const c1LocalRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
171
+ assert(segInfo);
172
+ const c1LocalRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
169
173
  assert.equal(client1.localReferencePositionToPosition(c1LocalRef), 3, "ref created");
170
174
  const remove1 = client1.makeOpMessage(client1.removeRangeLocal(3, 4), ++seq);
171
175
  remove1.minimumSequenceNumber = seq - 1;
@@ -190,41 +194,41 @@ describe("MergeTree.Client", () => {
190
194
  // Position depends on op
191
195
  const createReference1 = client2.makeOpMessage({ type: MergeTreeDeltaType.INSERT }, ++seq, insert1.sequenceNumber);
192
196
  let segoff = getSlideOnRemoveReferencePosition(client1, 1, createReference1);
193
- assert(segoff.segment);
194
- assert.equal(client1.getPosition(segoff.segment), 3);
197
+ assert(segoff?.segment);
198
+ assert.equal(client1.getPosition(segoff?.segment), 3);
195
199
  assert.equal(segoff.offset, 1);
196
200
  const createReference2 = client2.makeOpMessage({ type: MergeTreeDeltaType.INSERT }, ++seq, insert2.sequenceNumber);
197
201
  segoff = getSlideOnRemoveReferencePosition(client1, 2, createReference2);
198
- assert(segoff.segment);
199
- assert.equal(client1.getPosition(segoff.segment), 0);
202
+ assert(segoff?.segment);
203
+ assert.equal(client1.getPosition(segoff?.segment), 0);
200
204
  assert.equal(segoff.offset, 2);
201
205
  // On a removed, unacked segment
202
206
  let remove = client1.makeOpMessage(client1.removeRangeLocal(2, 5), ++seq);
203
207
  segoff = getSlideOnRemoveReferencePosition(client1, 3, createReference2);
204
- assert(segoff.segment);
205
- assert.notEqual(toRemovalInfo(segoff.segment), undefined);
206
- assert.equal(client1.getPosition(segoff.segment), 2);
208
+ assert(segoff?.segment);
209
+ assert.notEqual(toRemovalInfo(segoff?.segment), undefined);
210
+ assert.equal(client1.getPosition(segoff?.segment), 2);
207
211
  assert.equal(segoff.offset, 0);
208
212
  // Slid from a removed, acked segment
209
213
  client1.applyMsg(remove);
210
214
  segoff = getSlideOnRemoveReferencePosition(client1, 3, createReference2);
211
- assert(segoff.segment);
212
- assert.equal(toRemovalInfo(segoff.segment), undefined);
213
- assert.equal(client1.getPosition(segoff.segment), 2);
215
+ assert(segoff?.segment);
216
+ assert.equal(toRemovalInfo(segoff?.segment), undefined);
217
+ assert.equal(client1.getPosition(segoff?.segment), 2);
214
218
  assert.equal(segoff.offset, 0);
215
219
  // On a removed, unacked segment, end of string
216
220
  remove = client1.makeOpMessage(client1.removeRangeLocal(2, 3), ++seq);
217
221
  segoff = getSlideOnRemoveReferencePosition(client1, 3, createReference2);
218
- assert(segoff.segment);
219
- assert.notEqual(toRemovalInfo(segoff.segment), undefined);
220
- assert.equal(client1.getPosition(segoff.segment), 2);
222
+ assert(segoff?.segment);
223
+ assert.notEqual(toRemovalInfo(segoff?.segment), undefined);
224
+ assert.equal(client1.getPosition(segoff?.segment), 2);
221
225
  assert.equal(segoff.offset, 0);
222
226
  // Slid from a removed, acked segment, end of string
223
227
  client1.applyMsg(remove);
224
228
  segoff = getSlideOnRemoveReferencePosition(client1, 3, createReference2);
225
- assert(segoff.segment);
226
- assert.equal(toRemovalInfo(segoff.segment), undefined);
227
- assert.equal(client1.getPosition(segoff.segment), 0);
229
+ assert(segoff?.segment);
230
+ assert.equal(toRemovalInfo(segoff?.segment), undefined);
231
+ assert.equal(client1.getPosition(segoff?.segment), 0);
228
232
  assert.equal(segoff.offset, 1);
229
233
  });
230
234
  it("Remove all segments with sliding local reference", () => {
@@ -240,7 +244,8 @@ describe("MergeTree.Client", () => {
240
244
  client2.applyMsg(insert);
241
245
  }
242
246
  const segInfo = client1.getContainingSegment(2);
243
- const c1LocalRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
247
+ assert(segInfo);
248
+ const c1LocalRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
244
249
  assert.equal(client1.localReferencePositionToPosition(c1LocalRef), 2);
245
250
  const remove = client2.makeOpMessage(client2.removeRangeLocal(0, client2.getLength()), ++seq);
246
251
  remove.minimumSequenceNumber = seq - 1;
@@ -259,14 +264,18 @@ describe("MergeTree.Client", () => {
259
264
  client1.applyMsg(insert1);
260
265
  client2.applyMsg(insert1);
261
266
  const segInfo1 = client1.getContainingSegment(1);
267
+ assert(segInfo1);
262
268
  const LocalRef1 = client1.createLocalReferencePosition(segInfo1.segment, segInfo1.offset, ReferenceType.SlideOnRemove, undefined);
263
269
  const segInfo3 = client1.getContainingSegment(3);
270
+ assert(segInfo3);
264
271
  const LocalRef2 = client1.createLocalReferencePosition(segInfo3.segment, segInfo3.offset, ReferenceType.SlideOnRemove, undefined);
265
272
  const insert2 = client1.makeOpMessage(client1.insertTextLocal(2, "XY"), ++seq);
266
273
  assert.equal(client1.localReferencePositionToPosition(LocalRef1), 1);
267
274
  assert.equal(client1.localReferencePositionToPosition(LocalRef2), 5);
268
275
  const c2SegInfo1 = client2.getContainingSegment(1);
276
+ assert(c2SegInfo1);
269
277
  const c2SegInfo3 = client2.getContainingSegment(3);
278
+ assert(c2SegInfo3);
270
279
  const remove = client2.makeOpMessage(client2.removeRangeLocal(0, client2.getLength()), ++seq);
271
280
  const c2LocalRef1 = client2.createLocalReferencePosition(c2SegInfo1.segment, c2SegInfo1.offset, ReferenceType.SlideOnRemove, undefined);
272
281
  const c2LocalRef2 = client2.createLocalReferencePosition(c2SegInfo3.segment, c2SegInfo3.offset, ReferenceType.SlideOnRemove, undefined);
@@ -299,7 +308,7 @@ describe("MergeTree.Client", () => {
299
308
  const { segment, offset } = client1.getContainingSegment(0, {
300
309
  referenceSequenceNumber: opFromBeforeRemovePerspective.referenceSequenceNumber,
301
310
  clientId: opFromBeforeRemovePerspective.clientId,
302
- });
311
+ }) ?? {};
303
312
  assert(segment && toRemovalInfo(segment) !== undefined);
304
313
  const transientRef = client1.createLocalReferencePosition(segment, offset, ReferenceType.Transient, {});
305
314
  assert.equal(transientRef.getSegment(), segment);
@@ -315,13 +324,15 @@ describe("MergeTree.Client", () => {
315
324
  client1.applyMsg(insert1);
316
325
  client2.applyMsg(insert1);
317
326
  const segInfo = client1.getContainingSegment(4);
318
- const localRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
327
+ assert(segInfo);
328
+ const localRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
319
329
  const createReference1 = client1.makeOpMessage({ type: MergeTreeDeltaType.INSERT }, ++seq, insert1.sequenceNumber);
320
330
  const remove1 = client2.makeOpMessage(client2.removeRangeLocal(4, 5), ++seq);
321
331
  const insert2 = client1.makeOpMessage(client1.insertTextLocal(2, "XY"), ++seq);
322
332
  const remove2 = client2.makeOpMessage(client2.removeRangeLocal(1, 4), ++seq);
323
333
  const segoff = getSlideOnRemoveReferencePosition(client2, 4, createReference1);
324
- const c2LocalRef = client2.createLocalReferencePosition(segoff.segment, segoff.offset, ReferenceType.SlideOnRemove, undefined);
334
+ assert(segoff);
335
+ const c2LocalRef = client2.createLocalReferencePosition(segoff?.segment, segoff.offset, ReferenceType.SlideOnRemove, undefined);
325
336
  assert.equal(client1.localReferencePositionToPosition(localRef), 6);
326
337
  assert.equal(client2.localReferencePositionToPosition(c2LocalRef), 1);
327
338
  client1.applyMsg(remove1);
@@ -346,6 +357,7 @@ describe("MergeTree.Client", () => {
346
357
  // initialize the local reference collection on the segment, but keep it empty
347
358
  {
348
359
  const segInfo = clients.A.getContainingSegment(9);
360
+ assert(segInfo);
349
361
  const segment = segInfo.segment;
350
362
  assert(segment !== undefined && TextSegment.is(segment));
351
363
  assert.strictEqual(segment.text[segInfo.offset], "9");
@@ -357,7 +369,8 @@ describe("MergeTree.Client", () => {
357
369
  // add a local reference to the newly inserted segment that caused the split
358
370
  {
359
371
  const segInfo = clients.A.getContainingSegment(6);
360
- const segment = segInfo.segment;
372
+ assert(segInfo);
373
+ const segment = segInfo?.segment;
361
374
  assert(segment !== undefined && TextSegment.is(segment));
362
375
  assert.strictEqual(segment.text[segInfo.offset], "B");
363
376
  clients.A.createLocalReferencePosition(segment, segInfo.offset, ReferenceType.Simple, undefined);
@@ -423,7 +436,8 @@ describe("MergeTree.Client", () => {
423
436
  client1.applyMsg(insert1);
424
437
  client2.applyMsg(insert1);
425
438
  const segInfo = client1.getContainingSegment(3);
426
- const localRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined, SlidingPreference.BACKWARD);
439
+ assert(segInfo);
440
+ const localRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined, SlidingPreference.BACKWARD);
427
441
  assert.equal(client1.localReferencePositionToPosition(localRef), 3);
428
442
  const insert2 = client1.makeOpMessage(client1.insertTextLocal(4, "ghi"), ++seq);
429
443
  client1.applyMsg(insert2);
@@ -469,20 +483,20 @@ describe("MergeTree.Client", () => {
469
483
  client1.applyMsg(insert1);
470
484
  client2.applyMsg(insert1);
471
485
  const segInfo = client1.getContainingSegment(3);
472
- assert(segInfo.segment);
473
- const localRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
486
+ assert(segInfo?.segment);
487
+ const localRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
474
488
  addRef(localRef);
475
- assert.equal(localRef.getSegment(), segInfo.segment);
476
- assert(segInfo.segment.localRefs);
477
- assert(!segInfo.segment.localRefs.empty);
478
- segInfo.segment.localRefs.removeLocalRef(localRef);
479
- assert(segInfo.segment.localRefs.empty);
489
+ assert.equal(localRef.getSegment(), segInfo?.segment);
490
+ assert(segInfo?.segment.localRefs);
491
+ assert(!segInfo?.segment.localRefs.empty);
492
+ segInfo?.segment.localRefs.removeLocalRef(localRef);
493
+ assert(segInfo?.segment.localRefs.empty);
480
494
  // Cast is necessary because LocalReference is not exported, so we can't directly call link.
481
495
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
482
496
  localRef.link(undefined, 0, undefined);
483
- assert(segInfo.segment.localRefs.empty);
484
- assert.equal(segInfo.segment.localRefs.empty, true);
485
- assert.equal(segInfo.segment.localRefs.has(localRef), false);
497
+ assert(segInfo?.segment.localRefs.empty);
498
+ assert.equal(segInfo?.segment.localRefs.empty, true);
499
+ assert.equal(segInfo?.segment.localRefs.has(localRef), false);
486
500
  assert.equal(localRef.getSegment(), undefined);
487
501
  assert.equal(localRef.getOffset(), 0);
488
502
  });
@@ -500,20 +514,20 @@ describe("MergeTree.Client", () => {
500
514
  client1.applyMsg(insert1);
501
515
  client2.applyMsg(insert1);
502
516
  const segInfo = client1.getContainingSegment(3);
503
- assert(segInfo.segment);
504
- const localRef = client1.createLocalReferencePosition(segInfo.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
517
+ assert(segInfo?.segment);
518
+ const localRef = client1.createLocalReferencePosition(segInfo?.segment, segInfo.offset, ReferenceType.SlideOnRemove, undefined);
505
519
  addRef(localRef);
506
- assert.equal(localRef.getSegment(), segInfo.segment);
507
- assert(segInfo.segment.localRefs);
508
- assert(!segInfo.segment.localRefs.empty);
520
+ assert.equal(localRef.getSegment(), segInfo?.segment);
521
+ assert(segInfo?.segment.localRefs);
522
+ assert(!segInfo?.segment.localRefs.empty);
509
523
  // Cast is necessary because LocalReference is not exported, so we can't directly call link
510
524
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
511
525
  localRef.link(undefined, 0, undefined);
512
- assert(segInfo.segment.localRefs.empty);
513
- segInfo.segment.localRefs.removeLocalRef(localRef);
514
- assert(segInfo.segment.localRefs.empty);
515
- assert.equal(segInfo.segment.localRefs.empty, true);
516
- assert.equal(segInfo.segment.localRefs.has(localRef), false);
526
+ assert(segInfo?.segment.localRefs.empty);
527
+ segInfo?.segment.localRefs.removeLocalRef(localRef);
528
+ assert(segInfo?.segment.localRefs.empty);
529
+ assert.equal(segInfo?.segment.localRefs.empty, true);
530
+ assert.equal(segInfo?.segment.localRefs.has(localRef), false);
517
531
  assert.equal(localRef.getSegment(), undefined);
518
532
  assert.equal(localRef.getOffset(), 0);
519
533
  });