@fluid-internal/presence-runtime 2.101.1 → 2.103.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.
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/runtime/extension/containerPresence.d.ts +1 -1
- package/dist/runtime/presenceDatastoreManager.d.ts +2 -2
- package/dist/runtime/presenceDatastoreManager.d.ts.map +1 -1
- package/dist/runtime/presenceDatastoreManager.js.map +1 -1
- package/dist/runtime/presenceManager.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/runtime/extension/containerPresence.d.ts +1 -1
- package/lib/runtime/presenceDatastoreManager.d.ts +2 -2
- package/lib/runtime/presenceDatastoreManager.d.ts.map +1 -1
- package/lib/runtime/presenceDatastoreManager.js.map +1 -1
- package/lib/runtime/presenceManager.js.map +1 -1
- package/package.json +14 -14
- package/dist/runtime/test/presenceDatastoreManager.spec.js +0 -618
- package/dist/runtime/test/presenceDatastoreManager.spec.js.map +0 -1
- package/dist/runtime/test/presenceManager.spec.js +0 -651
- package/dist/runtime/test/presenceManager.spec.js.map +0 -1
- package/dist/states/test/batching.spec.js +0 -843
- package/dist/states/test/batching.spec.js.map +0 -1
- package/dist/states/test/broadcastControlsTests.js +0 -60
- package/dist/states/test/broadcastControlsTests.js.map +0 -1
- package/dist/states/test/eventing.spec.js +0 -576
- package/dist/states/test/eventing.spec.js.map +0 -1
- package/dist/states/test/latestMapValueManager.spec.js +0 -210
- package/dist/states/test/latestMapValueManager.spec.js.map +0 -1
- package/dist/states/test/latestValueManager.spec.js +0 -193
- package/dist/states/test/latestValueManager.spec.js.map +0 -1
- package/dist/states/test/mockEphemeralRuntime.js +0 -11
- package/dist/states/test/mockEphemeralRuntime.js.map +0 -1
- package/dist/states/test/notificationsManager.spec.js +0 -460
- package/dist/states/test/notificationsManager.spec.js.map +0 -1
- package/dist/states/test/presenceStates.spec.js +0 -73
- package/dist/states/test/presenceStates.spec.js.map +0 -1
- package/dist/states/test/schemaValidation/protocol.spec.js +0 -246
- package/dist/states/test/schemaValidation/protocol.spec.js.map +0 -1
- package/dist/states/test/schemaValidation/valueManagers.spec.js +0 -784
- package/dist/states/test/schemaValidation/valueManagers.spec.js.map +0 -1
- package/dist/states/test/testUtils.js +0 -21
- package/dist/states/test/testUtils.js.map +0 -1
- package/dist/test/mockEphemeralRuntime.js +0 -175
- package/dist/test/mockEphemeralRuntime.js.map +0 -1
- package/dist/test/testUtils.js +0 -262
- package/dist/test/testUtils.js.map +0 -1
- package/dist/test/utils/index.js +0 -27
- package/dist/test/utils/index.js.map +0 -1
- package/dist/utils/test/timerManager.spec.js +0 -93
- package/dist/utils/test/timerManager.spec.js.map +0 -1
- package/lib/runtime/test/presenceDatastoreManager.spec.js +0 -616
- package/lib/runtime/test/presenceDatastoreManager.spec.js.map +0 -1
- package/lib/runtime/test/presenceManager.spec.js +0 -649
- package/lib/runtime/test/presenceManager.spec.js.map +0 -1
- package/lib/states/test/batching.spec.js +0 -841
- package/lib/states/test/batching.spec.js.map +0 -1
- package/lib/states/test/broadcastControlsTests.js +0 -56
- package/lib/states/test/broadcastControlsTests.js.map +0 -1
- package/lib/states/test/eventing.spec.js +0 -574
- package/lib/states/test/eventing.spec.js.map +0 -1
- package/lib/states/test/latestMapValueManager.spec.js +0 -206
- package/lib/states/test/latestMapValueManager.spec.js.map +0 -1
- package/lib/states/test/latestValueManager.spec.js +0 -189
- package/lib/states/test/latestValueManager.spec.js.map +0 -1
- package/lib/states/test/mockEphemeralRuntime.js +0 -6
- package/lib/states/test/mockEphemeralRuntime.js.map +0 -1
- package/lib/states/test/notificationsManager.spec.js +0 -456
- package/lib/states/test/notificationsManager.spec.js.map +0 -1
- package/lib/states/test/presenceStates.spec.js +0 -69
- package/lib/states/test/presenceStates.spec.js.map +0 -1
- package/lib/states/test/schemaValidation/protocol.spec.js +0 -244
- package/lib/states/test/schemaValidation/protocol.spec.js.map +0 -1
- package/lib/states/test/schemaValidation/valueManagers.spec.js +0 -782
- package/lib/states/test/schemaValidation/valueManagers.spec.js.map +0 -1
- package/lib/states/test/testUtils.js +0 -6
- package/lib/states/test/testUtils.js.map +0 -1
- package/lib/test/mockEphemeralRuntime.js +0 -171
- package/lib/test/mockEphemeralRuntime.js.map +0 -1
- package/lib/test/testUtils.js +0 -251
- package/lib/test/testUtils.js.map +0 -1
- package/lib/test/utils/index.js +0 -8
- package/lib/test/utils/index.js.map +0 -1
- package/lib/utils/test/timerManager.spec.js +0 -91
- package/lib/utils/test/timerManager.spec.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"presenceManager.spec.js","sourceRoot":"","sources":["../../../src/runtime/test/presenceManager.spec.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 { strict as assert } from \"node:assert\";\n\nimport type {\n\tAttendee,\n\tClientConnectionId,\n\tPresence,\n} from \"@fluid-internal/presence-definitions\";\nimport { AttendeeStatus } from \"@fluid-internal/presence-definitions\";\nimport type { IClient } from \"@fluidframework/driver-definitions\";\nimport { EventAndErrorTrackingLogger } from \"@fluidframework/test-utils/internal\";\nimport type { SinonFakeTimers } from \"sinon\";\nimport { useFakeTimers } from \"sinon\";\n\nimport { createPresenceManager } from \"@fluid-internal/presence-runtime/internal/test\";\nimport type { ProcessSignalFunction } from \"@fluid-internal/presence-runtime/internal/test-utils\";\nimport {\n\tassertFinalExpectations,\n\tinitialLocalClientConnectionId,\n\tlocalAttendeeId,\n\tcreateSpecificAttendeeId,\n\tgenerateBasicClientJoin,\n\tMockEphemeralRuntime,\n\tprepareConnectedPresence,\n\tprepareDisconnectedPresence,\n} from \"@fluid-internal/presence-runtime/internal/test-utils\";\n\nconst collateralSessionId = createSpecificAttendeeId(\"collateral-id\");\n/**\n * Mock {@link ClientConnectionId} for the local client after first reconnection.\n */\nconst rejoinedLocalClientConnectionId1 =\n\t\"localClientRejoin1\" as const satisfies ClientConnectionId;\n/**\n * Mock {@link ClientConnectionId} for the local client after second reconnection.\n */\nconst rejoinedLocalClientConnectionId2 =\n\t\"localClientRejoin2\" as const satisfies ClientConnectionId;\n\nfunction verify<T>(value: T | undefined, message?: string): T {\n\tassert(value !== undefined, message ?? \"Expected value to be defined\");\n\treturn value;\n}\n\ndescribe(\"Presence/Runtime\", () => {\n\tdescribe(\"PresenceManager\", () => {\n\t\tlet runtime: MockEphemeralRuntime;\n\t\tlet logger: EventAndErrorTrackingLogger;\n\t\tconst initialTime = 1000;\n\t\tlet clock: SinonFakeTimers;\n\n\t\tbefore(async () => {\n\t\t\tclock = useFakeTimers();\n\t\t});\n\n\t\tbeforeEach(() => {\n\t\t\tlogger = new EventAndErrorTrackingLogger();\n\t\t\truntime = new MockEphemeralRuntime(logger);\n\t\t\tclock.setSystemTime(initialTime);\n\t\t});\n\n\t\tafterEach(function (done: Mocha.Done) {\n\t\t\tclock.reset();\n\n\t\t\t// If the test passed so far, check final expectations.\n\t\t\tif (this.currentTest?.state === \"passed\") {\n\t\t\t\tassertFinalExpectations(runtime, logger);\n\t\t\t}\n\t\t\tdone();\n\t\t});\n\n\t\tafter(() => {\n\t\t\tclock.restore();\n\t\t});\n\n\t\tit(\"can be created\", () => {\n\t\t\t// Act & Verify (does not throw)\n\t\t\tcreatePresenceManager(runtime);\n\t\t});\n\n\t\tit(\"creation logs initialization event\", () => {\n\t\t\t// Setup\n\t\t\tlogger.registerExpectedEvent({ eventName: \"Presence:PresenceInstantiated\" });\n\n\t\t\t// Act\n\t\t\tcreatePresenceManager(runtime);\n\n\t\t\t// Verify\n\t\t\tassertFinalExpectations(runtime, logger);\n\t\t});\n\n\t\tit(\"throws when unknown attendee is requested via `getAttendee`\", () => {\n\t\t\t// Setup\n\t\t\tconst presence = createPresenceManager(runtime);\n\n\t\t\t// Act & Verify\n\t\t\tassert.throws(() => presence.attendees.getAttendee(\"unknown\"), /Attendee not found/);\n\t\t});\n\n\t\tdescribe(\"self attendee\", () => {\n\t\t\tit(\"is announced via `attendeeConnected` upon connect while self is in audience\", () => {\n\t\t\t\t// Setup - create presence in disconnected state\n\t\t\t\tconst { presence, connect } = prepareDisconnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\tconst connectedAttendees: Attendee[] = [];\n\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\tconnectedAttendees.push(attendee);\n\t\t\t\t});\n\n\t\t\t\t// Act - connect\n\t\t\t\tconnect();\n\n\t\t\t\t// Verify - self attendee was announced\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees.length,\n\t\t\t\t\t1,\n\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees[0],\n\t\t\t\t\tselfAttendee,\n\t\t\t\t\t\"Expected self attendee to be announced\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('has status \"Disconnected\" when presence initializes while container is disconnected', () => {\n\t\t\t\t// Setup - create presence while container is disconnected\n\t\t\t\tconst { presence } = prepareDisconnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\t// Verify - self attendee has \"Disconnected\" status\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\"Self attendee should have status 'Disconnected' when presence initializes while container is disconnected\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit('has status \"Disconnected\" when runtime is connected but self is not yet in Audience', () => {\n\t\t\t\t// Setup - set runtime to connected state but remove self from audience\n\t\t\t\truntime.clientId = initialLocalClientConnectionId;\n\t\t\t\truntime.joined = true;\n\t\t\t\truntime.removeMember(initialLocalClientConnectionId);\n\n\t\t\t\t// Create presence - it will see runtime as connected but self not in audience\n\t\t\t\tlogger.registerExpectedEvent({ eventName: \"Presence:PresenceInstantiated\" });\n\t\t\t\tconst presence = createPresenceManager(runtime, localAttendeeId);\n\n\t\t\t\t// Verify - self attendee should have \"Disconnected\" status since\n\t\t\t\t// we haven't received the ClientJoin signal yet\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\"Self attendee should have status 'Disconnected' when runtime is connected but self is not yet in Audience\",\n\t\t\t\t);\n\n\t\t\t\tassertFinalExpectations(runtime, logger);\n\t\t\t});\n\n\t\t\tit(\"is announced via `attendeeConnected` when added to Audience while runtime is connected\", () => {\n\t\t\t\t// Setup - set runtime to connected state but remove self from audience\n\t\t\t\truntime.clientId = initialLocalClientConnectionId;\n\t\t\t\truntime.joined = true;\n\t\t\t\truntime.removeMember(initialLocalClientConnectionId);\n\n\t\t\t\t// Create presence - it will see runtime as connected but self not in audience\n\t\t\t\tlogger.registerExpectedEvent({ eventName: \"Presence:PresenceInstantiated\" });\n\t\t\t\tconst presence = createPresenceManager(runtime, localAttendeeId);\n\n\t\t\t\t// Verify initial state - self is Disconnected\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\"Self attendee should initially have status 'Disconnected'\",\n\t\t\t\t);\n\n\t\t\t\t// Listen for attendeeConnected\n\t\t\t\tconst connectedAttendees: Attendee[] = [];\n\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\tconnectedAttendees.push(attendee);\n\t\t\t\t});\n\n\t\t\t\t// Expect join signal when self is added to audience while connected\n\t\t\t\tconst expectedJoin = generateBasicClientJoin(clock.now, {\n\t\t\t\t\tattendeeId: localAttendeeId,\n\t\t\t\t\tclientConnectionId: initialLocalClientConnectionId,\n\t\t\t\t\tupdateProviders: [\"client0\", \"client1\", \"client3\"],\n\t\t\t\t});\n\t\t\t\tdelete (expectedJoin as Partial<typeof expectedJoin>).clientId;\n\t\t\t\truntime.signalsExpected.push([expectedJoin]);\n\n\t\t\t\t// Act - self added to audience\n\t\t\t\truntime.audience.addMember(initialLocalClientConnectionId, {\n\t\t\t\t\tmode: \"write\",\n\t\t\t\t\tdetails: { capabilities: { interactive: true } },\n\t\t\t\t\tpermission: [],\n\t\t\t\t\tuser: { id: \"test-user\" },\n\t\t\t\t\tscopes: [],\n\t\t\t\t});\n\n\t\t\t\t// Verify - attendeeConnected was raised for self with Connected status\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees.length,\n\t\t\t\t\t1,\n\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees[0],\n\t\t\t\t\tselfAttendee,\n\t\t\t\t\t\"Expected self attendee to be announced\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\"Self attendee should have status 'Connected' after being added to Audience\",\n\t\t\t\t);\n\n\t\t\t\tassertFinalExpectations(runtime, logger);\n\t\t\t});\n\n\t\t\tit('has status \"Connected\" when announced via `attendeeConnected`', () => {\n\t\t\t\t// Setup - create presence in disconnected state\n\t\t\t\tconst { presence, connect } = prepareDisconnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\tlet attendeeConnectedRaised = false;\n\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\tif (attendee === presence.attendees.getMyself()) {\n\t\t\t\t\t\tattendeeConnectedRaised = true;\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tattendee.getConnectionStatus(),\n\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\"Self attendee should have status 'Connected' when announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\t// Act - connect\n\t\t\t\tconnect();\n\n\t\t\t\t// Verify - attendeeConnected was raised\n\t\t\t\tassert(\n\t\t\t\t\tattendeeConnectedRaised,\n\t\t\t\t\t\"attendeeConnected event should be raised for self attendee\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit(\"is announced via `attendeeDisconnected` when local client disconnects\", () => {\n\t\t\t\t// Setup - create presence in disconnected state and connect\n\t\t\t\tconst { presence, connect } = prepareDisconnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\tconnect();\n\n\t\t\t\tconst disconnectedAttendees: Attendee[] = [];\n\t\t\t\tpresence.attendees.events.on(\"attendeeDisconnected\", (attendee) => {\n\t\t\t\t\tdisconnectedAttendees.push(attendee);\n\t\t\t\t});\n\n\t\t\t\t// Act - disconnect\n\t\t\t\truntime.disconnect();\n\n\t\t\t\t// Verify - self attendee was announced as disconnected\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tdisconnectedAttendees.length,\n\t\t\t\t\t1,\n\t\t\t\t\t\"Expected exactly one attendee to be announced as disconnected\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tdisconnectedAttendees[0],\n\t\t\t\t\tselfAttendee,\n\t\t\t\t\t\"Expected self attendee to be announced as disconnected\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\"Self attendee should have status 'Disconnected' after disconnect\",\n\t\t\t\t);\n\t\t\t});\n\n\t\t\tit(\"is announced via `attendeeConnected` when local client reconnects\", () => {\n\t\t\t\t// Setup - create presence in disconnected state, connect and then disconnect\n\t\t\t\tconst { presence, connect } = prepareDisconnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t);\n\n\t\t\t\t// Initial connection\n\t\t\t\tconnect();\n\n\t\t\t\t// Disconnect\n\t\t\t\truntime.disconnect();\n\n\t\t\t\t// Ignore submitted signals for reconnection\n\t\t\t\truntime.submitSignal = () => {};\n\n\t\t\t\tconst connectedAttendees: Attendee[] = [];\n\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\tconnectedAttendees.push(attendee);\n\t\t\t\t});\n\n\t\t\t\t// Act - reconnect with new connection id\n\t\t\t\truntime.connect(rejoinedLocalClientConnectionId1, initialLocalClientConnectionId);\n\n\t\t\t\t// Verify - self attendee was announced\n\t\t\t\tconst selfAttendee = presence.attendees.getMyself();\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees.length,\n\t\t\t\t\t1,\n\t\t\t\t\t\"Expected exactly one attendee to be announced on reconnect\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tconnectedAttendees[0],\n\t\t\t\t\tselfAttendee,\n\t\t\t\t\t\"Expected self attendee to be announced on reconnect\",\n\t\t\t\t);\n\t\t\t\tassert.strictEqual(\n\t\t\t\t\tselfAttendee.getConnectionStatus(),\n\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\"Self attendee should have status 'Connected' after reconnect\",\n\t\t\t\t);\n\t\t\t});\n\t\t});\n\n\t\tdescribe(\"when connected\", () => {\n\t\t\tlet presence: Presence;\n\t\t\tlet processSignal: ProcessSignalFunction;\n\t\t\tconst afterCleanUp: (() => void)[] = [];\n\n\t\t\tbeforeEach(() => {\n\t\t\t\t({ presence, processSignal } = prepareConnectedPresence(\n\t\t\t\t\truntime,\n\t\t\t\t\tlocalAttendeeId,\n\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\tclock,\n\t\t\t\t\tlogger,\n\t\t\t\t));\n\t\t\t});\n\n\t\t\tafterEach(() => {\n\t\t\t\tfor (const cleanUp of afterCleanUp) {\n\t\t\t\t\tcleanUp();\n\t\t\t\t}\n\t\t\t\tafterCleanUp.length = 0;\n\t\t\t});\n\n\t\t\tdescribe(\"attendee\", () => {\n\t\t\t\tconst attendeeSessionId = \"attendeeId-4\";\n\t\t\t\tconst initialAttendeeConnectionId = \"client4\";\n\t\t\t\t// Note: this connection id exists in the mock runtime audience since\n\t\t\t\t// initialization, but should go unnoticed by the presence manager\n\t\t\t\t// until there is a join signal related to it.\n\t\t\t\tconst rejoinAttendeeConnectionId = \"client7\";\n\t\t\t\tlet initialAttendeeSignal: ReturnType<typeof generateBasicClientJoin>;\n\t\t\t\tlet rejoinAttendeeSignal: ReturnType<typeof generateBasicClientJoin>;\n\n\t\t\t\t// Processes join signals and returns the attendees that were announced via `attendeeConnected`\n\t\t\t\tfunction processJoinSignals(\n\t\t\t\t\tsignals: ReturnType<typeof generateBasicClientJoin>[],\n\t\t\t\t): Attendee[] {\n\t\t\t\t\tconst joinedAttendees: Attendee[] = [];\n\t\t\t\t\tconst cleanUpListener = presence.attendees.events.on(\n\t\t\t\t\t\t\"attendeeConnected\",\n\t\t\t\t\t\t(attendee) => {\n\t\t\t\t\t\t\tjoinedAttendees.push(attendee);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tfor (const signal of signals) {\n\t\t\t\t\t\tprocessSignal([], signal, false);\n\t\t\t\t\t}\n\n\t\t\t\t\tcleanUpListener();\n\t\t\t\t\treturn joinedAttendees;\n\t\t\t\t}\n\n\t\t\t\tfunction verifyAttendee(\n\t\t\t\t\tactualAttendee: Attendee,\n\t\t\t\t\texpectedConnectionId: ClientConnectionId,\n\t\t\t\t\texpectedSessionId: string,\n\t\t\t\t\texpectedConnectionStatus: AttendeeStatus = AttendeeStatus.Connected,\n\t\t\t\t): void {\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tactualAttendee.attendeeId,\n\t\t\t\t\t\texpectedSessionId,\n\t\t\t\t\t\t\"Attendee has wrong session id\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tactualAttendee.getConnectionId(),\n\t\t\t\t\t\texpectedConnectionId,\n\t\t\t\t\t\t\"Attendee has wrong client connection id\",\n\t\t\t\t\t);\n\t\t\t\t\tassert.equal(\n\t\t\t\t\t\tactualAttendee.getConnectionStatus(),\n\t\t\t\t\t\texpectedConnectionStatus,\n\t\t\t\t\t\t`Attendee connection status is not ${expectedConnectionStatus}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tbeforeEach(() => {\n\t\t\t\t\t// Ignore submitted signals\n\t\t\t\t\truntime.submitSignal = () => {};\n\n\t\t\t\t\tinitialAttendeeSignal = generateBasicClientJoin(clock.now - 50, {\n\t\t\t\t\t\taverageLatency: 50,\n\t\t\t\t\t\tattendeeId: attendeeSessionId,\n\t\t\t\t\t\tclientConnectionId: initialAttendeeConnectionId,\n\t\t\t\t\t\tupdateProviders: [initialLocalClientConnectionId],\n\t\t\t\t\t});\n\n\t\t\t\t\trejoinAttendeeSignal = generateBasicClientJoin(clock.now - 20, {\n\t\t\t\t\t\taverageLatency: 20,\n\t\t\t\t\t\tattendeeId: attendeeSessionId, // Same session id\n\t\t\t\t\t\tclientConnectionId: rejoinAttendeeConnectionId, // Different connection id\n\t\t\t\t\t\tconnectionOrder: 1,\n\t\t\t\t\t\tupdateProviders: [initialLocalClientConnectionId],\n\t\t\t\t\t\tpriorClientToSessionId:\n\t\t\t\t\t\t\tinitialAttendeeSignal.content.data[\"system:presence\"].clientToSessionId,\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tit(\"is not announced via `attendeeDisconnected` when unknown connection is removed\", () => {\n\t\t\t\t\t// Setup\n\t\t\t\t\tpresence.attendees.events.on(\"attendeeDisconnected\", () => {\n\t\t\t\t\t\tassert.fail(\n\t\t\t\t\t\t\t\"`attendeeDisconnected` should not be emitted for unknown connection.\",\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\n\t\t\t\t\t// Act & Verify - remove connection unknown to presence\n\t\t\t\t\truntime.removeMember(\"client5\");\n\t\t\t\t});\n\n\t\t\t\tdescribe(\"that is joining\", () => {\n\t\t\t\t\tit('first time is announced via `attendeeConnected` with status \"Connected\"', () => {\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t\t// Verify\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], initialAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit('second time is announced once via `attendeeConnected` with status \"Connected\" when prior is unknown', () => {\n\t\t\t\t\t\t// Setup\n\t\t\t\t\t\tconst priorClientData = verify(\n\t\t\t\t\t\t\truntime.getAudience().getMember(initialAttendeeConnectionId),\n\t\t\t\t\t\t);\n\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\t\t\t\t\t\truntime.audience.addMember(rejoinAttendeeConnectionId, priorClientData);\n\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);\n\n\t\t\t\t\t\t// Verify\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit('second time is announced once via `attendeeConnected` with status \"Connected\" when prior is still connected', () => {\n\t\t\t\t\t\tconst initialClientData = verify(\n\t\t\t\t\t\t\truntime.getAudience().getMember(initialAttendeeConnectionId),\n\t\t\t\t\t\t);\n\t\t\t\t\t\truntime.audience.addMember(rejoinAttendeeConnectionId, initialClientData);\n\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);\n\n\t\t\t\t\t\t// Verify\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit('first time is announced via `attendeeConnected` with status \"Connected\" even if unknown to audience', () => {\n\t\t\t\t\t\t// Setup - remove connection from audience\n\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([initialAttendeeSignal]);\n\n\t\t\t\t\t\t// Verify\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], initialAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit('second time is announced once via `attendeeConnected` with status \"Connected\" even if most recent unknown to audience', () => {\n\t\t\t\t\t\t// Setup - remove connection from audience\n\t\t\t\t\t\truntime.removeMember(rejoinAttendeeConnectionId);\n\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit(\"as collateral and disconnected is NOT announced via `attendeeConnected`\", () => {\n\t\t\t\t\t\t// Setup - remove connections from audience\n\t\t\t\t\t\tconst collateralAttendeeConnectionId = \"client3\";\n\t\t\t\t\t\tconst collateralAttendeeSignal = generateBasicClientJoin(clock.now - 10, {\n\t\t\t\t\t\t\taverageLatency: 40,\n\t\t\t\t\t\t\tattendeeId: attendeeSessionId,\n\t\t\t\t\t\t\tclientConnectionId: rejoinAttendeeConnectionId,\n\t\t\t\t\t\t\tconnectionOrder: 1,\n\t\t\t\t\t\t\tupdateProviders: [initialLocalClientConnectionId],\n\t\t\t\t\t\t\tpriorClientToSessionId: {\n\t\t\t\t\t\t\t\t...initialAttendeeSignal.content.data[\"system:presence\"].clientToSessionId,\n\t\t\t\t\t\t\t\t[collateralAttendeeConnectionId]: {\n\t\t\t\t\t\t\t\t\trev: 0,\n\t\t\t\t\t\t\t\t\ttimestamp: 0,\n\t\t\t\t\t\t\t\t\tvalue: collateralSessionId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\t\t\t\t\t\truntime.removeMember(collateralAttendeeConnectionId);\n\n\t\t\t\t\t\t// Act - simulate join message from client\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([collateralAttendeeSignal]);\n\n\t\t\t\t\t\t// Verify - only the rejoining attendee is announced\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tverifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit(\"as collateral with old connection info and connected is NOT announced via `attendeeConnected`\", () => {\n\t\t\t\t\t\t// Setup - generate signals\n\n\t\t\t\t\t\t// Both connection Id's unknown to audience\n\t\t\t\t\t\tconst oldAttendeeConnectionId = \"client9\";\n\t\t\t\t\t\tconst newAttendeeConnectionId = \"client10\";\n\n\t\t\t\t\t\t// Rejoin signal for the collateral attendee unknown to audience\n\t\t\t\t\t\tconst rejoinSignal = generateBasicClientJoin(clock.now - 10, {\n\t\t\t\t\t\t\taverageLatency: 40,\n\t\t\t\t\t\t\tattendeeId: collateralSessionId,\n\t\t\t\t\t\t\tclientConnectionId: newAttendeeConnectionId,\n\t\t\t\t\t\t\tupdateProviders: [initialAttendeeConnectionId],\n\t\t\t\t\t\t\tconnectionOrder: 1,\n\t\t\t\t\t\t\tpriorClientToSessionId: {\n\t\t\t\t\t\t\t\t[oldAttendeeConnectionId]: {\n\t\t\t\t\t\t\t\t\trev: 0,\n\t\t\t\t\t\t\t\t\ttimestamp: 0,\n\t\t\t\t\t\t\t\t\tvalue: collateralSessionId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Response signal sent by the initial attendee responding to the collateral attendees rejoin signal\n\t\t\t\t\t\tconst responseSignal = generateBasicClientJoin(clock.now - 5, {\n\t\t\t\t\t\t\taverageLatency: 20,\n\t\t\t\t\t\t\tattendeeId: attendeeSessionId,\n\t\t\t\t\t\t\tclientConnectionId: initialAttendeeConnectionId,\n\t\t\t\t\t\t\tpriorClientToSessionId: {\n\t\t\t\t\t\t\t\t...initialAttendeeSignal.content.data[\"system:presence\"].clientToSessionId,\n\t\t\t\t\t\t\t\t// Old connection id of rejoining attendee\n\t\t\t\t\t\t\t\t// This should be ignored by local client\n\t\t\t\t\t\t\t\t[oldAttendeeConnectionId]: {\n\t\t\t\t\t\t\t\t\trev: 0,\n\t\t\t\t\t\t\t\t\ttimestamp: 0,\n\t\t\t\t\t\t\t\t\tvalue: collateralSessionId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Process initial join signal so initial attendee is known\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tjoinedAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Simulate rejoin message from remote client\n\t\t\t\t\t\tconst rejoinAttendees = processJoinSignals([rejoinSignal]);\n\t\t\t\t\t\t// Confirm that rejoining attendee is announced so we can verify it remains the same after response\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\trejoinAttendees.length,\n\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Act - simulate response message from remote client\n\t\t\t\t\t\tconst responseAttendees = processJoinSignals([responseSignal]);\n\n\t\t\t\t\t\t// Verify - No collateral attendee should be announced by response signal and rejoined attendee information should remain unchanged\n\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\tresponseAttendees.length,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\"Expected no attendees to be announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Check attendee information remains unchanged\n\t\t\t\t\t\tverifyAttendee(rejoinAttendees[0], newAttendeeConnectionId, collateralSessionId);\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tdescribe(\"that is already known\", () => {\n\t\t\t\t\tlet knownAttendee: Attendee | undefined;\n\n\t\t\t\t\tbeforeEach(() => {\n\t\t\t\t\t\t// Setup known attendee\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\tjoinedAttendees.length === 1,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tknownAttendee = joinedAttendees[0];\n\t\t\t\t\t});\n\n\t\t\t\t\tit('is NOT announced when \"rejoined\" with same connection (duplicate signal)', () => {\n\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\t\t\t\tassert.fail(\n\t\t\t\t\t\t\t\t\t\"Attendee should not be announced when rejoining with same connection\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tclock.tick(10);\n\t\t\t\t\t\t// Act & Verify - simulate duplicate join message from client\n\t\t\t\t\t\tprocessJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t});\n\n\t\t\t\t\t// To retain symmetry across Joined and Disconnected events, do not announce\n\t\t\t\t\t// attendeeConnected when the attendee is already connected and we only see\n\t\t\t\t\t// a connection id update. This can happen when audience removal is late.\n\t\t\t\t\tit('is not announced via `attendeeConnected` when already \"Connected\"', () => {\n\t\t\t\t\t\t// Setup\n\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", () => {\n\t\t\t\t\t\t\t\tassert.fail(\"No attendee should be announced in join processing\");\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Act & Verify - simulate rejoin message from client\n\t\t\t\t\t\tprocessJoinSignals([rejoinAttendeeSignal]);\n\t\t\t\t\t});\n\n\t\t\t\t\tfor (const [status, setup] of [\n\t\t\t\t\t\t[AttendeeStatus.Connected, () => {}] as const,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\t\t() => runtime.removeMember(initialAttendeeConnectionId),\n\t\t\t\t\t\t] as const,\n\t\t\t\t\t]) {\n\t\t\t\t\t\tfor (const [desc, id] of [\n\t\t\t\t\t\t\t[\"connection id\", initialAttendeeConnectionId] as const,\n\t\t\t\t\t\t\t[\"session id\", attendeeSessionId] as const,\n\t\t\t\t\t\t]) {\n\t\t\t\t\t\t\tit(`with status \"${status}\" is available from \\`getAttendee\\` by ${desc}`, () => {\n\t\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\t\tsetup();\n\n\t\t\t\t\t\t\t\t// Act\n\t\t\t\t\t\t\t\tconst attendee = presence.attendees.getAttendee(id);\n\n\t\t\t\t\t\t\t\t// Verify\n\t\t\t\t\t\t\t\tassert.equal(attendee, knownAttendee, \"`getAttendee` returned wrong attendee\");\n\t\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\t\tattendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t\t\t\"`getAttendee` returned attendee with wrong status\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tit(`with status \"${status}\" is available from \\`getAttendees\\``, () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\t\t\t\t\t\t\tsetup();\n\n\t\t\t\t\t\t\t// Act\n\t\t\t\t\t\t\tconst attendees = presence.attendees.getAttendees();\n\t\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\t\tattendees.has(knownAttendee),\n\t\t\t\t\t\t\t\t\"`getAttendees` set does not contain attendee\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tstatus,\n\t\t\t\t\t\t\t\t\"`getAttendees` set contains attendee with wrong status\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// When local client disconnects, we lose the connectivity status updates for remote attendees in the session.\n\t\t\t\t\t// Upon reconnect, we mark all remote attendees connections as \"stale\".\n\t\t\t\t\t// Remote attendees with stale connections are given 30 seconds after local reconnection to prove they are connected\n\t\t\t\t\t// (e.g. being in audience, sending an update, or (re)joining the session) before their connection status set to \"Disconnected\".\n\t\t\t\t\t// If an attendee with a stale connection becomes active, their \"stale\" status is removed.\n\t\t\t\t\tdescribe(\"and then local client disconnects\", () => {\n\t\t\t\t\t\tlet remoteDisconnectedAttendees: Attendee[];\n\t\t\t\t\t\tbeforeEach(() => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\t\t\t\t\t\t\tremoteDisconnectedAttendees = [];\n\t\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeDisconnected\", (attendee) => {\n\t\t\t\t\t\t\t\t\tif (attendee !== presence.attendees.getMyself()) {\n\t\t\t\t\t\t\t\t\t\tremoteDisconnectedAttendees.push(attendee);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"updates status of attendee with stale connection after 30s delay upon local reconnection\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Act - disconnect & reconnect local client\n\t\t\t\t\t\t\truntime.disconnect(); // Simulate local client disconnect\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\t// Simulate remote client disconnect (while local is disconnected)\n\t\t\t\t\t\t\truntime.audience.removeMember(knownAttendee.getConnectionId());\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t); // Simulate local client reconnect with new connection id\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should still be 'Connected' after 15 seconds\n\t\t\t\t\t\t\tclock.tick(15_001);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection should still be 'Connected' after 15s\",\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should be 'Disconnected' after 30 seconds and announced via `attendeeDisconnected`\n\t\t\t\t\t\t\tclock.tick(15_001);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection should be 'Disconnected' 30s after reconnection\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tremoteDisconnectedAttendees.length,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"Exactly one attendee should be announced as disconnected\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"does not update status of attendee with stale connection if local client does not reconnect\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Act - disconnect local client and advance timer\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\tclock.tick(600_000);\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should still be 'Connected' if local client never reconnects\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection should still be 'Connected' after 30s\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"does not update status of attendee with stale connection if local client reconnection lasts less than 30s\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Act - disconnect, reconnect for 15 second, disconnect local client again, then advance timer\n\t\t\t\t\t\t\truntime.disconnect(); // First disconnect\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t); // Reconnect\n\t\t\t\t\t\t\tclock.tick(15_000); // Advance 15 seconds\n\t\t\t\t\t\t\truntime.disconnect(); // Disconnect again\n\t\t\t\t\t\t\tclock.tick(600_000); // Advance 10 minutes\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should still be 'Connected' if local client never reconnects for at least 30s\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection should still be 'Connected' after 30s\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"does not update status of attendee with stale connection if attendee rejoins\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Setup - fail if non-self attendee joined is announced\n\t\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\t\t\t\t\t// Self attendee will be announced on reconnect, which is expected\n\t\t\t\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\t\t\t\tattendee === presence.attendees.getMyself(),\n\t\t\t\t\t\t\t\t\t\t\"No `attendeeConnected` should be announced for rejoining attendee that's already 'Connected'\",\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Act - disconnect, reconnect, process rejoin signal from known attendee after 15s, then advance timer\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tclock.tick(15_000);\n\t\t\t\t\t\t\tprocessJoinSignals([rejoinAttendeeSignal]);\n\t\t\t\t\t\t\tclock.tick(600_000);\n\n\t\t\t\t\t\t\t// Verify - rejoining attendee should still be 'Connected' with no `attendeeConnected` announced\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Active attendee should still be 'Connected' 30s after reconnection\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"does not update status of attendee with stale connection if attendee sends datastore update\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Setup - fail if non-self attendee joined is announced\n\t\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\t\t\t\t\t// Self attendee will be announced on reconnect, which is expected\n\t\t\t\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\t\t\t\tattendee === presence.attendees.getMyself(),\n\t\t\t\t\t\t\t\t\t\t\"No `attendeeConnected` should be announced for active attendee that's already 'Connected'\",\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Act - disconnect, reconnect, process datatstore update signal from known attendee before 30s delay, then advance timer\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tclock.tick(15_000);\n\t\t\t\t\t\t\tprocessSignal(\n\t\t\t\t\t\t\t\t[],\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttype: \"Pres:DatastoreUpdate\",\n\t\t\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\t\tsendTimestamp: clock.now - 10,\n\t\t\t\t\t\t\t\t\t\tavgLatency: 20,\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\t\"system:presence\": {\n\t\t\t\t\t\t\t\t\t\t\t\tclientToSessionId:\n\t\t\t\t\t\t\t\t\t\t\t\t\tinitialAttendeeSignal.content.data[\"system:presence\"]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.clientToSessionId,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tclientId: initialAttendeeConnectionId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tclock.tick(600_000);\n\n\t\t\t\t\t\t\t// Verify - active attendee should still be 'Connected'\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Active attendee should still be 'Connected' 30s after reconnection\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"announces `attendeeDisconnected` once when remote client disconnects after local client reconnects\", () => {\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\t\t// Setup - initial attendee joins before local client disconnects\n\t\t\t\t\t\t\tprocessJoinSignals([initialAttendeeSignal]);\n\n\t\t\t\t\t\t\t// Act - disconnect, reconnect, remove remote client connection, then advance timer\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tclock.tick(15_001);\n\t\t\t\t\t\t\truntime.audience.removeMember(initialAttendeeConnectionId); // Remove remote client connection before 30s timeout\n\t\t\t\t\t\t\t// Confirm that `attendeeDisconnected` is announced for when active attendee disconnects\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tremoteDisconnectedAttendees.length,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"Exactly one attendee should be announced as disconnected\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tclock.tick(600_000);\n\n\t\t\t\t\t\t\t// Verify - active attendee status should be 'Disconnected' and no other `attendeeDisconnected` should be announced.\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\t\t\t\"Attendee should be 'Disconnected'\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tremoteDisconnectedAttendees.length,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"Exactly one attendee should be announced as disconnected\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit(\"updates status of attendee with stale connection only 30s after most recent local reconnection\", () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Known attendee is not connected\",\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Act - disconnect & reconnect local client multiple times with 15s delay\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\truntime.audience.removeMember(knownAttendee.getConnectionId()); // Simulate remote client disconnect (while local is disconnected)\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t\tinitialLocalClientConnectionId,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\tclock.tick(15_001);\n\n\t\t\t\t\t\t\truntime.disconnect();\n\t\t\t\t\t\t\tclock.tick(1000);\n\t\t\t\t\t\t\truntime.connect(\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId2,\n\t\t\t\t\t\t\t\trejoinedLocalClientConnectionId1,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should still be connected after 15 seconds\n\t\t\t\t\t\t\tclock.tick(15_001);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Connected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection should still be connected\",\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Verify - attendee with stale connection should be disconnected after 30 seconds\n\t\t\t\t\t\t\tclock.tick(15_001);\n\t\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\t\tknownAttendee.getConnectionStatus(),\n\t\t\t\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\t\t\t\"Attendee with stale connection has wrong status\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert.strictEqual(\n\t\t\t\t\t\t\t\tremoteDisconnectedAttendees.length,\n\t\t\t\t\t\t\t\t1,\n\t\t\t\t\t\t\t\t\"Exactly one attendee should be announced as disconnected\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\n\t\t\t\t\tdescribe(\"and has their connection removed\", () => {\n\t\t\t\t\t\tit(\"is announced via `attendeeDisconnected`\", () => {\n\t\t\t\t\t\t\t// Setup\n\t\t\t\t\t\t\tassert(knownAttendee !== undefined, \"No attendee was set in beforeEach\");\n\t\t\t\t\t\t\tlet disconnectedAttendee: Attendee | undefined;\n\t\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeDisconnected\", (attendee) => {\n\t\t\t\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\t\t\t\tdisconnectedAttendee === undefined,\n\t\t\t\t\t\t\t\t\t\t\"Only one attendee should be disconnected\",\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tdisconnectedAttendee = attendee;\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Act - remove client connection id\n\t\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\n\t\t\t\t\t\t\t// Verify\n\t\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\t\tdisconnectedAttendee !== undefined,\n\t\t\t\t\t\t\t\t\"No attendee was disconnected during `removeMember`\",\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tverifyAttendee(\n\t\t\t\t\t\t\t\tdisconnectedAttendee,\n\t\t\t\t\t\t\t\tinitialAttendeeConnectionId,\n\t\t\t\t\t\t\t\tattendeeSessionId,\n\t\t\t\t\t\t\t\tAttendeeStatus.Disconnected,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tit('is not announced via `attendeeDisconnected` when already \"Disconnected\"', () => {\n\t\t\t\t\t\t\t// Setup\n\n\t\t\t\t\t\t\tconst clientToDisconnect = runtime.audience.getMember(\n\t\t\t\t\t\t\t\tinitialAttendeeConnectionId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tassert(clientToDisconnect !== undefined, \"No client to disconnect\");\n\n\t\t\t\t\t\t\t// Remove client connection id\n\t\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\n\t\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeDisconnected\", (attendee) => {\n\t\t\t\t\t\t\t\t\tassert.fail(\n\t\t\t\t\t\t\t\t\t\t\"`attendeeDisconnected` should not be emitted for already disconnected attendee\",\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Act & Verify - fake event to remove client connection id again\n\t\t\t\t\t\t\truntime.audience.emit(\n\t\t\t\t\t\t\t\t\"removeMember\",\n\t\t\t\t\t\t\t\tinitialAttendeeConnectionId,\n\t\t\t\t\t\t\t\tclientToDisconnect,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tdescribe(\"that is rejoining\", () => {\n\t\t\t\t\tlet priorClientData: IClient;\n\t\t\t\t\tlet priorAttendee: Attendee | undefined;\n\t\t\t\t\tbeforeEach(() => {\n\t\t\t\t\t\tpriorClientData = verify(\n\t\t\t\t\t\t\truntime.getAudience().getMember(initialAttendeeConnectionId),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// Setup prior attendee\n\t\t\t\t\t\tconst joinedAttendees = processJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t\tassert(\n\t\t\t\t\t\t\tjoinedAttendees.length === 1 && joinedAttendees[0] !== undefined,\n\t\t\t\t\t\t\t\"Expected exactly one attendee to be announced\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tpriorAttendee = joinedAttendees[0];\n\n\t\t\t\t\t\t// Disconnect the attendee\n\t\t\t\t\t\truntime.removeMember(initialAttendeeConnectionId);\n\t\t\t\t\t});\n\n\t\t\t\t\tit(\"is NOT announced when rejoined with same connection (duplicate signal)\", () => {\n\t\t\t\t\t\t// Setup\n\t\t\t\t\t\tafterCleanUp.push(\n\t\t\t\t\t\t\tpresence.attendees.events.on(\"attendeeConnected\", (attendee) => {\n\t\t\t\t\t\t\t\tassert.fail(\n\t\t\t\t\t\t\t\t\t\"Attendee should not be announced when rejoining with same connection\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tclock.tick(10);\n\t\t\t\t\t\t// Act & Verify - simulate duplicate join message from client\n\t\t\t\t\t\tprocessJoinSignals([initialAttendeeSignal]);\n\t\t\t\t\t});\n\n\t\t\t\t\tit(\"is announced when rejoined with different connection and current information is updated\", () => {\n\t\t\t\t\t\t// Setup\n\t\t\t\t\t\tassert(priorAttendee !== undefined, \"No attendee was set in beforeEach\");\n\n\t\t\t\t\t\tclock.tick(20);\n\n\t\t\t\t\t\t// Act - add to audience and simulate new join message from same client (without disconnect)\n\t\t\t\t\t\truntime.audience.addMember(rejoinAttendeeConnectionId, priorClientData);\n\t\t\t\t\t\tprocessJoinSignals([rejoinAttendeeSignal]);\n\n\t\t\t\t\t\t// Verify - session id is unchanged and connection id is updated\n\t\t\t\t\t\tverifyAttendee(priorAttendee, rejoinAttendeeConnectionId, attendeeSessionId);\n\t\t\t\t\t\t// Attendee is available via new connection id\n\t\t\t\t\t\tconst attendeeViaUpdatedId = presence.attendees.getAttendee(\n\t\t\t\t\t\t\trejoinAttendeeConnectionId,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\tattendeeViaUpdatedId,\n\t\t\t\t\t\t\tpriorAttendee,\n\t\t\t\t\t\t\t\"getAttendee returned wrong attendee for updated connection id\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Attendee is available via old connection id\n\t\t\t\t\t\tconst attendeeViaOriginalId = presence.attendees.getAttendee(\n\t\t\t\t\t\t\tinitialAttendeeConnectionId,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tassert.equal(\n\t\t\t\t\t\t\tattendeeViaOriginalId,\n\t\t\t\t\t\t\tpriorAttendee,\n\t\t\t\t\t\t\t\"getAttendee returned wrong attendee for original connection id\",\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});\n\t});\n});\n"]}
|