@fluidframework/merge-tree 2.31.0 → 2.32.0

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 (137) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/client.d.ts +7 -1
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +153 -44
  5. package/dist/client.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +3 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/mergeTree.d.ts +17 -5
  11. package/dist/mergeTree.d.ts.map +1 -1
  12. package/dist/mergeTree.js +188 -79
  13. package/dist/mergeTree.js.map +1 -1
  14. package/dist/mergeTreeNodes.d.ts +16 -18
  15. package/dist/mergeTreeNodes.d.ts.map +1 -1
  16. package/dist/mergeTreeNodes.js +6 -0
  17. package/dist/mergeTreeNodes.js.map +1 -1
  18. package/dist/perspective.d.ts +9 -0
  19. package/dist/perspective.d.ts.map +1 -1
  20. package/dist/perspective.js +14 -1
  21. package/dist/perspective.js.map +1 -1
  22. package/dist/segmentInfos.d.ts +32 -4
  23. package/dist/segmentInfos.d.ts.map +1 -1
  24. package/dist/segmentInfos.js +3 -1
  25. package/dist/segmentInfos.js.map +1 -1
  26. package/dist/sortedSegmentSet.d.ts +1 -0
  27. package/dist/sortedSegmentSet.d.ts.map +1 -1
  28. package/dist/sortedSegmentSet.js +3 -0
  29. package/dist/sortedSegmentSet.js.map +1 -1
  30. package/dist/test/beastTest.spec.js +5 -5
  31. package/dist/test/beastTest.spec.js.map +1 -1
  32. package/dist/test/client.localReference.spec.js +3 -3
  33. package/dist/test/client.localReference.spec.js.map +1 -1
  34. package/dist/test/client.rollback.spec.js +17 -0
  35. package/dist/test/client.rollback.spec.js.map +1 -1
  36. package/dist/test/clientTestHelper.d.ts +100 -0
  37. package/dist/test/clientTestHelper.d.ts.map +1 -0
  38. package/dist/test/clientTestHelper.js +196 -0
  39. package/dist/test/clientTestHelper.js.map +1 -0
  40. package/dist/test/mergeTree.annotate.spec.js +12 -12
  41. package/dist/test/mergeTree.annotate.spec.js.map +1 -1
  42. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +1 -1
  43. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  44. package/dist/test/obliterate.concurrent.spec.js +93 -90
  45. package/dist/test/obliterate.concurrent.spec.js.map +1 -1
  46. package/dist/test/obliterate.deltaCallback.spec.js +121 -116
  47. package/dist/test/obliterate.deltaCallback.spec.js.map +1 -1
  48. package/dist/test/obliterate.rangeExpansion.spec.js +29 -79
  49. package/dist/test/obliterate.rangeExpansion.spec.js.map +1 -1
  50. package/dist/test/obliterate.reconnect.spec.js +235 -58
  51. package/dist/test/obliterate.reconnect.spec.js.map +1 -1
  52. package/dist/test/testClient.js +1 -1
  53. package/dist/test/testClient.js.map +1 -1
  54. package/dist/test/testUtils.d.ts +13 -0
  55. package/dist/test/testUtils.d.ts.map +1 -1
  56. package/dist/test/testUtils.js +22 -1
  57. package/dist/test/testUtils.js.map +1 -1
  58. package/lib/client.d.ts +7 -1
  59. package/lib/client.d.ts.map +1 -1
  60. package/lib/client.js +155 -46
  61. package/lib/client.js.map +1 -1
  62. package/lib/index.d.ts +1 -1
  63. package/lib/index.d.ts.map +1 -1
  64. package/lib/index.js +1 -0
  65. package/lib/index.js.map +1 -1
  66. package/lib/mergeTree.d.ts +17 -5
  67. package/lib/mergeTree.d.ts.map +1 -1
  68. package/lib/mergeTree.js +192 -83
  69. package/lib/mergeTree.js.map +1 -1
  70. package/lib/mergeTreeNodes.d.ts +16 -18
  71. package/lib/mergeTreeNodes.d.ts.map +1 -1
  72. package/lib/mergeTreeNodes.js +7 -1
  73. package/lib/mergeTreeNodes.js.map +1 -1
  74. package/lib/perspective.d.ts +9 -0
  75. package/lib/perspective.d.ts.map +1 -1
  76. package/lib/perspective.js +12 -0
  77. package/lib/perspective.js.map +1 -1
  78. package/lib/segmentInfos.d.ts +32 -4
  79. package/lib/segmentInfos.d.ts.map +1 -1
  80. package/lib/segmentInfos.js +2 -1
  81. package/lib/segmentInfos.js.map +1 -1
  82. package/lib/sortedSegmentSet.d.ts +1 -0
  83. package/lib/sortedSegmentSet.d.ts.map +1 -1
  84. package/lib/sortedSegmentSet.js +3 -0
  85. package/lib/sortedSegmentSet.js.map +1 -1
  86. package/lib/test/beastTest.spec.js +5 -5
  87. package/lib/test/beastTest.spec.js.map +1 -1
  88. package/lib/test/client.localReference.spec.js +3 -3
  89. package/lib/test/client.localReference.spec.js.map +1 -1
  90. package/lib/test/client.rollback.spec.js +18 -1
  91. package/lib/test/client.rollback.spec.js.map +1 -1
  92. package/lib/test/clientTestHelper.d.ts +100 -0
  93. package/lib/test/clientTestHelper.d.ts.map +1 -0
  94. package/lib/test/clientTestHelper.js +192 -0
  95. package/lib/test/clientTestHelper.js.map +1 -0
  96. package/lib/test/mergeTree.annotate.spec.js +12 -12
  97. package/lib/test/mergeTree.annotate.spec.js.map +1 -1
  98. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +1 -1
  99. package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
  100. package/lib/test/obliterate.concurrent.spec.js +93 -90
  101. package/lib/test/obliterate.concurrent.spec.js.map +1 -1
  102. package/lib/test/obliterate.deltaCallback.spec.js +121 -116
  103. package/lib/test/obliterate.deltaCallback.spec.js.map +1 -1
  104. package/lib/test/obliterate.rangeExpansion.spec.js +1 -51
  105. package/lib/test/obliterate.rangeExpansion.spec.js.map +1 -1
  106. package/lib/test/obliterate.reconnect.spec.js +236 -59
  107. package/lib/test/obliterate.reconnect.spec.js.map +1 -1
  108. package/lib/test/testClient.js +1 -1
  109. package/lib/test/testClient.js.map +1 -1
  110. package/lib/test/testUtils.d.ts +13 -0
  111. package/lib/test/testUtils.d.ts.map +1 -1
  112. package/lib/test/testUtils.js +20 -0
  113. package/lib/test/testUtils.js.map +1 -1
  114. package/package.json +19 -18
  115. package/src/client.ts +286 -55
  116. package/src/index.ts +1 -1
  117. package/src/mergeTree.ts +265 -98
  118. package/src/mergeTreeNodes.ts +24 -18
  119. package/src/perspective.ts +21 -0
  120. package/src/segmentInfos.ts +48 -6
  121. package/src/sortedSegmentSet.ts +4 -0
  122. package/dist/test/partialSyncHelper.d.ts +0 -42
  123. package/dist/test/partialSyncHelper.d.ts.map +0 -1
  124. package/dist/test/partialSyncHelper.js +0 -96
  125. package/dist/test/partialSyncHelper.js.map +0 -1
  126. package/dist/test/reconnectHelper.d.ts +0 -50
  127. package/dist/test/reconnectHelper.d.ts.map +0 -1
  128. package/dist/test/reconnectHelper.js +0 -106
  129. package/dist/test/reconnectHelper.js.map +0 -1
  130. package/lib/test/partialSyncHelper.d.ts +0 -42
  131. package/lib/test/partialSyncHelper.d.ts.map +0 -1
  132. package/lib/test/partialSyncHelper.js +0 -92
  133. package/lib/test/partialSyncHelper.js.map +0 -1
  134. package/lib/test/reconnectHelper.d.ts +0 -50
  135. package/lib/test/reconnectHelper.d.ts.map +0 -1
  136. package/lib/test/reconnectHelper.js +0 -102
  137. package/lib/test/reconnectHelper.js.map +0 -1
