@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.
- package/dist/loaderContainerTracker.d.ts +9 -1
- package/dist/loaderContainerTracker.d.ts.map +1 -1
- package/dist/loaderContainerTracker.js +42 -10
- package/dist/loaderContainerTracker.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/testObjectProvider.d.ts +2 -2
- package/dist/testObjectProvider.d.ts.map +1 -1
- package/dist/testObjectProvider.js +9 -2
- package/dist/testObjectProvider.js.map +1 -1
- package/package.json +22 -22
- package/src/loaderContainerTracker.ts +48 -10
- package/src/packageVersion.ts +1 -1
- package/src/testObjectProvider.ts +8 -3
|
@@ -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
|
-
|
|
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;
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
-
|
|
176
|
-
|
|
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 (
|
|
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 (
|
|
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"]}
|
package/dist/packageVersion.d.ts
CHANGED
|
@@ -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.
|
|
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,
|
|
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"}
|
package/dist/packageVersion.js
CHANGED
|
@@ -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.
|
|
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,
|
|
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":"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,
|
|
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
|
-
|
|
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.
|
|
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": "
|
|
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": "
|
|
62
|
-
"@fluidframework/container-loader": "
|
|
63
|
-
"@fluidframework/container-runtime": "
|
|
64
|
-
"@fluidframework/container-runtime-definitions": "
|
|
65
|
-
"@fluidframework/core-interfaces": "
|
|
66
|
-
"@fluidframework/datastore": "
|
|
67
|
-
"@fluidframework/datastore-definitions": "
|
|
68
|
-
"@fluidframework/driver-definitions": "
|
|
69
|
-
"@fluidframework/driver-utils": "
|
|
70
|
-
"@fluidframework/local-driver": "
|
|
71
|
-
"@fluidframework/map": "
|
|
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": "
|
|
74
|
-
"@fluidframework/routerlicious-driver": "
|
|
75
|
-
"@fluidframework/runtime-definitions": "
|
|
76
|
-
"@fluidframework/runtime-utils": "
|
|
77
|
-
"@fluidframework/telemetry-utils": "
|
|
78
|
-
"@fluidframework/test-driver-definitions": "
|
|
79
|
-
"@fluidframework/test-runtime-utils": "
|
|
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.
|
|
86
|
-
"@fluidframework/build-tools": "^0.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
[
|
|
200
|
-
|
|
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
|
|
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
|
|
501
|
+
if (!canBeCoalescedByService(message)
|
|
464
502
|
&& message.clientId === (container as Container).clientId
|
|
465
503
|
&& inflightTracker.get(container) === message.clientSequenceNumber) {
|
|
466
504
|
inflightTracker.delete(container);
|
package/src/packageVersion.ts
CHANGED
|
@@ -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
|
-
|
|
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) {
|