@fluidframework/azure-end-to-end-tests 2.60.0 → 2.61.0-355516
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/lib/test/multiprocess/{childClient.js → childClient.tool.js} +24 -7
- package/lib/test/multiprocess/childClient.tool.js.map +1 -0
- package/lib/test/multiprocess/orchestratorUtils.js +35 -16
- package/lib/test/multiprocess/orchestratorUtils.js.map +1 -1
- package/lib/test/multiprocess/presenceTest.spec.js +214 -177
- package/lib/test/multiprocess/presenceTest.spec.js.map +1 -1
- package/package.json +26 -26
- package/src/test/.mocharc.cjs +0 -1
- package/src/test/multiprocess/{childClient.ts → childClient.tool.ts} +27 -6
- package/src/test/multiprocess/orchestratorUtils.ts +102 -31
- package/src/test/multiprocess/presenceTest.spec.ts +313 -265
- package/lib/test/multiprocess/childClient.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/azure-end-to-end-tests",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.61.0-355516",
|
|
4
4
|
"description": "Azure client end to end tests",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -33,29 +33,29 @@
|
|
|
33
33
|
"temp-directory": "nyc/.nyc_output"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@fluid-experimental/data-objects": "
|
|
37
|
-
"@fluid-internal/client-utils": "
|
|
38
|
-
"@fluid-internal/mocha-test-setup": "
|
|
39
|
-
"@fluid-private/test-version-utils": "
|
|
40
|
-
"@fluidframework/aqueduct": "
|
|
41
|
-
"@fluidframework/azure-client": "
|
|
36
|
+
"@fluid-experimental/data-objects": "2.61.0-355516",
|
|
37
|
+
"@fluid-internal/client-utils": "2.61.0-355516",
|
|
38
|
+
"@fluid-internal/mocha-test-setup": "2.61.0-355516",
|
|
39
|
+
"@fluid-private/test-version-utils": "2.61.0-355516",
|
|
40
|
+
"@fluidframework/aqueduct": "2.61.0-355516",
|
|
41
|
+
"@fluidframework/azure-client": "2.61.0-355516",
|
|
42
42
|
"@fluidframework/azure-client-legacy": "npm:@fluidframework/azure-client@^1.2.0",
|
|
43
|
-
"@fluidframework/container-definitions": "
|
|
44
|
-
"@fluidframework/container-loader": "
|
|
45
|
-
"@fluidframework/core-interfaces": "
|
|
46
|
-
"@fluidframework/counter": "
|
|
47
|
-
"@fluidframework/datastore-definitions": "
|
|
48
|
-
"@fluidframework/fluid-static": "
|
|
49
|
-
"@fluidframework/map": "
|
|
43
|
+
"@fluidframework/container-definitions": "2.61.0-355516",
|
|
44
|
+
"@fluidframework/container-loader": "2.61.0-355516",
|
|
45
|
+
"@fluidframework/core-interfaces": "2.61.0-355516",
|
|
46
|
+
"@fluidframework/counter": "2.61.0-355516",
|
|
47
|
+
"@fluidframework/datastore-definitions": "2.61.0-355516",
|
|
48
|
+
"@fluidframework/fluid-static": "2.61.0-355516",
|
|
49
|
+
"@fluidframework/map": "2.61.0-355516",
|
|
50
50
|
"@fluidframework/map-legacy": "npm:@fluidframework/map@^1.4.0",
|
|
51
|
-
"@fluidframework/matrix": "
|
|
52
|
-
"@fluidframework/presence": "
|
|
53
|
-
"@fluidframework/runtime-definitions": "
|
|
54
|
-
"@fluidframework/sequence": "
|
|
55
|
-
"@fluidframework/telemetry-utils": "
|
|
56
|
-
"@fluidframework/test-runtime-utils": "
|
|
57
|
-
"@fluidframework/test-utils": "
|
|
58
|
-
"@fluidframework/tree": "
|
|
51
|
+
"@fluidframework/matrix": "2.61.0-355516",
|
|
52
|
+
"@fluidframework/presence": "2.61.0-355516",
|
|
53
|
+
"@fluidframework/runtime-definitions": "2.61.0-355516",
|
|
54
|
+
"@fluidframework/sequence": "2.61.0-355516",
|
|
55
|
+
"@fluidframework/telemetry-utils": "2.61.0-355516",
|
|
56
|
+
"@fluidframework/test-runtime-utils": "2.61.0-355516",
|
|
57
|
+
"@fluidframework/test-utils": "2.61.0-355516",
|
|
58
|
+
"@fluidframework/tree": "2.61.0-355516",
|
|
59
59
|
"axios": "^1.8.4",
|
|
60
60
|
"cross-env": "^7.0.3",
|
|
61
61
|
"mocha": "^10.8.2",
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@biomejs/biome": "~1.9.3",
|
|
70
70
|
"@fluidframework/build-common": "^2.0.3",
|
|
71
|
-
"@fluidframework/build-tools": "^0.
|
|
72
|
-
"@fluidframework/driver-definitions": "
|
|
71
|
+
"@fluidframework/build-tools": "^0.58.1",
|
|
72
|
+
"@fluidframework/driver-definitions": "2.61.0-355516",
|
|
73
73
|
"@fluidframework/eslint-config-fluid": "^6.0.0",
|
|
74
74
|
"@types/mocha": "^10.0.10",
|
|
75
75
|
"@types/nock": "^9.3.0",
|
|
76
76
|
"@types/node": "^18.19.0",
|
|
77
77
|
"@types/sinon": "^17.0.3",
|
|
78
|
-
"c8": "^
|
|
78
|
+
"c8": "^10.1.3",
|
|
79
79
|
"eslint": "~8.55.0",
|
|
80
80
|
"nock": "^13.3.3",
|
|
81
81
|
"rimraf": "^4.4.0",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"test:coverage": "c8 npm test",
|
|
114
114
|
"test:realsvc": "npm run test:realsvc:tinylicious",
|
|
115
115
|
"test:realsvc:azure": "cross-env FLUID_CLIENT=azure npm run test:realsvc:azure:run -- --driver=r11s --r11sEndpointName=frs",
|
|
116
|
-
"test:realsvc:azure:run": "mocha --
|
|
116
|
+
"test:realsvc:azure:run": "mocha --exit --timeout 20000 --config src/test/.mocharc.cjs",
|
|
117
117
|
"test:realsvc:tinylicious": "start-server-and-test start:tinylicious:test 7071 test:realsvc:tinylicious:run",
|
|
118
118
|
"test:realsvc:tinylicious:report": "npm run test:realsvc:tinylicious",
|
|
119
119
|
"test:realsvc:tinylicious:run": "npm run test:realsvc:azure:run -- --driver=t9s",
|
package/src/test/.mocharc.cjs
CHANGED
|
@@ -160,6 +160,19 @@ function createSendFunction(): (msg: MessageToParent) => void {
|
|
|
160
160
|
|
|
161
161
|
const send = createSendFunction();
|
|
162
162
|
|
|
163
|
+
function sendAttendeeConnected(attendee: Attendee): void {
|
|
164
|
+
send({
|
|
165
|
+
event: "attendeeConnected",
|
|
166
|
+
attendeeId: attendee.attendeeId,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function sendAttendeeDisconnected(attendee: Attendee): void {
|
|
170
|
+
send({
|
|
171
|
+
event: "attendeeDisconnected",
|
|
172
|
+
attendeeId: attendee.attendeeId,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
163
176
|
function isConnected(container: IFluidContainer | undefined): boolean {
|
|
164
177
|
return container !== undefined && container.connectionState === ConnectionState.Connected;
|
|
165
178
|
}
|
|
@@ -365,17 +378,25 @@ class MessageHandler {
|
|
|
365
378
|
this.container = container;
|
|
366
379
|
this.presence = presence;
|
|
367
380
|
this.containerId = containerId;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
});
|
|
371
|
-
presence.attendees.events.on("attendeeDisconnected", (attendee: Attendee) => {
|
|
372
|
-
send({ event: "attendeeDisconnected", attendeeId: attendee.attendeeId });
|
|
373
|
-
});
|
|
381
|
+
|
|
382
|
+
// Acknowledge connection before sending current attendee information
|
|
374
383
|
send({
|
|
375
384
|
event: "connected",
|
|
376
385
|
containerId,
|
|
377
386
|
attendeeId: presence.attendees.getMyself().attendeeId,
|
|
378
387
|
});
|
|
388
|
+
|
|
389
|
+
// Send existing attendees excluding self to parent/orchestrator
|
|
390
|
+
const self = presence.attendees.getMyself();
|
|
391
|
+
for (const attendee of presence.attendees.getAttendees()) {
|
|
392
|
+
if (attendee !== self) {
|
|
393
|
+
sendAttendeeConnected(attendee);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Listen for presence events to notify parent/orchestrator when a new attendee joins or leaves the session.
|
|
398
|
+
presence.attendees.events.on("attendeeConnected", sendAttendeeConnected);
|
|
399
|
+
presence.attendees.events.on("attendeeDisconnected", sendAttendeeDisconnected);
|
|
379
400
|
}
|
|
380
401
|
|
|
381
402
|
private handleDisconnectSelf(): void {
|
|
@@ -64,7 +64,7 @@ export async function forkChildProcesses(
|
|
|
64
64
|
const childReadyPromises: Promise<void>[] = [];
|
|
65
65
|
const childErrorPromises: Promise<never>[] = [];
|
|
66
66
|
for (let i = 0; i < numProcesses; i++) {
|
|
67
|
-
const child = fork("./lib/test/multiprocess/childClient.js", [
|
|
67
|
+
const child = fork("./lib/test/multiprocess/childClient.tool.js", [
|
|
68
68
|
`child ${i}` /* identifier passed to child process */,
|
|
69
69
|
childLoggingVerbosity /* console logging verbosity */,
|
|
70
70
|
]);
|
|
@@ -114,10 +114,15 @@ function composeConnectMessage(
|
|
|
114
114
|
name: `test-user-name-${id}`,
|
|
115
115
|
},
|
|
116
116
|
scopes,
|
|
117
|
-
createScopes: [ScopeType.DocWrite],
|
|
117
|
+
createScopes: [ScopeType.DocWrite, ScopeType.DocRead],
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
interface CreatorAttendeeIdAndAttendeePromises {
|
|
122
|
+
containerCreatorAttendeeId: AttendeeId;
|
|
123
|
+
attendeeIdPromises: Promise<AttendeeId>[];
|
|
124
|
+
}
|
|
125
|
+
|
|
121
126
|
/**
|
|
122
127
|
* Sends connect commands to the provided child processes.
|
|
123
128
|
*
|
|
@@ -127,10 +132,7 @@ function composeConnectMessage(
|
|
|
127
132
|
export async function connectChildProcesses(
|
|
128
133
|
childProcesses: ChildProcess[],
|
|
129
134
|
{ writeClients, readyTimeoutMs }: { writeClients: number; readyTimeoutMs: number },
|
|
130
|
-
): Promise<{
|
|
131
|
-
containerCreatorAttendeeId: AttendeeId;
|
|
132
|
-
attendeeIdPromises: Promise<AttendeeId>[];
|
|
133
|
-
}> {
|
|
135
|
+
): Promise<CreatorAttendeeIdAndAttendeePromises> {
|
|
134
136
|
if (childProcesses.length === 0) {
|
|
135
137
|
throw new Error("No child processes provided for connection.");
|
|
136
138
|
}
|
|
@@ -154,9 +156,10 @@ export async function connectChildProcesses(
|
|
|
154
156
|
// Note that DocWrite is used to have this attendee be the "leader".
|
|
155
157
|
// DocRead would also be valid as DocWrite is specified for attach when there
|
|
156
158
|
// is no document id (container id).
|
|
157
|
-
const connectContainerCreator = composeConnectMessage(
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
const connectContainerCreator = composeConnectMessage(
|
|
160
|
+
0,
|
|
161
|
+
writeClients > 0 ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],
|
|
162
|
+
);
|
|
160
163
|
firstChild.send(connectContainerCreator);
|
|
161
164
|
}
|
|
162
165
|
const { containerCreatorAttendeeId, containerId } = await timeoutAwait(
|
|
@@ -173,9 +176,10 @@ export async function connectChildProcesses(
|
|
|
173
176
|
attendeeIdPromises.push(Promise.resolve(containerCreatorAttendeeId));
|
|
174
177
|
continue;
|
|
175
178
|
}
|
|
176
|
-
const message = composeConnectMessage(
|
|
177
|
-
index
|
|
178
|
-
|
|
179
|
+
const message = composeConnectMessage(
|
|
180
|
+
index,
|
|
181
|
+
index < writeClients ? [ScopeType.DocWrite, ScopeType.DocRead] : [ScopeType.DocRead],
|
|
182
|
+
);
|
|
179
183
|
message.containerId = containerId;
|
|
180
184
|
attendeeIdPromises.push(
|
|
181
185
|
new Promise<AttendeeId>((resolve, reject) => {
|
|
@@ -193,49 +197,116 @@ export async function connectChildProcesses(
|
|
|
193
197
|
return { containerCreatorAttendeeId, attendeeIdPromises };
|
|
194
198
|
}
|
|
195
199
|
|
|
200
|
+
interface ConnectAndListenForAttendees extends CreatorAttendeeIdAndAttendeePromises {
|
|
201
|
+
attendeeCountRequiredPromises: Promise<void>[];
|
|
202
|
+
}
|
|
203
|
+
|
|
196
204
|
/**
|
|
197
|
-
* Connects the child processes and
|
|
205
|
+
* Connects the child processes and creates promises for the specified number of
|
|
206
|
+
* attendees to connect.
|
|
198
207
|
*/
|
|
199
|
-
export async function
|
|
208
|
+
export async function connectAndListenForAttendees(
|
|
200
209
|
children: ChildProcess[],
|
|
201
210
|
{
|
|
202
211
|
writeClients,
|
|
203
212
|
attendeeCountRequired,
|
|
204
213
|
childConnectTimeoutMs,
|
|
205
|
-
attendeesJoinedTimeoutMs,
|
|
206
214
|
}: {
|
|
215
|
+
/**
|
|
216
|
+
* The number of clients that should have write access.
|
|
217
|
+
*/
|
|
207
218
|
writeClients: number;
|
|
219
|
+
/**
|
|
220
|
+
* The number of attendees that must connect.
|
|
221
|
+
*/
|
|
208
222
|
attendeeCountRequired: number;
|
|
223
|
+
/**
|
|
224
|
+
* Timeout duration for child process connections.
|
|
225
|
+
*/
|
|
209
226
|
childConnectTimeoutMs: number;
|
|
210
|
-
attendeesJoinedTimeoutMs: number;
|
|
211
227
|
},
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
attendeesJoinedEvents
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
): Promise<ConnectAndListenForAttendees> {
|
|
229
|
+
// Setup
|
|
230
|
+
const attendeeCountRequiredPromises = children.map(
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
232
|
+
(child) =>
|
|
233
|
+
new Promise<void>((resolve) => {
|
|
234
|
+
let attendeesJoinedEvents = 0;
|
|
235
|
+
const listenForAttendees = (msg: MessageFromChild): void => {
|
|
236
|
+
if (msg.event === "attendeeConnected") {
|
|
237
|
+
attendeesJoinedEvents++;
|
|
238
|
+
if (attendeesJoinedEvents >= attendeeCountRequired) {
|
|
239
|
+
resolve();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
child.on("message", listenForAttendees);
|
|
244
|
+
}),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
// Act - connect all child processes
|
|
225
248
|
const connectResult = await connectChildProcesses(children, {
|
|
226
249
|
writeClients,
|
|
227
250
|
readyTimeoutMs: childConnectTimeoutMs,
|
|
228
251
|
});
|
|
252
|
+
|
|
229
253
|
Promise.all(connectResult.attendeeIdPromises)
|
|
230
254
|
.then(() => console.log("All attendees connected."))
|
|
231
255
|
.catch((error) => {
|
|
232
256
|
testConsole.error("Error connecting children:", error);
|
|
233
257
|
});
|
|
258
|
+
|
|
259
|
+
return { ...connectResult, attendeeCountRequiredPromises };
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Connects the child processes and waits for the specified number of attendees to connect.
|
|
264
|
+
*
|
|
265
|
+
* @remarks
|
|
266
|
+
* This function can be used directly as a test. Comments in the functionality describe the
|
|
267
|
+
* breakdown of test blocks.
|
|
268
|
+
*/
|
|
269
|
+
export async function connectAndWaitForAttendees(
|
|
270
|
+
children: ChildProcess[],
|
|
271
|
+
{
|
|
272
|
+
writeClients,
|
|
273
|
+
attendeeCountRequired,
|
|
274
|
+
childConnectTimeoutMs,
|
|
275
|
+
allAttendeesJoinedTimeoutMs,
|
|
276
|
+
}: {
|
|
277
|
+
/**
|
|
278
|
+
* The number of clients that should have write access.
|
|
279
|
+
*/
|
|
280
|
+
writeClients: number;
|
|
281
|
+
/**
|
|
282
|
+
* The number of attendees that must connect.
|
|
283
|
+
*/
|
|
284
|
+
attendeeCountRequired: number;
|
|
285
|
+
/**
|
|
286
|
+
* Timeout duration for child process connections.
|
|
287
|
+
*/
|
|
288
|
+
childConnectTimeoutMs: number;
|
|
289
|
+
/**
|
|
290
|
+
* Timeout duration for all required attendees to join.
|
|
291
|
+
*/
|
|
292
|
+
allAttendeesJoinedTimeoutMs: number;
|
|
293
|
+
},
|
|
294
|
+
earlyExitPromise: Promise<never>,
|
|
295
|
+
): Promise<{ containerCreatorAttendeeId: AttendeeId }> {
|
|
296
|
+
// Setup and Act - connect all child processes
|
|
297
|
+
const connectAndListenResult = await connectAndListenForAttendees(children, {
|
|
298
|
+
writeClients,
|
|
299
|
+
attendeeCountRequired,
|
|
300
|
+
childConnectTimeoutMs,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const attendeeConnectedPromise = connectAndListenResult.attendeeCountRequiredPromises[0];
|
|
304
|
+
|
|
234
305
|
await timeoutAwait(Promise.race([attendeeConnectedPromise, earlyExitPromise]), {
|
|
235
|
-
durationMs:
|
|
306
|
+
durationMs: allAttendeesJoinedTimeoutMs,
|
|
236
307
|
errorMsg: "child 0 did not receive all 'attendeeConnected' events",
|
|
237
308
|
});
|
|
238
|
-
return
|
|
309
|
+
return connectAndListenResult;
|
|
239
310
|
}
|
|
240
311
|
|
|
241
312
|
/**
|