@@ -0,0 +1,100 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
6
+ import type { IMergeTreeOptions, InteriorSequencePlace } from "../index.js";
7
+ import type { TestClient } from "./testClient.js";
8
+ import { TestClientLogger } from "./testClientLogger.js";
9
+ declare const ClientIds: readonly ["A", "B", "C", "D"];
10
+ type ClientName = (typeof ClientIds)[number];
11
+ /**
12
+ * Helper for authoring tests which perform operations on a number of clients.
13
+ * This class essentially serves the role of the server in that it maintains a sequencing order of ops as well as information
14
+ * about the latest op that each client has applied.
15
+ *
16
+ * When using this class, *do not* perform operations which may submit ops on clients directly: it does not currently wire up client events
17
+ * to the server. Instead, use methods on the helper and pass the client name they should apply to as the first argument.
18
+ *
19
+ * It is analogous to MockContainerRuntimeFactory in the test-runtime-utils package, though the APIs are not completely equivalent
20
+ * (see for example differences noted on disconnect and reconnect).
21
+ *
22
+ * This helper is also designed to support advancing only some clients to a given sequence number
23
+ * (not all clients must be synchronized at the same time).
24
+ *
25
+ * This allows testing sequences of operations where clients have varying refSeqs, rather than having all clients advance refSeq
26
+ * in lockstep.
27
+ *
28
+ * @remarks
29
+ * If we wired the server up to "delta" events on the client, it would be reasonable to rename this to `MockServer` and the API for tests
30
+ * would be a bit cleaner.
31
+ */
32
+ export declare class ClientTestHelper {
33
+ clients: Record<ClientName, TestClient> & {
34
+ all: TestClient[];
35
+ };
36
+ idxFromName(name: ClientName): number;
37
+ logger: TestClientLogger;
38
+ ops: ISequencedDocumentMessage[];
39
+ clientToLastAppliedSeq: Map<"A" | "B" | "C" | "D", number>;
40
+ perClientOps: ISequencedDocumentMessage[][];
41
+ private readonly disconnectedClientOps;
42
+ private seq;
43
+ constructor(options?: IMergeTreeOptions);
44
+ private addMessage;
45
+ insertText(clientName: ClientName, pos: number, text: string): void;
46
+ removeRange(clientName: ClientName, start: number, end: number): void;
47
+ obliterateRange(clientName: ClientName, start: number | InteriorSequencePlace, end: number | InteriorSequencePlace): void;
48
+ advanceClientToSeq(clientName: ClientName, seq: number): void;
49
+ /**
50
+ * Sends all known ops to the procieded client ids.
51
+ */
52
+ advanceClients(...clientNames: ClientName[]): void;
53
+ processAllOps(): void;
54
+ /**
55
+ * Causes the provided clients to "disconnect" by isolating their outbound queue from the op stream.
56
+ * These clients will still receive ops from this helper just like all other clients.
57
+ * When a client reconnects (see {@link reconnect}), the helper will rebase all of the client's pending ops (that they submitted since
58
+ * `disconnect` was called) and re-add them to the op stream.
59
+ *
60
+ * BEWARE: This is slightly different from what the mocks in test-runtime-utils do in two ways:
61
+ *
62
+ * 1. Those mocks actually wipe outstanding ops submitted by the disconnected clients from the op stream and rebases those as well.
63
+ * 2. Those mocks freeze the inbound queue of the disconnected clients as well as the outbound queue.
64
+ *
65
+ * E.g. (pseudocode; syntax is different for those mocks and these):
66
+ *
67
+ * ```typescript
68
+ * B.submitLocalOp1()
69
+ * B.submitLocalOp2()
70
+ * disconnect(B)
71
+ * A.submitLocalOp1()
72
+ * B.submitLocalOp3()
73
+ * processAllOps()
74
+ * ```
75
+ *
76
+ * the test-runtime-mocks will...
77
+ *
78
+ * - have none of B's local ops be receieved by A in the processAllOps() line
79
+ * - have B not receive A's local op 1
80
+ *
81
+ * whereas this helper will...
82
+ *
83
+ * - have B's local ops 1 and 2 be received by A, but not its third local op
84
+ * - have B receive acks for its first two local ops as well as A's op in the processAllOps() line
85
+ *
86
+ * This operation is a no-op if called multiple times on the same client with no intervening reconnects.
87
+ */
88
+ disconnect(...clientNames: ClientName[]): void;
89
+ /**
90
+ * Reconnects clients which have been disconnected. No-ops on any client which is already connected.
91
+ * For disconnected clients, any pending ops they have will be resubmitted using the resubmit flow, see {@link disconnect} for details and an example.
92
+ *
93
+ * @remarks
94
+ * If reconnecting multiple clients, the order that their ops will be resubmitted in will match the order in the array
95
+ */
96
+ reconnect(...clientNames: ClientName[]): void;
97
+ private isDisconnected;
98
+ }
99
+ export {};
100
+ //# sourceMappingURL=clientTestHelper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientTestHelper.d.ts","sourceRoot":"","sources":["../../src/test/clientTestHelper.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AAExF,OAAO,KAAK,EAAgB,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAG1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAA+B,MAAM,uBAAuB,CAAC;AAEtF,QAAA,MAAM,SAAS,+BAAgC,CAAC;AAChD,KAAK,UAAU,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAY7C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAgB;IAC5B,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG;QAAE,GAAG,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IAEhE,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM;IAIrC,MAAM,EAAE,gBAAgB,CAAC;IAEzB,GAAG,EAAE,yBAAyB,EAAE,CAAM;IACtC,sBAAsB,qCAAiC;IAEvD,YAAY,EAAE,yBAAyB,EAAE,EAAE,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAGlC;IAEJ,OAAO,CAAC,GAAG,CAAa;gBAEL,OAAO,GAAE,iBAAsB;IAgBlD,OAAO,CAAC,UAAU;IAmBX,UAAU,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAQnE,WAAW,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAKrE,eAAe,CACrB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,MAAM,GAAG,qBAAqB,EACrC,GAAG,EAAE,MAAM,GAAG,qBAAqB,GACjC,IAAI;IAKA,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAwBpE;;OAEG;IACI,cAAc,CAAC,GAAG,WAAW,EAAE,UAAU,EAAE,GAAG,IAAI;IAOlD,aAAa,IAAI,IAAI;IAO5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACI,UAAU,CAAC,GAAG,WAAW,EAAE,UAAU,EAAE,GAAG,IAAI;IAUrD;;;;;;OAMG;IACI,SAAS,CAAC,GAAG,WAAW,EAAE,UAAU,EAAE,GAAG,IAAI;IAepD,OAAO,CAAC,cAAc;CAGtB"}
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ClientTestHelper = void 0;
8
+ const node_assert_1 = require("node:assert");
9
+ const testClientLogger_js_1 = require("./testClientLogger.js");
10
+ const ClientIds = ["A", "B", "C", "D"];
11
+ function isClientId(s) {
12
+ return ClientIds.includes(s);
13
+ }
14
+ function clientNameOf(client) {
15
+ const { longClientId } = client;
16
+ (0, node_assert_1.strict)(isClientId(longClientId), "Client ID is not a valid client name");
17
+ return longClientId;
18
+ }
19
+ /**
20
+ * Helper for authoring tests which perform operations on a number of clients.
21
+ * This class essentially serves the role of the server in that it maintains a sequencing order of ops as well as information
22
+ * about the latest op that each client has applied.
23
+ *
24
+ * When using this class, *do not* perform operations which may submit ops on clients directly: it does not currently wire up client events
25
+ * to the server. Instead, use methods on the helper and pass the client name they should apply to as the first argument.
26
+ *
27
+ * It is analogous to MockContainerRuntimeFactory in the test-runtime-utils package, though the APIs are not completely equivalent
28
+ * (see for example differences noted on disconnect and reconnect).
29
+ *
30
+ * This helper is also designed to support advancing only some clients to a given sequence number
31
+ * (not all clients must be synchronized at the same time).
32
+ *
33
+ * This allows testing sequences of operations where clients have varying refSeqs, rather than having all clients advance refSeq
34
+ * in lockstep.
35
+ *
36
+ * @remarks
37
+ * If we wired the server up to "delta" events on the client, it would be reasonable to rename this to `MockServer` and the API for tests
38
+ * would be a bit cleaner.
39
+ */
40
+ class ClientTestHelper {
41
+ idxFromName(name) {
42
+ return (name.codePointAt(0) ?? 0) - ("A".codePointAt(0) ?? 0);
43
+ }
44
+ constructor(options = {}) {
45
+ this.ops = [];
46
+ this.clientToLastAppliedSeq = new Map();
47
+ this.disconnectedClientOps = new Map();
48
+ this.seq = 0;
49
+ this.clients = (0, testClientLogger_js_1.createClientsAtInitialState)({
50
+ initialState: "",
51
+ options: {
52
+ mergeTreeEnableObliterate: true,
53
+ mergeTreeEnableObliterateReconnect: true,
54
+ ...options,
55
+ },
56
+ }, ...ClientIds);
57
+ this.logger = new testClientLogger_js_1.TestClientLogger(this.clients.all);
58
+ this.perClientOps = this.clients.all.map(() => []);
59
+ }
60
+ addMessage(client, op) {
61
+ const disconnectedQueue = this.disconnectedClientOps.get(clientNameOf(client));
62
+ if (disconnectedQueue === undefined) {
63
+ const message = client.makeOpMessage(op, ++this.seq);
64
+ this.ops.push(message);
65
+ // This implementation (specifically, that of applying ops / synchronizing clients) assumes messages
66
+ // are pushed sequentially starting with seq 1.
67
+ (0, node_assert_1.strict)(message.sequenceNumber === this.ops.length, "Partial sync test helper invariant violated");
68
+ }
69
+ else {
70
+ // Client is not currently connected.
71
+ const segmentGroup = client.peekPendingSegmentGroups();
72
+ (0, node_assert_1.strict)(segmentGroup !== undefined, "Client should have a pending segment group");
73
+ disconnectedQueue.push({ op, segmentGroup });
74
+ }
75
+ }
76
+ insertText(clientName, pos, text) {
77
+ const client = this.clients[clientName];
78
+ const insertOp = client.insertTextLocal(pos, text);
79
+ if (insertOp) {
80
+ this.addMessage(client, insertOp);
81
+ }
82
+ }
83
+ removeRange(clientName, start, end) {
84
+ const client = this.clients[clientName];
85
+ this.addMessage(client, client.removeRangeLocal(start, end));
86
+ }
87
+ obliterateRange(clientName, start, end) {
88
+ const client = this.clients[clientName];
89
+ this.addMessage(client, client.obliterateRangeLocal(start, end));
90
+ }
91
+ advanceClientToSeq(clientName, seq) {
92
+ const client = this.clients[clientName];
93
+ const lastApplied = this.clientToLastAppliedSeq.get(clientName);
94
+ (0, node_assert_1.strict)(seq > 0, "Can only advance clients to sequence numbers that exist");
95
+ (0, node_assert_1.strict)(this.ops.length >= seq, "Cannot attempt to advance clients to sequence numbers that don't yet exist");
96
+ let startIndex;
97
+ if (lastApplied === undefined) {
98
+ startIndex = 0;
99
+ }
100
+ else {
101
+ if (lastApplied >= seq) {
102
+ return;
103
+ }
104
+ startIndex = lastApplied;
105
+ }
106
+ for (let i = startIndex; i < seq; i++) {
107
+ const nextMessage = this.ops[i];
108
+ client.applyMsg(nextMessage);
109
+ this.clientToLastAppliedSeq.set(clientName, nextMessage.sequenceNumber);
110
+ }
111
+ }
112
+ /**
113
+ * Sends all known ops to the procieded client ids.
114
+ */
115
+ advanceClients(...clientNames) {
116
+ const latestSeq = this.ops[this.ops.length - 1].sequenceNumber;
117
+ for (const name of clientNames) {
118
+ this.advanceClientToSeq(name, latestSeq);
119
+ }
120
+ }
121
+ processAllOps() {
122
+ const latestSeq = this.ops[this.ops.length - 1].sequenceNumber;
123
+ for (const name of ClientIds) {
124
+ this.advanceClientToSeq(name, latestSeq);
125
+ }
126
+ }
127
+ /**
128
+ * Causes the provided clients to "disconnect" by isolating their outbound queue from the op stream.
129
+ * These clients will still receive ops from this helper just like all other clients.
130
+ * When a client reconnects (see {@link reconnect}), the helper will rebase all of the client's pending ops (that they submitted since
131
+ * `disconnect` was called) and re-add them to the op stream.
132
+ *
133
+ * BEWARE: This is slightly different from what the mocks in test-runtime-utils do in two ways:
134
+ *
135
+ * 1. Those mocks actually wipe outstanding ops submitted by the disconnected clients from the op stream and rebases those as well.
136
+ * 2. Those mocks freeze the inbound queue of the disconnected clients as well as the outbound queue.
137
+ *
138
+ * E.g. (pseudocode; syntax is different for those mocks and these):
139
+ *
140
+ * ```typescript
141
+ * B.submitLocalOp1()
142
+ * B.submitLocalOp2()
143
+ * disconnect(B)
144
+ * A.submitLocalOp1()
145
+ * B.submitLocalOp3()
146
+ * processAllOps()
147
+ * ```
148
+ *
149
+ * the test-runtime-mocks will...
150
+ *
151
+ * - have none of B's local ops be receieved by A in the processAllOps() line
152
+ * - have B not receive A's local op 1
153
+ *
154
+ * whereas this helper will...
155
+ *
156
+ * - have B's local ops 1 and 2 be received by A, but not its third local op
157
+ * - have B receive acks for its first two local ops as well as A's op in the processAllOps() line
158
+ *
159
+ * This operation is a no-op if called multiple times on the same client with no intervening reconnects.
160
+ */
161
+ disconnect(...clientNames) {
162
+ for (const clientName of clientNames) {
163
+ const client = this.clients[clientName];
164
+ if (this.isDisconnected(client)) {
165
+ continue;
166
+ }
167
+ this.disconnectedClientOps.set(clientName, []);
168
+ }
169
+ }
170
+ /**
171
+ * Reconnects clients which have been disconnected. No-ops on any client which is already connected.
172
+ * For disconnected clients, any pending ops they have will be resubmitted using the resubmit flow, see {@link disconnect} for details and an example.
173
+ *
174
+ * @remarks
175
+ * If reconnecting multiple clients, the order that their ops will be resubmitted in will match the order in the array
176
+ */
177
+ reconnect(...clientNames) {
178
+ for (const clientName of clientNames) {
179
+ const submittedOps = this.disconnectedClientOps.get(clientName);
180
+ if (submittedOps === undefined) {
181
+ continue;
182
+ }
183
+ this.disconnectedClientOps.delete(clientName);
184
+ const client = this.clients[clientName];
185
+ for (const { op, segmentGroup } of submittedOps) {
186
+ const rebasedOp = client.regeneratePendingOp(op, segmentGroup);
187
+ this.addMessage(client, rebasedOp);
188
+ }
189
+ }
190
+ }
191
+ isDisconnected(client) {
192
+ return this.disconnectedClientOps.has(clientNameOf(client));
193
+ }
194
+ }
195
+ exports.ClientTestHelper = ClientTestHelper;
196
+ //# sourceMappingURL=clientTestHelper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientTestHelper.js","sourceRoot":"","sources":["../../src/test/clientTestHelper.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 { ISequencedDocumentMessage } from \"@fluidframework/driver-definitions/internal\";\n\nimport type { IMergeTreeOp, IMergeTreeOptions, InteriorSequencePlace } from \"../index.js\";\nimport type { SegmentGroup } from \"../mergeTreeNodes.js\";\n\nimport type { TestClient } from \"./testClient.js\";\nimport { TestClientLogger, createClientsAtInitialState } from \"./testClientLogger.js\";\n\nconst ClientIds = [\"A\", \"B\", \"C\", \"D\"] as const;\ntype ClientName = (typeof ClientIds)[number];\n\nfunction isClientId(s: unknown): s is ClientName {\n\treturn ClientIds.includes(s as ClientName);\n}\n\nfunction clientNameOf(client: TestClient): ClientName {\n\tconst { longClientId } = client;\n\tassert(isClientId(longClientId), \"Client ID is not a valid client name\");\n\treturn longClientId;\n}\n\n/**\n * Helper for authoring tests which perform operations on a number of clients.\n * This class essentially serves the role of the server in that it maintains a sequencing order of ops as well as information\n * about the latest op that each client has applied.\n *\n * When using this class, *do not* perform operations which may submit ops on clients directly: it does not currently wire up client events\n * to the server. Instead, use methods on the helper and pass the client name they should apply to as the first argument.\n *\n * It is analogous to MockContainerRuntimeFactory in the test-runtime-utils package, though the APIs are not completely equivalent\n * (see for example differences noted on disconnect and reconnect).\n *\n * This helper is also designed to support advancing only some clients to a given sequence number\n * (not all clients must be synchronized at the same time).\n *\n * This allows testing sequences of operations where clients have varying refSeqs, rather than having all clients advance refSeq\n * in lockstep.\n *\n * @remarks\n * If we wired the server up to \"delta\" events on the client, it would be reasonable to rename this to `MockServer` and the API for tests\n * would be a bit cleaner.\n */\nexport class ClientTestHelper {\n\tclients: Record<ClientName, TestClient> & { all: TestClient[] };\n\n\tidxFromName(name: ClientName): number {\n\t\treturn (name.codePointAt(0) ?? 0) - (\"A\".codePointAt(0) ?? 0);\n\t}\n\n\tlogger: TestClientLogger;\n\n\tops: ISequencedDocumentMessage[] = [];\n\tclientToLastAppliedSeq = new Map<ClientName, number>();\n\n\tperClientOps: ISequencedDocumentMessage[][];\n\tprivate readonly disconnectedClientOps = new Map<\n\t\tClientName,\n\t\t{ op: IMergeTreeOp; segmentGroup: SegmentGroup }[]\n\t>();\n\n\tprivate seq: number = 0;\n\n\tpublic constructor(options: IMergeTreeOptions = {}) {\n\t\tthis.clients = createClientsAtInitialState(\n\t\t\t{\n\t\t\t\tinitialState: \"\",\n\t\t\t\toptions: {\n\t\t\t\t\tmergeTreeEnableObliterate: true,\n\t\t\t\t\tmergeTreeEnableObliterateReconnect: true,\n\t\t\t\t\t...options,\n\t\t\t\t},\n\t\t\t},\n\t\t\t...ClientIds,\n\t\t);\n\t\tthis.logger = new TestClientLogger(this.clients.all);\n\t\tthis.perClientOps = this.clients.all.map(() => []);\n\t}\n\n\tprivate addMessage(client: TestClient, op: IMergeTreeOp): void {\n\t\tconst disconnectedQueue = this.disconnectedClientOps.get(clientNameOf(client));\n\t\tif (disconnectedQueue === undefined) {\n\t\t\tconst message = client.makeOpMessage(op, ++this.seq);\n\t\t\tthis.ops.push(message);\n\t\t\t// This implementation (specifically, that of applying ops / synchronizing clients) assumes messages\n\t\t\t// are pushed sequentially starting with seq 1.\n\t\t\tassert(\n\t\t\t\tmessage.sequenceNumber === this.ops.length,\n\t\t\t\t\"Partial sync test helper invariant violated\",\n\t\t\t);\n\t\t} else {\n\t\t\t// Client is not currently connected.\n\t\t\tconst segmentGroup = client.peekPendingSegmentGroups();\n\t\t\tassert(segmentGroup !== undefined, \"Client should have a pending segment group\");\n\t\t\tdisconnectedQueue.push({ op, segmentGroup });\n\t\t}\n\t}\n\n\tpublic insertText(clientName: ClientName, pos: number, text: string): void {\n\t\tconst client = this.clients[clientName];\n\t\tconst insertOp = client.insertTextLocal(pos, text);\n\t\tif (insertOp) {\n\t\t\tthis.addMessage(client, insertOp);\n\t\t}\n\t}\n\n\tpublic removeRange(clientName: ClientName, start: number, end: number): void {\n\t\tconst client = this.clients[clientName];\n\t\tthis.addMessage(client, client.removeRangeLocal(start, end));\n\t}\n\n\tpublic obliterateRange(\n\t\tclientName: ClientName,\n\t\tstart: number | InteriorSequencePlace,\n\t\tend: number | InteriorSequencePlace,\n\t): void {\n\t\tconst client = this.clients[clientName];\n\t\tthis.addMessage(client, client.obliterateRangeLocal(start, end));\n\t}\n\n\tpublic advanceClientToSeq(clientName: ClientName, seq: number): void {\n\t\tconst client = this.clients[clientName];\n\t\tconst lastApplied = this.clientToLastAppliedSeq.get(clientName);\n\t\tassert(seq > 0, \"Can only advance clients to sequence numbers that exist\");\n\t\tassert(\n\t\t\tthis.ops.length >= seq,\n\t\t\t\"Cannot attempt to advance clients to sequence numbers that don't yet exist\",\n\t\t);\n\t\tlet startIndex: number;\n\t\tif (lastApplied === undefined) {\n\t\t\tstartIndex = 0;\n\t\t} else {\n\t\t\tif (lastApplied >= seq) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstartIndex = lastApplied;\n\t\t}\n\t\tfor (let i = startIndex; i < seq; i++) {\n\t\t\tconst nextMessage = this.ops[i];\n\t\t\tclient.applyMsg(nextMessage);\n\t\t\tthis.clientToLastAppliedSeq.set(clientName, nextMessage.sequenceNumber);\n\t\t}\n\t}\n\n\t/**\n\t * Sends all known ops to the procieded client ids.\n\t */\n\tpublic advanceClients(...clientNames: ClientName[]): void {\n\t\tconst latestSeq = this.ops[this.ops.length - 1].sequenceNumber;\n\t\tfor (const name of clientNames) {\n\t\t\tthis.advanceClientToSeq(name, latestSeq);\n\t\t}\n\t}\n\n\tpublic processAllOps(): void {\n\t\tconst latestSeq = this.ops[this.ops.length - 1].sequenceNumber;\n\t\tfor (const name of ClientIds) {\n\t\t\tthis.advanceClientToSeq(name, latestSeq);\n\t\t}\n\t}\n\n\t/**\n\t * Causes the provided clients to \"disconnect\" by isolating their outbound queue from the op stream.\n\t * These clients will still receive ops from this helper just like all other clients.\n\t * When a client reconnects (see {@link reconnect}), the helper will rebase all of the client's pending ops (that they submitted since\n\t * `disconnect` was called) and re-add them to the op stream.\n\t *\n\t * BEWARE: This is slightly different from what the mocks in test-runtime-utils do in two ways:\n\t *\n\t * 1. Those mocks actually wipe outstanding ops submitted by the disconnected clients from the op stream and rebases those as well.\n\t * 2. Those mocks freeze the inbound queue of the disconnected clients as well as the outbound queue.\n\t *\n\t * E.g. (pseudocode; syntax is different for those mocks and these):\n\t *\n\t * ```typescript\n\t * B.submitLocalOp1()\n\t * B.submitLocalOp2()\n\t * disconnect(B)\n\t * A.submitLocalOp1()\n\t * B.submitLocalOp3()\n\t * processAllOps()\n\t * ```\n\t *\n\t * the test-runtime-mocks will...\n\t *\n\t * - have none of B's local ops be receieved by A in the processAllOps() line\n\t * - have B not receive A's local op 1\n\t *\n\t * whereas this helper will...\n\t *\n\t * - have B's local ops 1 and 2 be received by A, but not its third local op\n\t * - have B receive acks for its first two local ops as well as A's op in the processAllOps() line\n\t *\n\t * This operation is a no-op if called multiple times on the same client with no intervening reconnects.\n\t */\n\tpublic disconnect(...clientNames: ClientName[]): void {\n\t\tfor (const clientName of clientNames) {\n\t\t\tconst client = this.clients[clientName];\n\t\t\tif (this.isDisconnected(client)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.disconnectedClientOps.set(clientName, []);\n\t\t}\n\t}\n\n\t/**\n\t * Reconnects clients which have been disconnected. No-ops on any client which is already connected.\n\t * For disconnected clients, any pending ops they have will be resubmitted using the resubmit flow, see {@link disconnect} for details and an example.\n\t *\n\t * @remarks\n\t * If reconnecting multiple clients, the order that their ops will be resubmitted in will match the order in the array\n\t */\n\tpublic reconnect(...clientNames: ClientName[]): void {\n\t\tfor (const clientName of clientNames) {\n\t\t\tconst submittedOps = this.disconnectedClientOps.get(clientName);\n\t\t\tif (submittedOps === undefined) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.disconnectedClientOps.delete(clientName);\n\t\t\tconst client = this.clients[clientName];\n\t\t\tfor (const { op, segmentGroup } of submittedOps) {\n\t\t\t\tconst rebasedOp = client.regeneratePendingOp(op, segmentGroup);\n\t\t\t\tthis.addMessage(client, rebasedOp);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate isDisconnected(client: TestClient): boolean {\n\t\treturn this.disconnectedClientOps.has(clientNameOf(client));\n\t}\n}\n"]}
@@ -113,7 +113,7 @@ describe("MergeTree", () => {
113
113
  node_assert_1.strict.equal(splitSegment.properties?.propertySource, "local");
114
114
  node_assert_1.strict.equal(splitSegment.properties?.secondChange, 1);
115
115
  node_assert_1.strict.equal(splitSegment.properties?.splitOnly, 1);
116
- mergeTree.ackPendingSegment({
116
+ mergeTree.ackOp({
117
117
  op: {
118
118
  pos1: annotateStart,
119
119
  pos2: annotateEnd,
@@ -132,7 +132,7 @@ describe("MergeTree", () => {
132
132
  node_assert_1.strict.equal(splitSegment.properties?.propertySource, "local");
133
133
  node_assert_1.strict.equal(splitSegment.properties?.secondChange, 1);
134
134
  node_assert_1.strict.equal(splitSegment.properties?.splitOnly, 1);
135
- mergeTree.ackPendingSegment({
135
+ mergeTree.ackOp({
136
136
  op: {
137
137
  pos1: annotateStart,
138
138
  pos2: annotateEnd,
@@ -151,7 +151,7 @@ describe("MergeTree", () => {
151
151
  node_assert_1.strict.equal(splitSegment.properties?.propertySource, "local");
152
152
  node_assert_1.strict.equal(splitSegment.properties?.secondChange, 1);
153
153
  node_assert_1.strict.equal(splitSegment.properties?.splitOnly, 1);
154
- mergeTree.ackPendingSegment({
154
+ mergeTree.ackOp({
155
155
  op: {
156
156
  pos1: splitPos,
157
157
  pos2: annotateEnd,
@@ -182,7 +182,7 @@ describe("MergeTree", () => {
182
182
  node_assert_1.strict.equal(segment.properties?.remoteProperty, 1);
183
183
  });
184
184
  it("sequenced local", () => {
185
- mergeTree.ackPendingSegment({
185
+ mergeTree.ackOp({
186
186
  op: {
187
187
  pos1: annotateStart,
188
188
  pos2: annotateEnd,
@@ -199,7 +199,7 @@ describe("MergeTree", () => {
199
199
  node_assert_1.strict.equal(segment.properties?.propertySource, "local");
200
200
  });
201
201
  it("sequenced local before remote", () => {
202
- mergeTree.ackPendingSegment({
202
+ mergeTree.ackOp({
203
203
  op: {
204
204
  pos1: annotateStart,
205
205
  pos2: annotateEnd,
@@ -238,7 +238,7 @@ describe("MergeTree", () => {
238
238
  node_assert_1.strict.equal(segment.properties?.propertySource, "local2");
239
239
  node_assert_1.strict.equal(segment.properties?.secondSource, 1);
240
240
  node_assert_1.strict.equal(segment.properties?.thirdSource, 1);
241
- mergeTree.ackPendingSegment({
241
+ mergeTree.ackOp({
242
242
  op: {
243
243
  pos1: annotateStart,
244
244
  pos2: annotateEnd,
@@ -252,7 +252,7 @@ describe("MergeTree", () => {
252
252
  node_assert_1.strict.equal(segment.properties?.propertySource, "local2");
253
253
  node_assert_1.strict.equal(segment.properties?.secondSource, 1);
254
254
  node_assert_1.strict.equal(segment.properties?.thirdSource, 1);
255
- mergeTree.ackPendingSegment({
255
+ mergeTree.ackOp({
256
256
  op: {
257
257
  pos1: annotateStart,
258
258
  pos2: annotateEnd,
@@ -266,7 +266,7 @@ describe("MergeTree", () => {
266
266
  node_assert_1.strict.equal(segment.properties?.propertySource, "local2");
267
267
  node_assert_1.strict.equal(segment.properties?.secondSource, 1);
268
268
  node_assert_1.strict.equal(segment.properties?.thirdSource, 1);
269
- mergeTree.ackPendingSegment({
269
+ mergeTree.ackOp({
270
270
  op: {
271
271
  pos1: annotateStart,
272
272
  pos2: annotateEnd,
@@ -285,7 +285,7 @@ describe("MergeTree", () => {
285
285
  mergeTree.annotateRange(annotateStart, annotateEnd, {
286
286
  props: { secondSource: "local2" },
287
287
  }, mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
288
- mergeTree.ackPendingSegment({
288
+ mergeTree.ackOp({
289
289
  op: {
290
290
  pos1: annotateStart,
291
291
  pos2: annotateEnd,
@@ -346,7 +346,7 @@ describe("MergeTree", () => {
346
346
  (0, node_assert_1.strict)(segmentInfo.segment?.segmentGroups?.empty !== false);
347
347
  mergeTree.annotateRange(annotateStart, annotateEnd, props, mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
348
348
  node_assert_1.strict.equal(segmentInfo.segment?.segmentGroups?.size, 1);
349
- mergeTree.ackPendingSegment({
349
+ mergeTree.ackOp({
350
350
  op: {
351
351
  pos1: annotateStart,
352
352
  pos2: annotateEnd,
@@ -389,7 +389,7 @@ describe("MergeTree", () => {
389
389
  node_assert_1.strict.equal(segment.properties?.remoteProperty, 1);
390
390
  });
391
391
  it("sequenced local before remote", () => {
392
- mergeTree.ackPendingSegment({
392
+ mergeTree.ackOp({
393
393
  op: {
394
394
  pos1: annotateStart,
395
395
  pos2: annotateEnd,
@@ -413,7 +413,7 @@ describe("MergeTree", () => {
413
413
  mergeTree.annotateRange(annotateStart, annotateEnd, {
414
414
  props: { secondSource: "local2" },
415
415
  }, mergeTree.localPerspective, mergeTree.collabWindow.mintNextLocalOperationStamp(), undefined);
416
- mergeTree.ackPendingSegment({
416
+ mergeTree.ackOp({
417
417
  op: {
418
418
  pos1: annotateStart,
419
419
  pos2: annotateEnd,