@fluidframework/test-utils 2.0.0-internal.1.1.1 → 2.0.0-internal.1.2.0.93071

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.
@@ -33,6 +33,14 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
33
33
  * Reset the tracker, closing all containers and stop tracking them.
34
34
  */
35
35
  reset(): void;
36
+ /**
37
+ * Ensure all tracked containers are synchronized
38
+ */
39
+ ensureSynchronized(...containers: IContainer[]): Promise<void>;
40
+ /**
41
+ * Ensure all tracked containers are synchronized with a time limit
42
+ */
43
+ ensureSynchronizedWithTimeout?(timeoutDuration: number | undefined, ...containers: IContainer[]): Promise<void>;
36
44
  /**
37
45
  * Make sure all the tracked containers are synchronized.
38
46
  * - No isDirty (non-readonly) containers
@@ -44,7 +52,7 @@ export declare class LoaderContainerTracker implements IOpProcessingController {
44
52
  * - this overlaps with !isDirty, but include task scheduler ops.
45
53
  * - Trailing NoOp is tracked and don't count as pending ops.
46
54
  */
47
- ensureSynchronized(...containers: IContainer[]): Promise<void>;
55
+ private processSynchronized;
48
56
  /**
49
57
  * Utility to calculate the set of clientId per container in quorum that is NOT associated with
50
58
  * any container we tracked, indicating there is a pending join or leave op that we need to wait.
@@ -1 +1 @@
1
- {"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAI7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAqB/D,qBAAa,sBAAuB,YAAW,uBAAuB;IAItD,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAHlD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,kBAAkB,CAAa;gBAEV,qBAAqB,GAAE,OAAe;IAEnE;;;OAGG;IACI,GAAG,CAAC,UAAU,SAAS,WAAW,EAAE,MAAM,EAAE,UAAU;IAiB7D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAoBpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,KAAK;IAUZ;;;;;;;;;;OAUG;IACU,kBAAkB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAwD3D;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IA0CpC;;;;;;;OAOG;YACW,qBAAqB;IA6BnC;;;OAGG;YACW,oBAAoB;IAclC;;OAEG;IACI,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAgBnD;;;OAGG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAexD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;OAEG;YACW,YAAY;IAqC1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8DlB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAIxB"}
1
+ {"version":3,"file":"loaderContainerTracker.d.ts","sourceRoot":"","sources":["../src/loaderContainerTracker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,UAAU,EAAe,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAK7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAyB/D,qBAAa,sBAAuB,YAAW,uBAAuB;IAItD,OAAO,CAAC,QAAQ,CAAC,qBAAqB;IAHlD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,kBAAkB,CAAa;gBAEV,qBAAqB,GAAE,OAAe;IAEnE;;;OAGG;IACI,GAAG,CAAC,UAAU,SAAS,WAAW,EAAE,MAAM,EAAE,UAAU;IAiB7D;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAoBpB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACI,KAAK;IAUZ;;OAEG;IACU,kBAAkB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAI3D;;OAEG;IACU,6BAA6B,CAAC,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,UAAU,EAAE,UAAU,EAAE;IAI5G;;;;;;;;;;OAUG;YACW,mBAAmB;IA0EjC;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IA0CpC;;;;;;;OAOG;YACW,qBAAqB;IA6BnC;;;OAGG;YACW,oBAAoB;IAclC;;OAEG;IACI,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAgBnD;;;OAGG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAexD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;;;OAIG;IACU,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE;IAIxD;;OAEG;YACW,YAAY;IAqC1B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAyBzB;;OAEG;IACH,OAAO,CAAC,UAAU;IA8DlB;;;;OAIG;IACH,OAAO,CAAC,aAAa;CAIxB"}
@@ -3,13 +3,18 @@
3
3
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
4
  * Licensed under the MIT License.
5
5
  */
6
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
6
7
  Object.defineProperty(exports, "__esModule", { value: true });
7
8
  exports.LoaderContainerTracker = void 0;
8
9
  const common_utils_1 = require("@fluidframework/common-utils");
10
+ const driver_utils_1 = require("@fluidframework/driver-utils");
9
11
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
10
12
  const debug_1 = require("./debug");
13
+ const timeoutUtils_1 = require("./timeoutUtils");
11
14
  const debugOp = debug_1.debug.extend("ops");
12
15
  const debugWait = debug_1.debug.extend("wait");
