@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,651 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*!
|
|
3
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
-
* Licensed under the MIT License.
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
const node_assert_1 = require("node:assert");
|
|
8
|
-
const presence_definitions_1 = require("@fluid-internal/presence-definitions");
|
|
9
|
-
const internal_1 = require("@fluidframework/test-utils/internal");
|
|
10
|
-
const sinon_1 = require("sinon");
|
|
11
|
-
const test_1 = require("@fluid-internal/presence-runtime/internal/test");
|
|
12
|
-
const test_utils_1 = require("@fluid-internal/presence-runtime/internal/test-utils");
|
|
13
|
-
const collateralSessionId = (0, test_utils_1.createSpecificAttendeeId)("collateral-id");
|
|
14
|
-
/**
|
|
15
|
-
* Mock {@link ClientConnectionId} for the local client after first reconnection.
|
|
16
|
-
*/
|
|
17
|
-
const rejoinedLocalClientConnectionId1 = "localClientRejoin1";
|
|
18
|
-
/**
|
|
19
|
-
* Mock {@link ClientConnectionId} for the local client after second reconnection.
|
|
20
|
-
*/
|
|
21
|
-
const rejoinedLocalClientConnectionId2 = "localClientRejoin2";
|
|
22
|
-
function verify(value, message) {
|
|
23
|
-
(0, node_assert_1.strict)(value !== undefined, message ?? "Expected value to be defined");
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
|
-
describe("Presence/Runtime", () => {
|
|
27
|
-
describe("PresenceManager", () => {
|
|
28
|
-
let runtime;
|
|
29
|
-
let logger;
|
|
30
|
-
const initialTime = 1000;
|
|
31
|
-
let clock;
|
|
32
|
-
before(async () => {
|
|
33
|
-
clock = (0, sinon_1.useFakeTimers)();
|
|
34
|
-
});
|
|
35
|
-
beforeEach(() => {
|
|
36
|
-
logger = new internal_1.EventAndErrorTrackingLogger();
|
|
37
|
-
runtime = new test_utils_1.MockEphemeralRuntime(logger);
|
|
38
|
-
clock.setSystemTime(initialTime);
|
|
39
|
-
});
|
|
40
|
-
afterEach(function (done) {
|
|
41
|
-
clock.reset();
|
|
42
|
-
// If the test passed so far, check final expectations.
|
|
43
|
-
if (this.currentTest?.state === "passed") {
|
|
44
|
-
(0, test_utils_1.assertFinalExpectations)(runtime, logger);
|
|
45
|
-
}
|
|
46
|
-
done();
|
|
47
|
-
});
|
|
48
|
-
after(() => {
|
|
49
|
-
clock.restore();
|
|
50
|
-
});
|
|
51
|
-
it("can be created", () => {
|
|
52
|
-
// Act & Verify (does not throw)
|
|
53
|
-
(0, test_1.createPresenceManager)(runtime);
|
|
54
|
-
});
|
|
55
|
-
it("creation logs initialization event", () => {
|
|
56
|
-
// Setup
|
|
57
|
-
logger.registerExpectedEvent({ eventName: "Presence:PresenceInstantiated" });
|
|
58
|
-
// Act
|
|
59
|
-
(0, test_1.createPresenceManager)(runtime);
|
|
60
|
-
// Verify
|
|
61
|
-
(0, test_utils_1.assertFinalExpectations)(runtime, logger);
|
|
62
|
-
});
|
|
63
|
-
it("throws when unknown attendee is requested via `getAttendee`", () => {
|
|
64
|
-
// Setup
|
|
65
|
-
const presence = (0, test_1.createPresenceManager)(runtime);
|
|
66
|
-
// Act & Verify
|
|
67
|
-
node_assert_1.strict.throws(() => presence.attendees.getAttendee("unknown"), /Attendee not found/);
|
|
68
|
-
});
|
|
69
|
-
describe("self attendee", () => {
|
|
70
|
-
it("is announced via `attendeeConnected` upon connect while self is in audience", () => {
|
|
71
|
-
// Setup - create presence in disconnected state
|
|
72
|
-
const { presence, connect } = (0, test_utils_1.prepareDisconnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger);
|
|
73
|
-
const connectedAttendees = [];
|
|
74
|
-
presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
75
|
-
connectedAttendees.push(attendee);
|
|
76
|
-
});
|
|
77
|
-
// Act - connect
|
|
78
|
-
connect();
|
|
79
|
-
// Verify - self attendee was announced
|
|
80
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
81
|
-
node_assert_1.strict.strictEqual(connectedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
82
|
-
node_assert_1.strict.strictEqual(connectedAttendees[0], selfAttendee, "Expected self attendee to be announced");
|
|
83
|
-
});
|
|
84
|
-
it('has status "Disconnected" when presence initializes while container is disconnected', () => {
|
|
85
|
-
// Setup - create presence while container is disconnected
|
|
86
|
-
const { presence } = (0, test_utils_1.prepareDisconnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger);
|
|
87
|
-
// Verify - self attendee has "Disconnected" status
|
|
88
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
89
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Self attendee should have status 'Disconnected' when presence initializes while container is disconnected");
|
|
90
|
-
});
|
|
91
|
-
it('has status "Disconnected" when runtime is connected but self is not yet in Audience', () => {
|
|
92
|
-
// Setup - set runtime to connected state but remove self from audience
|
|
93
|
-
runtime.clientId = test_utils_1.initialLocalClientConnectionId;
|
|
94
|
-
runtime.joined = true;
|
|
95
|
-
runtime.removeMember(test_utils_1.initialLocalClientConnectionId);
|
|
96
|
-
// Create presence - it will see runtime as connected but self not in audience
|
|
97
|
-
logger.registerExpectedEvent({ eventName: "Presence:PresenceInstantiated" });
|
|
98
|
-
const presence = (0, test_1.createPresenceManager)(runtime, test_utils_1.localAttendeeId);
|
|
99
|
-
// Verify - self attendee should have "Disconnected" status since
|
|
100
|
-
// we haven't received the ClientJoin signal yet
|
|
101
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
102
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Self attendee should have status 'Disconnected' when runtime is connected but self is not yet in Audience");
|
|
103
|
-
(0, test_utils_1.assertFinalExpectations)(runtime, logger);
|
|
104
|
-
});
|
|
105
|
-
it("is announced via `attendeeConnected` when added to Audience while runtime is connected", () => {
|
|
106
|
-
// Setup - set runtime to connected state but remove self from audience
|
|
107
|
-
runtime.clientId = test_utils_1.initialLocalClientConnectionId;
|
|
108
|
-
runtime.joined = true;
|
|
109
|
-
runtime.removeMember(test_utils_1.initialLocalClientConnectionId);
|
|
110
|
-
// Create presence - it will see runtime as connected but self not in audience
|
|
111
|
-
logger.registerExpectedEvent({ eventName: "Presence:PresenceInstantiated" });
|
|
112
|
-
const presence = (0, test_1.createPresenceManager)(runtime, test_utils_1.localAttendeeId);
|
|
113
|
-
// Verify initial state - self is Disconnected
|
|
114
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
115
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Self attendee should initially have status 'Disconnected'");
|
|
116
|
-
// Listen for attendeeConnected
|
|
117
|
-
const connectedAttendees = [];
|
|
118
|
-
presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
119
|
-
connectedAttendees.push(attendee);
|
|
120
|
-
});
|
|
121
|
-
// Expect join signal when self is added to audience while connected
|
|
122
|
-
const expectedJoin = (0, test_utils_1.generateBasicClientJoin)(clock.now, {
|
|
123
|
-
attendeeId: test_utils_1.localAttendeeId,
|
|
124
|
-
clientConnectionId: test_utils_1.initialLocalClientConnectionId,
|
|
125
|
-
updateProviders: ["client0", "client1", "client3"],
|
|
126
|
-
});
|
|
127
|
-
delete expectedJoin.clientId;
|
|
128
|
-
runtime.signalsExpected.push([expectedJoin]);
|
|
129
|
-
// Act - self added to audience
|
|
130
|
-
runtime.audience.addMember(test_utils_1.initialLocalClientConnectionId, {
|
|
131
|
-
mode: "write",
|
|
132
|
-
details: { capabilities: { interactive: true } },
|
|
133
|
-
permission: [],
|
|
134
|
-
user: { id: "test-user" },
|
|
135
|
-
scopes: [],
|
|
136
|
-
});
|
|
137
|
-
// Verify - attendeeConnected was raised for self with Connected status
|
|
138
|
-
node_assert_1.strict.strictEqual(connectedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
139
|
-
node_assert_1.strict.strictEqual(connectedAttendees[0], selfAttendee, "Expected self attendee to be announced");
|
|
140
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Self attendee should have status 'Connected' after being added to Audience");
|
|
141
|
-
(0, test_utils_1.assertFinalExpectations)(runtime, logger);
|
|
142
|
-
});
|
|
143
|
-
it('has status "Connected" when announced via `attendeeConnected`', () => {
|
|
144
|
-
// Setup - create presence in disconnected state
|
|
145
|
-
const { presence, connect } = (0, test_utils_1.prepareDisconnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger);
|
|
146
|
-
let attendeeConnectedRaised = false;
|
|
147
|
-
presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
148
|
-
if (attendee === presence.attendees.getMyself()) {
|
|
149
|
-
attendeeConnectedRaised = true;
|
|
150
|
-
node_assert_1.strict.strictEqual(attendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Self attendee should have status 'Connected' when announced");
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
// Act - connect
|
|
154
|
-
connect();
|
|
155
|
-
// Verify - attendeeConnected was raised
|
|
156
|
-
(0, node_assert_1.strict)(attendeeConnectedRaised, "attendeeConnected event should be raised for self attendee");
|
|
157
|
-
});
|
|
158
|
-
it("is announced via `attendeeDisconnected` when local client disconnects", () => {
|
|
159
|
-
// Setup - create presence in disconnected state and connect
|
|
160
|
-
const { presence, connect } = (0, test_utils_1.prepareDisconnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger);
|
|
161
|
-
connect();
|
|
162
|
-
const disconnectedAttendees = [];
|
|
163
|
-
presence.attendees.events.on("attendeeDisconnected", (attendee) => {
|
|
164
|
-
disconnectedAttendees.push(attendee);
|
|
165
|
-
});
|
|
166
|
-
// Act - disconnect
|
|
167
|
-
runtime.disconnect();
|
|
168
|
-
// Verify - self attendee was announced as disconnected
|
|
169
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
170
|
-
node_assert_1.strict.strictEqual(disconnectedAttendees.length, 1, "Expected exactly one attendee to be announced as disconnected");
|
|
171
|
-
node_assert_1.strict.strictEqual(disconnectedAttendees[0], selfAttendee, "Expected self attendee to be announced as disconnected");
|
|
172
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Self attendee should have status 'Disconnected' after disconnect");
|
|
173
|
-
});
|
|
174
|
-
it("is announced via `attendeeConnected` when local client reconnects", () => {
|
|
175
|
-
// Setup - create presence in disconnected state, connect and then disconnect
|
|
176
|
-
const { presence, connect } = (0, test_utils_1.prepareDisconnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger);
|
|
177
|
-
// Initial connection
|
|
178
|
-
connect();
|
|
179
|
-
// Disconnect
|
|
180
|
-
runtime.disconnect();
|
|
181
|
-
// Ignore submitted signals for reconnection
|
|
182
|
-
runtime.submitSignal = () => { };
|
|
183
|
-
const connectedAttendees = [];
|
|
184
|
-
presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
185
|
-
connectedAttendees.push(attendee);
|
|
186
|
-
});
|
|
187
|
-
// Act - reconnect with new connection id
|
|
188
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId);
|
|
189
|
-
// Verify - self attendee was announced
|
|
190
|
-
const selfAttendee = presence.attendees.getMyself();
|
|
191
|
-
node_assert_1.strict.strictEqual(connectedAttendees.length, 1, "Expected exactly one attendee to be announced on reconnect");
|
|
192
|
-
node_assert_1.strict.strictEqual(connectedAttendees[0], selfAttendee, "Expected self attendee to be announced on reconnect");
|
|
193
|
-
node_assert_1.strict.strictEqual(selfAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Self attendee should have status 'Connected' after reconnect");
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
describe("when connected", () => {
|
|
197
|
-
let presence;
|
|
198
|
-
let processSignal;
|
|
199
|
-
const afterCleanUp = [];
|
|
200
|
-
beforeEach(() => {
|
|
201
|
-
({ presence, processSignal } = (0, test_utils_1.prepareConnectedPresence)(runtime, test_utils_1.localAttendeeId, test_utils_1.initialLocalClientConnectionId, clock, logger));
|
|
202
|
-
});
|
|
203
|
-
afterEach(() => {
|
|
204
|
-
for (const cleanUp of afterCleanUp) {
|
|
205
|
-
cleanUp();
|
|
206
|
-
}
|
|
207
|
-
afterCleanUp.length = 0;
|
|
208
|
-
});
|
|
209
|
-
describe("attendee", () => {
|
|
210
|
-
const attendeeSessionId = "attendeeId-4";
|
|
211
|
-
const initialAttendeeConnectionId = "client4";
|
|
212
|
-
// Note: this connection id exists in the mock runtime audience since
|
|
213
|
-
// initialization, but should go unnoticed by the presence manager
|
|
214
|
-
// until there is a join signal related to it.
|
|
215
|
-
const rejoinAttendeeConnectionId = "client7";
|
|
216
|
-
let initialAttendeeSignal;
|
|
217
|
-
let rejoinAttendeeSignal;
|
|
218
|
-
// Processes join signals and returns the attendees that were announced via `attendeeConnected`
|
|
219
|
-
function processJoinSignals(signals) {
|
|
220
|
-
const joinedAttendees = [];
|
|
221
|
-
const cleanUpListener = presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
222
|
-
joinedAttendees.push(attendee);
|
|
223
|
-
});
|
|
224
|
-
for (const signal of signals) {
|
|
225
|
-
processSignal([], signal, false);
|
|
226
|
-
}
|
|
227
|
-
cleanUpListener();
|
|
228
|
-
return joinedAttendees;
|
|
229
|
-
}
|
|
230
|
-
function verifyAttendee(actualAttendee, expectedConnectionId, expectedSessionId, expectedConnectionStatus = presence_definitions_1.AttendeeStatus.Connected) {
|
|
231
|
-
node_assert_1.strict.equal(actualAttendee.attendeeId, expectedSessionId, "Attendee has wrong session id");
|
|
232
|
-
node_assert_1.strict.equal(actualAttendee.getConnectionId(), expectedConnectionId, "Attendee has wrong client connection id");
|
|
233
|
-
node_assert_1.strict.equal(actualAttendee.getConnectionStatus(), expectedConnectionStatus, `Attendee connection status is not ${expectedConnectionStatus}`);
|
|
234
|
-
}
|
|
235
|
-
beforeEach(() => {
|
|
236
|
-
// Ignore submitted signals
|
|
237
|
-
runtime.submitSignal = () => { };
|
|
238
|
-
initialAttendeeSignal = (0, test_utils_1.generateBasicClientJoin)(clock.now - 50, {
|
|
239
|
-
averageLatency: 50,
|
|
240
|
-
attendeeId: attendeeSessionId,
|
|
241
|
-
clientConnectionId: initialAttendeeConnectionId,
|
|
242
|
-
updateProviders: [test_utils_1.initialLocalClientConnectionId],
|
|
243
|
-
});
|
|
244
|
-
rejoinAttendeeSignal = (0, test_utils_1.generateBasicClientJoin)(clock.now - 20, {
|
|
245
|
-
averageLatency: 20,
|
|
246
|
-
attendeeId: attendeeSessionId, // Same session id
|
|
247
|
-
clientConnectionId: rejoinAttendeeConnectionId, // Different connection id
|
|
248
|
-
connectionOrder: 1,
|
|
249
|
-
updateProviders: [test_utils_1.initialLocalClientConnectionId],
|
|
250
|
-
priorClientToSessionId: initialAttendeeSignal.content.data["system:presence"].clientToSessionId,
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
it("is not announced via `attendeeDisconnected` when unknown connection is removed", () => {
|
|
254
|
-
// Setup
|
|
255
|
-
presence.attendees.events.on("attendeeDisconnected", () => {
|
|
256
|
-
node_assert_1.strict.fail("`attendeeDisconnected` should not be emitted for unknown connection.");
|
|
257
|
-
});
|
|
258
|
-
// Act & Verify - remove connection unknown to presence
|
|
259
|
-
runtime.removeMember("client5");
|
|
260
|
-
});
|
|
261
|
-
describe("that is joining", () => {
|
|
262
|
-
it('first time is announced via `attendeeConnected` with status "Connected"', () => {
|
|
263
|
-
// Act - simulate join message from client
|
|
264
|
-
const joinedAttendees = processJoinSignals([initialAttendeeSignal]);
|
|
265
|
-
// Verify
|
|
266
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
267
|
-
verifyAttendee(joinedAttendees[0], initialAttendeeConnectionId, attendeeSessionId);
|
|
268
|
-
});
|
|
269
|
-
it('second time is announced once via `attendeeConnected` with status "Connected" when prior is unknown', () => {
|
|
270
|
-
// Setup
|
|
271
|
-
const priorClientData = verify(runtime.getAudience().getMember(initialAttendeeConnectionId));
|
|
272
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
273
|
-
runtime.audience.addMember(rejoinAttendeeConnectionId, priorClientData);
|
|
274
|
-
// Act - simulate join message from client
|
|
275
|
-
const joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);
|
|
276
|
-
// Verify
|
|
277
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
278
|
-
verifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);
|
|
279
|
-
});
|
|
280
|
-
it('second time is announced once via `attendeeConnected` with status "Connected" when prior is still connected', () => {
|
|
281
|
-
const initialClientData = verify(runtime.getAudience().getMember(initialAttendeeConnectionId));
|
|
282
|
-
runtime.audience.addMember(rejoinAttendeeConnectionId, initialClientData);
|
|
283
|
-
// Act - simulate join message from client
|
|
284
|
-
const joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);
|
|
285
|
-
// Verify
|
|
286
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
287
|
-
verifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);
|
|
288
|
-
});
|
|
289
|
-
it('first time is announced via `attendeeConnected` with status "Connected" even if unknown to audience', () => {
|
|
290
|
-
// Setup - remove connection from audience
|
|
291
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
292
|
-
// Act - simulate join message from client
|
|
293
|
-
const joinedAttendees = processJoinSignals([initialAttendeeSignal]);
|
|
294
|
-
// Verify
|
|
295
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
296
|
-
verifyAttendee(joinedAttendees[0], initialAttendeeConnectionId, attendeeSessionId);
|
|
297
|
-
});
|
|
298
|
-
it('second time is announced once via `attendeeConnected` with status "Connected" even if most recent unknown to audience', () => {
|
|
299
|
-
// Setup - remove connection from audience
|
|
300
|
-
runtime.removeMember(rejoinAttendeeConnectionId);
|
|
301
|
-
// Act - simulate join message from client
|
|
302
|
-
const joinedAttendees = processJoinSignals([rejoinAttendeeSignal]);
|
|
303
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
304
|
-
verifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);
|
|
305
|
-
});
|
|
306
|
-
it("as collateral and disconnected is NOT announced via `attendeeConnected`", () => {
|
|
307
|
-
// Setup - remove connections from audience
|
|
308
|
-
const collateralAttendeeConnectionId = "client3";
|
|
309
|
-
const collateralAttendeeSignal = (0, test_utils_1.generateBasicClientJoin)(clock.now - 10, {
|
|
310
|
-
averageLatency: 40,
|
|
311
|
-
attendeeId: attendeeSessionId,
|
|
312
|
-
clientConnectionId: rejoinAttendeeConnectionId,
|
|
313
|
-
connectionOrder: 1,
|
|
314
|
-
updateProviders: [test_utils_1.initialLocalClientConnectionId],
|
|
315
|
-
priorClientToSessionId: {
|
|
316
|
-
...initialAttendeeSignal.content.data["system:presence"].clientToSessionId,
|
|
317
|
-
[collateralAttendeeConnectionId]: {
|
|
318
|
-
rev: 0,
|
|
319
|
-
timestamp: 0,
|
|
320
|
-
value: collateralSessionId,
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
});
|
|
324
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
325
|
-
runtime.removeMember(collateralAttendeeConnectionId);
|
|
326
|
-
// Act - simulate join message from client
|
|
327
|
-
const joinedAttendees = processJoinSignals([collateralAttendeeSignal]);
|
|
328
|
-
// Verify - only the rejoining attendee is announced
|
|
329
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
330
|
-
verifyAttendee(joinedAttendees[0], rejoinAttendeeConnectionId, attendeeSessionId);
|
|
331
|
-
});
|
|
332
|
-
it("as collateral with old connection info and connected is NOT announced via `attendeeConnected`", () => {
|
|
333
|
-
// Setup - generate signals
|
|
334
|
-
// Both connection Id's unknown to audience
|
|
335
|
-
const oldAttendeeConnectionId = "client9";
|
|
336
|
-
const newAttendeeConnectionId = "client10";
|
|
337
|
-
// Rejoin signal for the collateral attendee unknown to audience
|
|
338
|
-
const rejoinSignal = (0, test_utils_1.generateBasicClientJoin)(clock.now - 10, {
|
|
339
|
-
averageLatency: 40,
|
|
340
|
-
attendeeId: collateralSessionId,
|
|
341
|
-
clientConnectionId: newAttendeeConnectionId,
|
|
342
|
-
updateProviders: [initialAttendeeConnectionId],
|
|
343
|
-
connectionOrder: 1,
|
|
344
|
-
priorClientToSessionId: {
|
|
345
|
-
[oldAttendeeConnectionId]: {
|
|
346
|
-
rev: 0,
|
|
347
|
-
timestamp: 0,
|
|
348
|
-
value: collateralSessionId,
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
});
|
|
352
|
-
// Response signal sent by the initial attendee responding to the collateral attendees rejoin signal
|
|
353
|
-
const responseSignal = (0, test_utils_1.generateBasicClientJoin)(clock.now - 5, {
|
|
354
|
-
averageLatency: 20,
|
|
355
|
-
attendeeId: attendeeSessionId,
|
|
356
|
-
clientConnectionId: initialAttendeeConnectionId,
|
|
357
|
-
priorClientToSessionId: {
|
|
358
|
-
...initialAttendeeSignal.content.data["system:presence"].clientToSessionId,
|
|
359
|
-
// Old connection id of rejoining attendee
|
|
360
|
-
// This should be ignored by local client
|
|
361
|
-
[oldAttendeeConnectionId]: {
|
|
362
|
-
rev: 0,
|
|
363
|
-
timestamp: 0,
|
|
364
|
-
value: collateralSessionId,
|
|
365
|
-
},
|
|
366
|
-
},
|
|
367
|
-
});
|
|
368
|
-
// Process initial join signal so initial attendee is known
|
|
369
|
-
const joinedAttendees = processJoinSignals([initialAttendeeSignal]);
|
|
370
|
-
node_assert_1.strict.strictEqual(joinedAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
371
|
-
// Simulate rejoin message from remote client
|
|
372
|
-
const rejoinAttendees = processJoinSignals([rejoinSignal]);
|
|
373
|
-
// Confirm that rejoining attendee is announced so we can verify it remains the same after response
|
|
374
|
-
node_assert_1.strict.strictEqual(rejoinAttendees.length, 1, "Expected exactly one attendee to be announced");
|
|
375
|
-
// Act - simulate response message from remote client
|
|
376
|
-
const responseAttendees = processJoinSignals([responseSignal]);
|
|
377
|
-
// Verify - No collateral attendee should be announced by response signal and rejoined attendee information should remain unchanged
|
|
378
|
-
node_assert_1.strict.strictEqual(responseAttendees.length, 0, "Expected no attendees to be announced");
|
|
379
|
-
// Check attendee information remains unchanged
|
|
380
|
-
verifyAttendee(rejoinAttendees[0], newAttendeeConnectionId, collateralSessionId);
|
|
381
|
-
});
|
|
382
|
-
});
|
|
383
|
-
describe("that is already known", () => {
|
|
384
|
-
let knownAttendee;
|
|
385
|
-
beforeEach(() => {
|
|
386
|
-
// Setup known attendee
|
|
387
|
-
const joinedAttendees = processJoinSignals([initialAttendeeSignal]);
|
|
388
|
-
(0, node_assert_1.strict)(joinedAttendees.length === 1, "Expected exactly one attendee to be announced");
|
|
389
|
-
knownAttendee = joinedAttendees[0];
|
|
390
|
-
});
|
|
391
|
-
it('is NOT announced when "rejoined" with same connection (duplicate signal)', () => {
|
|
392
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
393
|
-
node_assert_1.strict.fail("Attendee should not be announced when rejoining with same connection");
|
|
394
|
-
}));
|
|
395
|
-
clock.tick(10);
|
|
396
|
-
// Act & Verify - simulate duplicate join message from client
|
|
397
|
-
processJoinSignals([initialAttendeeSignal]);
|
|
398
|
-
});
|
|
399
|
-
// To retain symmetry across Joined and Disconnected events, do not announce
|
|
400
|
-
// attendeeConnected when the attendee is already connected and we only see
|
|
401
|
-
// a connection id update. This can happen when audience removal is late.
|
|
402
|
-
it('is not announced via `attendeeConnected` when already "Connected"', () => {
|
|
403
|
-
// Setup
|
|
404
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeConnected", () => {
|
|
405
|
-
node_assert_1.strict.fail("No attendee should be announced in join processing");
|
|
406
|
-
}));
|
|
407
|
-
// Act & Verify - simulate rejoin message from client
|
|
408
|
-
processJoinSignals([rejoinAttendeeSignal]);
|
|
409
|
-
});
|
|
410
|
-
for (const [status, setup] of [
|
|
411
|
-
[presence_definitions_1.AttendeeStatus.Connected, () => { }],
|
|
412
|
-
[
|
|
413
|
-
presence_definitions_1.AttendeeStatus.Disconnected,
|
|
414
|
-
() => runtime.removeMember(initialAttendeeConnectionId),
|
|
415
|
-
],
|
|
416
|
-
]) {
|
|
417
|
-
for (const [desc, id] of [
|
|
418
|
-
["connection id", initialAttendeeConnectionId],
|
|
419
|
-
["session id", attendeeSessionId],
|
|
420
|
-
]) {
|
|
421
|
-
it(`with status "${status}" is available from \`getAttendee\` by ${desc}`, () => {
|
|
422
|
-
// Setup
|
|
423
|
-
setup();
|
|
424
|
-
// Act
|
|
425
|
-
const attendee = presence.attendees.getAttendee(id);
|
|
426
|
-
// Verify
|
|
427
|
-
node_assert_1.strict.equal(attendee, knownAttendee, "`getAttendee` returned wrong attendee");
|
|
428
|
-
node_assert_1.strict.equal(attendee.getConnectionStatus(), status, "`getAttendee` returned attendee with wrong status");
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
it(`with status "${status}" is available from \`getAttendees\``, () => {
|
|
432
|
-
// Setup
|
|
433
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
434
|
-
setup();
|
|
435
|
-
// Act
|
|
436
|
-
const attendees = presence.attendees.getAttendees();
|
|
437
|
-
(0, node_assert_1.strict)(attendees.has(knownAttendee), "`getAttendees` set does not contain attendee");
|
|
438
|
-
node_assert_1.strict.equal(knownAttendee.getConnectionStatus(), status, "`getAttendees` set contains attendee with wrong status");
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
// When local client disconnects, we lose the connectivity status updates for remote attendees in the session.
|
|
442
|
-
// Upon reconnect, we mark all remote attendees connections as "stale".
|
|
443
|
-
// Remote attendees with stale connections are given 30 seconds after local reconnection to prove they are connected
|
|
444
|
-
// (e.g. being in audience, sending an update, or (re)joining the session) before their connection status set to "Disconnected".
|
|
445
|
-
// If an attendee with a stale connection becomes active, their "stale" status is removed.
|
|
446
|
-
describe("and then local client disconnects", () => {
|
|
447
|
-
let remoteDisconnectedAttendees;
|
|
448
|
-
beforeEach(() => {
|
|
449
|
-
// Setup
|
|
450
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
451
|
-
remoteDisconnectedAttendees = [];
|
|
452
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeDisconnected", (attendee) => {
|
|
453
|
-
if (attendee !== presence.attendees.getMyself()) {
|
|
454
|
-
remoteDisconnectedAttendees.push(attendee);
|
|
455
|
-
}
|
|
456
|
-
}));
|
|
457
|
-
});
|
|
458
|
-
it("updates status of attendee with stale connection after 30s delay upon local reconnection", () => {
|
|
459
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
460
|
-
// Act - disconnect & reconnect local client
|
|
461
|
-
runtime.disconnect(); // Simulate local client disconnect
|
|
462
|
-
clock.tick(1000);
|
|
463
|
-
// Simulate remote client disconnect (while local is disconnected)
|
|
464
|
-
runtime.audience.removeMember(knownAttendee.getConnectionId());
|
|
465
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId); // Simulate local client reconnect with new connection id
|
|
466
|
-
// Verify - attendee with stale connection should still be 'Connected' after 15 seconds
|
|
467
|
-
clock.tick(15_001);
|
|
468
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Attendee with stale connection should still be 'Connected' after 15s");
|
|
469
|
-
// Verify - attendee with stale connection should be 'Disconnected' after 30 seconds and announced via `attendeeDisconnected`
|
|
470
|
-
clock.tick(15_001);
|
|
471
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Attendee with stale connection should be 'Disconnected' 30s after reconnection");
|
|
472
|
-
node_assert_1.strict.strictEqual(remoteDisconnectedAttendees.length, 1, "Exactly one attendee should be announced as disconnected");
|
|
473
|
-
});
|
|
474
|
-
it("does not update status of attendee with stale connection if local client does not reconnect", () => {
|
|
475
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
476
|
-
// Act - disconnect local client and advance timer
|
|
477
|
-
runtime.disconnect();
|
|
478
|
-
clock.tick(600_000);
|
|
479
|
-
// Verify - attendee with stale connection should still be 'Connected' if local client never reconnects
|
|
480
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Attendee with stale connection should still be 'Connected' after 30s");
|
|
481
|
-
});
|
|
482
|
-
it("does not update status of attendee with stale connection if local client reconnection lasts less than 30s", () => {
|
|
483
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
484
|
-
// Act - disconnect, reconnect for 15 second, disconnect local client again, then advance timer
|
|
485
|
-
runtime.disconnect(); // First disconnect
|
|
486
|
-
clock.tick(1000);
|
|
487
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId); // Reconnect
|
|
488
|
-
clock.tick(15_000); // Advance 15 seconds
|
|
489
|
-
runtime.disconnect(); // Disconnect again
|
|
490
|
-
clock.tick(600_000); // Advance 10 minutes
|
|
491
|
-
// Verify - attendee with stale connection should still be 'Connected' if local client never reconnects for at least 30s
|
|
492
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Attendee with stale connection should still be 'Connected' after 30s");
|
|
493
|
-
});
|
|
494
|
-
it("does not update status of attendee with stale connection if attendee rejoins", () => {
|
|
495
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
496
|
-
// Setup - fail if non-self attendee joined is announced
|
|
497
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
498
|
-
// Self attendee will be announced on reconnect, which is expected
|
|
499
|
-
(0, node_assert_1.strict)(attendee === presence.attendees.getMyself(), "No `attendeeConnected` should be announced for rejoining attendee that's already 'Connected'");
|
|
500
|
-
}));
|
|
501
|
-
// Act - disconnect, reconnect, process rejoin signal from known attendee after 15s, then advance timer
|
|
502
|
-
runtime.disconnect();
|
|
503
|
-
clock.tick(1000);
|
|
504
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId);
|
|
505
|
-
clock.tick(15_000);
|
|
506
|
-
processJoinSignals([rejoinAttendeeSignal]);
|
|
507
|
-
clock.tick(600_000);
|
|
508
|
-
// Verify - rejoining attendee should still be 'Connected' with no `attendeeConnected` announced
|
|
509
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Active attendee should still be 'Connected' 30s after reconnection");
|
|
510
|
-
});
|
|
511
|
-
it("does not update status of attendee with stale connection if attendee sends datastore update", () => {
|
|
512
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
513
|
-
// Setup - fail if non-self attendee joined is announced
|
|
514
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
515
|
-
// Self attendee will be announced on reconnect, which is expected
|
|
516
|
-
(0, node_assert_1.strict)(attendee === presence.attendees.getMyself(), "No `attendeeConnected` should be announced for active attendee that's already 'Connected'");
|
|
517
|
-
}));
|
|
518
|
-
// Act - disconnect, reconnect, process datatstore update signal from known attendee before 30s delay, then advance timer
|
|
519
|
-
runtime.disconnect();
|
|
520
|
-
clock.tick(1000);
|
|
521
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId);
|
|
522
|
-
clock.tick(15_000);
|
|
523
|
-
processSignal([], {
|
|
524
|
-
type: "Pres:DatastoreUpdate",
|
|
525
|
-
content: {
|
|
526
|
-
sendTimestamp: clock.now - 10,
|
|
527
|
-
avgLatency: 20,
|
|
528
|
-
data: {
|
|
529
|
-
"system:presence": {
|
|
530
|
-
clientToSessionId: initialAttendeeSignal.content.data["system:presence"]
|
|
531
|
-
.clientToSessionId,
|
|
532
|
-
},
|
|
533
|
-
},
|
|
534
|
-
},
|
|
535
|
-
clientId: initialAttendeeConnectionId,
|
|
536
|
-
}, false);
|
|
537
|
-
clock.tick(600_000);
|
|
538
|
-
// Verify - active attendee should still be 'Connected'
|
|
539
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Active attendee should still be 'Connected' 30s after reconnection");
|
|
540
|
-
});
|
|
541
|
-
it("announces `attendeeDisconnected` once when remote client disconnects after local client reconnects", () => {
|
|
542
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
543
|
-
// Setup - initial attendee joins before local client disconnects
|
|
544
|
-
processJoinSignals([initialAttendeeSignal]);
|
|
545
|
-
// Act - disconnect, reconnect, remove remote client connection, then advance timer
|
|
546
|
-
runtime.disconnect();
|
|
547
|
-
clock.tick(1000);
|
|
548
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId);
|
|
549
|
-
clock.tick(15_001);
|
|
550
|
-
runtime.audience.removeMember(initialAttendeeConnectionId); // Remove remote client connection before 30s timeout
|
|
551
|
-
// Confirm that `attendeeDisconnected` is announced for when active attendee disconnects
|
|
552
|
-
node_assert_1.strict.strictEqual(remoteDisconnectedAttendees.length, 1, "Exactly one attendee should be announced as disconnected");
|
|
553
|
-
clock.tick(600_000);
|
|
554
|
-
// Verify - active attendee status should be 'Disconnected' and no other `attendeeDisconnected` should be announced.
|
|
555
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Attendee should be 'Disconnected'");
|
|
556
|
-
node_assert_1.strict.strictEqual(remoteDisconnectedAttendees.length, 1, "Exactly one attendee should be announced as disconnected");
|
|
557
|
-
});
|
|
558
|
-
it("updates status of attendee with stale connection only 30s after most recent local reconnection", () => {
|
|
559
|
-
// Setup
|
|
560
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
561
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Known attendee is not connected");
|
|
562
|
-
// Act - disconnect & reconnect local client multiple times with 15s delay
|
|
563
|
-
runtime.disconnect();
|
|
564
|
-
runtime.audience.removeMember(knownAttendee.getConnectionId()); // Simulate remote client disconnect (while local is disconnected)
|
|
565
|
-
clock.tick(1000);
|
|
566
|
-
runtime.connect(rejoinedLocalClientConnectionId1, test_utils_1.initialLocalClientConnectionId);
|
|
567
|
-
clock.tick(15_001);
|
|
568
|
-
runtime.disconnect();
|
|
569
|
-
clock.tick(1000);
|
|
570
|
-
runtime.connect(rejoinedLocalClientConnectionId2, rejoinedLocalClientConnectionId1);
|
|
571
|
-
// Verify - attendee with stale connection should still be connected after 15 seconds
|
|
572
|
-
clock.tick(15_001);
|
|
573
|
-
node_assert_1.strict.strictEqual(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Connected, "Attendee with stale connection should still be connected");
|
|
574
|
-
// Verify - attendee with stale connection should be disconnected after 30 seconds
|
|
575
|
-
clock.tick(15_001);
|
|
576
|
-
node_assert_1.strict.equal(knownAttendee.getConnectionStatus(), presence_definitions_1.AttendeeStatus.Disconnected, "Attendee with stale connection has wrong status");
|
|
577
|
-
node_assert_1.strict.strictEqual(remoteDisconnectedAttendees.length, 1, "Exactly one attendee should be announced as disconnected");
|
|
578
|
-
});
|
|
579
|
-
});
|
|
580
|
-
describe("and has their connection removed", () => {
|
|
581
|
-
it("is announced via `attendeeDisconnected`", () => {
|
|
582
|
-
// Setup
|
|
583
|
-
(0, node_assert_1.strict)(knownAttendee !== undefined, "No attendee was set in beforeEach");
|
|
584
|
-
let disconnectedAttendee;
|
|
585
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeDisconnected", (attendee) => {
|
|
586
|
-
(0, node_assert_1.strict)(disconnectedAttendee === undefined, "Only one attendee should be disconnected");
|
|
587
|
-
disconnectedAttendee = attendee;
|
|
588
|
-
}));
|
|
589
|
-
// Act - remove client connection id
|
|
590
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
591
|
-
// Verify
|
|
592
|
-
(0, node_assert_1.strict)(disconnectedAttendee !== undefined, "No attendee was disconnected during `removeMember`");
|
|
593
|
-
verifyAttendee(disconnectedAttendee, initialAttendeeConnectionId, attendeeSessionId, presence_definitions_1.AttendeeStatus.Disconnected);
|
|
594
|
-
});
|
|
595
|
-
it('is not announced via `attendeeDisconnected` when already "Disconnected"', () => {
|
|
596
|
-
// Setup
|
|
597
|
-
const clientToDisconnect = runtime.audience.getMember(initialAttendeeConnectionId);
|
|
598
|
-
(0, node_assert_1.strict)(clientToDisconnect !== undefined, "No client to disconnect");
|
|
599
|
-
// Remove client connection id
|
|
600
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
601
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeDisconnected", (attendee) => {
|
|
602
|
-
node_assert_1.strict.fail("`attendeeDisconnected` should not be emitted for already disconnected attendee");
|
|
603
|
-
}));
|
|
604
|
-
// Act & Verify - fake event to remove client connection id again
|
|
605
|
-
runtime.audience.emit("removeMember", initialAttendeeConnectionId, clientToDisconnect);
|
|
606
|
-
});
|
|
607
|
-
});
|
|
608
|
-
});
|
|
609
|
-
describe("that is rejoining", () => {
|
|
610
|
-
let priorClientData;
|
|
611
|
-
let priorAttendee;
|
|
612
|
-
beforeEach(() => {
|
|
613
|
-
priorClientData = verify(runtime.getAudience().getMember(initialAttendeeConnectionId));
|
|
614
|
-
// Setup prior attendee
|
|
615
|
-
const joinedAttendees = processJoinSignals([initialAttendeeSignal]);
|
|
616
|
-
(0, node_assert_1.strict)(joinedAttendees.length === 1 && joinedAttendees[0] !== undefined, "Expected exactly one attendee to be announced");
|
|
617
|
-
priorAttendee = joinedAttendees[0];
|
|
618
|
-
// Disconnect the attendee
|
|
619
|
-
runtime.removeMember(initialAttendeeConnectionId);
|
|
620
|
-
});
|
|
621
|
-
it("is NOT announced when rejoined with same connection (duplicate signal)", () => {
|
|
622
|
-
// Setup
|
|
623
|
-
afterCleanUp.push(presence.attendees.events.on("attendeeConnected", (attendee) => {
|
|
624
|
-
node_assert_1.strict.fail("Attendee should not be announced when rejoining with same connection");
|
|
625
|
-
}));
|
|
626
|
-
clock.tick(10);
|
|
627
|
-
// Act & Verify - simulate duplicate join message from client
|
|
628
|
-
processJoinSignals([initialAttendeeSignal]);
|
|
629
|
-
});
|
|
630
|
-
it("is announced when rejoined with different connection and current information is updated", () => {
|
|
631
|
-
// Setup
|
|
632
|
-
(0, node_assert_1.strict)(priorAttendee !== undefined, "No attendee was set in beforeEach");
|
|
633
|
-
clock.tick(20);
|
|
634
|
-
// Act - add to audience and simulate new join message from same client (without disconnect)
|
|
635
|
-
runtime.audience.addMember(rejoinAttendeeConnectionId, priorClientData);
|
|
636
|
-
processJoinSignals([rejoinAttendeeSignal]);
|
|
637
|
-
// Verify - session id is unchanged and connection id is updated
|
|
638
|
-
verifyAttendee(priorAttendee, rejoinAttendeeConnectionId, attendeeSessionId);
|
|
639
|
-
// Attendee is available via new connection id
|
|
640
|
-
const attendeeViaUpdatedId = presence.attendees.getAttendee(rejoinAttendeeConnectionId);
|
|
641
|
-
node_assert_1.strict.equal(attendeeViaUpdatedId, priorAttendee, "getAttendee returned wrong attendee for updated connection id");
|
|
642
|
-
// Attendee is available via old connection id
|
|
643
|
-
const attendeeViaOriginalId = presence.attendees.getAttendee(initialAttendeeConnectionId);
|
|
644
|
-
node_assert_1.strict.equal(attendeeViaOriginalId, priorAttendee, "getAttendee returned wrong attendee for original connection id");
|
|
645
|
-
});
|
|
646
|
-
});
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
});
|
|
650
|
-
});
|
|
651
|
-
//# sourceMappingURL=presenceManager.spec.js.map
|