@fluidframework/azure-end-to-end-tests 2.70.0-361788 → 2.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"orchestratorUtils.js","sourceRoot":"","sources":["../../../src/test/multiprocess/orchestratorUtils.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 { fork } from \"node:child_process\";\nimport type { ChildProcess as AnyChildProcess } from \"node:child_process\";\n\nimport { ScopeType } from \"@fluidframework/driver-definitions/legacy\";\nimport type { AttendeeId } from \"@fluidframework/presence/beta\";\nimport { timeoutAwait, timeoutPromise } from \"@fluidframework/test-utils/internal\";\n\nimport type {\n\tConnectCommand,\n\tMessageFromChild,\n\tLatestValueUpdatedEvent,\n\tLatestMapValueUpdatedEvent,\n\tLatestValueGetResponseEvent,\n\tLatestMapValueGetResponseEvent,\n\tMessageToChild,\n\tEventEntry,\n} from \"./messageTypes.js\";\n\n/**\n * Child process to console logging verbosity\n *\n * @remarks\n * Meaningful substrings:\n * - \"msgs\"\n * - \"telem\"\n *\n * @example \"msgs+telem\"\n */\nconst childLoggingVerbosity = process.env.FLUID_TEST_VERBOSE ?? \"none\";\n\n/**\n * Capture console./warn/error before test infrastructure alters it.\n */\nexport const testConsole = {\n\tlog: console.log,\n\twarn: console.warn,\n\terror: console.error,\n};\n\ninterface ChildProcess extends AnyChildProcess {\n\tsend(message: MessageToChild): boolean;\n}\n\n/**\n * Fork child processes to simulate multiple Fluid clients.\n *\n * @remarks\n * Individual child processes may be scheduled concurrently on a multi-core CPU\n * and separate processes will never share a port when connected to a service.\n *\n * @param numProcesses - The number of child processes to fork.\n * @param cleanUpAccumulator - An array to accumulate cleanup functions for each child.\n * @returns A collection of child processes and a promise that rejects on the first child error.\n */\nexport async function forkChildProcesses(\n\tnumProcesses: number,\n\tcleanUpAccumulator: (() => void)[],\n): Promise<{\n\tchildren: ChildProcess[];\n\t/**\n\t * Will never resolve successfully, it is only used to reject on child process error.\n\t */\n\tchildErrorPromise: Promise<never>;\n}> {\n\tconst children: ChildProcess[] = [];\n\tconst childReadyPromises: Promise<void>[] = [];\n\tconst childErrorPromises: Promise<never>[] = [];\n\tfor (let i = 0; i < numProcesses; i++) {\n\t\tconst child = fork(\"./lib/test/multiprocess/childClient.tool.js\", [\n\t\t\t`child ${i}` /* identifier passed to child process */,\n\t\t\tchildLoggingVerbosity /* console logging verbosity */,\n\t\t]);\n\t\tcleanUpAccumulator.push(() => {\n\t\t\tchild.kill();\n\t\t\tchild.removeAllListeners();\n\t\t});\n\t\tconst readyPromise = new Promise<void>((resolve, reject) => {\n\t\t\tchild.once(\"message\", (msg: MessageFromChild) => {\n\t\t\t\tif (msg.event === \"ack\") {\n\t\t\t\t\tresolve();\n\t\t\t\t} else {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(`Unexpected (non-\"ack\") message from child${i}: ${JSON.stringify(msg)}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tchildReadyPromises.push(readyPromise);\n\t\tconst errorPromise = new Promise<never>((_resolve, reject) => {\n\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\treject(new Error(`Child${i} process errored: ${error.message}`));\n\t\t\t});\n\t\t\tchild.once(\"exit\", (code, signal) => {\n\t\t\t\treject(new Error(`Child${i} process exited: code ${code}, signal ${signal}`));\n\t\t\t});\n\t\t});\n\t\tchildErrorPromises.push(errorPromise);\n\t\tchild.send({ command: \"ping\" });\n\t\tchildren.push(child);\n\t}\n\tconst childErrorPromise = Promise.race(childErrorPromises);\n\tawait Promise.race([Promise.all(childReadyPromises), childErrorPromise]);\n\treturn { children, childErrorPromise };\n}\n\n/**\n * Instructs all listed child processes to send debug reports and then the\n * collection is output sorted by timestamp. Report content is up to the child\n * processes, but typically includes messages sent and some telemetry events.\n */\nexport async function executeDebugReports(\n\tchildrenRequestedToReport: ChildProcess[],\n): Promise<void> {\n\tconst debugReportPromises: Promise<EventEntry[]>[] = [];\n\tfor (const child of childrenRequestedToReport) {\n\t\tconst debugReportPromise = new Promise<EventEntry[]>((resolve) => {\n\t\t\tconst handler = (msg: MessageFromChild): void => {\n\t\t\t\tif (msg.event === \"debugReportComplete\") {\n\t\t\t\t\tresolve(msg.log ?? []);\n\t\t\t\t\tchild.off(\"message\", handler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tchild.on(\"message\", handler);\n\t\t});\n\t\tdebugReportPromises.push(debugReportPromise);\n\t\tchild.send({ command: \"debugReport\", sendEventLog: true, reportAttendees: true });\n\t}\n\n\tconst logs = await Promise.all(debugReportPromises);\n\tconst combinedLogs = logs.flat().sort((a, b) => a.timestamp - b.timestamp);\n\tfor (const entry of combinedLogs) {\n\t\ttestConsole.log(\n\t\t\t`[${new Date(entry.timestamp).toISOString()}] [${entry.agentId}] [${entry.eventCategory}] ${entry.eventName}${\n\t\t\t\tentry.details\n\t\t\t\t\t? ` - ${typeof entry.details === \"string\" ? entry.details : JSON.stringify(entry.details)}`\n\t\t\t\t\t: \"\"\n\t\t\t}`,\n\t\t);\n\t}\n}\n\n/**\n * Creates a {@link ConnectCommand} for a test user with a deterministic id and name.\n *\n * @param id - Suffix used to construct stable test user identity.\n */\nfunction composeConnectMessage(\n\tid: string | number,\n\tscopes: ScopeType[] = [ScopeType.DocRead],\n): ConnectCommand {\n\treturn {\n\t\tcommand: \"connect\",\n\t\tuser: {\n\t\t\tid: `test-user-id-${id}`,\n\t\t\tname: `test-user-name-${id}`,\n\t\t},\n\t\tscopes,\n\t\tcreateScopes: [ScopeType.DocWrite, ScopeType.DocRead],\n\t};\n}\n\n/**\n * Listens for a \"connected\" response from a child process\n * allowing/handling subset of other expected messages.\n */\nfunction listenForConnectedResponse({\n\tchild,\n\tchildId,\n\tonConnected,\n\treject,\n}: {\n\tchild: ChildProcess;\n\tchildId: number | string;\n\t/**\n\t * Will be called up to once when a \"connected\" message is received.\n\t */\n\tonConnected: (msg: Extract<MessageFromChild, { event: \"connected\" }>) => void;\n\t/**\n\t * Callback to reject for unexpected messages or child errors.\n\t */\n\treject: (reason?: unknown) => void;\n}): void {\n\tconst listener = (msg: MessageFromChild): void => {\n\t\tif (msg.event === \"connected\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\tonConnected(msg);\n\t\t} else if (msg.event === \"error\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\treject(new Error(`Child ${childId} process error: ${msg.error}`));\n\t\t} else if (msg.event !== \"ack\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\t// This is not strictly required, but is current expectation.\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Unexpected message from child ${childId} while connecting: ${JSON.stringify(msg)}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t};\n\tchild.on(\"message\", listener);\n}\n\ninterface CreatorAttendeeIdAndAttendeePromises {\n\tcontainerCreatorAttendeeId: AttendeeId;\n\tattendeeIdPromises: Promise<AttendeeId>[];\n}\n\n/**\n * Sends connect commands to the provided child processes.\n *\n * The first child will create the container unless a containerId is pre-specified; subsequent\n * children are sent the discovered containerId.\n */\nexport async function connectChildProcesses(\n\tchildProcesses: ChildProcess[],\n\t{ writeClients, readyTimeoutMs }: { writeClients: number; readyTimeoutMs: number },\n): Promise<CreatorAttendeeIdAndAttendeePromises> {\n\tif (childProcesses.length === 0) {\n\t\tthrow new Error(\"No child processes provided for connection.\");\n\t}\n\tconst firstChild = childProcesses[0];\n\tconst containerReadyPromise = new Promise<{\n\t\tcontainerCreatorAttendeeId: AttendeeId;\n\t\tcontainerId: string;\n\t}>((resolve, reject) =>\n\t\tlistenForConnectedResponse({\n\t\t\tchild: firstChild,\n\t\t\tchildId: 0,\n\t\t\tonConnected: (msg) => {\n\t\t\t\tif (msg.containerId) {\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tcontainerCreatorAttendeeId: msg.attendeeId,\n\t\t\t\t\t\tcontainerId: msg.containerId,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`Child 0 (creator) connected without containerId: ${JSON.stringify(msg)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t\treject,\n\t\t}),\n\t);\n\t{\n\t\t// Note that DocWrite is used to have this attendee be the \"leader\".\n\t\t// DocRead would also be valid as DocWrite is specified for attach when there\n\t\t// is no document id (container id).\n\t\tconst connectContainerCreator = composeConnectMessage(\n\t\t\t0,\n\t\t\twriteClients > 0 ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],\n\t\t);\n\t\tfirstChild.send(connectContainerCreator);\n\t}\n\tconst { containerCreatorAttendeeId, containerId } = await timeoutAwait(\n\t\tcontainerReadyPromise,\n\t\t{\n\t\t\tdurationMs: readyTimeoutMs,\n\t\t\terrorMsg: \"did not receive 'connected' from child process\",\n\t\t},\n\t);\n\n\tconst attendeeIdPromises: Promise<AttendeeId>[] = [];\n\tfor (const [index, child] of childProcesses.entries()) {\n\t\tif (index === 0) {\n\t\t\tattendeeIdPromises.push(Promise.resolve(containerCreatorAttendeeId));\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = composeConnectMessage(\n\t\t\tindex,\n\t\t\tindex < writeClients ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],\n\t\t);\n\t\tmessage.containerId = containerId;\n\t\tattendeeIdPromises.push(\n\t\t\tnew Promise<AttendeeId>((resolve, reject) =>\n\t\t\t\tlistenForConnectedResponse({\n\t\t\t\t\tchild,\n\t\t\t\t\tchildId: index,\n\t\t\t\t\tonConnected: (msg) => {\n\t\t\t\t\t\tresolve(msg.attendeeId);\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tchild.send(message);\n\t}\n\treturn { containerCreatorAttendeeId, attendeeIdPromises };\n}\n\ninterface ConnectAndListenForAttendees extends CreatorAttendeeIdAndAttendeePromises {\n\tattendeeCountRequiredPromises: Promise<void>[];\n}\n\n/**\n * Connects the child processes and creates promises for the specified number of\n * attendees to connect.\n */\nexport async function connectAndListenForAttendees(\n\tchildren: ChildProcess[],\n\t{\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t}: {\n\t\t/**\n\t\t * The number of clients that should have write access.\n\t\t */\n\t\twriteClients: number;\n\t\t/**\n\t\t * The number of attendees that must connect.\n\t\t */\n\t\tattendeeCountRequired: number;\n\t\t/**\n\t\t * Timeout duration for child process connections.\n\t\t */\n\t\tchildConnectTimeoutMs: number;\n\t},\n): Promise<ConnectAndListenForAttendees> {\n\t// Setup\n\tconst attendeeCountRequiredPromises = children.map(\n\t\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\t\t(child) =>\n\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\tlet attendeesJoinedEvents = 0;\n\t\t\t\tconst listenForAttendees = (msg: MessageFromChild): void => {\n\t\t\t\t\tif (msg.event === \"attendeeConnected\") {\n\t\t\t\t\t\tattendeesJoinedEvents++;\n\t\t\t\t\t\tif (attendeesJoinedEvents >= attendeeCountRequired) {\n\t\t\t\t\t\t\tchild.off(\"message\", listenForAttendees);\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tchild.on(\"message\", listenForAttendees);\n\t\t\t}),\n\t);\n\n\t// Act - connect all child processes\n\tconst connectResult = await connectChildProcesses(children, {\n\t\twriteClients,\n\t\treadyTimeoutMs: childConnectTimeoutMs,\n\t});\n\n\tPromise.all(connectResult.attendeeIdPromises)\n\t\t.then(() => console.log(\"All attendees connected.\"))\n\t\t.catch((error) => {\n\t\t\ttestConsole.error(\"Error connecting children:\", error);\n\t\t});\n\n\treturn { ...connectResult, attendeeCountRequiredPromises };\n}\n\n/**\n * Connects the child processes and waits for the specified number of attendees to connect.\n *\n * @remarks\n * This function can be used directly as a test. Comments in the functionality describe the\n * breakdown of test blocks.\n */\nexport async function connectAndWaitForAttendees(\n\tchildren: ChildProcess[],\n\t{\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t\tallAttendeesJoinedTimeoutMs,\n\t}: {\n\t\t/**\n\t\t * The number of clients that should have write access.\n\t\t */\n\t\twriteClients: number;\n\t\t/**\n\t\t * The number of attendees that must connect.\n\t\t */\n\t\tattendeeCountRequired: number;\n\t\t/**\n\t\t * Timeout duration for child process connections.\n\t\t */\n\t\tchildConnectTimeoutMs: number;\n\t\t/**\n\t\t * Timeout duration for all required attendees to join.\n\t\t */\n\t\tallAttendeesJoinedTimeoutMs: number;\n\t},\n\tearlyExitPromise: Promise<never>,\n): Promise<{ containerCreatorAttendeeId: AttendeeId }> {\n\t// Setup and Act - connect all child processes\n\tconst connectAndListenResult = await connectAndListenForAttendees(children, {\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t});\n\n\tconst attendeeConnectedPromise = connectAndListenResult.attendeeCountRequiredPromises[0];\n\n\tawait timeoutAwait(Promise.race([attendeeConnectedPromise, earlyExitPromise]), {\n\t\tdurationMs: allAttendeesJoinedTimeoutMs,\n\t\terrorMsg: \"child 0 did not receive all 'attendeeConnected' events\",\n\t});\n\treturn connectAndListenResult;\n}\n\n/**\n * Registers a workspace (latest and/or latestMap) on all provided child processes and waits for acknowledgement.\n *\n * @remarks\n * The listener for the acknowledgement event is attached before sending the command to avoid a race where the\n * child responds faster than the parent attaches the handler.\n *\n * @param children - Child processes representing Fluid clients.\n * @param workspaceId - Logical (unprefixed) workspace id used in tests.\n * @param options - Which state types to register plus optional timeout.\n */\nexport async function registerWorkspaceOnChildren(\n\tchildren: ChildProcess[],\n\tworkspaceId: string,\n\toptions: { latest?: true; latestMap?: true; timeoutMs: number },\n): Promise<void> {\n\tconst { latest, latestMap, timeoutMs } = options;\n\tconst promises = children.map(async (child, index) => {\n\t\tconst ackPromise = waitForEvent(\n\t\t\tchild,\n\t\t\t\"workspaceRegistered\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Child ${index} did not acknowledge workspace registration ${workspaceId}`,\n\t\t\t},\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tmsg.event === \"workspaceRegistered\" && msg.workspaceId === workspaceId,\n\t\t);\n\t\tchild.send({\n\t\t\tcommand: \"registerWorkspace\",\n\t\t\tworkspaceId,\n\t\t\tlatest,\n\t\t\tlatestMap,\n\t\t});\n\t\tawait ackPromise;\n\t});\n\tawait Promise.all(promises);\n}\n\n// Basic command type guards\nfunction isLatestValueGetResponse(msg: MessageFromChild): msg is LatestValueGetResponseEvent {\n\treturn msg.event === \"latestValueGetResponse\";\n}\nfunction isLatestMapValueGetResponse(\n\tmsg: MessageFromChild,\n): msg is LatestMapValueGetResponseEvent {\n\treturn msg.event === \"latestMapValueGetResponse\";\n}\nfunction isLatestValueUpdated(msg: MessageFromChild): msg is LatestValueUpdatedEvent {\n\treturn msg.event === \"latestValueUpdated\";\n}\nfunction isLatestMapValueUpdated(msg: MessageFromChild): msg is LatestMapValueUpdatedEvent {\n\treturn msg.event === \"latestMapValueUpdated\";\n}\n\n/**\n * Waits for a single message of the specified event type from a child process.\n */\nexport async function waitForEvent(\n\tchild: ChildProcess,\n\teventType: MessageFromChild[\"event\"],\n\toptions: { timeoutMs: number; errorMsg?: string },\n\tpredicate?: (msg: MessageFromChild) => boolean,\n): Promise<MessageFromChild> {\n\tconst { timeoutMs, errorMsg = `did not receive '${eventType}' event` } = options;\n\n\tlet handler: ((msg: MessageFromChild) => void) | undefined;\n\n\tconst cleanup = (): void => {\n\t\tif (handler) {\n\t\t\tchild.off(\"message\", handler);\n\t\t\thandler = undefined;\n\t\t}\n\t};\n\n\treturn timeoutPromise<MessageFromChild>(\n\t\t(resolve) => {\n\t\t\thandler = (msg: MessageFromChild): void => {\n\t\t\t\tif (msg.event === eventType && (!predicate || predicate(msg))) {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tresolve(msg);\n\t\t\t\t}\n\t\t\t};\n\t\t\tchild.on(\"message\", handler);\n\t\t},\n\t\t{ durationMs: timeoutMs, errorMsg },\n\t).finally(cleanup);\n}\n\n/**\n * Waits for latest value updates for the provided workspace from all clients.\n *\n * @param clients - Child processes to wait for updates from\n * @param workspaceId - Workspace ID to filter updates\n * @param earlyExitPromise - Promise that rejects early on error\n * @param timeoutMs - Timeout in milliseconds\n * @param options - Optional filtering criteria with fromAttendeeId and expectedValue properties\n */\nexport async function waitForLatestValueUpdates(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n\toptions: { fromAttendeeId?: AttendeeId; expectedValue?: unknown } = {},\n): Promise<LatestValueUpdatedEvent[]> {\n\tconst { fromAttendeeId, expectedValue } = options;\n\n\tconst filterMsg = (msg: MessageFromChild): boolean => {\n\t\tif (!isLatestValueUpdated(msg) || msg.workspaceId !== workspaceId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (fromAttendeeId !== undefined && msg.attendeeId !== fromAttendeeId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (expectedValue !== undefined) {\n\t\t\treturn JSON.stringify(msg.value) === JSON.stringify(expectedValue);\n\t\t}\n\t\treturn true;\n\t};\n\tlet filterDescription = \"update\";\n\tif (fromAttendeeId) filterDescription += ` from attendee ${fromAttendeeId}`;\n\tif (expectedValue !== undefined)\n\t\tfilterDescription += ` with specific value ${JSON.stringify(expectedValue)}`;\n\tif (filterDescription === \"update\") filterDescription = \"any update\";\n\n\tconst updatePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestValueUpdated\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Client ${index} did not receive latest value ${filterDescription}`,\n\t\t\t},\n\t\t\tfilterMsg,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(updatePromises), earlyExitPromise]);\n\tconst latestValueUpdatedEvents: LatestValueUpdatedEvent[] = [];\n\tfor (const response of responses) {\n\t\tif (isLatestValueUpdated(response)) {\n\t\t\tlatestValueUpdatedEvents.push(response);\n\t\t} else {\n\t\t\tthrow new TypeError(`Expected LatestValueUpdated but got ${response.event}`);\n\t\t}\n\t}\n\treturn latestValueUpdatedEvents;\n}\n\n/**\n * Waits for latest map value updates (specific key) from all clients.\n *\n * @param clients - Child processes to wait for updates from\n * @param workspaceId - Workspace ID to filter updates\n * @param key - Map key to filter updates\n * @param earlyExitPromise - Promise that rejects early on error\n * @param timeoutMs - Timeout in milliseconds\n * @param options - Optional filtering criteria with fromAttendeeId and expectedValue properties\n */\nexport async function waitForLatestMapValueUpdates(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tkey: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n\toptions: { fromAttendeeId?: AttendeeId; expectedValue?: unknown } = {},\n): Promise<LatestMapValueUpdatedEvent[]> {\n\tconst { fromAttendeeId, expectedValue } = options;\n\n\tconst filterMsg = (msg: MessageFromChild): boolean => {\n\t\tif (!isLatestMapValueUpdated(msg) || msg.workspaceId !== workspaceId || msg.key !== key) {\n\t\t\treturn false;\n\t\t}\n\t\tif (fromAttendeeId !== undefined && msg.attendeeId !== fromAttendeeId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (expectedValue !== undefined) {\n\t\t\treturn JSON.stringify(msg.value) === JSON.stringify(expectedValue);\n\t\t}\n\t\treturn true;\n\t};\n\tlet filterDescription = `update for key \"${key}\"`;\n\tif (fromAttendeeId) filterDescription += ` from attendee ${fromAttendeeId}`;\n\tif (expectedValue !== undefined)\n\t\tfilterDescription += ` with specific value ${JSON.stringify(expectedValue)}`;\n\n\tconst updatePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestMapValueUpdated\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Client ${index} did not receive latest map value ${filterDescription}`,\n\t\t\t},\n\t\t\tfilterMsg,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(updatePromises), earlyExitPromise]);\n\tconst latestMapValueUpdatedEvents: LatestMapValueUpdatedEvent[] = [];\n\tfor (const response of responses) {\n\t\tif (isLatestMapValueUpdated(response)) {\n\t\t\tlatestMapValueUpdatedEvents.push(response);\n\t\t} else {\n\t\t\tthrow new TypeError(`Expected LatestMapValueUpdated but got ${response.event}`);\n\t\t}\n\t}\n\treturn latestMapValueUpdatedEvents;\n}\n\n/**\n * Collects latest value get response events from all clients.\n */\nexport async function getLatestValueResponses(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n): Promise<LatestValueGetResponseEvent[]> {\n\tconst responsePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestValueGetResponse\",\n\t\t\t{ timeoutMs, errorMsg: `Client ${index} did not respond with latest value` },\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tisLatestValueGetResponse(msg) && msg.workspaceId === workspaceId,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(responsePromises), earlyExitPromise]);\n\treturn responses.map((response) => {\n\t\tif (!isLatestValueGetResponse(response)) {\n\t\t\tthrow new TypeError(`Expected LatestValueGetResponse but got ${response.event}`);\n\t\t}\n\t\treturn response;\n\t});\n}\n\n/**\n * Collects latest map value get response events from all clients.\n */\nexport async function getLatestMapValueResponses(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tkey: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n): Promise<LatestMapValueGetResponseEvent[]> {\n\tconst responsePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestMapValueGetResponse\",\n\t\t\t{ timeoutMs, errorMsg: `Client ${index} did not respond with latest map value` },\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tisLatestMapValueGetResponse(msg) && msg.workspaceId === workspaceId && msg.key === key,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(responsePromises), earlyExitPromise]);\n\treturn responses.map((response) => {\n\t\tif (!isLatestMapValueGetResponse(response)) {\n\t\t\tthrow new TypeError(`Expected LatestMapValueGetResponse but got ${response.event}`);\n\t\t}\n\t\treturn response;\n\t});\n}\n"]}
1
+ {"version":3,"file":"orchestratorUtils.js","sourceRoot":"","sources":["../../../src/test/multiprocess/orchestratorUtils.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 { fork } from \"node:child_process\";\nimport type { ChildProcess as AnyChildProcess } from \"node:child_process\";\n\nimport { ScopeType } from \"@fluidframework/driver-definitions/legacy\";\nimport type { AttendeeId } from \"@fluidframework/presence/beta\";\nimport { timeoutAwait, timeoutPromise } from \"@fluidframework/test-utils/internal\";\n\nimport type {\n\tConnectCommand,\n\tMessageFromChild,\n\tLatestValueUpdatedEvent,\n\tLatestMapValueUpdatedEvent,\n\tLatestValueGetResponseEvent,\n\tLatestMapValueGetResponseEvent,\n\tMessageToChild,\n\tEventEntry,\n} from \"./messageTypes.js\";\n\n/**\n * Child process to console logging verbosity\n *\n * @remarks\n * Meaningful substrings:\n * - \"msgs\"\n * - \"telem\"\n *\n * @example \"msgs+telem\"\n */\nconst childLoggingVerbosity = process.env.FLUID_TEST_VERBOSE ?? \"none\";\n\n/**\n * Capture console./warn/error before test infrastructure alters it.\n */\nexport const testConsole = {\n\tlog: console.log,\n\twarn: console.warn,\n\terror: console.error,\n};\n\ninterface ChildProcess extends AnyChildProcess {\n\tsend(message: MessageToChild): boolean;\n}\n\n/**\n * Fork child processes to simulate multiple Fluid clients.\n *\n * @remarks\n * Individual child processes may be scheduled concurrently on a multi-core CPU\n * and separate processes will never share a port when connected to a service.\n *\n * @param numProcesses - The number of child processes to fork.\n * @param cleanUpAccumulator - An array to accumulate cleanup functions for each child.\n * @returns A collection of child processes and a promise that rejects on the first child error.\n */\nexport async function forkChildProcesses(\n\ttestLabel: string,\n\tnumProcesses: number,\n\tcleanUpAccumulator: (() => void)[],\n): Promise<{\n\tchildren: ChildProcess[];\n\t/**\n\t * Will never resolve successfully, it is only used to reject on child process error.\n\t */\n\tchildErrorPromise: Promise<never>;\n}> {\n\tconst children: ChildProcess[] = [];\n\tconst childReadyPromises: Promise<void>[] = [];\n\tconst childErrorPromises: Promise<never>[] = [];\n\tfor (let i = 0; i < numProcesses; i++) {\n\t\tconst child = fork(\"./lib/test/multiprocess/childClient.tool.js\", [\n\t\t\ttestLabel,\n\t\t\t`child ${i}` /* identifier passed to child process */,\n\t\t\tchildLoggingVerbosity /* console logging verbosity */,\n\t\t]);\n\t\tcleanUpAccumulator.push(() => {\n\t\t\tchild.kill();\n\t\t\tchild.removeAllListeners();\n\t\t});\n\t\tconst readyPromise = new Promise<void>((resolve, reject) => {\n\t\t\tchild.once(\"message\", (msg: MessageFromChild) => {\n\t\t\t\tif (msg.event === \"ack\") {\n\t\t\t\t\tresolve();\n\t\t\t\t} else {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(`Unexpected (non-\"ack\") message from child${i}: ${JSON.stringify(msg)}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tchildReadyPromises.push(readyPromise);\n\t\tconst errorPromise = new Promise<never>((_resolve, reject) => {\n\t\t\tchild.once(\"error\", (error) => {\n\t\t\t\treject(new Error(`Child${i} process errored: ${error.message}`));\n\t\t\t});\n\t\t\tchild.once(\"exit\", (code, signal) => {\n\t\t\t\treject(new Error(`Child${i} process exited: code ${code}, signal ${signal}`));\n\t\t\t});\n\t\t});\n\t\tchildErrorPromises.push(errorPromise);\n\t\tchild.send({ command: \"ping\" });\n\t\tchildren.push(child);\n\t}\n\tconst childErrorPromise = Promise.race(childErrorPromises);\n\tawait Promise.race([Promise.all(childReadyPromises), childErrorPromise]);\n\treturn { children, childErrorPromise };\n}\n\n/**\n * Instructs all listed child processes to send debug reports and then the\n * collection is output sorted by timestamp. Report content is up to the child\n * processes, but typically includes messages sent and some telemetry events.\n */\nexport async function executeDebugReports(\n\tchildrenRequestedToReport: ChildProcess[],\n): Promise<void> {\n\tconst debugReportPromises: Promise<EventEntry[]>[] = [];\n\tfor (const child of childrenRequestedToReport) {\n\t\tconst debugReportPromise = new Promise<EventEntry[]>((resolve) => {\n\t\t\tconst handler = (msg: MessageFromChild): void => {\n\t\t\t\tif (msg.event === \"debugReportComplete\") {\n\t\t\t\t\tresolve(msg.log ?? []);\n\t\t\t\t\tchild.off(\"message\", handler);\n\t\t\t\t}\n\t\t\t};\n\t\t\tchild.on(\"message\", handler);\n\t\t});\n\t\tdebugReportPromises.push(debugReportPromise);\n\t\tchild.send({ command: \"debugReport\", sendEventLog: true, reportAttendees: true });\n\t}\n\n\tconst logs = await Promise.all(debugReportPromises);\n\tconst combinedLogs = logs.flat().sort((a, b) => a.timestamp - b.timestamp);\n\tfor (const entry of combinedLogs) {\n\t\ttestConsole.log(\n\t\t\t`[${new Date(entry.timestamp).toISOString()}] [${entry.agentId}] [${entry.eventCategory}] ${entry.eventName}${\n\t\t\t\tentry.details\n\t\t\t\t\t? ` - ${typeof entry.details === \"string\" ? entry.details : JSON.stringify(entry.details)}`\n\t\t\t\t\t: \"\"\n\t\t\t}`,\n\t\t);\n\t}\n}\n\n/**\n * Creates a {@link ConnectCommand} for a test user with a deterministic id and name.\n *\n * @param id - Suffix used to construct stable test user identity.\n */\nfunction composeConnectMessage(\n\tid: string | number,\n\tscopes: ScopeType[] = [ScopeType.DocRead],\n\tconnectTimeoutMs: number,\n): ConnectCommand {\n\treturn {\n\t\tcommand: \"connect\",\n\t\tuser: {\n\t\t\tid: `test-user-id-${id}`,\n\t\t\tname: `test-user-name-${id}`,\n\t\t},\n\t\tscopes,\n\t\tcreateScopes: [ScopeType.DocWrite, ScopeType.DocRead],\n\t\tconnectTimeoutMs,\n\t};\n}\n\n/**\n * Listens for a \"connected\" response from a child process\n * allowing/handling subset of other expected messages.\n */\nfunction listenForConnectedResponse({\n\tchild,\n\tchildId,\n\tonConnected,\n\treject,\n}: {\n\tchild: ChildProcess;\n\tchildId: number | string;\n\t/**\n\t * Will be called up to once when a \"connected\" message is received.\n\t */\n\tonConnected: (msg: Extract<MessageFromChild, { event: \"connected\" }>) => void;\n\t/**\n\t * Callback to reject for unexpected messages or child errors.\n\t */\n\treject: (reason?: unknown) => void;\n}): void {\n\tconst listener = (msg: MessageFromChild): void => {\n\t\tif (msg.event === \"connected\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\tonConnected(msg);\n\t\t} else if (msg.event === \"error\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\treject(new Error(`Child ${childId} process error: ${msg.error}`));\n\t\t} else if (msg.event !== \"ack\") {\n\t\t\tchild.off(\"message\", listener);\n\t\t\t// This is not strictly required, but is current expectation.\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Unexpected message from child ${childId} while connecting: ${JSON.stringify(msg)}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t};\n\tchild.on(\"message\", listener);\n}\n\ninterface CreatorAttendeeIdAndAttendeePromises {\n\tcontainerCreatorAttendeeId: AttendeeId;\n\tattendeeIdPromises: Promise<AttendeeId>[];\n}\n\n/**\n * Sends connect commands to the provided child processes.\n *\n * The first child will create the container unless a containerId is pre-specified; subsequent\n * children are sent the discovered containerId.\n */\nexport async function connectChildProcesses(\n\tchildProcesses: ChildProcess[],\n\t{ writeClients, readyTimeoutMs }: { writeClients: number; readyTimeoutMs: number },\n): Promise<CreatorAttendeeIdAndAttendeePromises> {\n\tif (childProcesses.length === 0) {\n\t\tthrow new Error(\"No child processes provided for connection.\");\n\t}\n\tconst firstChild = childProcesses[0];\n\tconst containerReadyPromise = new Promise<{\n\t\tcontainerCreatorAttendeeId: AttendeeId;\n\t\tcontainerId: string;\n\t}>((resolve, reject) =>\n\t\tlistenForConnectedResponse({\n\t\t\tchild: firstChild,\n\t\t\tchildId: 0,\n\t\t\tonConnected: (msg) => {\n\t\t\t\tif (msg.containerId) {\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tcontainerCreatorAttendeeId: msg.attendeeId,\n\t\t\t\t\t\tcontainerId: msg.containerId,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\treject(\n\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t`Child 0 (creator) connected without containerId: ${JSON.stringify(msg)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t\treject,\n\t\t}),\n\t);\n\t{\n\t\t// Note that DocWrite is used to have this attendee be the \"leader\".\n\t\t// DocRead would also be valid as DocWrite is specified for attach when there\n\t\t// is no document id (container id).\n\t\tconst connectContainerCreator = composeConnectMessage(\n\t\t\t0,\n\t\t\twriteClients > 0 ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],\n\t\t\t/* connectTimeoutMs */ readyTimeoutMs,\n\t\t);\n\t\tfirstChild.send(connectContainerCreator);\n\t}\n\tconst { containerCreatorAttendeeId, containerId } = await timeoutAwait(\n\t\tcontainerReadyPromise,\n\t\t{\n\t\t\tdurationMs: readyTimeoutMs,\n\t\t\terrorMsg: \"did not receive 'connected' from child process\",\n\t\t},\n\t).catch(async (error) => {\n\t\tawait executeDebugReports([firstChild]);\n\t\tthrow error;\n\t});\n\n\tconst attendeeIdPromises: Promise<AttendeeId>[] = [];\n\tfor (const [index, child] of childProcesses.entries()) {\n\t\tif (index === 0) {\n\t\t\tattendeeIdPromises.push(Promise.resolve(containerCreatorAttendeeId));\n\t\t\tcontinue;\n\t\t}\n\t\tconst message = composeConnectMessage(\n\t\t\tindex,\n\t\t\tindex < writeClients ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],\n\t\t\t/* connectTimeoutMs */ readyTimeoutMs,\n\t\t);\n\t\tmessage.containerId = containerId;\n\t\tattendeeIdPromises.push(\n\t\t\tnew Promise<AttendeeId>((resolve, reject) =>\n\t\t\t\tlistenForConnectedResponse({\n\t\t\t\t\tchild,\n\t\t\t\t\tchildId: index,\n\t\t\t\t\tonConnected: (msg) => {\n\t\t\t\t\t\tresolve(msg.attendeeId);\n\t\t\t\t\t},\n\t\t\t\t\treject,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\t\tchild.send(message);\n\t}\n\treturn { containerCreatorAttendeeId, attendeeIdPromises };\n}\n\ninterface ConnectAndListenForAttendees extends CreatorAttendeeIdAndAttendeePromises {\n\tattendeeCountRequiredPromises: Promise<void>[];\n}\n\n/**\n * Connects the child processes and creates promises for the specified number of\n * attendees to connect.\n */\nexport async function connectAndListenForAttendees(\n\tchildren: ChildProcess[],\n\t{\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t}: {\n\t\t/**\n\t\t * The number of clients that should have write access.\n\t\t */\n\t\twriteClients: number;\n\t\t/**\n\t\t * The number of attendees that must connect.\n\t\t */\n\t\tattendeeCountRequired: number;\n\t\t/**\n\t\t * Timeout duration for child process connections.\n\t\t */\n\t\tchildConnectTimeoutMs: number;\n\t},\n): Promise<ConnectAndListenForAttendees> {\n\t// Setup\n\tconst attendeeCountRequiredPromises = children.map(\n\t\t// eslint-disable-next-line @typescript-eslint/promise-function-async\n\t\t(child) =>\n\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\tlet attendeesJoinedEvents = 0;\n\t\t\t\tconst listenForAttendees = (msg: MessageFromChild): void => {\n\t\t\t\t\tif (msg.event === \"attendeeConnected\") {\n\t\t\t\t\t\tattendeesJoinedEvents++;\n\t\t\t\t\t\tif (attendeesJoinedEvents >= attendeeCountRequired) {\n\t\t\t\t\t\t\tchild.off(\"message\", listenForAttendees);\n\t\t\t\t\t\t\tresolve();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tchild.on(\"message\", listenForAttendees);\n\t\t\t}),\n\t);\n\n\t// Act - connect all child processes\n\tconst connectResult = await connectChildProcesses(children, {\n\t\twriteClients,\n\t\treadyTimeoutMs: childConnectTimeoutMs,\n\t});\n\n\t// These actions are not awaited. They are here to provide additional logging.\n\t// It is up to the caller to await attendeeIdPromises if desired. This can mean\n\t// An \"error\" message is output, but the caller does not care about attendee\n\t// ids and proceeds.\n\tPromise.all(connectResult.attendeeIdPromises)\n\t\t.then(() => console.log(\"All attendees connected.\"))\n\t\t.catch((error) => {\n\t\t\ttestConsole.error(\"Error connecting children:\", error);\n\t\t});\n\n\treturn { ...connectResult, attendeeCountRequiredPromises };\n}\n\n/**\n * Connects the child processes and waits for the specified number of attendees to connect.\n *\n * @remarks\n * This function can be used directly as a test. Comments in the functionality describe the\n * breakdown of test blocks.\n */\nexport async function connectAndWaitForAttendees(\n\tchildren: ChildProcess[],\n\t{\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t\tallAttendeesJoinedTimeoutMs,\n\t}: {\n\t\t/**\n\t\t * The number of clients that should have write access.\n\t\t */\n\t\twriteClients: number;\n\t\t/**\n\t\t * The number of attendees that must connect.\n\t\t */\n\t\tattendeeCountRequired: number;\n\t\t/**\n\t\t * Timeout duration for child process connections.\n\t\t */\n\t\tchildConnectTimeoutMs: number;\n\t\t/**\n\t\t * Timeout duration for all required attendees to join.\n\t\t */\n\t\tallAttendeesJoinedTimeoutMs: number;\n\t},\n\tearlyExitPromise: Promise<never>,\n): Promise<{ containerCreatorAttendeeId: AttendeeId }> {\n\t// Setup and Act - connect all child processes\n\tconst connectAndListenResult = await connectAndListenForAttendees(children, {\n\t\twriteClients,\n\t\tattendeeCountRequired,\n\t\tchildConnectTimeoutMs,\n\t});\n\n\tconst attendeeConnectedPromise = connectAndListenResult.attendeeCountRequiredPromises[0];\n\n\tawait timeoutAwait(Promise.race([attendeeConnectedPromise, earlyExitPromise]), {\n\t\tdurationMs: allAttendeesJoinedTimeoutMs,\n\t\terrorMsg: \"child 0 did not receive all 'attendeeConnected' events\",\n\t});\n\treturn connectAndListenResult;\n}\n\n/**\n * Registers a workspace (latest and/or latestMap) on all provided child processes and waits for acknowledgement.\n *\n * @remarks\n * The listener for the acknowledgement event is attached before sending the command to avoid a race where the\n * child responds faster than the parent attaches the handler.\n *\n * @param children - Child processes representing Fluid clients.\n * @param workspaceId - Logical (unprefixed) workspace id used in tests.\n * @param options - Which state types to register plus optional timeout.\n */\nexport async function registerWorkspaceOnChildren(\n\tchildren: ChildProcess[],\n\tworkspaceId: string,\n\toptions: { latest?: true; latestMap?: true; timeoutMs: number },\n): Promise<void> {\n\tconst { latest, latestMap, timeoutMs } = options;\n\tconst promises = children.map(async (child, index) => {\n\t\tconst ackPromise = waitForEvent(\n\t\t\tchild,\n\t\t\t\"workspaceRegistered\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Child ${index} did not acknowledge workspace registration ${workspaceId}`,\n\t\t\t},\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tmsg.event === \"workspaceRegistered\" && msg.workspaceId === workspaceId,\n\t\t);\n\t\tchild.send({\n\t\t\tcommand: \"registerWorkspace\",\n\t\t\tworkspaceId,\n\t\t\tlatest,\n\t\t\tlatestMap,\n\t\t});\n\t\tawait ackPromise;\n\t});\n\tawait Promise.all(promises);\n}\n\n// Basic command type guards\nfunction isLatestValueGetResponse(msg: MessageFromChild): msg is LatestValueGetResponseEvent {\n\treturn msg.event === \"latestValueGetResponse\";\n}\nfunction isLatestMapValueGetResponse(\n\tmsg: MessageFromChild,\n): msg is LatestMapValueGetResponseEvent {\n\treturn msg.event === \"latestMapValueGetResponse\";\n}\nfunction isLatestValueUpdated(msg: MessageFromChild): msg is LatestValueUpdatedEvent {\n\treturn msg.event === \"latestValueUpdated\";\n}\nfunction isLatestMapValueUpdated(msg: MessageFromChild): msg is LatestMapValueUpdatedEvent {\n\treturn msg.event === \"latestMapValueUpdated\";\n}\n\n/**\n * Waits for a single message of the specified event type from a child process.\n */\nexport async function waitForEvent(\n\tchild: ChildProcess,\n\teventType: MessageFromChild[\"event\"],\n\toptions: { timeoutMs: number; errorMsg?: string },\n\tpredicate?: (msg: MessageFromChild) => boolean,\n): Promise<MessageFromChild> {\n\tconst { timeoutMs, errorMsg = `did not receive '${eventType}' event` } = options;\n\n\tlet handler: ((msg: MessageFromChild) => void) | undefined;\n\n\tconst cleanup = (): void => {\n\t\tif (handler) {\n\t\t\tchild.off(\"message\", handler);\n\t\t\thandler = undefined;\n\t\t}\n\t};\n\n\treturn timeoutPromise<MessageFromChild>(\n\t\t(resolve) => {\n\t\t\thandler = (msg: MessageFromChild): void => {\n\t\t\t\tif (msg.event === eventType && (!predicate || predicate(msg))) {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tresolve(msg);\n\t\t\t\t}\n\t\t\t};\n\t\t\tchild.on(\"message\", handler);\n\t\t},\n\t\t{ durationMs: timeoutMs, errorMsg },\n\t).finally(cleanup);\n}\n\n/**\n * Waits for latest value updates for the provided workspace from all clients.\n *\n * @param clients - Child processes to wait for updates from\n * @param workspaceId - Workspace ID to filter updates\n * @param earlyExitPromise - Promise that rejects early on error\n * @param timeoutMs - Timeout in milliseconds\n * @param options - Optional filtering criteria with fromAttendeeId and expectedValue properties\n */\nexport async function waitForLatestValueUpdates(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n\toptions: { fromAttendeeId?: AttendeeId; expectedValue?: unknown } = {},\n): Promise<LatestValueUpdatedEvent[]> {\n\tconst { fromAttendeeId, expectedValue } = options;\n\n\tconst filterMsg = (msg: MessageFromChild): boolean => {\n\t\tif (!isLatestValueUpdated(msg) || msg.workspaceId !== workspaceId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (fromAttendeeId !== undefined && msg.attendeeId !== fromAttendeeId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (expectedValue !== undefined) {\n\t\t\treturn JSON.stringify(msg.value) === JSON.stringify(expectedValue);\n\t\t}\n\t\treturn true;\n\t};\n\tlet filterDescription = \"update\";\n\tif (fromAttendeeId) filterDescription += ` from attendee ${fromAttendeeId}`;\n\tif (expectedValue !== undefined)\n\t\tfilterDescription += ` with specific value ${JSON.stringify(expectedValue)}`;\n\tif (filterDescription === \"update\") filterDescription = \"any update\";\n\n\tconst updatePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestValueUpdated\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Client ${index} did not receive latest value ${filterDescription}`,\n\t\t\t},\n\t\t\tfilterMsg,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(updatePromises), earlyExitPromise]);\n\tconst latestValueUpdatedEvents: LatestValueUpdatedEvent[] = [];\n\tfor (const response of responses) {\n\t\tif (isLatestValueUpdated(response)) {\n\t\t\tlatestValueUpdatedEvents.push(response);\n\t\t} else {\n\t\t\tthrow new TypeError(`Expected LatestValueUpdated but got ${response.event}`);\n\t\t}\n\t}\n\treturn latestValueUpdatedEvents;\n}\n\n/**\n * Waits for latest map value updates (specific key) from all clients.\n *\n * @param clients - Child processes to wait for updates from\n * @param workspaceId - Workspace ID to filter updates\n * @param key - Map key to filter updates\n * @param earlyExitPromise - Promise that rejects early on error\n * @param timeoutMs - Timeout in milliseconds\n * @param options - Optional filtering criteria with fromAttendeeId and expectedValue properties\n */\nexport async function waitForLatestMapValueUpdates(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tkey: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n\toptions: { fromAttendeeId?: AttendeeId; expectedValue?: unknown } = {},\n): Promise<LatestMapValueUpdatedEvent[]> {\n\tconst { fromAttendeeId, expectedValue } = options;\n\n\tconst filterMsg = (msg: MessageFromChild): boolean => {\n\t\tif (!isLatestMapValueUpdated(msg) || msg.workspaceId !== workspaceId || msg.key !== key) {\n\t\t\treturn false;\n\t\t}\n\t\tif (fromAttendeeId !== undefined && msg.attendeeId !== fromAttendeeId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (expectedValue !== undefined) {\n\t\t\treturn JSON.stringify(msg.value) === JSON.stringify(expectedValue);\n\t\t}\n\t\treturn true;\n\t};\n\tlet filterDescription = `update for key \"${key}\"`;\n\tif (fromAttendeeId) filterDescription += ` from attendee ${fromAttendeeId}`;\n\tif (expectedValue !== undefined)\n\t\tfilterDescription += ` with specific value ${JSON.stringify(expectedValue)}`;\n\n\tconst updatePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestMapValueUpdated\",\n\t\t\t{\n\t\t\t\ttimeoutMs,\n\t\t\t\terrorMsg: `Client ${index} did not receive latest map value ${filterDescription}`,\n\t\t\t},\n\t\t\tfilterMsg,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(updatePromises), earlyExitPromise]);\n\tconst latestMapValueUpdatedEvents: LatestMapValueUpdatedEvent[] = [];\n\tfor (const response of responses) {\n\t\tif (isLatestMapValueUpdated(response)) {\n\t\t\tlatestMapValueUpdatedEvents.push(response);\n\t\t} else {\n\t\t\tthrow new TypeError(`Expected LatestMapValueUpdated but got ${response.event}`);\n\t\t}\n\t}\n\treturn latestMapValueUpdatedEvents;\n}\n\n/**\n * Collects latest value get response events from all clients.\n */\nexport async function getLatestValueResponses(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n): Promise<LatestValueGetResponseEvent[]> {\n\tconst responsePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestValueGetResponse\",\n\t\t\t{ timeoutMs, errorMsg: `Client ${index} did not respond with latest value` },\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tisLatestValueGetResponse(msg) && msg.workspaceId === workspaceId,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(responsePromises), earlyExitPromise]);\n\treturn responses.map((response) => {\n\t\tif (!isLatestValueGetResponse(response)) {\n\t\t\tthrow new TypeError(`Expected LatestValueGetResponse but got ${response.event}`);\n\t\t}\n\t\treturn response;\n\t});\n}\n\n/**\n * Collects latest map value get response events from all clients.\n */\nexport async function getLatestMapValueResponses(\n\tclients: ChildProcess[],\n\tworkspaceId: string,\n\tkey: string,\n\tearlyExitPromise: Promise<never>,\n\ttimeoutMs: number,\n): Promise<LatestMapValueGetResponseEvent[]> {\n\tconst responsePromises = clients.map(async (child, index) =>\n\t\twaitForEvent(\n\t\t\tchild,\n\t\t\t\"latestMapValueGetResponse\",\n\t\t\t{ timeoutMs, errorMsg: `Client ${index} did not respond with latest map value` },\n\t\t\t(msg: MessageFromChild) =>\n\t\t\t\tisLatestMapValueGetResponse(msg) && msg.workspaceId === workspaceId && msg.key === key,\n\t\t),\n\t);\n\tconst responses = await Promise.race([Promise.all(responsePromises), earlyExitPromise]);\n\treturn responses.map((response) => {\n\t\tif (!isLatestMapValueGetResponse(response)) {\n\t\t\tthrow new TypeError(`Expected LatestMapValueGetResponse but got ${response.event}`);\n\t\t}\n\t\treturn response;\n\t});\n}\n"]}