@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/azure-end-to-end-tests",
3
- "version": "2.60.0",
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": "~2.60.0",
37
- "@fluid-internal/client-utils": "~2.60.0",
38
- "@fluid-internal/mocha-test-setup": "~2.60.0",
39
- "@fluid-private/test-version-utils": "~2.60.0",
40
- "@fluidframework/aqueduct": "~2.60.0",
41
- "@fluidframework/azure-client": "~2.60.0",
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": "~2.60.0",
44
- "@fluidframework/container-loader": "~2.60.0",
45
- "@fluidframework/core-interfaces": "~2.60.0",
46
- "@fluidframework/counter": "~2.60.0",
47
- "@fluidframework/datastore-definitions": "~2.60.0",
48
- "@fluidframework/fluid-static": "~2.60.0",
49
- "@fluidframework/map": "~2.60.0",
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": "~2.60.0",
52
- "@fluidframework/presence": "~2.60.0",
53
- "@fluidframework/runtime-definitions": "~2.60.0",
54
- "@fluidframework/sequence": "~2.60.0",
55
- "@fluidframework/telemetry-utils": "~2.60.0",
56
- "@fluidframework/test-runtime-utils": "~2.60.0",
57
- "@fluidframework/test-utils": "~2.60.0",
58
- "@fluidframework/tree": "~2.60.0",
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.57.0",
72
- "@fluidframework/driver-definitions": "~2.60.0",
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": "^8.0.1",
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 --recursive \"lib/test/**/*.spec.*js\" --exit --timeout 20000 --config src/test/.mocharc.cjs",
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",
@@ -8,5 +8,4 @@
8
8
  const packageDir = `${__dirname}/../..`;
9
9
  const getFluidTestMochaConfig = require("@fluid-private/test-version-utils/mocharc-common");
10
10
  const config = getFluidTestMochaConfig(packageDir);
11
-
12
11
  module.exports = config;
@@ -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
- presence.attendees.events.on("attendeeConnected", (attendee: Attendee) => {
369
- send({ event: "attendeeConnected", attendeeId: attendee.attendeeId });
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(0, [
158
- writeClients > 0 ? ScopeType.DocWrite : ScopeType.DocRead,
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(index, [
177
- index < writeClients ? ScopeType.DocWrite : ScopeType.DocRead,
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 waits for the specified number of attendees to connect.
205
+ * Connects the child processes and creates promises for the specified number of
206
+ * attendees to connect.
198
207
  */
199
- export async function connectAndWaitForAttendees(
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
- earlyExitPromise: Promise<never>,
213
- ): Promise<{ containerCreatorAttendeeId: AttendeeId }> {
214
- const attendeeConnectedPromise = new Promise<void>((resolve) => {
215
- let attendeesJoinedEvents = 0;
216
- children[0].on("message", (msg: MessageFromChild) => {
217
- if (msg.event === "attendeeConnected") {
218
- attendeesJoinedEvents++;
219
- if (attendeesJoinedEvents >= attendeeCountRequired) {
220
- resolve();
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: attendeesJoinedTimeoutMs,
306
+ durationMs: allAttendeesJoinedTimeoutMs,
236
307
  errorMsg: "child 0 did not receive all 'attendeeConnected' events",
237
308
  });
238
- return connectResult;
309
+ return connectAndListenResult;
239
310
  }
240
311
 
241
312
  /**