16
+ // set the maximum timeout value as 5 mins
17
+ const defaultMaxTimeout = 5 * 6000;
13
18
  class LoaderContainerTracker {
14
19
  constructor(syncSummarizerClients = false) {
15
20
  this.syncSummarizerClients = syncSummarizerClients;
@@ -72,7 +77,7 @@ class LoaderContainerTracker {
72
77
  trackTrailingNoOps(container, record) {
73
78
  container.deltaManager.outbound.on("op", (messages) => {
74
79
  for (const msg of messages) {
75
- if (msg.type === protocol_definitions_1.MessageType.NoOp) {
80
+ if ((0, driver_utils_1.canBeCoalescedByService)(msg)) {
76
81
  // Track the NoOp that was sent.
77
82
  if (record.trailingNoOps === 0) {
78
83
  // record the starting sequence number of the trailing no ops if we haven't been tracking yet.
@@ -88,7 +93,7 @@ class LoaderContainerTracker {
88
93
  });
89
94
  container.deltaManager.inbound.on("push", (message) => {
90
95
  // Received the no op back, update the record if we are tracking
91
- if (message.type === protocol_definitions_1.MessageType.NoOp
96
+ if ((0, driver_utils_1.canBeCoalescedByService)(message)
92
97
  && message.clientId === container.clientId
93
98
  && record.trailingNoOps !== 0
94
99
  && record.startTrailingNoOps <= message.clientSequenceNumber) {
@@ -122,6 +127,18 @@ class LoaderContainerTracker {
122
127
  this.containers.clear();
123
128
  // REVIEW: do we need to unpatch the loaders?
124
129
  }
130
+ /**
131
+ * Ensure all tracked containers are synchronized
132
+ */
133
+ async ensureSynchronized(...containers) {
134
+ await this.processSynchronized(undefined, ...containers);
135
+ }
136
+ /**
137
+ * Ensure all tracked containers are synchronized with a time limit
138
+ */
139
+ async ensureSynchronizedWithTimeout(timeoutDuration, ...containers) {
140
+ await this.processSynchronized(timeoutDuration, ...containers);
141
+ }
125
142
  /**
126
143
  * Make sure all the tracked containers are synchronized.
127
144
  * - No isDirty (non-readonly) containers
@@ -133,7 +150,8 @@ class LoaderContainerTracker {
133
150
  * - this overlaps with !isDirty, but include task scheduler ops.
134
151
  * - Trailing NoOp is tracked and don't count as pending ops.
135
152
  */
136
- async ensureSynchronized(...containers) {
153
+ async processSynchronized(timeoutDuration, ...containers) {
154
+ const start = Date.now();
137
155
  const resumed = this.resumeProcessing(...containers);
138
156
  let waitingSequenceNumberSynchronized = false;
139
157
  // eslint-disable-next-line no-constant-condition
@@ -159,12 +177,18 @@ class LoaderContainerTracker {
159
177
  // Only write it out once
160
178
  waitingSequenceNumberSynchronized = true;
161
179
  debugWait("Waiting for sequence number synchronized");
162
- await this.waitForAnyInboundOps(containersToApply);
180
+ await (0, timeoutUtils_1.timeoutAwait)(this.waitForAnyInboundOps(containersToApply), {
181
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
182
+ errorMsg: "Timeout on waiting for sequence number synchronized",
183
+ });
163
184
  }
164
185
  }
165
186
  else {
166
187
  waitingSequenceNumberSynchronized = false;
167
- await this.waitForPendingClients(pendingClients);
188
+ await (0, timeoutUtils_1.timeoutAwait)(this.waitForPendingClients(pendingClients), {
189
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
190
+ errorMsg: "Timeout on waiting for pending join or leave op",
191
+ });
168
192
  }
169
193
  }
170
194
  else {
@@ -172,8 +196,13 @@ class LoaderContainerTracker {
172
196
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
173
197
  debugWait(`Waiting container to be saved ${dirtyContainers.map((c) => this.containers.get(c).index)}`);
174
198
  waitingSequenceNumberSynchronized = false;
175
- await Promise.all(dirtyContainers.map(async (c) => Promise.race([new Promise((resolve) => c.once("saved", resolve)),
176
- new Promise((resolve) => c.once("closed", resolve))])));
199
+ const remainedDuration = timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout;
200
+ await Promise.all(dirtyContainers.map(async (c) => Promise.race([(0, timeoutUtils_1.timeoutPromise)((resolve) => c.once("saved", () => resolve()), {
201
+ durationMs: remainedDuration,
202
+ errorMsg: "Timeout on waiting a container to be saved",
203
+ }),
204
+ new Promise((resolve) => c.once("closed", resolve)),
205
+ ])));
177
206
  }
178
207
  // yield a turn to allow side effect of the ops we just processed execute before we check again
179
208
  await new Promise((resolve) => { setTimeout(resolve, 0); });
@@ -181,7 +210,10 @@ class LoaderContainerTracker {
181
210
  // Pause all container that was resumed
182
211
  // don't call pause if resumed is empty and pause everything, which is not what we want
183
212
  if (resumed.length !== 0) {
184
- await this.pauseProcessing(...resumed);
213
+ await (0, timeoutUtils_1.timeoutAwait)(this.pauseProcessing(...resumed), {
214
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
215
+ errorMsg: "Timeout on waiting for pausing all resumed containers",
216
+ });
185
217
  }
186
218
  debugWait("Synchronized");
187
219
  }
@@ -405,13 +437,13 @@ class LoaderContainerTracker {
405
437
  setupInOutTracker(container, inflightTracker) {
406
438
  const outHandler = (messages) => {
407
439
  for (const message of messages) {
408
- if (message.type !== protocol_definitions_1.MessageType.NoOp) {
440
+ if (!(0, driver_utils_1.canBeCoalescedByService)(message)) {
409
441
  inflightTracker.set(container, message.clientSequenceNumber);
410
442
  }
411
443
  }
412
444
  };
413
445
  const inHandler = (message) => {
414
- if (message.type !== protocol_definitions_1.MessageType.NoOp
446
+ if (!(0, driver_utils_1.canBeCoalescedByService)(message)
415
447
  && message.clientId === container.clientId
416
448
  && inflightTracker.get(container) === message.clientSequenceNumber) {
417
449
  inflightTracker.delete(container);
@@ -1 +1 @@
1
- {"version":3,"file":"loaderContainerTracker.js","sourceRoot":"","sources":["../src/loaderContainerTracker.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 { assert } from \"@fluidframework/common-utils\";\nimport { IContainer, IDeltaQueue, IHostLoader } from \"@fluidframework/container-definitions\";\nimport { Container } from \"@fluidframework/container-loader\";\nimport { IDocumentMessage, ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport { debug } from \"./debug\";\nimport { IOpProcessingController } from \"./testObjectProvider\";\n\nconst debugOp = debug.extend(\"ops\");\nconst debugWait = debug.extend(\"wait\");\n\ninterface ContainerRecord {\n // A short number for debug output\n index: number;\n\n // LoaderContainerTracker paused state\n paused: boolean;\n\n // Tracking trailing no-op that may or may be acked by the server so we can discount them\n // See issue #5629\n startTrailingNoOps: number;\n trailingNoOps: number;\n\n // Track last proposal to ensure no unresolved proposal\n lastProposal: number;\n}\n\nexport class LoaderContainerTracker implements IOpProcessingController {\n private readonly containers = new Map<IContainer, ContainerRecord>();\n private lastProposalSeqNum: number = 0;\n\n constructor(private readonly syncSummarizerClients: boolean = false) {}\n\n /**\n * Add a loader to start to track any container created from them\n * @param loader - loader to start tracking any container created.\n */\n public add<LoaderType extends IHostLoader>(loader: LoaderType) {\n // TODO: Expose Loader API to able to intercept container creation (See issue #5114)\n const patch = <T, C extends IContainer>(fn: (...args) => Promise<C>) => {\n const boundFn = fn.bind(loader);\n return async (...args: T[]) => {\n const container = await boundFn(...args);\n this.addContainer(container);\n return container;\n };\n };\n /* eslint-disable @typescript-eslint/unbound-method */\n loader.resolve = patch(loader.resolve);\n loader.createDetachedContainer = patch(loader.createDetachedContainer);\n loader.rehydrateDetachedContainerFromSnapshot = patch(loader.rehydrateDetachedContainerFromSnapshot);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Utility function to add container to be tracked.\n *\n * @param container - container to add\n */\n private addContainer(container: IContainer) {\n // ignore summarizer\n if (!container.deltaManager.clientDetails.capabilities.interactive && !this.syncSummarizerClients) { return; }\n\n // don't add container that is already tracked\n if (this.containers.has(container)) { return; }\n\n const record = {\n index: this.containers.size,\n paused: false,\n startTrailingNoOps: 0,\n trailingNoOps: 0,\n lastProposal: 0,\n };\n this.containers.set(container, record);\n this.trackTrailingNoOps(container, record);\n this.trackLastProposal(container);\n this.setupTrace(container, record.index);\n }\n\n /**\n * Keep track of the trailing NoOp that was sent so we can discount them in the clientSequenceNumber tracking.\n * The server might coalesce them with other ops, or a single NoOp, or delay it if it don't think it is necessary.\n *\n * @param container - the container to track\n * @param record - the record to update the trailing op information\n */\n private trackTrailingNoOps(container: IContainer, record: ContainerRecord) {\n container.deltaManager.outbound.on(\"op\", (messages) => {\n for (const msg of messages) {\n if (msg.type === MessageType.NoOp) {\n // Track the NoOp that was sent.\n if (record.trailingNoOps === 0) {\n // record the starting sequence number of the trailing no ops if we haven't been tracking yet.\n record.startTrailingNoOps = msg.clientSequenceNumber;\n }\n record.trailingNoOps++;\n } else {\n // Other ops has been sent. We would like to see those ack'ed, so no more need to track NoOps\n record.trailingNoOps = 0;\n }\n }\n });\n\n container.deltaManager.inbound.on(\"push\", (message) => {\n // Received the no op back, update the record if we are tracking\n if (message.type === MessageType.NoOp\n && message.clientId === (container as Container).clientId\n && record.trailingNoOps !== 0\n && record.startTrailingNoOps <= message.clientSequenceNumber\n ) {\n // NoOp might have coalesced and skipped ahead some sequence number\n // update the record and skip ahead as well\n const oldStartTrailingNoOps = record.startTrailingNoOps;\n record.startTrailingNoOps = message.clientSequenceNumber + 1;\n record.trailingNoOps -= (record.startTrailingNoOps - oldStartTrailingNoOps);\n }\n });\n\n container.on(\"disconnected\", () => {\n // reset on disconnect.\n record.trailingNoOps = 0;\n });\n }\n\n private trackLastProposal(container: IContainer) {\n container.on(\"codeDetailsProposed\", (value, proposal) => {\n if (proposal.sequenceNumber > this.lastProposalSeqNum) {\n this.lastProposalSeqNum = proposal.sequenceNumber;\n }\n });\n }\n\n /**\n * Reset the tracker, closing all containers and stop tracking them.\n */\n public reset() {\n this.lastProposalSeqNum = 0;\n for (const container of this.containers.keys()) {\n container.close();\n }\n this.containers.clear();\n\n // REVIEW: do we need to unpatch the loaders?\n }\n\n /**\n * Make sure all the tracked containers are synchronized.\n * - No isDirty (non-readonly) containers\n * - No extra clientId in quorum of any container that is not tracked and still opened.\n * - i.e. no pending Join/Leave message.\n * - No unresolved proposal (minSeqNum \\>= lastProposalSeqNum)\n * - lastSequenceNumber of all container is the same\n * - clientSequenceNumberObserved is the same as clientSequenceNumber sent\n * - this overlaps with !isDirty, but include task scheduler ops.\n * - Trailing NoOp is tracked and don't count as pending ops.\n */\n public async ensureSynchronized(...containers: IContainer[]) {\n const resumed = this.resumeProcessing(...containers);\n\n let waitingSequenceNumberSynchronized = false;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const containersToApply = this.getContainers(containers);\n if (containersToApply.length === 0) { break; }\n\n // Ignore readonly dirty containers, because it can't sent up and nothing can be done about it being dirty\n const dirtyContainers = containersToApply.filter((c) => {\n const { deltaManager, isDirty } = c;\n return deltaManager.readOnlyInfo.readonly !== true && isDirty;\n });\n if (dirtyContainers.length === 0) {\n // Wait for all the leave messages\n const pendingClients = this.getPendingClients(containersToApply);\n if (pendingClients.length === 0) {\n if (this.isSequenceNumberSynchronized(containersToApply)) {\n // done, we are in sync\n break;\n }\n if (!waitingSequenceNumberSynchronized) {\n // Only write it out once\n waitingSequenceNumberSynchronized = true;\n debugWait(\"Waiting for sequence number synchronized\");\n await this.waitForAnyInboundOps(containersToApply);\n }\n } else {\n waitingSequenceNumberSynchronized = false;\n await this.waitForPendingClients(pendingClients);\n }\n } else {\n // Wait for all the containers to be saved\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n debugWait(`Waiting container to be saved ${dirtyContainers.map((c) => this.containers.get(c)!.index)}`);\n waitingSequenceNumberSynchronized = false;\n await Promise.all(dirtyContainers.map(async (c) => Promise.race(\n [new Promise((resolve) => c.once(\"saved\", resolve)),\n new Promise((resolve) => c.once(\"closed\", resolve))],\n )));\n }\n\n // yield a turn to allow side effect of the ops we just processed execute before we check again\n await new Promise<void>((resolve) => { setTimeout(resolve, 0); });\n }\n\n // Pause all container that was resumed\n // don't call pause if resumed is empty and pause everything, which is not what we want\n if (resumed.length !== 0) {\n await this.pauseProcessing(...resumed);\n }\n\n debugWait(\"Synchronized\");\n }\n\n /**\n * Utility to calculate the set of clientId per container in quorum that is NOT associated with\n * any container we tracked, indicating there is a pending join or leave op that we need to wait.\n *\n * @param containersToApply - the set of containers to check\n */\n private getPendingClients(containersToApply: IContainer[]) {\n // All the clientId we track should be a superset of the quorum, otherwise, we are missing\n // leave messages\n const openedDocuments = Array.from(this.containers.keys()).filter((c) => !c.closed);\n const openedClientId = openedDocuments.map((container) => (container as Container).clientId);\n\n const pendingClients: [IContainer, Set<string>][] = [];\n containersToApply.forEach((container) => {\n const pendingClientId = new Set<string>();\n const quorum = container.getQuorum();\n quorum.getMembers().forEach((client, clientId) => {\n // ignore summarizer\n if (!client.client.details.capabilities.interactive && !this.syncSummarizerClients) { return; }\n if (!openedClientId.includes(clientId)) {\n pendingClientId.add(clientId);\n }\n });\n\n if (pendingClientId.size !== 0) {\n pendingClients.push([container, pendingClientId]);\n }\n });\n return pendingClients;\n }\n\n /**\n * Utility to check synchronization based on sequence number\n * See ensureSynchronized for more detail\n *\n * @param containersToApply - the set of containers to check\n */\n private isSequenceNumberSynchronized(containersToApply: IContainer[]) {\n // clientSequenceNumber check detects ops in flight, both on the wire and in the outbound queue\n // We need both client sequence number and isDirty check because:\n // - Currently isDirty flag ignores ops for task scheduler, so we need the client sequence number check\n // - But isDirty flags include ops during forceReadonly and disconnected, because we don't submit\n // the ops in the first place, clientSequenceNumber is not assigned\n\n const isClientSequenceNumberSynchronized = containersToApply.every((container) => {\n if (container.deltaManager.readOnlyInfo.readonly === true) {\n // Ignore readonly container. the clientSeqNum and clientSeqNumObserved might be out of sync\n // because we transition to readonly when outbound is not empty or the in transit op got lost\n return true;\n }\n // Note that in read only mode, the op won't be submitted\n let deltaManager = (container.deltaManager as any);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const { trailingNoOps } = this.containers.get(container)!;\n // Back-compat: clientSequenceNumber & clientSequenceNumberObserved moved to ConnectionManager in 0.53\n if (!(\"clientSequenceNumber\" in deltaManager)) {\n deltaManager = deltaManager.connectionManager;\n }\n assert(\"clientSequenceNumber\" in deltaManager, \"no clientSequenceNumber\");\n assert(\"clientSequenceNumberObserved\" in deltaManager, \"no clientSequenceNumber\");\n return deltaManager.clientSequenceNumber ===\n (deltaManager.clientSequenceNumberObserved as number) + trailingNoOps;\n });\n\n if (!isClientSequenceNumberSynchronized) {\n return false;\n }\n\n const minSeqNum = containersToApply[0].deltaManager.minimumSequenceNumber;\n if (minSeqNum < this.lastProposalSeqNum) {\n // There is an unresolved proposal\n return false;\n }\n\n // Check to see if all the container has process the same number of ops.\n const seqNum = containersToApply[0].deltaManager.lastSequenceNumber;\n return containersToApply.every((c) => c.deltaManager.lastSequenceNumber === seqNum);\n }\n\n /**\n * Utility to wait for any clientId in quorum that is NOT associated with any container we\n * tracked, indicating there is a pending join or leave op that we need to wait.\n *\n * Note that this function doesn't account for container that got added after we started waiting\n *\n * @param containersToApply - the set of containers to wait for any inbound ops for\n */\n private async waitForPendingClients(pendingClients: [IContainer, Set<string>][]) {\n const unconnectedClients =\n Array.from(this.containers.keys()).filter((c) => !c.closed && !(c as Container).connected);\n return Promise.all(pendingClients.map(async ([container, pendingClientId]) => {\n return new Promise<void>((resolve) => {\n const cleanup = () => {\n unconnectedClients.forEach((c) => c.off(\"connected\", handler));\n container.getQuorum().off(\"removeMember\", handler);\n };\n const handler = (clientId: string) => {\n pendingClientId.delete(clientId);\n if (pendingClientId.size === 0) {\n cleanup();\n resolve();\n }\n };\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const index = this.containers.get(container)!.index;\n debugWait(`${index}: Waiting for pending clients ${Array.from(pendingClientId.keys())}`);\n unconnectedClients.forEach((c) => c.on(\"connected\", handler));\n container.getQuorum().on(\"removeMember\", handler);\n container.on(\"closed\", () => {\n cleanup();\n resolve();\n });\n });\n }));\n }\n\n /**\n * Utility to wait for any inbound ops from a set of containers\n * @param containersToApply - the set of containers to wait for any inbound ops for\n */\n private async waitForAnyInboundOps(containersToApply: IContainer[]) {\n return new Promise<void>((resolve) => {\n const handler = () => {\n containersToApply.map((c) => {\n c.deltaManager.inbound.off(\"push\", handler);\n });\n resolve();\n };\n containersToApply.map((c) => {\n c.deltaManager.inbound.on(\"push\", handler);\n });\n });\n }\n\n /**\n * Resume all queue activities on all paused tracked containers and return them\n */\n public resumeProcessing(...containers: IContainer[]) {\n const resumed: IContainer[] = [];\n const containersToApply = this.getContainers(containers);\n for (const container of containersToApply) {\n const record = this.containers.get(container);\n if (record?.paused === true) {\n debugWait(`${record.index}: container resumed`);\n container.deltaManager.inbound.resume();\n container.deltaManager.outbound.resume();\n resumed.push(container);\n record.paused = false;\n }\n }\n return resumed;\n }\n\n /**\n * Pause all queue activities on the containers given, or all tracked containers\n * Any containers given that is not tracked will be ignored.\n */\n public async pauseProcessing(...containers: IContainer[]) {\n const pauseP: Promise<void>[] = [];\n const containersToApply = this.getContainers(containers);\n for (const container of containersToApply) {\n const record = this.containers.get(container);\n if (record !== undefined && !record.paused) {\n debugWait(`${record.index}: container paused`);\n pauseP.push(container.deltaManager.inbound.pause());\n pauseP.push(container.deltaManager.outbound.pause());\n record.paused = true;\n }\n }\n await Promise.all(pauseP);\n }\n\n /**\n * Pause all queue activities on all tracked containers, and resume only\n * inbound to process ops until it is idle. All queues are left in the paused state\n * after the function\n */\n public async processIncoming(...containers: IContainer[]) {\n return this.processQueue(containers, (container) => container.deltaManager.inbound);\n }\n\n /**\n * Pause all queue activities on all tracked containers, and resume only\n * outbound to process ops until it is idle. All queues are left in the paused state\n * after the function\n */\n public async processOutgoing(...containers: IContainer[]) {\n return this.processQueue(containers, (container) => container.deltaManager.outbound);\n }\n\n /**\n * Implementation of processIncoming and processOutgoing\n */\n private async processQueue<U>(containers: IContainer[], getQueue: (container: IContainer) => IDeltaQueue<U>) {\n await this.pauseProcessing(...containers);\n const resumed: IDeltaQueue<U>[] = [];\n\n const containersToApply = this.getContainers(containers);\n const inflightTracker = new Map<IContainer, number>();\n const cleanup: (() => void)[] = [];\n for (const container of containersToApply) {\n const queue = getQueue(container);\n\n // track the outgoing ops (if any) to make sure they make the round trip to at least to the same client\n // to make sure they are sequenced.\n cleanup.push(this.setupInOutTracker(container, inflightTracker));\n queue.resume();\n resumed.push(queue);\n }\n\n while (resumed.some((queue) => !queue.idle)) {\n debugWait(\"Wait until queue is idle\");\n await new Promise<void>((resolve) => { setTimeout(resolve, 0); });\n }\n\n // Make sure all the op that we sent out are acked first\n // This is no op if we are processing incoming\n if (inflightTracker.size) {\n debugWait(\"Wait for inflight ops\");\n do {\n await this.waitForAnyInboundOps(containersToApply);\n } while (inflightTracker.size);\n }\n\n // remove the handlers\n cleanup.forEach((clean) => clean());\n\n await Promise.all(resumed.map(async (queue) => queue.pause()));\n }\n\n /**\n * Utility to set up listener to track the outbound ops until it round trip back\n * Returns a function to remove the handler after it is done.\n *\n * @param container - the container to setup\n * @param inflightTracker - a map to track the clientSequenceNumber per container it expect to get ops back\n */\n private setupInOutTracker(container: IContainer, inflightTracker: Map<IContainer, number>) {\n const outHandler = (messages: IDocumentMessage[]) => {\n for (const message of messages) {\n if (message.type !== MessageType.NoOp) {\n inflightTracker.set(container, message.clientSequenceNumber);\n }\n }\n };\n const inHandler = (message: ISequencedDocumentMessage) => {\n if (message.type !== MessageType.NoOp\n && message.clientId === (container as Container).clientId\n && inflightTracker.get(container) === message.clientSequenceNumber) {\n inflightTracker.delete(container);\n }\n };\n\n container.deltaManager.outbound.on(\"op\", outHandler);\n container.deltaManager.inbound.on(\"push\", inHandler);\n\n return () => {\n container.deltaManager.outbound.off(\"op\", outHandler);\n container.deltaManager.inbound.off(\"push\", inHandler);\n };\n }\n\n /**\n * Setup debug traces for connection and ops\n */\n private setupTrace(container: IContainer, index: number) {\n if (debugOp.enabled) {\n const getContentsString = (type: string, msgContents: any) => {\n try {\n if (type !== MessageType.Operation) {\n if (typeof msgContents === \"string\") { return msgContents; }\n return JSON.stringify(msgContents);\n }\n let address = \"\";\n\n // contents comes in the wire as JSON string (\"push\" event)\n // But already parsed when apply (\"op\" event)\n let contents = typeof msgContents === \"string\" ?\n JSON.parse(msgContents) : msgContents;\n while (contents !== undefined && contents !== null) {\n if (contents.contents?.address !== undefined) {\n address += `/${contents.contents.address}`;\n contents = contents.contents.contents;\n } else if (contents.content?.address !== undefined) {\n address += `/${contents.content.address}`;\n contents = contents.content.contents;\n } else {\n break;\n }\n }\n if (address) {\n return `${address} ${JSON.stringify(contents)}`;\n }\n return JSON.stringify(contents);\n } catch (e: any) {\n return `${e.message}: ${e.stack}`;\n }\n };\n debugOp(`${index}: ADD: clientId: ${(container as Container).clientId}`);\n container.deltaManager.outbound.on(\"op\", (messages) => {\n for (const msg of messages) {\n debugOp(`${index}: OUT: `\n + `cli: ${msg.clientSequenceNumber.toString().padStart(3)} `\n + `rsq: ${msg.referenceSequenceNumber.toString().padStart(3)} `\n + `${msg.type} ${getContentsString(msg.type, msg.contents)}`);\n }\n });\n const getInboundHandler = (type: string) => {\n return (msg: ISequencedDocumentMessage) => {\n const clientSeq = msg.clientId === (container as Container).clientId ?\n `cli: ${msg.clientSequenceNumber.toString().padStart(3)}` : \" \";\n debugOp(`${index}: ${type}: seq: ${msg.sequenceNumber.toString().padStart(3)} `\n + `${clientSeq} min: ${msg.minimumSequenceNumber.toString().padStart(3)} `\n + `${msg.type} ${getContentsString(msg.type, msg.contents)}`);\n };\n };\n container.deltaManager.inbound.on(\"push\", getInboundHandler(\"IN \"));\n container.deltaManager.inbound.on(\"op\", getInboundHandler(\"OP \"));\n container.deltaManager.on(\"connect\", (details) => {\n debugOp(`${index}: CON: clientId: ${details.clientId}`);\n });\n container.deltaManager.on(\"disconnect\", (reason) => {\n debugOp(`${index}: DIS: ${reason}`);\n });\n }\n }\n\n /**\n * Filter out the opened containers based on param.\n * @param containers - The container to filter to. If the array is empty, it means don't filter and return\n * all open containers.\n */\n private getContainers(containers: IContainer[]) {\n const containersToApply = containers.length === 0 ? Array.from(this.containers.keys()) : containers;\n return containersToApply.filter((container) => !container.closed);\n }\n}\n"]}
1
+ {"version":3,"file":"loaderContainerTracker.js","sourceRoot":"","sources":["../src/loaderContainerTracker.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/* eslint-disable @typescript-eslint/strict-boolean-expressions */\n\nimport { assert } from \"@fluidframework/common-utils\";\nimport { IContainer, IDeltaQueue, IHostLoader } from \"@fluidframework/container-definitions\";\nimport { Container } from \"@fluidframework/container-loader\";\nimport { canBeCoalescedByService } from \"@fluidframework/driver-utils\";\nimport { IDocumentMessage, ISequencedDocumentMessage, MessageType } from \"@fluidframework/protocol-definitions\";\nimport { debug } from \"./debug\";\nimport { IOpProcessingController } from \"./testObjectProvider\";\nimport { timeoutAwait, timeoutPromise } from \"./timeoutUtils\";\n\nconst debugOp = debug.extend(\"ops\");\nconst debugWait = debug.extend(\"wait\");\n\n// set the maximum timeout value as 5 mins\nconst defaultMaxTimeout = 5 * 6000;\n\ninterface ContainerRecord {\n // A short number for debug output\n index: number;\n\n // LoaderContainerTracker paused state\n paused: boolean;\n\n // Tracking trailing no-op that may or may be acked by the server so we can discount them\n // See issue #5629\n startTrailingNoOps: number;\n trailingNoOps: number;\n\n // Track last proposal to ensure no unresolved proposal\n lastProposal: number;\n}\n\nexport class LoaderContainerTracker implements IOpProcessingController {\n private readonly containers = new Map<IContainer, ContainerRecord>();\n private lastProposalSeqNum: number = 0;\n\n constructor(private readonly syncSummarizerClients: boolean = false) {}\n\n /**\n * Add a loader to start to track any container created from them\n * @param loader - loader to start tracking any container created.\n */\n public add<LoaderType extends IHostLoader>(loader: LoaderType) {\n // TODO: Expose Loader API to able to intercept container creation (See issue #5114)\n const patch = <T, C extends IContainer>(fn: (...args) => Promise<C>) => {\n const boundFn = fn.bind(loader);\n return async (...args: T[]) => {\n const container = await boundFn(...args);\n this.addContainer(container);\n return container;\n };\n };\n /* eslint-disable @typescript-eslint/unbound-method */\n loader.resolve = patch(loader.resolve);\n loader.createDetachedContainer = patch(loader.createDetachedContainer);\n loader.rehydrateDetachedContainerFromSnapshot = patch(loader.rehydrateDetachedContainerFromSnapshot);\n /* eslint-enable @typescript-eslint/unbound-method */\n }\n\n /**\n * Utility function to add container to be tracked.\n *\n * @param container - container to add\n */\n private addContainer(container: IContainer) {\n // ignore summarizer\n if (!container.deltaManager.clientDetails.capabilities.interactive && !this.syncSummarizerClients) { return; }\n\n // don't add container that is already tracked\n if (this.containers.has(container)) { return; }\n\n const record = {\n index: this.containers.size,\n paused: false,\n startTrailingNoOps: 0,\n trailingNoOps: 0,\n lastProposal: 0,\n };\n this.containers.set(container, record);\n this.trackTrailingNoOps(container, record);\n this.trackLastProposal(container);\n this.setupTrace(container, record.index);\n }\n\n /**\n * Keep track of the trailing NoOp that was sent so we can discount them in the clientSequenceNumber tracking.\n * The server might coalesce them with other ops, or a single NoOp, or delay it if it don't think it is necessary.\n *\n * @param container - the container to track\n * @param record - the record to update the trailing op information\n */\n private trackTrailingNoOps(container: IContainer, record: ContainerRecord) {\n container.deltaManager.outbound.on(\"op\", (messages) => {\n for (const msg of messages) {\n if (canBeCoalescedByService(msg)) {\n // Track the NoOp that was sent.\n if (record.trailingNoOps === 0) {\n // record the starting sequence number of the trailing no ops if we haven't been tracking yet.\n record.startTrailingNoOps = msg.clientSequenceNumber;\n }\n record.trailingNoOps++;\n } else {\n // Other ops has been sent. We would like to see those ack'ed, so no more need to track NoOps\n record.trailingNoOps = 0;\n }\n }\n });\n\n container.deltaManager.inbound.on(\"push\", (message) => {\n // Received the no op back, update the record if we are tracking\n if (canBeCoalescedByService(message)\n && message.clientId === (container as Container).clientId\n && record.trailingNoOps !== 0\n && record.startTrailingNoOps <= message.clientSequenceNumber\n ) {\n // NoOp might have coalesced and skipped ahead some sequence number\n // update the record and skip ahead as well\n const oldStartTrailingNoOps = record.startTrailingNoOps;\n record.startTrailingNoOps = message.clientSequenceNumber + 1;\n record.trailingNoOps -= (record.startTrailingNoOps - oldStartTrailingNoOps);\n }\n });\n\n container.on(\"disconnected\", () => {\n // reset on disconnect.\n record.trailingNoOps = 0;\n });\n }\n\n private trackLastProposal(container: IContainer) {\n container.on(\"codeDetailsProposed\", (value, proposal) => {\n if (proposal.sequenceNumber > this.lastProposalSeqNum) {\n this.lastProposalSeqNum = proposal.sequenceNumber;\n }\n });\n }\n\n /**\n * Reset the tracker, closing all containers and stop tracking them.\n */\n public reset() {\n this.lastProposalSeqNum = 0;\n for (const container of this.containers.keys()) {\n container.close();\n }\n this.containers.clear();\n\n // REVIEW: do we need to unpatch the loaders?\n }\n\n /**\n * Ensure all tracked containers are synchronized\n */\n public async ensureSynchronized(...containers: IContainer[]) {\n await this.processSynchronized(undefined, ...containers);\n }\n\n /**\n * Ensure all tracked containers are synchronized with a time limit\n */\n public async ensureSynchronizedWithTimeout?(timeoutDuration: number | undefined, ...containers: IContainer[]) {\n await this.processSynchronized(timeoutDuration, ...containers);\n }\n\n /**\n * Make sure all the tracked containers are synchronized.\n * - No isDirty (non-readonly) containers\n * - No extra clientId in quorum of any container that is not tracked and still opened.\n * - i.e. no pending Join/Leave message.\n * - No unresolved proposal (minSeqNum \\>= lastProposalSeqNum)\n * - lastSequenceNumber of all container is the same\n * - clientSequenceNumberObserved is the same as clientSequenceNumber sent\n * - this overlaps with !isDirty, but include task scheduler ops.\n * - Trailing NoOp is tracked and don't count as pending ops.\n */\n private async processSynchronized(timeoutDuration: number | undefined, ...containers: IContainer[]) {\n const start = Date.now();\n const resumed = this.resumeProcessing(...containers);\n\n let waitingSequenceNumberSynchronized = false;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const containersToApply = this.getContainers(containers);\n if (containersToApply.length === 0) { break; }\n\n // Ignore readonly dirty containers, because it can't sent up and nothing can be done about it being dirty\n const dirtyContainers = containersToApply.filter((c) => {\n const { deltaManager, isDirty } = c;\n return deltaManager.readOnlyInfo.readonly !== true && isDirty;\n });\n if (dirtyContainers.length === 0) {\n // Wait for all the leave messages\n const pendingClients = this.getPendingClients(containersToApply);\n if (pendingClients.length === 0) {\n if (this.isSequenceNumberSynchronized(containersToApply)) {\n // done, we are in sync\n break;\n }\n if (!waitingSequenceNumberSynchronized) {\n // Only write it out once\n waitingSequenceNumberSynchronized = true;\n debugWait(\"Waiting for sequence number synchronized\");\n await timeoutAwait(this.waitForAnyInboundOps(containersToApply), {\n durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,\n errorMsg: \"Timeout on waiting for sequence number synchronized\",\n });\n }\n } else {\n waitingSequenceNumberSynchronized = false;\n await timeoutAwait(this.waitForPendingClients(pendingClients), {\n durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,\n errorMsg: \"Timeout on waiting for pending join or leave op\",\n });\n }\n } else {\n // Wait for all the containers to be saved\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n debugWait(`Waiting container to be saved ${dirtyContainers.map((c) => this.containers.get(c)!.index)}`);\n waitingSequenceNumberSynchronized = false;\n const remainedDuration = timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout;\n await Promise.all(dirtyContainers.map(async (c) => Promise.race(\n [timeoutPromise(\n (resolve) => c.once(\"saved\", () => resolve()),\n {\n durationMs: remainedDuration,\n errorMsg: \"Timeout on waiting a container to be saved\",\n },\n ),\n new Promise((resolve) => c.once(\"closed\", resolve)),\n ],\n )));\n }\n\n // yield a turn to allow side effect of the ops we just processed execute before we check again\n await new Promise<void>((resolve) => { setTimeout(resolve, 0); });\n }\n\n // Pause all container that was resumed\n // don't call pause if resumed is empty and pause everything, which is not what we want\n if (resumed.length !== 0) {\n await timeoutAwait(this.pauseProcessing(...resumed), {\n durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,\n errorMsg: \"Timeout on waiting for pausing all resumed containers\",\n });\n }\n\n debugWait(\"Synchronized\");\n }\n\n /**\n * Utility to calculate the set of clientId per container in quorum that is NOT associated with\n * any container we tracked, indicating there is a pending join or leave op that we need to wait.\n *\n * @param containersToApply - the set of containers to check\n */\n private getPendingClients(containersToApply: IContainer[]) {\n // All the clientId we track should be a superset of the quorum, otherwise, we are missing\n // leave messages\n const openedDocuments = Array.from(this.containers.keys()).filter((c) => !c.closed);\n const openedClientId = openedDocuments.map((container) => (container as Container).clientId);\n\n const pendingClients: [IContainer, Set<string>][] = [];\n containersToApply.forEach((container) => {\n const pendingClientId = new Set<string>();\n const quorum = container.getQuorum();\n quorum.getMembers().forEach((client, clientId) => {\n // ignore summarizer\n if (!client.client.details.capabilities.interactive && !this.syncSummarizerClients) { return; }\n if (!openedClientId.includes(clientId)) {\n pendingClientId.add(clientId);\n }\n });\n\n if (pendingClientId.size !== 0) {\n pendingClients.push([container, pendingClientId]);\n }\n });\n return pendingClients;\n }\n\n /**\n * Utility to check synchronization based on sequence number\n * See ensureSynchronized for more detail\n *\n * @param containersToApply - the set of containers to check\n */\n private isSequenceNumberSynchronized(containersToApply: IContainer[]) {\n // clientSequenceNumber check detects ops in flight, both on the wire and in the outbound queue\n // We need both client sequence number and isDirty check because:\n // - Currently isDirty flag ignores ops for task scheduler, so we need the client sequence number check\n // - But isDirty flags include ops during forceReadonly and disconnected, because we don't submit\n // the ops in the first place, clientSequenceNumber is not assigned\n\n const isClientSequenceNumberSynchronized = containersToApply.every((container) => {\n if (container.deltaManager.readOnlyInfo.readonly === true) {\n // Ignore readonly container. the clientSeqNum and clientSeqNumObserved might be out of sync\n // because we transition to readonly when outbound is not empty or the in transit op got lost\n return true;\n }\n // Note that in read only mode, the op won't be submitted\n let deltaManager = (container.deltaManager as any);\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const { trailingNoOps } = this.containers.get(container)!;\n // Back-compat: clientSequenceNumber & clientSequenceNumberObserved moved to ConnectionManager in 0.53\n if (!(\"clientSequenceNumber\" in deltaManager)) {\n deltaManager = deltaManager.connectionManager;\n }\n assert(\"clientSequenceNumber\" in deltaManager, \"no clientSequenceNumber\");\n assert(\"clientSequenceNumberObserved\" in deltaManager, \"no clientSequenceNumber\");\n return deltaManager.clientSequenceNumber ===\n (deltaManager.clientSequenceNumberObserved as number) + trailingNoOps;\n });\n\n if (!isClientSequenceNumberSynchronized) {\n return false;\n }\n\n const minSeqNum = containersToApply[0].deltaManager.minimumSequenceNumber;\n if (minSeqNum < this.lastProposalSeqNum) {\n // There is an unresolved proposal\n return false;\n }\n\n // Check to see if all the container has process the same number of ops.\n const seqNum = containersToApply[0].deltaManager.lastSequenceNumber;\n return containersToApply.every((c) => c.deltaManager.lastSequenceNumber === seqNum);\n }\n\n /**\n * Utility to wait for any clientId in quorum that is NOT associated with any container we\n * tracked, indicating there is a pending join or leave op that we need to wait.\n *\n * Note that this function doesn't account for container that got added after we started waiting\n *\n * @param containersToApply - the set of containers to wait for any inbound ops for\n */\n private async waitForPendingClients(pendingClients: [IContainer, Set<string>][]) {\n const unconnectedClients =\n Array.from(this.containers.keys()).filter((c) => !c.closed && !(c as Container).connected);\n return Promise.all(pendingClients.map(async ([container, pendingClientId]) => {\n return new Promise<void>((resolve) => {\n const cleanup = () => {\n unconnectedClients.forEach((c) => c.off(\"connected\", handler));\n container.getQuorum().off(\"removeMember\", handler);\n };\n const handler = (clientId: string) => {\n pendingClientId.delete(clientId);\n if (pendingClientId.size === 0) {\n cleanup();\n resolve();\n }\n };\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const index = this.containers.get(container)!.index;\n debugWait(`${index}: Waiting for pending clients ${Array.from(pendingClientId.keys())}`);\n unconnectedClients.forEach((c) => c.on(\"connected\", handler));\n container.getQuorum().on(\"removeMember\", handler);\n container.on(\"closed\", () => {\n cleanup();\n resolve();\n });\n });\n }));\n }\n\n /**\n * Utility to wait for any inbound ops from a set of containers\n * @param containersToApply - the set of containers to wait for any inbound ops for\n */\n private async waitForAnyInboundOps(containersToApply: IContainer[]) {\n return new Promise<void>((resolve) => {\n const handler = () => {\n containersToApply.map((c) => {\n c.deltaManager.inbound.off(\"push\", handler);\n });\n resolve();\n };\n containersToApply.map((c) => {\n c.deltaManager.inbound.on(\"push\", handler);\n });\n });\n }\n\n /**\n * Resume all queue activities on all paused tracked containers and return them\n */\n public resumeProcessing(...containers: IContainer[]) {\n const resumed: IContainer[] = [];\n const containersToApply = this.getContainers(containers);\n for (const container of containersToApply) {\n const record = this.containers.get(container);\n if (record?.paused === true) {\n debugWait(`${record.index}: container resumed`);\n container.deltaManager.inbound.resume();\n container.deltaManager.outbound.resume();\n resumed.push(container);\n record.paused = false;\n }\n }\n return resumed;\n }\n\n /**\n * Pause all queue activities on the containers given, or all tracked containers\n * Any containers given that is not tracked will be ignored.\n */\n public async pauseProcessing(...containers: IContainer[]) {\n const pauseP: Promise<void>[] = [];\n const containersToApply = this.getContainers(containers);\n for (const container of containersToApply) {\n const record = this.containers.get(container);\n if (record !== undefined && !record.paused) {\n debugWait(`${record.index}: container paused`);\n pauseP.push(container.deltaManager.inbound.pause());\n pauseP.push(container.deltaManager.outbound.pause());\n record.paused = true;\n }\n }\n await Promise.all(pauseP);\n }\n\n /**\n * Pause all queue activities on all tracked containers, and resume only\n * inbound to process ops until it is idle. All queues are left in the paused state\n * after the function\n */\n public async processIncoming(...containers: IContainer[]) {\n return this.processQueue(containers, (container) => container.deltaManager.inbound);\n }\n\n /**\n * Pause all queue activities on all tracked containers, and resume only\n * outbound to process ops until it is idle. All queues are left in the paused state\n * after the function\n */\n public async processOutgoing(...containers: IContainer[]) {\n return this.processQueue(containers, (container) => container.deltaManager.outbound);\n }\n\n /**\n * Implementation of processIncoming and processOutgoing\n */\n private async processQueue<U>(containers: IContainer[], getQueue: (container: IContainer) => IDeltaQueue<U>) {\n await this.pauseProcessing(...containers);\n const resumed: IDeltaQueue<U>[] = [];\n\n const containersToApply = this.getContainers(containers);\n const inflightTracker = new Map<IContainer, number>();\n const cleanup: (() => void)[] = [];\n for (const container of containersToApply) {\n const queue = getQueue(container);\n\n // track the outgoing ops (if any) to make sure they make the round trip to at least to the same client\n // to make sure they are sequenced.\n cleanup.push(this.setupInOutTracker(container, inflightTracker));\n queue.resume();\n resumed.push(queue);\n }\n\n while (resumed.some((queue) => !queue.idle)) {\n debugWait(\"Wait until queue is idle\");\n await new Promise<void>((resolve) => { setTimeout(resolve, 0); });\n }\n\n // Make sure all the op that we sent out are acked first\n // This is no op if we are processing incoming\n if (inflightTracker.size) {\n debugWait(\"Wait for inflight ops\");\n do {\n await this.waitForAnyInboundOps(containersToApply);\n } while (inflightTracker.size);\n }\n\n // remove the handlers\n cleanup.forEach((clean) => clean());\n\n await Promise.all(resumed.map(async (queue) => queue.pause()));\n }\n\n /**\n * Utility to set up listener to track the outbound ops until it round trip back\n * Returns a function to remove the handler after it is done.\n *\n * @param container - the container to setup\n * @param inflightTracker - a map to track the clientSequenceNumber per container it expect to get ops back\n */\n private setupInOutTracker(container: IContainer, inflightTracker: Map<IContainer, number>) {\n const outHandler = (messages: IDocumentMessage[]) => {\n for (const message of messages) {\n if (!canBeCoalescedByService(message)) {\n inflightTracker.set(container, message.clientSequenceNumber);\n }\n }\n };\n const inHandler = (message: ISequencedDocumentMessage) => {\n if (!canBeCoalescedByService(message)\n && message.clientId === (container as Container).clientId\n && inflightTracker.get(container) === message.clientSequenceNumber) {\n inflightTracker.delete(container);\n }\n };\n\n container.deltaManager.outbound.on(\"op\", outHandler);\n container.deltaManager.inbound.on(\"push\", inHandler);\n\n return () => {\n container.deltaManager.outbound.off(\"op\", outHandler);\n container.deltaManager.inbound.off(\"push\", inHandler);\n };\n }\n\n /**\n * Setup debug traces for connection and ops\n */\n private setupTrace(container: IContainer, index: number) {\n if (debugOp.enabled) {\n const getContentsString = (type: string, msgContents: any) => {\n try {\n if (type !== MessageType.Operation) {\n if (typeof msgContents === \"string\") { return msgContents; }\n return JSON.stringify(msgContents);\n }\n let address = \"\";\n\n // contents comes in the wire as JSON string (\"push\" event)\n // But already parsed when apply (\"op\" event)\n let contents = typeof msgContents === \"string\" ?\n JSON.parse(msgContents) : msgContents;\n while (contents !== undefined && contents !== null) {\n if (contents.contents?.address !== undefined) {\n address += `/${contents.contents.address}`;\n contents = contents.contents.contents;\n } else if (contents.content?.address !== undefined) {\n address += `/${contents.content.address}`;\n contents = contents.content.contents;\n } else {\n break;\n }\n }\n if (address) {\n return `${address} ${JSON.stringify(contents)}`;\n }\n return JSON.stringify(contents);\n } catch (e: any) {\n return `${e.message}: ${e.stack}`;\n }\n };\n debugOp(`${index}: ADD: clientId: ${(container as Container).clientId}`);\n container.deltaManager.outbound.on(\"op\", (messages) => {\n for (const msg of messages) {\n debugOp(`${index}: OUT: `\n + `cli: ${msg.clientSequenceNumber.toString().padStart(3)} `\n + `rsq: ${msg.referenceSequenceNumber.toString().padStart(3)} `\n + `${msg.type} ${getContentsString(msg.type, msg.contents)}`);\n }\n });\n const getInboundHandler = (type: string) => {\n return (msg: ISequencedDocumentMessage) => {\n const clientSeq = msg.clientId === (container as Container).clientId ?\n `cli: ${msg.clientSequenceNumber.toString().padStart(3)}` : \" \";\n debugOp(`${index}: ${type}: seq: ${msg.sequenceNumber.toString().padStart(3)} `\n + `${clientSeq} min: ${msg.minimumSequenceNumber.toString().padStart(3)} `\n + `${msg.type} ${getContentsString(msg.type, msg.contents)}`);\n };\n };\n container.deltaManager.inbound.on(\"push\", getInboundHandler(\"IN \"));\n container.deltaManager.inbound.on(\"op\", getInboundHandler(\"OP \"));\n container.deltaManager.on(\"connect\", (details) => {\n debugOp(`${index}: CON: clientId: ${details.clientId}`);\n });\n container.deltaManager.on(\"disconnect\", (reason) => {\n debugOp(`${index}: DIS: ${reason}`);\n });\n }\n }\n\n /**\n * Filter out the opened containers based on param.\n * @param containers - The container to filter to. If the array is empty, it means don't filter and return\n * all open containers.\n */\n private getContainers(containers: IContainer[]) {\n const containersToApply = containers.length === 0 ? Array.from(this.containers.keys()) : containers;\n return containersToApply.filter((container) => !container.closed);\n }\n}\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/test-utils";
8
- export declare const pkgVersion = "2.0.0-internal.1.1.1";
8
+ export declare const pkgVersion = "2.0.0-internal.1.2.0.93071";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,yBAAyB,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,+BAA+B,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/test-utils";
11
- exports.pkgVersion = "2.0.0-internal.1.1.1";
11
+ exports.pkgVersion = "2.0.0-internal.1.2.0.93071";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/test-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.1.1\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,4BAA4B,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/test-utils\";\nexport const pkgVersion = \"2.0.0-internal.1.2.0.93071\";\n"]}
@@ -40,7 +40,7 @@ export interface ITestObjectProvider {
40
40
  urlResolver: IUrlResolver;
41
41
  defaultCodeDetails: IFluidCodeDetails;
42
42
  opProcessingController: IOpProcessingController;
43
- ensureSynchronized(): Promise<void>;
43
+ ensureSynchronized(timeoutDuration?: number): Promise<void>;
44
44
  reset(): void;
45
45
  documentId: string;
46
46
  driver: ITestDriver;
@@ -147,7 +147,7 @@ export declare class TestObjectProvider implements ITestObjectProvider {
147
147
  */
148
148
  loadTestContainer(testContainerConfig?: ITestContainerConfig, requestHeader?: IRequestHeader): Promise<IContainer>;
149
149
  reset(): void;
150
- ensureSynchronized(): Promise<void>;
150
+ ensureSynchronized(timeoutDuration?: number): Promise<void>;
151
151
  waitContainerToCatchUp(container: IContainer): Promise<boolean>;
152
152
  updateDocumentId(resolvedUrl: IResolvedUrl | undefined): void;
153
153
  resetLoaderContainerTracker(syncSummarizerClients?: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"testObjectProvider.d.ts","sourceRoot":"","sources":["../src/testObjectProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testObjectProvider.d.ts","sourceRoot":"","sources":["../src/testObjectProvider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACvH,OAAO,EACH,YAAY,EACZ,MAAM,EAET,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEzG,OAAO,EAAE,WAAW,EAAmB,MAAM,yCAAyC,CAAC;AAEvF,OAAO,EAAgC,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAEhG,OAAO,EAAE,eAAe,EAAmB,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAO3D,MAAM,WAAW,uBAAuB;IACpC,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,eAAe,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,gBAAgB,CAAC,GAAG,UAAU,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;CACvD;AAED,MAAM,WAAW,mBAAmB;IAChC,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe,CAAC;IACvF,YAAY,CACR,cAAc,EAAE,QAAQ,CAAC,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,EAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACpC,WAAW,CAAC;IACf,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACvG,aAAa,CACT,UAAU,EAAE,eAAe,EAC3B,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EACnC,aAAa,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,CAAC,CAAC;IAEvB;;;OAGG;IACH,cAAc,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,WAAW,CAAC;IACxE,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnF,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,EAAE,aAAa,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnH;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,GAAG,IAAI,CAAC;IAEtD,MAAM,EAAE,oBAAoB,CAAC;IAC7B,sBAAsB,EAAE,uBAAuB,CAAC;IAChD,WAAW,EAAE,YAAY,CAAC;IAC1B,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,sBAAsB,EAAE,uBAAuB,CAAC;IAEhD,kBAAkB,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,KAAK,IAAI,IAAI,CAAC;IAEd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;CACvB;AAED,oBAAY,qBAAqB;IAC7B,MAAM,IAAA;IACN,IAAI,IAAA;CACP;AAED,MAAM,WAAW,oBAAoB;IACjC,qDAAqD;IACrD,mBAAmB,CAAC,EAAE,qBAAqB,CAAC;IAE5C,yFAAyF;IACzF,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAElC,2DAA2D;IAC3D,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAE1C,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,gBAAgB,QAAO,MAAgB,CAAC;AAkCrD;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,eAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,oBAAoB;IAI7D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqF;IACpH,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAEvD,qBAAqB,CAAC,GAAI,qBAAqB,EAAE,sBAAsB,EAAE;IAWhF,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IA6B/B,2BAA2B;;;;;;;CAQrC;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,mBAAmB;aAetC,iBAAiB,EAAE,OAAO,MAAM;aAChC,MAAM,EAAE,WAAW;aACnB,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe;IAhB1G,OAAO,CAAC,uBAAuB,CAAgC;IAC/D,OAAO,CAAC,uBAAuB,CAAsC;IACrE,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAE1D,OAAO,CAAC,gBAAgB,CAAS;IAEjC;;;;OAIG;gBAEiB,iBAAiB,EAAE,OAAO,MAAM,EAChC,MAAM,EAAE,WAAW,EACnB,qBAAqB,EAAE,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,KAAK,eAAe;IAK1G,IAAI,MAAM,IAAI,2BAA2B,CAcxC;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,2BAA2B,EAE7C;IAED,IAAI,sBAAsB,4BAKzB;IAED,IAAI,WAAW,iBAKd;IAED,IAAI,UAAU,WAEb;IAED,IAAI,kBAAkB,sBAErB;IAED,IAAI,sBAAsB,IAAI,uBAAuB,CAEpD;IAED;;;;;;;OAOG;IACI,YAAY,CACf,cAAc,EAAE,QAAQ,CAAC,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,EAC9D,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAmBvC;;;;;;;;OAQG;IACU,eAAe,CAAC,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC;IAkBhF,aAAa,CACtB,UAAU,EAAE,eAAe,EAC3B,WAAW,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,EACnC,aAAa,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAKxD;;;;OAIG;IACI,cAAc,CAAC,mBAAmB,CAAC,EAAE,oBAAoB;IAOhE;;;;OAIG;IACU,iBAAiB,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC;IAkB/F;;;;;OAKG;IACU,iBAAiB,CAC1B,mBAAmB,CAAC,EAAE,oBAAoB,EAC1C,aAAa,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,CAAC;IAWf,KAAK;IAaC,kBAAkB,CAAC,eAAe,CAAC,EAAE,MAAM;IAS3C,sBAAsB,CAAC,SAAS,EAAE,UAAU;IAYzD,gBAAgB,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS;IAI/C,2BAA2B,CAAC,qBAAqB,GAAE,OAAe;CAI5E;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,2BAA2B,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,qBAa9G"}
@@ -260,8 +260,15 @@ class TestObjectProvider {
260
260
  this._logger = undefined;
261
261
  this._documentCreated = false;
262
262
  }
263
- async ensureSynchronized() {
264
- return this._loaderContainerTracker.ensureSynchronized();
263
+ async ensureSynchronized(timeoutDuration) {
264
+ var _a, _b;
265
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
266
+ if (!timeoutDuration) {
267
+ return this._loaderContainerTracker.ensureSynchronized();
268
+ }
269
+ else {
270
+ return (_b = (_a = this._loaderContainerTracker).ensureSynchronizedWithTimeout) === null || _b === void 0 ? void 0 : _b.call(_a, timeoutDuration);
271
+ }
265
272
  }
266
273
  async waitContainerToCatchUp(container) {
267
274
  // The original waitContainerToCatchUp() from container loader uses either Container.resume()
@@ -1 +1 @@
1
- {"version":3,"file":"testObjectProvider.js","sourceRoot":"","sources":["../src/testObjectProvider.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 { IContainer, IHostLoader, IFluidCodeDetails } from \"@fluidframework/container-definitions\";\nimport { ITelemetryGenericEvent, ITelemetryBaseLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport {\n ILoaderProps,\n Loader,\n waitContainerToCatchUp as waitContainerToCatchUp_original,\n} from \"@fluidframework/container-loader\";\nimport { IContainerRuntimeOptions } from \"@fluidframework/container-runtime\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ensureFluidResolvedUrl } from \"@fluidframework/driver-utils\";\nimport { ITestDriver, TestDriverTypes } from \"@fluidframework/test-driver-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { ChildLogger, MultiSinkLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { LoaderContainerTracker } from \"./loaderContainerTracker\";\nimport { fluidEntryPoint, LocalCodeLoader } from \"./localCodeLoader\";\nimport { createAndAttachContainer } from \"./localLoader\";\nimport { ChannelFactoryRegistry } from \"./testFluidObject\";\n\nconst defaultCodeDetails: IFluidCodeDetails = {\n package: \"defaultTestPackage\",\n config: {},\n};\n\nexport interface IOpProcessingController {\n processIncoming(...containers: IContainer[]): Promise<void>;\n processOutgoing(...containers: IContainer[]): Promise<void>;\n pauseProcessing(...containers: IContainer[]): Promise<void>;\n resumeProcessing(...containers: IContainer[]): void;\n}\n\nexport interface ITestObjectProvider {\n createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint;\n createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ): IHostLoader;\n createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>): Promise<IContainer>;\n loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer>;\n\n /**\n * Used to create a test Container. The Loader/ContainerRuntime/DataRuntime might be different versioned.\n * In generateLocalCompatTest(), this Container and its runtime will be arbitrarily-versioned.\n */\n makeTestLoader(testContainerConfig?: ITestContainerConfig): IHostLoader;\n makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer>;\n loadTestContainer(testContainerConfig?: ITestContainerConfig, requestHeader?: IRequestHeader): Promise<IContainer>;\n /**\n *\n * @param url - Resolved container URL\n */\n updateDocumentId(url: IResolvedUrl | undefined): void;\n\n logger: ITelemetryBaseLogger;\n documentServiceFactory: IDocumentServiceFactory;\n urlResolver: IUrlResolver;\n defaultCodeDetails: IFluidCodeDetails;\n opProcessingController: IOpProcessingController;\n\n ensureSynchronized(): Promise<void>;\n reset(): void;\n\n documentId: string;\n driver: ITestDriver;\n}\n\nexport enum DataObjectFactoryType {\n Primed, // default\n Test,\n}\n\nexport interface ITestContainerConfig {\n /** TestFluidDataObject instead of PrimedDataStore */\n fluidDataObjectType?: DataObjectFactoryType;\n\n /** An array of channel name and DDS factory pair to create on container creation time */\n registry?: ChannelFactoryRegistry;\n\n /** Container runtime options for the container instance */\n runtimeOptions?: IContainerRuntimeOptions;\n\n /** Loader options for the loader used to create containers */\n loaderProps?: Partial<ILoaderProps>;\n}\n\nexport const createDocumentId = (): string => uuid();\n\ninterface IDocumentIdStrategy {\n get(): string;\n update(resolvedUrl?: IResolvedUrl): void;\n reset(): void;\n}\n\n/**\n * Document ID is treated differently by test drivers. The key difference is in generating\n * a new container ID and accessing the container in multi-instance test cases.\n */\nfunction getDocumentIdStrategy(type?: TestDriverTypes): IDocumentIdStrategy {\n let documentId = createDocumentId();\n switch (type) {\n case \"odsp\":\n return {\n get: () => documentId,\n update: () => { }, // do not update the document ID in odsp test cases\n reset: () => { documentId = createDocumentId(); },\n };\n default:\n return {\n get: () => documentId,\n update: (resolvedUrl?: IResolvedUrl) => {\n // Extract the document ID from the resolved container's URL and reset the ID property\n ensureFluidResolvedUrl(resolvedUrl);\n documentId = resolvedUrl.id ?? documentId;\n },\n reset: () => { documentId = createDocumentId(); },\n };\n }\n}\n\n/**\n * This class tracks events. It allows specifying expected events, which will be looked for in order.\n * It also tracks all unexpected errors.\n * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and\n * any expected events that have not occurred.\n */\nexport class EventAndErrorTrackingLogger extends TelemetryLogger {\n constructor(private readonly baseLogger: ITelemetryBaseLogger) {\n super();\n }\n\n private readonly expectedEvents: ({ index: number; event: ITelemetryGenericEvent | undefined; } | undefined)[] = [];\n private readonly unexpectedErrors: ITelemetryBaseEvent[] = [];\n\n public registerExpectedEvent(... orderedExpectedEvents: ITelemetryGenericEvent[]) {\n if (this.expectedEvents.length !== 0) {\n // we don't have to error here. just no reason not to. given the events must be\n // ordered it could be tricky to figure out problems around multiple registrations.\n throw new Error(\n \"Expected events already registered.\\n\"\n + \"Call reportAndClearTrackedEvents to clear them before registering more\");\n }\n this.expectedEvents.push(... orderedExpectedEvents.map((event, index) => ({ index, event })));\n }\n\n send(event: ITelemetryBaseEvent): void {\n const ee = this.expectedEvents[0]?.event;\n if (ee?.eventName === event.eventName) {\n let matches = true;\n for (const key of Object.keys(ee)) {\n if (ee[key] !== event[key]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n // we found an expected event\n // so remove it from the list of expected events\n // and if it is an error, change it to generic\n // this helps keep our telemetry clear of\n // expected errors.\n this.expectedEvents.shift();\n if (event.category === \"error\") {\n event.category = \"generic\";\n }\n }\n }\n if (event.category === \"error\") {\n this.unexpectedErrors.push(event);\n }\n\n this.baseLogger.send(event);\n }\n\n public reportAndClearTrackedEvents() {\n const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);\n const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);\n return {\n expectedNotFound,\n unexpectedErrors,\n };\n }\n}\n\n/**\n * Shared base class for test object provider. Contain code for loader and container creation and loading\n */\nexport class TestObjectProvider implements ITestObjectProvider {\n private _loaderContainerTracker = new LoaderContainerTracker();\n private _documentServiceFactory: IDocumentServiceFactory | undefined;\n private _urlResolver: IUrlResolver | undefined;\n private _logger: EventAndErrorTrackingLogger | undefined;\n private readonly _documentIdStrategy: IDocumentIdStrategy;\n // Since documentId doesn't change we can only create/make one container. Call the load functions instead.\n private _documentCreated = false;\n\n /**\n * Manage objects for loading and creating container, including the driver, loader, and OpProcessingController\n * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name\n * and factory for TestFluidObject\n */\n constructor(\n public readonly LoaderConstructor: typeof Loader,\n public readonly driver: ITestDriver,\n public readonly createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint,\n ) {\n this._documentIdStrategy = getDocumentIdStrategy(driver.type);\n }\n\n get logger(): EventAndErrorTrackingLogger {\n if (this._logger === undefined) {\n this._logger = new EventAndErrorTrackingLogger(\n ChildLogger.create(getTestLogger?.(), undefined,\n {\n all: {\n driverType: this.driver.type,\n driverEndpointName: this.driver.endpointName,\n driverTenantName: this.driver.tenantName,\n driverUserIndex: this.driver.userIndex,\n },\n }));\n }\n return this._logger;\n }\n\n set logger(logger: EventAndErrorTrackingLogger) {\n this._logger = logger;\n }\n\n get documentServiceFactory() {\n if (!this._documentServiceFactory) {\n this._documentServiceFactory = this.driver.createDocumentServiceFactory();\n }\n return this._documentServiceFactory;\n }\n\n get urlResolver() {\n if (!this._urlResolver) {\n this._urlResolver = this.driver.createUrlResolver();\n }\n return this._urlResolver;\n }\n\n get documentId() {\n return this._documentIdStrategy.get();\n }\n\n get defaultCodeDetails() {\n return defaultCodeDetails;\n }\n\n get opProcessingController(): IOpProcessingController {\n return this._loaderContainerTracker;\n }\n\n /**\n * Create a loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ) {\n const multiSinkLogger = new MultiSinkLogger();\n multiSinkLogger.addLogger(this.logger);\n if (loaderProps?.logger !== undefined) {\n multiSinkLogger.addLogger(loaderProps.logger);\n }\n\n const loader = new this.LoaderConstructor({\n ... loaderProps,\n logger: multiSinkLogger,\n codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),\n urlResolver: loaderProps?.urlResolver ?? this.urlResolver,\n documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,\n });\n this._loaderContainerTracker.add(loader);\n return loader;\n }\n\n /**\n * Create a container using a default document id and code details.\n * Container created is automatically added to the OpProcessingController to manage op flow\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public async createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>) {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadContainer\");\n }\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n const container = await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId),\n );\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n public async loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader): Promise<IContainer> {\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n return loader.resolve({ url: await this.driver.createContainerUrl(this.documentId), headers: requestHeader });\n }\n\n /**\n * Make a test loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n * The version of the loader/containerRuntime/dataRuntime may vary based on compat config of the current run\n * @param testContainerConfig - optional configuring the test Container\n */\n public makeTestLoader(testContainerConfig?: ITestContainerConfig) {\n return this.createLoader(\n [[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]],\n testContainerConfig?.loaderProps,\n );\n }\n\n /**\n * Make a container using a default document id and code details\n * Container loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n */\n public async makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer> {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadTestContainer\");\n }\n const loader = this.makeTestLoader(testContainerConfig);\n const container =\n await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId));\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n /**\n * Load a container using a default document id and code details.\n * IContainer loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n * @param requestHeader - optional headers to be supplied to the loader\n */\n public async loadTestContainer(\n testContainerConfig?: ITestContainerConfig,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer> {\n const loader = this.makeTestLoader(testContainerConfig);\n const container = await loader.resolve({\n url: await this.driver.createContainerUrl(this.documentId),\n headers: requestHeader,\n });\n await this.waitContainerToCatchUp(container);\n\n return container;\n }\n\n public reset() {\n this._loaderContainerTracker.reset();\n this._documentServiceFactory = undefined;\n this._urlResolver = undefined;\n this._documentIdStrategy.reset();\n const logError = getUnexpectedLogErrorException(this._logger);\n if (logError) {\n throw logError;\n }\n this._logger = undefined;\n this._documentCreated = false;\n }\n\n public async ensureSynchronized() {\n return this._loaderContainerTracker.ensureSynchronized();\n }\n\n public async waitContainerToCatchUp(container: IContainer) {\n // The original waitContainerToCatchUp() from container loader uses either Container.resume()\n // or Container.connect() as part of its implementation. However, resume() was deprecated\n // and eventually replaced with connect(). To avoid issues during LTS compatibility testing\n // with older container versions issues, we use resume() when connect() is unavailable.\n if ((container as any).connect === undefined) {\n (container as any).connect = (container as any).resume;\n }\n\n return waitContainerToCatchUp_original(container);\n }\n\n updateDocumentId(resolvedUrl: IResolvedUrl | undefined) {\n this._documentIdStrategy.update(resolvedUrl);\n }\n\n public resetLoaderContainerTracker(syncSummarizerClients: boolean = false) {\n this._loaderContainerTracker.reset();\n this._loaderContainerTracker = new LoaderContainerTracker(syncSummarizerClients);\n }\n}\n\nexport function getUnexpectedLogErrorException(logger: EventAndErrorTrackingLogger | undefined, prefix?: string) {\n if (logger === undefined) {\n return;\n }\n const results = logger.reportAndClearTrackedEvents();\n if (results.unexpectedErrors.length > 0) {\n return new Error(\n `${prefix ?? \"\"}Unexpected Errors in Logs:\\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);\n }\n if (results.expectedNotFound.length > 0) {\n return new Error(\n `${prefix ?? \"\"}Expected Events not found:\\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);\n }\n}\n"]}
1
+ {"version":3,"file":"testObjectProvider.js","sourceRoot":"","sources":["../src/testObjectProvider.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 { IContainer, IHostLoader, IFluidCodeDetails } from \"@fluidframework/container-definitions\";\nimport { ITelemetryGenericEvent, ITelemetryBaseLogger, ITelemetryBaseEvent } from \"@fluidframework/common-definitions\";\nimport {\n ILoaderProps,\n Loader,\n waitContainerToCatchUp as waitContainerToCatchUp_original,\n} from \"@fluidframework/container-loader\";\nimport { IContainerRuntimeOptions } from \"@fluidframework/container-runtime\";\nimport { IRequestHeader } from \"@fluidframework/core-interfaces\";\nimport { IDocumentServiceFactory, IResolvedUrl, IUrlResolver } from \"@fluidframework/driver-definitions\";\nimport { ensureFluidResolvedUrl } from \"@fluidframework/driver-utils\";\nimport { ITestDriver, TestDriverTypes } from \"@fluidframework/test-driver-definitions\";\nimport { v4 as uuid } from \"uuid\";\nimport { ChildLogger, MultiSinkLogger, TelemetryLogger } from \"@fluidframework/telemetry-utils\";\nimport { LoaderContainerTracker } from \"./loaderContainerTracker\";\nimport { fluidEntryPoint, LocalCodeLoader } from \"./localCodeLoader\";\nimport { createAndAttachContainer } from \"./localLoader\";\nimport { ChannelFactoryRegistry } from \"./testFluidObject\";\n\nconst defaultCodeDetails: IFluidCodeDetails = {\n package: \"defaultTestPackage\",\n config: {},\n};\n\nexport interface IOpProcessingController {\n processIncoming(...containers: IContainer[]): Promise<void>;\n processOutgoing(...containers: IContainer[]): Promise<void>;\n pauseProcessing(...containers: IContainer[]): Promise<void>;\n resumeProcessing(...containers: IContainer[]): void;\n}\n\nexport interface ITestObjectProvider {\n createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint;\n createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ): IHostLoader;\n createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>): Promise<IContainer>;\n loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer>;\n\n /**\n * Used to create a test Container. The Loader/ContainerRuntime/DataRuntime might be different versioned.\n * In generateLocalCompatTest(), this Container and its runtime will be arbitrarily-versioned.\n */\n makeTestLoader(testContainerConfig?: ITestContainerConfig): IHostLoader;\n makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer>;\n loadTestContainer(testContainerConfig?: ITestContainerConfig, requestHeader?: IRequestHeader): Promise<IContainer>;\n /**\n *\n * @param url - Resolved container URL\n */\n updateDocumentId(url: IResolvedUrl | undefined): void;\n\n logger: ITelemetryBaseLogger;\n documentServiceFactory: IDocumentServiceFactory;\n urlResolver: IUrlResolver;\n defaultCodeDetails: IFluidCodeDetails;\n opProcessingController: IOpProcessingController;\n\n ensureSynchronized(timeoutDuration?: number): Promise<void>;\n reset(): void;\n\n documentId: string;\n driver: ITestDriver;\n}\n\nexport enum DataObjectFactoryType {\n Primed, // default\n Test,\n}\n\nexport interface ITestContainerConfig {\n /** TestFluidDataObject instead of PrimedDataStore */\n fluidDataObjectType?: DataObjectFactoryType;\n\n /** An array of channel name and DDS factory pair to create on container creation time */\n registry?: ChannelFactoryRegistry;\n\n /** Container runtime options for the container instance */\n runtimeOptions?: IContainerRuntimeOptions;\n\n /** Loader options for the loader used to create containers */\n loaderProps?: Partial<ILoaderProps>;\n}\n\nexport const createDocumentId = (): string => uuid();\n\ninterface IDocumentIdStrategy {\n get(): string;\n update(resolvedUrl?: IResolvedUrl): void;\n reset(): void;\n}\n\n/**\n * Document ID is treated differently by test drivers. The key difference is in generating\n * a new container ID and accessing the container in multi-instance test cases.\n */\nfunction getDocumentIdStrategy(type?: TestDriverTypes): IDocumentIdStrategy {\n let documentId = createDocumentId();\n switch (type) {\n case \"odsp\":\n return {\n get: () => documentId,\n update: () => { }, // do not update the document ID in odsp test cases\n reset: () => { documentId = createDocumentId(); },\n };\n default:\n return {\n get: () => documentId,\n update: (resolvedUrl?: IResolvedUrl) => {\n // Extract the document ID from the resolved container's URL and reset the ID property\n ensureFluidResolvedUrl(resolvedUrl);\n documentId = resolvedUrl.id ?? documentId;\n },\n reset: () => { documentId = createDocumentId(); },\n };\n }\n}\n\n/**\n * This class tracks events. It allows specifying expected events, which will be looked for in order.\n * It also tracks all unexpected errors.\n * At any point you call reportAndClearTrackedEvents which will provide all unexpected errors, and\n * any expected events that have not occurred.\n */\nexport class EventAndErrorTrackingLogger extends TelemetryLogger {\n constructor(private readonly baseLogger: ITelemetryBaseLogger) {\n super();\n }\n\n private readonly expectedEvents: ({ index: number; event: ITelemetryGenericEvent | undefined; } | undefined)[] = [];\n private readonly unexpectedErrors: ITelemetryBaseEvent[] = [];\n\n public registerExpectedEvent(... orderedExpectedEvents: ITelemetryGenericEvent[]) {\n if (this.expectedEvents.length !== 0) {\n // we don't have to error here. just no reason not to. given the events must be\n // ordered it could be tricky to figure out problems around multiple registrations.\n throw new Error(\n \"Expected events already registered.\\n\"\n + \"Call reportAndClearTrackedEvents to clear them before registering more\");\n }\n this.expectedEvents.push(... orderedExpectedEvents.map((event, index) => ({ index, event })));\n }\n\n send(event: ITelemetryBaseEvent): void {\n const ee = this.expectedEvents[0]?.event;\n if (ee?.eventName === event.eventName) {\n let matches = true;\n for (const key of Object.keys(ee)) {\n if (ee[key] !== event[key]) {\n matches = false;\n break;\n }\n }\n if (matches) {\n // we found an expected event\n // so remove it from the list of expected events\n // and if it is an error, change it to generic\n // this helps keep our telemetry clear of\n // expected errors.\n this.expectedEvents.shift();\n if (event.category === \"error\") {\n event.category = \"generic\";\n }\n }\n }\n if (event.category === \"error\") {\n this.unexpectedErrors.push(event);\n }\n\n this.baseLogger.send(event);\n }\n\n public reportAndClearTrackedEvents() {\n const expectedNotFound = this.expectedEvents.splice(0, this.expectedEvents.length);\n const unexpectedErrors = this.unexpectedErrors.splice(0, this.unexpectedErrors.length);\n return {\n expectedNotFound,\n unexpectedErrors,\n };\n }\n}\n\n/**\n * Shared base class for test object provider. Contain code for loader and container creation and loading\n */\nexport class TestObjectProvider implements ITestObjectProvider {\n private _loaderContainerTracker = new LoaderContainerTracker();\n private _documentServiceFactory: IDocumentServiceFactory | undefined;\n private _urlResolver: IUrlResolver | undefined;\n private _logger: EventAndErrorTrackingLogger | undefined;\n private readonly _documentIdStrategy: IDocumentIdStrategy;\n // Since documentId doesn't change we can only create/make one container. Call the load functions instead.\n private _documentCreated = false;\n\n /**\n * Manage objects for loading and creating container, including the driver, loader, and OpProcessingController\n * @param createFluidEntryPoint - callback to create a fluidEntryPoint, with an optional set of channel name\n * and factory for TestFluidObject\n */\n constructor(\n public readonly LoaderConstructor: typeof Loader,\n public readonly driver: ITestDriver,\n public readonly createFluidEntryPoint: (testContainerConfig?: ITestContainerConfig) => fluidEntryPoint,\n ) {\n this._documentIdStrategy = getDocumentIdStrategy(driver.type);\n }\n\n get logger(): EventAndErrorTrackingLogger {\n if (this._logger === undefined) {\n this._logger = new EventAndErrorTrackingLogger(\n ChildLogger.create(getTestLogger?.(), undefined,\n {\n all: {\n driverType: this.driver.type,\n driverEndpointName: this.driver.endpointName,\n driverTenantName: this.driver.tenantName,\n driverUserIndex: this.driver.userIndex,\n },\n }));\n }\n return this._logger;\n }\n\n set logger(logger: EventAndErrorTrackingLogger) {\n this._logger = logger;\n }\n\n get documentServiceFactory() {\n if (!this._documentServiceFactory) {\n this._documentServiceFactory = this.driver.createDocumentServiceFactory();\n }\n return this._documentServiceFactory;\n }\n\n get urlResolver() {\n if (!this._urlResolver) {\n this._urlResolver = this.driver.createUrlResolver();\n }\n return this._urlResolver;\n }\n\n get documentId() {\n return this._documentIdStrategy.get();\n }\n\n get defaultCodeDetails() {\n return defaultCodeDetails;\n }\n\n get opProcessingController(): IOpProcessingController {\n return this._loaderContainerTracker;\n }\n\n /**\n * Create a loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public createLoader(\n packageEntries: Iterable<[IFluidCodeDetails, fluidEntryPoint]>,\n loaderProps?: Partial<ILoaderProps>,\n ) {\n const multiSinkLogger = new MultiSinkLogger();\n multiSinkLogger.addLogger(this.logger);\n if (loaderProps?.logger !== undefined) {\n multiSinkLogger.addLogger(loaderProps.logger);\n }\n\n const loader = new this.LoaderConstructor({\n ... loaderProps,\n logger: multiSinkLogger,\n codeLoader: loaderProps?.codeLoader ?? new LocalCodeLoader(packageEntries),\n urlResolver: loaderProps?.urlResolver ?? this.urlResolver,\n documentServiceFactory: loaderProps?.documentServiceFactory ?? this.documentServiceFactory,\n });\n this._loaderContainerTracker.add(loader);\n return loader;\n }\n\n /**\n * Create a container using a default document id and code details.\n * Container created is automatically added to the OpProcessingController to manage op flow\n *\n * Only the version of the loader will vary based on compat config. The version of\n * containerRuntime/dataRuntime used in fluidEntryPoint will be used as is from what is passed in.\n *\n * @param packageEntries - list of code details and fluidEntryPoint pairs.\n */\n public async createContainer(entryPoint: fluidEntryPoint, loaderProps?: Partial<ILoaderProps>) {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadContainer\");\n }\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n const container = await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId),\n );\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n public async loadContainer(\n entryPoint: fluidEntryPoint,\n loaderProps?: Partial<ILoaderProps>,\n requestHeader?: IRequestHeader): Promise<IContainer> {\n const loader = this.createLoader([[defaultCodeDetails, entryPoint]], loaderProps);\n return loader.resolve({ url: await this.driver.createContainerUrl(this.documentId), headers: requestHeader });\n }\n\n /**\n * Make a test loader. Containers created/loaded through this loader will be added to the OpProcessingController.\n * The version of the loader/containerRuntime/dataRuntime may vary based on compat config of the current run\n * @param testContainerConfig - optional configuring the test Container\n */\n public makeTestLoader(testContainerConfig?: ITestContainerConfig) {\n return this.createLoader(\n [[defaultCodeDetails, this.createFluidEntryPoint(testContainerConfig)]],\n testContainerConfig?.loaderProps,\n );\n }\n\n /**\n * Make a container using a default document id and code details\n * Container loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n */\n public async makeTestContainer(testContainerConfig?: ITestContainerConfig): Promise<IContainer> {\n if (this._documentCreated) {\n throw new Error(\n \"Only one container/document can be created. To load the container/document use loadTestContainer\");\n }\n const loader = this.makeTestLoader(testContainerConfig);\n const container =\n await createAndAttachContainer(\n defaultCodeDetails,\n loader,\n this.driver.createCreateNewRequest(this.documentId));\n this._documentCreated = true;\n // r11s driver will generate a new ID for the new container.\n // update the document ID with the actual ID of the attached container.\n this._documentIdStrategy.update(container.resolvedUrl);\n return container;\n }\n\n /**\n * Load a container using a default document id and code details.\n * IContainer loaded is automatically added to the OpProcessingController to manage op flow\n * @param testContainerConfig - optional configuring the test Container\n * @param requestHeader - optional headers to be supplied to the loader\n */\n public async loadTestContainer(\n testContainerConfig?: ITestContainerConfig,\n requestHeader?: IRequestHeader,\n ): Promise<IContainer> {\n const loader = this.makeTestLoader(testContainerConfig);\n const container = await loader.resolve({\n url: await this.driver.createContainerUrl(this.documentId),\n headers: requestHeader,\n });\n await this.waitContainerToCatchUp(container);\n\n return container;\n }\n\n public reset() {\n this._loaderContainerTracker.reset();\n this._documentServiceFactory = undefined;\n this._urlResolver = undefined;\n this._documentIdStrategy.reset();\n const logError = getUnexpectedLogErrorException(this._logger);\n if (logError) {\n throw logError;\n }\n this._logger = undefined;\n this._documentCreated = false;\n }\n\n public async ensureSynchronized(timeoutDuration?: number) {\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (!timeoutDuration) {\n return this._loaderContainerTracker.ensureSynchronized();\n } else {\n return this._loaderContainerTracker.ensureSynchronizedWithTimeout?.(timeoutDuration);\n }\n }\n\n public async waitContainerToCatchUp(container: IContainer) {\n // The original waitContainerToCatchUp() from container loader uses either Container.resume()\n // or Container.connect() as part of its implementation. However, resume() was deprecated\n // and eventually replaced with connect(). To avoid issues during LTS compatibility testing\n // with older container versions issues, we use resume() when connect() is unavailable.\n if ((container as any).connect === undefined) {\n (container as any).connect = (container as any).resume;\n }\n\n return waitContainerToCatchUp_original(container);\n }\n\n updateDocumentId(resolvedUrl: IResolvedUrl | undefined) {\n this._documentIdStrategy.update(resolvedUrl);\n }\n\n public resetLoaderContainerTracker(syncSummarizerClients: boolean = false) {\n this._loaderContainerTracker.reset();\n this._loaderContainerTracker = new LoaderContainerTracker(syncSummarizerClients);\n }\n}\n\nexport function getUnexpectedLogErrorException(logger: EventAndErrorTrackingLogger | undefined, prefix?: string) {\n if (logger === undefined) {\n return;\n }\n const results = logger.reportAndClearTrackedEvents();\n if (results.unexpectedErrors.length > 0) {\n return new Error(\n `${prefix ?? \"\"}Unexpected Errors in Logs:\\n${JSON.stringify(results.unexpectedErrors, undefined, 2)}`);\n }\n if (results.expectedNotFound.length > 0) {\n return new Error(\n `${prefix ?? \"\"}Expected Events not found:\\n${JSON.stringify(results.expectedNotFound, undefined, 2)}`);\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/test-utils",
3
- "version": "2.0.0-internal.1.1.1",
3
+ "version": "2.0.0-internal.1.2.0.93071",
4
4
  "description": "Utilities for Fluid tests",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -55,35 +55,35 @@
55
55
  "temp-directory": "nyc/.nyc_output"
56
56
  },
57
57
  "dependencies": {
58
- "@fluidframework/aqueduct": "^2.0.0-internal.1.1.1",
58
+ "@fluidframework/aqueduct": "2.0.0-internal.1.2.0.93071",
59
59
  "@fluidframework/common-definitions": "^0.20.1",
60
60
  "@fluidframework/common-utils": "^1.0.0",
61
- "@fluidframework/container-definitions": "^2.0.0-internal.1.1.1",
62
- "@fluidframework/container-loader": "^2.0.0-internal.1.1.1",
63
- "@fluidframework/container-runtime": "^2.0.0-internal.1.1.1",
64
- "@fluidframework/container-runtime-definitions": "^2.0.0-internal.1.1.1",
65
- "@fluidframework/core-interfaces": "^2.0.0-internal.1.1.1",
66
- "@fluidframework/datastore": "^2.0.0-internal.1.1.1",
67
- "@fluidframework/datastore-definitions": "^2.0.0-internal.1.1.1",
68
- "@fluidframework/driver-definitions": "^2.0.0-internal.1.1.1",
69
- "@fluidframework/driver-utils": "^2.0.0-internal.1.1.1",
70
- "@fluidframework/local-driver": "^2.0.0-internal.1.1.1",
71
- "@fluidframework/map": "^2.0.0-internal.1.1.1",
61
+ "@fluidframework/container-definitions": "2.0.0-internal.1.2.0.93071",
62
+ "@fluidframework/container-loader": "2.0.0-internal.1.2.0.93071",
63
+ "@fluidframework/container-runtime": "2.0.0-internal.1.2.0.93071",
64
+ "@fluidframework/container-runtime-definitions": "2.0.0-internal.1.2.0.93071",
65
+ "@fluidframework/core-interfaces": "2.0.0-internal.1.2.0.93071",
66
+ "@fluidframework/datastore": "2.0.0-internal.1.2.0.93071",
67
+ "@fluidframework/datastore-definitions": "2.0.0-internal.1.2.0.93071",
68
+ "@fluidframework/driver-definitions": "2.0.0-internal.1.2.0.93071",
69
+ "@fluidframework/driver-utils": "2.0.0-internal.1.2.0.93071",
70
+ "@fluidframework/local-driver": "2.0.0-internal.1.2.0.93071",
71
+ "@fluidframework/map": "2.0.0-internal.1.2.0.93071",
72
72
  "@fluidframework/protocol-definitions": "^1.0.0",
73
- "@fluidframework/request-handler": "^2.0.0-internal.1.1.1",
74
- "@fluidframework/routerlicious-driver": "^2.0.0-internal.1.1.1",
75
- "@fluidframework/runtime-definitions": "^2.0.0-internal.1.1.1",
76
- "@fluidframework/runtime-utils": "^2.0.0-internal.1.1.1",
77
- "@fluidframework/telemetry-utils": "^2.0.0-internal.1.1.1",
78
- "@fluidframework/test-driver-definitions": "^2.0.0-internal.1.1.1",
79
- "@fluidframework/test-runtime-utils": "^2.0.0-internal.1.1.1",
73
+ "@fluidframework/request-handler": "2.0.0-internal.1.2.0.93071",
74
+ "@fluidframework/routerlicious-driver": "2.0.0-internal.1.2.0.93071",
75
+ "@fluidframework/runtime-definitions": "2.0.0-internal.1.2.0.93071",
76
+ "@fluidframework/runtime-utils": "2.0.0-internal.1.2.0.93071",
77
+ "@fluidframework/telemetry-utils": "2.0.0-internal.1.2.0.93071",
78
+ "@fluidframework/test-driver-definitions": "2.0.0-internal.1.2.0.93071",
79
+ "@fluidframework/test-runtime-utils": "2.0.0-internal.1.2.0.93071",
80
80
  "best-random": "^1.0.0",
81
81
  "debug": "^4.1.1",
82
82
  "uuid": "^8.3.1"
83
83
  },
84
84
  "devDependencies": {
85
- "@fluidframework/build-common": "^0.24.0",
86
- "@fluidframework/build-tools": "^0.3.1000",
85
+ "@fluidframework/build-common": "^1.0.0",
86
+ "@fluidframework/build-tools": "^0.4.4000",
87
87
  "@fluidframework/eslint-config-fluid": "^0.28.2000",
88
88
  "@fluidframework/test-utils-previous": "npm:@fluidframework/test-utils@^1.0.0",
89
89
  "@microsoft/api-extractor": "^7.22.2",
@@ -2,17 +2,23 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
+ /* eslint-disable @typescript-eslint/strict-boolean-expressions */
5
6
 
6
7
  import { assert } from "@fluidframework/common-utils";
7
8
  import { IContainer, IDeltaQueue, IHostLoader } from "@fluidframework/container-definitions";
8
9
  import { Container } from "@fluidframework/container-loader";
10
+ import { canBeCoalescedByService } from "@fluidframework/driver-utils";
9
11
  import { IDocumentMessage, ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
10
12
  import { debug } from "./debug";
11
13
  import { IOpProcessingController } from "./testObjectProvider";
14
+ import { timeoutAwait, timeoutPromise } from "./timeoutUtils";
12
15
 
13
16
  const debugOp = debug.extend("ops");
14
17
  const debugWait = debug.extend("wait");
15
18
 
19
+ // set the maximum timeout value as 5 mins
20
+ const defaultMaxTimeout = 5 * 6000;
21
+
16
22
  interface ContainerRecord {
17
23
  // A short number for debug output
18
24
  index: number;
@@ -91,7 +97,7 @@ export class LoaderContainerTracker implements IOpProcessingController {
91
97
  private trackTrailingNoOps(container: IContainer, record: ContainerRecord) {
92
98
  container.deltaManager.outbound.on("op", (messages) => {
93
99
  for (const msg of messages) {
94
- if (msg.type === MessageType.NoOp) {
100
+ if (canBeCoalescedByService(msg)) {
95
101
  // Track the NoOp that was sent.
96
102
  if (record.trailingNoOps === 0) {
97
103
  // record the starting sequence number of the trailing no ops if we haven't been tracking yet.
@@ -107,7 +113,7 @@ export class LoaderContainerTracker implements IOpProcessingController {
107
113
 
108
114
  container.deltaManager.inbound.on("push", (message) => {
109
115
  // Received the no op back, update the record if we are tracking
110
- if (message.type === MessageType.NoOp
116
+ if (canBeCoalescedByService(message)
111
117
  && message.clientId === (container as Container).clientId
112
118
  && record.trailingNoOps !== 0
113
119
  && record.startTrailingNoOps <= message.clientSequenceNumber
@@ -147,6 +153,20 @@ export class LoaderContainerTracker implements IOpProcessingController {
147
153
  // REVIEW: do we need to unpatch the loaders?
148
154
  }
149
155
 
156
+ /**
157
+ * Ensure all tracked containers are synchronized
158
+ */
159
+ public async ensureSynchronized(...containers: IContainer[]) {
160
+ await this.processSynchronized(undefined, ...containers);
161
+ }
162
+
163
+ /**
164
+ * Ensure all tracked containers are synchronized with a time limit
165
+ */
166
+ public async ensureSynchronizedWithTimeout?(timeoutDuration: number | undefined, ...containers: IContainer[]) {
167
+ await this.processSynchronized(timeoutDuration, ...containers);
168
+ }
169
+
150
170
  /**
151
171
  * Make sure all the tracked containers are synchronized.
152
172
  * - No isDirty (non-readonly) containers
@@ -158,7 +178,8 @@ export class LoaderContainerTracker implements IOpProcessingController {
158
178
  * - this overlaps with !isDirty, but include task scheduler ops.
159
179
  * - Trailing NoOp is tracked and don't count as pending ops.
160
180
  */
161
- public async ensureSynchronized(...containers: IContainer[]) {
181
+ private async processSynchronized(timeoutDuration: number | undefined, ...containers: IContainer[]) {
182
+ const start = Date.now();
162
183
  const resumed = this.resumeProcessing(...containers);
163
184
 
164
185
  let waitingSequenceNumberSynchronized = false;
@@ -184,20 +205,34 @@ export class LoaderContainerTracker implements IOpProcessingController {
184
205
  // Only write it out once
185
206
  waitingSequenceNumberSynchronized = true;
186
207
  debugWait("Waiting for sequence number synchronized");
187
- await this.waitForAnyInboundOps(containersToApply);
208
+ await timeoutAwait(this.waitForAnyInboundOps(containersToApply), {
209
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
210
+ errorMsg: "Timeout on waiting for sequence number synchronized",
211
+ });
188
212
  }
189
213
  } else {
190
214
  waitingSequenceNumberSynchronized = false;
191
- await this.waitForPendingClients(pendingClients);
215
+ await timeoutAwait(this.waitForPendingClients(pendingClients), {
216
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
217
+ errorMsg: "Timeout on waiting for pending join or leave op",
218
+ });
192
219
  }
193
220
  } else {
194
221
  // Wait for all the containers to be saved
195
222
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
196
223
  debugWait(`Waiting container to be saved ${dirtyContainers.map((c) => this.containers.get(c)!.index)}`);
197
224
  waitingSequenceNumberSynchronized = false;
225
+ const remainedDuration = timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout;
198
226
  await Promise.all(dirtyContainers.map(async (c) => Promise.race(
199
- [new Promise((resolve) => c.once("saved", resolve)),
200
- new Promise((resolve) => c.once("closed", resolve))],
227
+ [timeoutPromise(
228
+ (resolve) => c.once("saved", () => resolve()),
229
+ {
230
+ durationMs: remainedDuration,
231
+ errorMsg: "Timeout on waiting a container to be saved",
232
+ },
233
+ ),
234
+ new Promise((resolve) => c.once("closed", resolve)),
235
+ ],
201
236
  )));
202
237
  }
203
238
 
@@ -208,7 +243,10 @@ export class LoaderContainerTracker implements IOpProcessingController {
208
243
  // Pause all container that was resumed
209
244
  // don't call pause if resumed is empty and pause everything, which is not what we want
210
245
  if (resumed.length !== 0) {
211
- await this.pauseProcessing(...resumed);
246
+ await timeoutAwait(this.pauseProcessing(...resumed), {
247
+ durationMs: timeoutDuration ? timeoutDuration - (Date.now() - start) : defaultMaxTimeout,
248
+ errorMsg: "Timeout on waiting for pausing all resumed containers",
249
+ });
212
250
  }
213
251
 
214
252
  debugWait("Synchronized");
@@ -454,13 +492,13 @@ export class LoaderContainerTracker implements IOpProcessingController {
454
492
  private setupInOutTracker(container: IContainer, inflightTracker: Map<IContainer, number>) {
455
493
  const outHandler = (messages: IDocumentMessage[]) => {
456
494
  for (const message of messages) {
457
- if (message.type !== MessageType.NoOp) {
495
+ if (!canBeCoalescedByService(message)) {
458
496
  inflightTracker.set(container, message.clientSequenceNumber);
459
497
  }
460
498
  }
461
499
  };
462
500
  const inHandler = (message: ISequencedDocumentMessage) => {
463
- if (message.type !== MessageType.NoOp
501
+ if (!canBeCoalescedByService(message)
464
502
  && message.clientId === (container as Container).clientId
465
503
  && inflightTracker.get(container) === message.clientSequenceNumber) {
466
504
  inflightTracker.delete(container);
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/test-utils";
9
- export const pkgVersion = "2.0.0-internal.1.1.1";
9
+ export const pkgVersion = "2.0.0-internal.1.2.0.93071";
@@ -66,7 +66,7 @@ export interface ITestObjectProvider {
66
66
  defaultCodeDetails: IFluidCodeDetails;
67
67
  opProcessingController: IOpProcessingController;
68
68
 
69
- ensureSynchronized(): Promise<void>;
69
+ ensureSynchronized(timeoutDuration?: number): Promise<void>;
70
70
  reset(): void;
71
71
 
72
72
  documentId: string;
@@ -393,8 +393,13 @@ export class TestObjectProvider implements ITestObjectProvider {
393
393
  this._documentCreated = false;
394
394
  }
395
395
 
396
- public async ensureSynchronized() {
397
- return this._loaderContainerTracker.ensureSynchronized();
396
+ public async ensureSynchronized(timeoutDuration?: number) {
397
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
398
+ if (!timeoutDuration) {
399
+ return this._loaderContainerTracker.ensureSynchronized();
400
+ } else {
401
+ return this._loaderContainerTracker.ensureSynchronizedWithTimeout?.(timeoutDuration);
402
+ }
398
403
  }
399
404
 
400
405
  public async waitContainerToCatchUp(container: IContainer) {