@webex/internal-plugin-metrics 3.11.0 → 3.12.0-llmrefactor.2

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.
Files changed (74) hide show
  1. package/dist/automated-user.js +19 -0
  2. package/dist/automated-user.js.map +1 -0
  3. package/dist/batcher.js +3 -0
  4. package/dist/batcher.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +639 -65
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +168 -76
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +18 -4
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  11. package/dist/call-diagnostic/config.js +17 -3
  12. package/dist/call-diagnostic/config.js.map +1 -1
  13. package/dist/config.js +1 -0
  14. package/dist/config.js.map +1 -1
  15. package/dist/generic-metrics.js +8 -6
  16. package/dist/generic-metrics.js.map +1 -1
  17. package/dist/index.js +22 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/metrics.js +1 -1
  20. package/dist/metrics.types.js +4 -0
  21. package/dist/metrics.types.js.map +1 -1
  22. package/dist/new-metrics.js +105 -26
  23. package/dist/new-metrics.js.map +1 -1
  24. package/dist/prelogin-metrics.js +106 -0
  25. package/dist/prelogin-metrics.js.map +1 -0
  26. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  27. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  28. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  29. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  30. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  31. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  32. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  33. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  34. package/dist/types/automated-user.d.ts +2 -0
  35. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  36. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +79 -15
  37. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +5 -0
  38. package/dist/types/call-diagnostic/config.d.ts +5 -0
  39. package/dist/types/config.d.ts +1 -0
  40. package/dist/types/index.d.ts +6 -3
  41. package/dist/types/metrics.types.d.ts +9 -4
  42. package/dist/types/new-metrics.d.ts +29 -1
  43. package/dist/types/prelogin-metrics.d.ts +47 -0
  44. package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
  45. package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
  46. package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
  47. package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
  48. package/package.json +12 -11
  49. package/src/automated-user.ts +16 -0
  50. package/src/batcher.js +4 -0
  51. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -75
  52. package/src/call-diagnostic/call-diagnostic-metrics.ts +102 -15
  53. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +22 -2
  54. package/src/call-diagnostic/config.ts +15 -0
  55. package/src/config.js +1 -0
  56. package/src/generic-metrics.ts +6 -6
  57. package/src/index.ts +9 -0
  58. package/src/metrics.types.ts +27 -5
  59. package/src/new-metrics.ts +95 -6
  60. package/src/prelogin-metrics.ts +94 -0
  61. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  62. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  63. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  64. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  65. package/test/unit/spec/automated-user.ts +43 -0
  66. package/test/unit/spec/batcher.js +43 -0
  67. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +47 -11
  68. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1550 -416
  69. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +887 -159
  70. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +61 -3
  71. package/test/unit/spec/new-metrics.ts +183 -50
  72. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  73. package/test/unit/spec/prelogin-metrics.ts +132 -0
  74. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
@@ -5,11 +5,12 @@ import sinon from 'sinon';
5
5
  describe('internal-plugin-metrics', () => {
6
6
  describe('CallDiagnosticLatencies', () => {
7
7
  let cdl: CallDiagnosticLatencies;
8
+ let clock: ReturnType<typeof sinon.useFakeTimers>;
8
9
  var now = new Date();
9
10
 
10
11
  beforeEach(() => {
11
12
  sinon.createSandbox();
12
- sinon.useFakeTimers(now.getTime());
13
+ clock = sinon.useFakeTimers(now.getTime());
13
14
  const webex = {
14
15
  meetings: {
15
16
  getBasicMeetingInformation: (id: string) => {
@@ -51,17 +52,17 @@ describe('internal-plugin-metrics', () => {
51
52
 
52
53
  it('should overwrite latency when accumulate is false', () => {
53
54
  assert.deepEqual(cdl.precomputedLatencies.size, 0);
54
- cdl.saveLatency('internal.client.pageJMT', 10, false);
55
+ cdl.saveLatency('internal.client.pageJMT', 10, {accumulate: false});
55
56
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
56
57
  assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
57
- cdl.saveLatency('internal.client.pageJMT', 20, false);
58
+ cdl.saveLatency('internal.client.pageJMT', 20, {accumulate: false});
58
59
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
59
60
  assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
60
61
  });
61
62
 
62
63
  it('should save latency correctly when accumulate is true', () => {
63
64
  assert.deepEqual(cdl.precomputedLatencies.size, 0);
64
- cdl.saveLatency('internal.client.pageJMT', 10, true);
65
+ cdl.saveLatency('internal.client.pageJMT', 10, {accumulate: true});
65
66
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
66
67
  assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
67
68
  });
@@ -71,11 +72,31 @@ describe('internal-plugin-metrics', () => {
71
72
  cdl.saveLatency('internal.client.pageJMT', 10);
72
73
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
73
74
  assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 10);
74
- cdl.saveLatency('internal.client.pageJMT', 10, true);
75
+ cdl.saveLatency('internal.client.pageJMT', 10, {accumulate: true});
75
76
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
76
77
  assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 20);
77
78
  });
78
79
 
80
+ it('accumulates when accumulate is passed as the legacy boolean argument', () => {
81
+ assert.deepEqual(cdl.precomputedLatencies.size, 0);
82
+ // @ts-ignore - legacy boolean third argument from older (untyped) SDK/plugin consumers
83
+ cdl.saveLatency('internal.client.pageJMT', 10, true);
84
+ // @ts-ignore - legacy boolean third argument from older (untyped) SDK/plugin consumers
85
+ cdl.saveLatency('internal.client.pageJMT', 15, true);
86
+ assert.deepEqual(cdl.precomputedLatencies.size, 1);
87
+ assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 25);
88
+ });
89
+
90
+ it('overwrites when the legacy boolean argument is false', () => {
91
+ assert.deepEqual(cdl.precomputedLatencies.size, 0);
92
+ // @ts-ignore - legacy boolean third argument from older (untyped) SDK/plugin consumers
93
+ cdl.saveLatency('internal.client.pageJMT', 10, false);
94
+ // @ts-ignore - legacy boolean third argument from older (untyped) SDK/plugin consumers
95
+ cdl.saveLatency('internal.client.pageJMT', 15, false);
96
+ assert.deepEqual(cdl.precomputedLatencies.size, 1);
97
+ assert.deepEqual(cdl.precomputedLatencies.get('internal.client.pageJMT'), 15);
98
+ });
99
+
79
100
  it('should save only first timestamp correctly', () => {
80
101
  assert.deepEqual(cdl.latencyTimestamps.size, 0);
81
102
  cdl.saveFirstTimestampOnly('client.alert.displayed', 10);
@@ -108,11 +129,1174 @@ describe('internal-plugin-metrics', () => {
108
129
  assert.deepEqual(cdl.latencyTimestamps.size, 2);
109
130
  cdl.saveLatency('internal.api.fetch.intelligence.models', 42);
110
131
  assert.deepEqual(cdl.precomputedLatencies.size, 1);
132
+ cdl.saveTimestamp({
133
+ key: 'internal.client.locus.sync.start',
134
+ value: 1,
135
+ options: {
136
+ meetingId: 'meeting-1',
137
+ dataSetName: 'main',
138
+ randomBackoffTime: 10,
139
+ trackingId: 'sync-tracking-id',
140
+ },
141
+ });
142
+ assert.deepEqual(cdl.meetingLatencies.size, 1);
111
143
 
112
144
  cdl.clearTimestamps();
113
145
 
114
146
  assert.deepEqual(cdl.latencyTimestamps.size, 0);
115
147
  assert.deepEqual(cdl.precomputedLatencies.size, 0);
148
+ assert.deepEqual(cdl.meetingLatencies.size, 0);
149
+ });
150
+
151
+ describe('locus sync latencies', () => {
152
+ it('uses pending sync backoff latency when sync starts', () => {
153
+ cdl.saveLatency('internal.client.locus.sync.random.backoff', 10.4, {
154
+ meetingId: 'meeting-1',
155
+ dataSetName: 'main',
156
+ });
157
+ cdl.saveTimestamp({
158
+ key: 'internal.client.locus.sync.start',
159
+ value: 100,
160
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
161
+ });
162
+ cdl.saveTimestamp({
163
+ key: 'internal.client.locus.sync.request',
164
+ value: 110,
165
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
166
+ });
167
+ cdl.saveTimestamp({
168
+ key: 'internal.client.locus.sync.response',
169
+ value: 130,
170
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
171
+ });
172
+ cdl.saveTimestamp({
173
+ key: 'internal.client.locus.sync.message.received',
174
+ value: 140,
175
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
176
+ });
177
+
178
+ assert.deepEqual(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-id'), {
179
+ randomBackoffTime: 10,
180
+ hashtreePrepTime: 0,
181
+ hashtreeResponseTime: 0,
182
+ syncPrepTime: 10,
183
+ syncResponseTime: 20,
184
+ syncMessageReceiveTime: 30,
185
+ totalTime: 40,
186
+ });
187
+ });
188
+
189
+ it('calculates sync latency values from milestones', () => {
190
+ cdl.saveLatency('internal.client.locus.sync.random.backoff', 10.4, {
191
+ meetingId: 'meeting-1',
192
+ dataSetName: 'main',
193
+ });
194
+ cdl.saveTimestamp({
195
+ key: 'internal.client.locus.sync.start',
196
+ value: 100,
197
+ options: {
198
+ meetingId: 'meeting-1',
199
+ dataSetName: 'main',
200
+ trackingId: 'sync-tracking-id',
201
+ },
202
+ });
203
+ cdl.saveTimestamp({
204
+ key: 'internal.client.locus.hashtree.request',
205
+ value: 105,
206
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
207
+ });
208
+ cdl.saveTimestamp({
209
+ key: 'internal.client.locus.hashtree.response',
210
+ value: 125,
211
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
212
+ });
213
+ cdl.saveTimestamp({
214
+ key: 'internal.client.locus.sync.request',
215
+ value: 128,
216
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
217
+ });
218
+ cdl.saveTimestamp({
219
+ key: 'internal.client.locus.sync.response',
220
+ value: 143,
221
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
222
+ });
223
+ cdl.saveTimestamp({
224
+ key: 'internal.client.locus.sync.message.received',
225
+ value: 150,
226
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
227
+ });
228
+
229
+ assert.deepEqual(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-id'), {
230
+ randomBackoffTime: 10,
231
+ hashtreePrepTime: 5,
232
+ hashtreeResponseTime: 20,
233
+ syncPrepTime: 3,
234
+ syncResponseTime: 15,
235
+ syncMessageReceiveTime: 22,
236
+ totalTime: 50,
237
+ });
238
+ });
239
+
240
+ it('calculates sync latency values when hash tree request is skipped', () => {
241
+ cdl.saveTimestamp({
242
+ key: 'internal.client.locus.sync.start',
243
+ value: 100,
244
+ options: {
245
+ meetingId: 'meeting-1',
246
+ dataSetName: 'main',
247
+ randomBackoffTime: 0,
248
+ trackingId: 'sync-tracking-1',
249
+ },
250
+ });
251
+ cdl.saveTimestamp({
252
+ key: 'internal.client.locus.sync.request',
253
+ value: 110,
254
+ options: {
255
+ meetingId: 'meeting-1',
256
+ dataSetName: 'main',
257
+ trackingId: 'sync-tracking-1',
258
+ },
259
+ });
260
+ cdl.saveTimestamp({
261
+ key: 'internal.client.locus.sync.response',
262
+ value: 130,
263
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
264
+ });
265
+ cdl.saveTimestamp({
266
+ key: 'internal.client.locus.sync.message.received',
267
+ value: 140,
268
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
269
+ });
270
+
271
+ assert.deepEqual(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-1'), {
272
+ randomBackoffTime: 0,
273
+ hashtreePrepTime: 0,
274
+ hashtreeResponseTime: 0,
275
+ syncPrepTime: 10,
276
+ syncResponseTime: 20,
277
+ syncMessageReceiveTime: 30,
278
+ totalTime: 40,
279
+ });
280
+ });
281
+
282
+ it('associates sync response tracking id and completes the matching meeting record', () => {
283
+ clock.setSystemTime(150);
284
+
285
+ try {
286
+ cdl.saveTimestamp({
287
+ key: 'internal.client.locus.sync.start',
288
+ value: 100,
289
+ options: {
290
+ meetingId: 'meeting-1',
291
+ dataSetName: 'main',
292
+ randomBackoffTime: 0,
293
+ trackingId: 'our-sync-tracking-id',
294
+ },
295
+ });
296
+ cdl.saveTimestamp({
297
+ key: 'internal.client.locus.sync.request',
298
+ value: 110,
299
+ options: {
300
+ meetingId: 'meeting-1',
301
+ dataSetName: 'main',
302
+ trackingId: 'our-sync-tracking-id',
303
+ },
304
+ });
305
+ cdl.saveTimestamp({
306
+ key: 'internal.client.locus.sync.response',
307
+ value: 130,
308
+ options: {
309
+ meetingId: 'meeting-1',
310
+ dataSetName: 'main',
311
+ trackingId: 'our-sync-tracking-id',
312
+ },
313
+ });
314
+ // the LLM state-update message that gates the metric arrives for this sync
315
+ cdl.saveTimestamp({
316
+ key: 'internal.client.locus.sync.message.received',
317
+ value: 150,
318
+ options: {
319
+ meetingId: 'meeting-1',
320
+ dataSetName: 'main',
321
+ trackingId: 'our-sync-tracking-id',
322
+ },
323
+ });
324
+ cdl.saveLatency('internal.client.locus.sync.random.backoff', 99, {
325
+ meetingId: 'meeting-1',
326
+ dataSetName: 'main',
327
+ });
328
+
329
+ // eager completion: both the /sync response and the LLM message are present
330
+ assert.deepEqual(cdl.completeLocusSyncLatency('meeting-1', 'our-sync-tracking-id'), {
331
+ dataSet: 'main',
332
+ syncLatency: {
333
+ randomBackoffTime: 0,
334
+ hashtreePrepTime: 0,
335
+ hashtreeResponseTime: 0,
336
+ syncPrepTime: 10,
337
+ syncResponseTime: 20,
338
+ syncMessageReceiveTime: 40,
339
+ totalTime: 50,
340
+ },
341
+ });
342
+ // completing the metric removes the matching record, leaving only the pending
343
+ // backoff record created above for the next sync to consume
344
+ assert.lengthOf(cdl.meetingLatencies.get('meeting-1'), 1);
345
+
346
+ cdl.saveTimestamp({
347
+ key: 'internal.client.locus.sync.start',
348
+ value: 200,
349
+ options: {
350
+ meetingId: 'meeting-1',
351
+ dataSetName: 'main',
352
+ trackingId: 'next-sync-tracking-id',
353
+ },
354
+ });
355
+ assert.deepInclude(cdl.meetingLatencies.get('meeting-1'), {
356
+ locusSync: {
357
+ meetingId: 'meeting-1',
358
+ dataSetName: 'main',
359
+ randomBackoffTime: 99,
360
+ trackingId: 'next-sync-tracking-id',
361
+ syncStart: 200,
362
+ },
363
+ });
364
+ } finally {
365
+ clock.setSystemTime(now.getTime());
366
+ }
367
+ });
368
+
369
+ it('does not bind message.received when tracking id does not match any record', () => {
370
+ clock.setSystemTime(500);
371
+
372
+ try {
373
+ cdl.saveTimestamp({
374
+ key: 'internal.client.locus.sync.start',
375
+ value: 100,
376
+ options: {
377
+ meetingId: 'meeting-1',
378
+ dataSetName: 'main',
379
+ randomBackoffTime: 0,
380
+ trackingId: 'sync-tracking-id',
381
+ },
382
+ });
383
+ cdl.saveTimestamp({
384
+ key: 'internal.client.locus.sync.request',
385
+ value: 110,
386
+ options: {
387
+ meetingId: 'meeting-1',
388
+ dataSetName: 'main',
389
+ trackingId: 'sync-tracking-id',
390
+ },
391
+ });
392
+ cdl.saveTimestamp({
393
+ key: 'internal.client.locus.sync.response',
394
+ value: 130,
395
+ options: {
396
+ meetingId: 'meeting-1',
397
+ dataSetName: 'main',
398
+ trackingId: 'sync-tracking-id',
399
+ },
400
+ });
401
+ cdl.saveTimestamp({
402
+ key: 'internal.client.locus.sync.message.received',
403
+ value: 140,
404
+ options: {
405
+ meetingId: 'meeting-1',
406
+ dataSetName: 'main',
407
+ trackingId: 'llm-envelope-id',
408
+ },
409
+ });
410
+
411
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'llm-envelope-id'));
412
+ assert.isUndefined(cdl.meetingLatencies.get('meeting-1')?.[0].locusSync.messageReceived);
413
+ } finally {
414
+ clock.setSystemTime(now.getTime());
415
+ }
416
+ });
417
+
418
+ it('does not allow totalTime to drop below sync response duration when message.received is stale', () => {
419
+ cdl.saveTimestamp({
420
+ key: 'internal.client.locus.sync.start',
421
+ value: 100,
422
+ options: {
423
+ meetingId: 'meeting-1',
424
+ dataSetName: 'main',
425
+ randomBackoffTime: 0,
426
+ trackingId: 'sync-tracking-id',
427
+ },
428
+ });
429
+ cdl.saveTimestamp({
430
+ key: 'internal.client.locus.sync.request',
431
+ value: 101,
432
+ options: {
433
+ meetingId: 'meeting-1',
434
+ dataSetName: 'main',
435
+ trackingId: 'sync-tracking-id',
436
+ },
437
+ });
438
+ cdl.saveTimestamp({
439
+ key: 'internal.client.locus.sync.response',
440
+ value: 475,
441
+ options: {
442
+ meetingId: 'meeting-1',
443
+ dataSetName: 'main',
444
+ trackingId: 'sync-tracking-id',
445
+ },
446
+ });
447
+ cdl.saveTimestamp({
448
+ key: 'internal.client.locus.sync.message.received',
449
+ value: 90,
450
+ options: {
451
+ meetingId: 'meeting-1',
452
+ dataSetName: 'main',
453
+ trackingId: 'sync-tracking-id',
454
+ },
455
+ });
456
+
457
+ assert.deepEqual(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'), {
458
+ dataSet: 'main',
459
+ syncLatency: {
460
+ randomBackoffTime: 0,
461
+ hashtreePrepTime: 0,
462
+ hashtreeResponseTime: 0,
463
+ syncPrepTime: 1,
464
+ syncResponseTime: 374,
465
+ syncMessageReceiveTime: 0,
466
+ totalTime: 375,
467
+ },
468
+ });
469
+ });
470
+
471
+ it('drops and consumes a completed sync latency record when a segment exceeds the clock skew threshold', () => {
472
+ cdl.saveTimestamp({
473
+ key: 'internal.client.locus.sync.start',
474
+ value: 100,
475
+ options: {
476
+ meetingId: 'meeting-1',
477
+ dataSetName: 'main',
478
+ trackingId: 'sync-tracking-id',
479
+ },
480
+ });
481
+ cdl.saveTimestamp({
482
+ key: 'internal.client.locus.sync.request',
483
+ value: 110,
484
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
485
+ });
486
+ cdl.saveTimestamp({
487
+ key: 'internal.client.locus.sync.response',
488
+ value: 600111,
489
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
490
+ });
491
+ cdl.saveTimestamp({
492
+ key: 'internal.client.locus.sync.message.received',
493
+ value: 600112,
494
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
495
+ });
496
+
497
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'));
498
+ assert.isFalse(cdl.meetingLatencies.has('meeting-1'));
499
+ });
500
+
501
+ it('allows a completed sync latency record when the largest segment equals the clock skew threshold', () => {
502
+ cdl.saveTimestamp({
503
+ key: 'internal.client.locus.sync.start',
504
+ value: 100,
505
+ options: {
506
+ meetingId: 'meeting-1',
507
+ dataSetName: 'main',
508
+ trackingId: 'sync-tracking-id',
509
+ },
510
+ });
511
+ cdl.saveTimestamp({
512
+ key: 'internal.client.locus.sync.request',
513
+ value: 110,
514
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
515
+ });
516
+ cdl.saveTimestamp({
517
+ key: 'internal.client.locus.sync.response',
518
+ value: 600100,
519
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
520
+ });
521
+ cdl.saveTimestamp({
522
+ key: 'internal.client.locus.sync.message.received',
523
+ value: 600100,
524
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
525
+ });
526
+
527
+ assert.deepEqual(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'), {
528
+ dataSet: 'main',
529
+ syncLatency: {
530
+ randomBackoffTime: 0,
531
+ hashtreePrepTime: 0,
532
+ hashtreeResponseTime: 0,
533
+ syncPrepTime: 10,
534
+ syncResponseTime: 599990,
535
+ syncMessageReceiveTime: 599990,
536
+ totalTime: 600000,
537
+ },
538
+ });
539
+ assert.isFalse(cdl.meetingLatencies.has('meeting-1'));
540
+ });
541
+
542
+ it('matches exact record by tracking id on first pass', () => {
543
+ clock.setSystemTime(300);
544
+
545
+ try {
546
+ cdl.saveTimestamp({
547
+ key: 'internal.client.locus.sync.start',
548
+ value: 100,
549
+ options: {
550
+ meetingId: 'meeting-1',
551
+ dataSetName: 'main',
552
+ randomBackoffTime: 0,
553
+ trackingId: 'sync-tracking-1',
554
+ },
555
+ });
556
+ cdl.saveTimestamp({
557
+ key: 'internal.client.locus.sync.request',
558
+ value: 110,
559
+ options: {
560
+ meetingId: 'meeting-1',
561
+ dataSetName: 'main',
562
+ trackingId: 'sync-tracking-1',
563
+ },
564
+ });
565
+ cdl.saveTimestamp({
566
+ key: 'internal.client.locus.sync.response',
567
+ value: 130,
568
+ options: {
569
+ meetingId: 'meeting-1',
570
+ dataSetName: 'main',
571
+ trackingId: 'sync-tracking-1',
572
+ },
573
+ });
574
+
575
+ cdl.saveTimestamp({
576
+ key: 'internal.client.locus.sync.start',
577
+ value: 200,
578
+ options: {
579
+ meetingId: 'meeting-1',
580
+ dataSetName: 'main',
581
+ randomBackoffTime: 0,
582
+ trackingId: 'sync-tracking-2',
583
+ },
584
+ });
585
+ cdl.saveTimestamp({
586
+ key: 'internal.client.locus.sync.request',
587
+ value: 210,
588
+ options: {
589
+ meetingId: 'meeting-1',
590
+ dataSetName: 'main',
591
+ trackingId: 'sync-tracking-2',
592
+ },
593
+ });
594
+ cdl.saveTimestamp({
595
+ key: 'internal.client.locus.sync.response',
596
+ value: 230,
597
+ options: {
598
+ meetingId: 'meeting-1',
599
+ dataSetName: 'main',
600
+ trackingId: 'sync-tracking-2',
601
+ },
602
+ });
603
+ cdl.saveTimestamp({
604
+ key: 'internal.client.locus.sync.message.received',
605
+ value: 240,
606
+ options: {
607
+ meetingId: 'meeting-1',
608
+ dataSetName: 'main',
609
+ trackingId: 'sync-tracking-2',
610
+ },
611
+ });
612
+
613
+ assert.deepEqual(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-2'), {
614
+ dataSet: 'main',
615
+ syncLatency: {
616
+ randomBackoffTime: 0,
617
+ hashtreePrepTime: 0,
618
+ hashtreeResponseTime: 0,
619
+ syncPrepTime: 10,
620
+ syncResponseTime: 20,
621
+ syncMessageReceiveTime: 30,
622
+ totalTime: 40,
623
+ },
624
+ });
625
+ } finally {
626
+ clock.setSystemTime(now.getTime());
627
+ }
628
+ });
629
+
630
+ it('does not bind message.received when tracking id does not match any record', () => {
631
+ cdl.saveTimestamp({
632
+ key: 'internal.client.locus.sync.start',
633
+ value: 100,
634
+ options: {
635
+ meetingId: 'meeting-1',
636
+ dataSetName: 'main',
637
+ randomBackoffTime: 0,
638
+ trackingId: 'sync-tracking-1',
639
+ },
640
+ });
641
+ cdl.saveTimestamp({
642
+ key: 'internal.client.locus.sync.request',
643
+ value: 110,
644
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
645
+ });
646
+ cdl.saveTimestamp({
647
+ key: 'internal.client.locus.sync.response',
648
+ value: 130,
649
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
650
+ });
651
+
652
+ cdl.saveTimestamp({
653
+ key: 'internal.client.locus.sync.start',
654
+ value: 200,
655
+ options: {
656
+ meetingId: 'meeting-1',
657
+ dataSetName: 'main',
658
+ randomBackoffTime: 0,
659
+ trackingId: 'sync-tracking-2',
660
+ },
661
+ });
662
+ cdl.saveTimestamp({
663
+ key: 'internal.client.locus.sync.request',
664
+ value: 210,
665
+ options: {
666
+ meetingId: 'meeting-1',
667
+ dataSetName: 'main',
668
+ trackingId: 'sync-tracking-2',
669
+ },
670
+ });
671
+ cdl.saveTimestamp({
672
+ key: 'internal.client.locus.sync.response',
673
+ value: 230,
674
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-2'},
675
+ });
676
+
677
+ cdl.saveTimestamp({
678
+ key: 'internal.client.locus.sync.message.received',
679
+ value: 120,
680
+ options: {
681
+ meetingId: 'meeting-1',
682
+ dataSetName: 'main',
683
+ trackingId: 'llm-unknown-id',
684
+ },
685
+ });
686
+
687
+ const records = cdl.meetingLatencies.get('meeting-1');
688
+
689
+ assert.isDefined(records);
690
+ assert.lengthOf(records!, 2);
691
+ assert.isUndefined(records![0].locusSync.messageReceived);
692
+ assert.isUndefined(records![1].locusSync.messageReceived);
693
+ });
694
+
695
+ it('binds message.received when the tracking id matches the only record', () => {
696
+ cdl.saveTimestamp({
697
+ key: 'internal.client.locus.sync.start',
698
+ value: 100,
699
+ options: {
700
+ meetingId: 'meeting-1',
701
+ dataSetName: 'main',
702
+ randomBackoffTime: 0,
703
+ trackingId: 'sync-tracking-id',
704
+ },
705
+ });
706
+ cdl.saveTimestamp({
707
+ key: 'internal.client.locus.sync.request',
708
+ value: 110,
709
+ options: {
710
+ meetingId: 'meeting-1',
711
+ dataSetName: 'main',
712
+ trackingId: 'sync-tracking-id',
713
+ },
714
+ });
715
+ cdl.saveTimestamp({
716
+ key: 'internal.client.locus.sync.response',
717
+ value: 130,
718
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
719
+ });
720
+
721
+ cdl.saveTimestamp({
722
+ key: 'internal.client.locus.sync.message.received',
723
+ value: 140,
724
+ options: {
725
+ meetingId: 'meeting-1',
726
+ dataSetName: 'main',
727
+ trackingId: 'sync-tracking-id',
728
+ },
729
+ });
730
+
731
+ const records = cdl.meetingLatencies.get('meeting-1');
732
+
733
+ assert.isDefined(records);
734
+ assert.lengthOf(records!, 1);
735
+ assert.equal(records![0].locusSync.messageReceived, 140);
736
+ });
737
+
738
+ it('returns undefined when the tracking id does not match', () => {
739
+ clock.setSystemTime(150);
740
+
741
+ try {
742
+ cdl.saveTimestamp({
743
+ key: 'internal.client.locus.sync.start',
744
+ value: 100,
745
+ options: {
746
+ meetingId: 'meeting-1',
747
+ dataSetName: 'main',
748
+ randomBackoffTime: 0,
749
+ trackingId: 'our-sync-tracking-id',
750
+ },
751
+ });
752
+ cdl.saveTimestamp({
753
+ key: 'internal.client.locus.sync.request',
754
+ value: 110,
755
+ options: {
756
+ meetingId: 'meeting-1',
757
+ dataSetName: 'main',
758
+ trackingId: 'our-sync-tracking-id',
759
+ },
760
+ });
761
+ cdl.saveTimestamp({
762
+ key: 'internal.client.locus.sync.response',
763
+ value: 130,
764
+ options: {
765
+ meetingId: 'meeting-1',
766
+ dataSetName: 'main',
767
+ trackingId: 'our-sync-tracking-id',
768
+ },
769
+ });
770
+
771
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'llm-envelope-tracking-id'));
772
+ } finally {
773
+ clock.setSystemTime(now.getTime());
774
+ }
775
+ });
776
+
777
+ it('does not clean up older never-completed record for the same dataset when newer sync completes', () => {
778
+ // first sync: all sync milestones recorded, but its completing LLM event never arrives
779
+ cdl.saveTimestamp({
780
+ key: 'internal.client.locus.sync.start',
781
+ value: 100,
782
+ options: {
783
+ meetingId: 'meeting-1',
784
+ dataSetName: 'main',
785
+ randomBackoffTime: 0,
786
+ trackingId: 'sync-tracking-1',
787
+ },
788
+ });
789
+ cdl.saveTimestamp({
790
+ key: 'internal.client.locus.sync.request',
791
+ value: 110,
792
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
793
+ });
794
+ cdl.saveTimestamp({
795
+ key: 'internal.client.locus.sync.response',
796
+ value: 130,
797
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
798
+ });
799
+
800
+ // a second sync for the same dataset starts before the first one completed.
801
+ // because the first record already has syncStart set, it is not reused and a
802
+ // brand new record is created for the second sync
803
+ cdl.saveTimestamp({
804
+ key: 'internal.client.locus.sync.start',
805
+ value: 200,
806
+ options: {
807
+ meetingId: 'meeting-1',
808
+ dataSetName: 'main',
809
+ randomBackoffTime: 0,
810
+ trackingId: 'sync-tracking-2',
811
+ },
812
+ });
813
+ cdl.saveTimestamp({
814
+ key: 'internal.client.locus.sync.request',
815
+ value: 210,
816
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-2'},
817
+ });
818
+ cdl.saveTimestamp({
819
+ key: 'internal.client.locus.sync.response',
820
+ value: 230,
821
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-2'},
822
+ });
823
+ cdl.saveTimestamp({
824
+ key: 'internal.client.locus.sync.message.received',
825
+ value: 240,
826
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-2'},
827
+ });
828
+
829
+ // both records exist before completion
830
+ assert.lengthOf(cdl.meetingLatencies.get('meeting-1')!, 2);
831
+
832
+ // completing the second sync removes only its own record; the older pending record is left
833
+ // in place because a late LLM message could still complete it (stale cleanup is handled by
834
+ // the TTL / capacity pruning, not by completion).
835
+ const completed = cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-2');
836
+
837
+ assert.isDefined(completed);
838
+ assert.equal(completed!.dataSet, 'main');
839
+
840
+ const remaining = cdl.meetingLatencies.get('meeting-1');
841
+
842
+ assert.isDefined(remaining);
843
+ assert.lengthOf(remaining!, 1);
844
+ assert.equal(remaining![0].locusSync.trackingId, 'sync-tracking-1');
845
+ });
846
+
847
+ it('prunes an incomplete record once it is older than the pending TTL', () => {
848
+ // an incomplete sync record that never received its LLM message
849
+ cdl.saveTimestamp({
850
+ key: 'internal.client.locus.sync.start',
851
+ value: 100,
852
+ options: {
853
+ meetingId: 'meeting-1',
854
+ dataSetName: 'main',
855
+ trackingId: 'stale-tracking-id',
856
+ },
857
+ });
858
+
859
+ // a brand new sync for the same dataset starts more than the TTL later
860
+ cdl.saveTimestamp({
861
+ key: 'internal.client.locus.sync.start',
862
+ value: 100 + 5 * 60 * 1000 + 1,
863
+ options: {
864
+ meetingId: 'meeting-1',
865
+ dataSetName: 'main',
866
+ trackingId: 'fresh-tracking-id',
867
+ },
868
+ });
869
+
870
+ const records = cdl.meetingLatencies.get('meeting-1');
871
+
872
+ assert.isDefined(records);
873
+ assert.lengthOf(records!, 1);
874
+ assert.equal(records![0].locusSync.trackingId, 'fresh-tracking-id');
875
+ });
876
+
877
+ it('keeps an incomplete record that is still within the pending TTL', () => {
878
+ cdl.saveTimestamp({
879
+ key: 'internal.client.locus.sync.start',
880
+ value: 100,
881
+ options: {
882
+ meetingId: 'meeting-1',
883
+ dataSetName: 'main',
884
+ trackingId: 'pending-tracking-id',
885
+ },
886
+ });
887
+
888
+ // a new sync for the same dataset starts well within the TTL window
889
+ cdl.saveTimestamp({
890
+ key: 'internal.client.locus.sync.start',
891
+ value: 100 + 1000,
892
+ options: {
893
+ meetingId: 'meeting-1',
894
+ dataSetName: 'main',
895
+ trackingId: 'fresh-tracking-id',
896
+ },
897
+ });
898
+
899
+ const records = cdl.meetingLatencies.get('meeting-1');
900
+
901
+ assert.isDefined(records);
902
+ assert.lengthOf(records!, 2);
903
+ assert.equal(records![0].locusSync.trackingId, 'pending-tracking-id');
904
+ assert.equal(records![1].locusSync.trackingId, 'fresh-tracking-id');
905
+ });
906
+
907
+ it('does not prune incomplete records from a different dataset', () => {
908
+ cdl.saveTimestamp({
909
+ key: 'internal.client.locus.sync.start',
910
+ value: 100,
911
+ options: {
912
+ meetingId: 'meeting-1',
913
+ dataSetName: 'other',
914
+ trackingId: 'other-tracking-id',
915
+ },
916
+ });
917
+
918
+ // a much later sync for a different dataset must not touch the "other" record
919
+ cdl.saveTimestamp({
920
+ key: 'internal.client.locus.sync.start',
921
+ value: 100 + 5 * 60 * 1000 + 1,
922
+ options: {
923
+ meetingId: 'meeting-1',
924
+ dataSetName: 'main',
925
+ trackingId: 'main-tracking-id',
926
+ },
927
+ });
928
+
929
+ const records = cdl.meetingLatencies.get('meeting-1');
930
+
931
+ assert.isDefined(records);
932
+ assert.lengthOf(records!, 2);
933
+ assert.equal(records![0].locusSync.trackingId, 'other-tracking-id');
934
+ assert.equal(records![1].locusSync.trackingId, 'main-tracking-id');
935
+ });
936
+
937
+ it('caps the number of incomplete records kept per dataset', () => {
938
+ // create more incomplete records than the per-dataset cap, all within the TTL window
939
+ for (let i = 0; i <= 20; i += 1) {
940
+ cdl.saveTimestamp({
941
+ key: 'internal.client.locus.sync.start',
942
+ value: 100 + i,
943
+ options: {
944
+ meetingId: 'meeting-1',
945
+ dataSetName: 'main',
946
+ trackingId: `sync-tracking-${i}`,
947
+ },
948
+ });
949
+ }
950
+
951
+ const records = cdl.meetingLatencies.get('meeting-1');
952
+ const trackingIds = records!.map(({locusSync}) => locusSync.trackingId);
953
+
954
+ assert.isDefined(records);
955
+ assert.lengthOf(records!, 20);
956
+ // the oldest record is dropped, the newest is kept
957
+ assert.notInclude(trackingIds, 'sync-tracking-0');
958
+ assert.include(trackingIds, 'sync-tracking-20');
959
+ });
960
+
961
+ it('does not clean up never-completed records for a different dataset', () => {
962
+ // never-completed sync for dataset "other"
963
+ cdl.saveTimestamp({
964
+ key: 'internal.client.locus.sync.start',
965
+ value: 100,
966
+ options: {
967
+ meetingId: 'meeting-1',
968
+ dataSetName: 'other',
969
+ randomBackoffTime: 0,
970
+ trackingId: 'other-tracking-1',
971
+ },
972
+ });
973
+ cdl.saveTimestamp({
974
+ key: 'internal.client.locus.sync.request',
975
+ value: 110,
976
+ options: {meetingId: 'meeting-1', dataSetName: 'other', trackingId: 'other-tracking-1'},
977
+ });
978
+ cdl.saveTimestamp({
979
+ key: 'internal.client.locus.sync.response',
980
+ value: 130,
981
+ options: {meetingId: 'meeting-1', dataSetName: 'other', trackingId: 'other-tracking-1'},
982
+ });
983
+
984
+ // completed sync for dataset "main"
985
+ cdl.saveTimestamp({
986
+ key: 'internal.client.locus.sync.start',
987
+ value: 200,
988
+ options: {
989
+ meetingId: 'meeting-1',
990
+ dataSetName: 'main',
991
+ randomBackoffTime: 0,
992
+ trackingId: 'main-tracking-1',
993
+ },
994
+ });
995
+ cdl.saveTimestamp({
996
+ key: 'internal.client.locus.sync.request',
997
+ value: 210,
998
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'main-tracking-1'},
999
+ });
1000
+ cdl.saveTimestamp({
1001
+ key: 'internal.client.locus.sync.response',
1002
+ value: 230,
1003
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'main-tracking-1'},
1004
+ });
1005
+ cdl.saveTimestamp({
1006
+ key: 'internal.client.locus.sync.message.received',
1007
+ value: 240,
1008
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'main-tracking-1'},
1009
+ });
1010
+
1011
+ const completed = cdl.completeLocusSyncLatency('meeting-1', 'main-tracking-1');
1012
+
1013
+ assert.isDefined(completed);
1014
+
1015
+ // the "other" dataset record must remain untouched
1016
+ const records = cdl.meetingLatencies.get('meeting-1');
1017
+
1018
+ assert.isDefined(records);
1019
+ assert.lengthOf(records!, 1);
1020
+ assert.equal(records![0].locusSync.dataSetName, 'other');
1021
+ assert.equal(records![0].locusSync.trackingId, 'other-tracking-1');
1022
+ });
1023
+
1024
+ it('keys sync latency records by meeting id', () => {
1025
+ cdl.saveTimestamp({
1026
+ key: 'internal.client.locus.sync.start',
1027
+ value: 100,
1028
+ options: {
1029
+ meetingId: 'meeting-1',
1030
+ dataSetName: 'main',
1031
+ randomBackoffTime: 10,
1032
+ trackingId: 'sync-tracking-1',
1033
+ },
1034
+ });
1035
+ cdl.saveTimestamp({
1036
+ key: 'internal.client.locus.sync.request',
1037
+ value: 110,
1038
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
1039
+ });
1040
+
1041
+ cdl.saveTimestamp({
1042
+ key: 'internal.client.locus.sync.start',
1043
+ value: 200,
1044
+ options: {
1045
+ meetingId: 'meeting-2',
1046
+ dataSetName: 'main',
1047
+ randomBackoffTime: 23,
1048
+ trackingId: 'sync-tracking-2',
1049
+ },
1050
+ });
1051
+ cdl.saveTimestamp({
1052
+ key: 'internal.client.locus.sync.request',
1053
+ value: 217,
1054
+ options: {meetingId: 'meeting-2', dataSetName: 'main', trackingId: 'sync-tracking-2'},
1055
+ });
1056
+ cdl.saveTimestamp({
1057
+ key: 'internal.client.locus.sync.response',
1058
+ value: 241,
1059
+ options: {meetingId: 'meeting-2', dataSetName: 'main', trackingId: 'sync-tracking-2'},
1060
+ });
1061
+ cdl.saveTimestamp({
1062
+ key: 'internal.client.locus.sync.message.received',
1063
+ value: 268,
1064
+ options: {meetingId: 'meeting-2', dataSetName: 'main', trackingId: 'sync-tracking-2'},
1065
+ });
1066
+
1067
+ cdl.saveTimestamp({
1068
+ key: 'internal.client.locus.sync.response',
1069
+ value: 125,
1070
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
1071
+ });
1072
+ cdl.saveTimestamp({
1073
+ key: 'internal.client.locus.sync.message.received',
1074
+ value: 150,
1075
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-1'},
1076
+ });
1077
+
1078
+ assert.deepEqual(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-1'), {
1079
+ randomBackoffTime: 0,
1080
+ hashtreePrepTime: 0,
1081
+ hashtreeResponseTime: 0,
1082
+ syncPrepTime: 10,
1083
+ syncResponseTime: 15,
1084
+ syncMessageReceiveTime: 40,
1085
+ totalTime: 50,
1086
+ });
1087
+ assert.deepEqual(cdl.getLocusSyncLatency('meeting-2', 'sync-tracking-2'), {
1088
+ randomBackoffTime: 0,
1089
+ hashtreePrepTime: 0,
1090
+ hashtreeResponseTime: 0,
1091
+ syncPrepTime: 17,
1092
+ syncResponseTime: 24,
1093
+ syncMessageReceiveTime: 51,
1094
+ totalTime: 68,
1095
+ });
1096
+
1097
+ cdl.clearLocusSyncLatency('main', 'meeting-1');
1098
+
1099
+ assert.isUndefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-1'));
1100
+ assert.isDefined(cdl.getLocusSyncLatency('meeting-2', 'sync-tracking-2'));
1101
+ });
1102
+
1103
+ it('returns undefined and clears state when required milestones are missing', () => {
1104
+ cdl.saveTimestamp({
1105
+ key: 'internal.client.locus.sync.start',
1106
+ value: 100,
1107
+ options: {
1108
+ meetingId: 'meeting-1',
1109
+ dataSetName: 'main',
1110
+ randomBackoffTime: 0,
1111
+ trackingId: 'sync-tracking-id',
1112
+ },
1113
+ });
1114
+ cdl.saveTimestamp({
1115
+ key: 'internal.client.locus.sync.message.received',
1116
+ value: 140,
1117
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
1118
+ });
1119
+
1120
+ assert.isUndefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-id'));
1121
+ cdl.clearLocusSyncLatency('main', 'meeting-1');
1122
+ assert.isFalse(cdl.meetingLatencies.has('meeting-1'));
1123
+ });
1124
+
1125
+ it('clears only the record matching the tracking id when one is supplied', () => {
1126
+ const stampFullRecord = (trackingId: string, base: number) => {
1127
+ cdl.saveTimestamp({
1128
+ key: 'internal.client.locus.sync.start',
1129
+ value: base,
1130
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1131
+ });
1132
+ cdl.saveTimestamp({
1133
+ key: 'internal.client.locus.sync.request',
1134
+ value: base + 10,
1135
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1136
+ });
1137
+ cdl.saveTimestamp({
1138
+ key: 'internal.client.locus.sync.response',
1139
+ value: base + 25,
1140
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1141
+ });
1142
+ cdl.saveTimestamp({
1143
+ key: 'internal.client.locus.sync.message.received',
1144
+ value: base + 50,
1145
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1146
+ });
1147
+ };
1148
+
1149
+ // Two records for the same dataset/meeting but different tracking ids.
1150
+ stampFullRecord('sync-tracking-1', 100);
1151
+ stampFullRecord('sync-tracking-2', 200);
1152
+
1153
+ assert.isDefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-1'));
1154
+ assert.isDefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-2'));
1155
+
1156
+ // Clearing with a tracking id drops only that record, leaving the other intact.
1157
+ cdl.clearLocusSyncLatency('main', 'meeting-1', 'sync-tracking-1');
1158
+
1159
+ assert.isUndefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-1'));
1160
+ assert.isDefined(cdl.getLocusSyncLatency('meeting-1', 'sync-tracking-2'));
1161
+ });
1162
+
1163
+ describe('recordLocusSyncMessageReceived', () => {
1164
+ const startPendingSync = (trackingId: string) => {
1165
+ cdl.saveTimestamp({
1166
+ key: 'internal.client.locus.sync.start',
1167
+ value: 100,
1168
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1169
+ });
1170
+ };
1171
+
1172
+ it('stamps messageReceived on the matching pending record using the current time', () => {
1173
+ clock.setSystemTime(500);
1174
+
1175
+ try {
1176
+ startPendingSync('sync-tracking-id');
1177
+ cdl.recordLocusSyncMessageReceived('meeting-1', 'sync-tracking-id');
1178
+
1179
+ assert.equal(cdl.meetingLatencies.get('meeting-1')![0].locusSync.messageReceived, 500);
1180
+ } finally {
1181
+ clock.setSystemTime(now.getTime());
1182
+ }
1183
+ });
1184
+
1185
+ it('does not overwrite an already recorded messageReceived', () => {
1186
+ clock.setSystemTime(999);
1187
+
1188
+ try {
1189
+ startPendingSync('sync-tracking-id');
1190
+ cdl.saveTimestamp({
1191
+ key: 'internal.client.locus.sync.message.received',
1192
+ value: 140,
1193
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId: 'sync-tracking-id'},
1194
+ });
1195
+ cdl.recordLocusSyncMessageReceived('meeting-1', 'sync-tracking-id');
1196
+
1197
+ assert.equal(cdl.meetingLatencies.get('meeting-1')![0].locusSync.messageReceived, 140);
1198
+ } finally {
1199
+ clock.setSystemTime(now.getTime());
1200
+ }
1201
+ });
1202
+
1203
+ it('is a no-op when no record matches the tracking id', () => {
1204
+ startPendingSync('sync-tracking-id');
1205
+ cdl.recordLocusSyncMessageReceived('meeting-1', 'some-other-tracking-id');
1206
+
1207
+ assert.isUndefined(cdl.meetingLatencies.get('meeting-1')![0].locusSync.messageReceived);
1208
+ });
1209
+
1210
+ it('is a no-op when trackingId is empty', () => {
1211
+ startPendingSync('sync-tracking-id');
1212
+
1213
+ assert.doesNotThrow(() => cdl.recordLocusSyncMessageReceived('meeting-1', ''));
1214
+ assert.isUndefined(cdl.meetingLatencies.get('meeting-1')![0].locusSync.messageReceived);
1215
+ });
1216
+ });
1217
+
1218
+ describe('completeLocusSyncLatency requires both milestones', () => {
1219
+ const recordSyncRequest = (trackingId: string) => {
1220
+ cdl.saveTimestamp({
1221
+ key: 'internal.client.locus.sync.start',
1222
+ value: 100,
1223
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1224
+ });
1225
+ cdl.saveTimestamp({
1226
+ key: 'internal.client.locus.sync.request',
1227
+ value: 110,
1228
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1229
+ });
1230
+ };
1231
+ const recordSyncResponse = (trackingId: string) =>
1232
+ cdl.saveTimestamp({
1233
+ key: 'internal.client.locus.sync.response',
1234
+ value: 130,
1235
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1236
+ });
1237
+ const recordMessageReceived = (trackingId: string) =>
1238
+ cdl.saveTimestamp({
1239
+ key: 'internal.client.locus.sync.message.received',
1240
+ value: 150,
1241
+ options: {meetingId: 'meeting-1', dataSetName: 'main', trackingId},
1242
+ });
1243
+
1244
+ it('returns undefined and keeps the record when only the /sync response is present', () => {
1245
+ recordSyncRequest('sync-tracking-id');
1246
+ recordSyncResponse('sync-tracking-id');
1247
+
1248
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'));
1249
+ assert.lengthOf(cdl.meetingLatencies.get('meeting-1')!, 1);
1250
+ });
1251
+
1252
+ it('returns undefined and keeps the record when only the LLM message is present', () => {
1253
+ recordSyncRequest('sync-tracking-id');
1254
+ recordMessageReceived('sync-tracking-id');
1255
+
1256
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'));
1257
+ assert.lengthOf(cdl.meetingLatencies.get('meeting-1')!, 1);
1258
+ });
1259
+
1260
+ it('emits and consumes the record when the /sync response arrives after the LLM message', () => {
1261
+ recordSyncRequest('sync-tracking-id');
1262
+ // LLM message arrives first, before the HTTP response
1263
+ recordMessageReceived('sync-tracking-id');
1264
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'));
1265
+
1266
+ // /sync response lands second -> now both milestones are in
1267
+ recordSyncResponse('sync-tracking-id');
1268
+
1269
+ assert.deepEqual(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'), {
1270
+ dataSet: 'main',
1271
+ syncLatency: {
1272
+ randomBackoffTime: 0,
1273
+ hashtreePrepTime: 0,
1274
+ hashtreeResponseTime: 0,
1275
+ syncPrepTime: 10,
1276
+ syncResponseTime: 20,
1277
+ syncMessageReceiveTime: 40,
1278
+ totalTime: 50,
1279
+ },
1280
+ });
1281
+ assert.isUndefined(cdl.meetingLatencies.get('meeting-1'));
1282
+ });
1283
+
1284
+ it('emits and consumes the record when the LLM message arrives after the /sync response', () => {
1285
+ recordSyncRequest('sync-tracking-id');
1286
+ // HTTP response arrives first
1287
+ recordSyncResponse('sync-tracking-id');
1288
+ assert.isUndefined(cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id'));
1289
+
1290
+ // LLM message lands second
1291
+ recordMessageReceived('sync-tracking-id');
1292
+
1293
+ const completed = cdl.completeLocusSyncLatency('meeting-1', 'sync-tracking-id');
1294
+
1295
+ assert.isDefined(completed);
1296
+ assert.equal(completed!.dataSet, 'main');
1297
+ assert.isUndefined(cdl.meetingLatencies.get('meeting-1'));
1298
+ });
1299
+ });
116
1300
  });
117
1301
 
118
1302
  it('should calculate diff between timestamps correctly', () => {
@@ -143,7 +1327,7 @@ describe('internal-plugin-metrics', () => {
143
1327
  cdl.saveTimestamp({key: 'client.alert.removed', value: 50});
144
1328
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
145
1329
  minimum: 0,
146
- maximum: 100
1330
+ maximum: 100,
147
1331
  });
148
1332
  assert.deepEqual(res, 40);
149
1333
  });
@@ -153,7 +1337,7 @@ describe('internal-plugin-metrics', () => {
153
1337
  cdl.saveTimestamp({key: 'client.alert.removed', value: 45});
154
1338
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
155
1339
  minimum: 10,
156
- maximum: 100
1340
+ maximum: 100,
157
1341
  });
158
1342
  assert.deepEqual(res, 10);
159
1343
  });
@@ -163,7 +1347,7 @@ describe('internal-plugin-metrics', () => {
163
1347
  cdl.saveTimestamp({key: 'client.alert.removed', value: 210});
164
1348
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
165
1349
  minimum: 0,
166
- maximum: 100
1350
+ maximum: 100,
167
1351
  });
168
1352
  assert.deepEqual(res, 100);
169
1353
  });
@@ -172,7 +1356,7 @@ describe('internal-plugin-metrics', () => {
172
1356
  cdl.saveTimestamp({key: 'client.alert.displayed', value: 50});
173
1357
  cdl.saveTimestamp({key: 'client.alert.removed', value: 45});
174
1358
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
175
- maximum: 100
1359
+ maximum: 100,
176
1360
  });
177
1361
  assert.deepEqual(res, 0);
178
1362
  });
@@ -181,7 +1365,7 @@ describe('internal-plugin-metrics', () => {
181
1365
  cdl.saveTimestamp({key: 'client.alert.displayed', value: 10});
182
1366
  cdl.saveTimestamp({key: 'client.alert.removed', value: 2000});
183
1367
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
184
- minimum: 5
1368
+ minimum: 5,
185
1369
  });
186
1370
  assert.deepEqual(res, 1990);
187
1371
  });
@@ -191,7 +1375,7 @@ describe('internal-plugin-metrics', () => {
191
1375
  cdl.saveTimestamp({key: 'client.alert.removed', value: 50});
192
1376
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
193
1377
  minimum: 10,
194
- maximum: 1000
1378
+ maximum: 1000,
195
1379
  });
196
1380
  assert.deepEqual(res, 10);
197
1381
  });
@@ -200,7 +1384,7 @@ describe('internal-plugin-metrics', () => {
200
1384
  cdl.saveTimestamp({key: 'client.alert.displayed', value: 10});
201
1385
  const res = cdl.getDiffBetweenTimestamps('client.alert.displayed', 'client.alert.removed', {
202
1386
  minimum: 0,
203
- maximum: 100
1387
+ maximum: 100,
204
1388
  });
205
1389
  assert.deepEqual(res, undefined);
206
1390
  });
@@ -235,20 +1419,12 @@ describe('internal-plugin-metrics', () => {
235
1419
  });
236
1420
 
237
1421
  describe('measureLatency', () => {
238
- let clock;
239
1422
  let saveLatencySpy;
240
1423
 
241
1424
  beforeEach(() => {
242
- clock = sinon.useFakeTimers();
243
-
244
1425
  saveLatencySpy = sinon.stub(cdl, 'saveLatency');
245
1426
  });
246
1427
 
247
- afterEach(() => {
248
- clock.restore();
249
- sinon.restore();
250
- });
251
-
252
1428
  it('checks measureLatency with accumulate false', async () => {
253
1429
  const key = 'internal.client.pageJMT';
254
1430
  const accumulate = false;
@@ -264,7 +1440,7 @@ describe('internal-plugin-metrics', () => {
264
1440
  const resolvedValue = await promise;
265
1441
  assert.deepEqual(resolvedValue, 'test');
266
1442
  assert.calledOnceWithExactly(callbackStub);
267
- assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
1443
+ assert.calledOnceWithExactly(saveLatencySpy, key, 50, {accumulate});
268
1444
  });
269
1445
 
270
1446
  it('checks measureLatency with accumulate true', async () => {
@@ -280,7 +1456,7 @@ describe('internal-plugin-metrics', () => {
280
1456
  const resolvedValue = await promise;
281
1457
  assert.deepEqual(resolvedValue, 'test123');
282
1458
  assert.calledOnceWithExactly(callbackStub);
283
- assert.calledOnceWithExactly(saveLatencySpy, key, 20, accumulate);
1459
+ assert.calledOnceWithExactly(saveLatencySpy, key, 20, {accumulate});
284
1460
  });
285
1461
 
286
1462
  it('checks measureLatency when callBack rejects', async () => {
@@ -297,7 +1473,7 @@ describe('internal-plugin-metrics', () => {
297
1473
  const rejectedValue = await assert.isRejected(promise);
298
1474
  assert.deepEqual(rejectedValue, error);
299
1475
  assert.calledOnceWithExactly(callbackStub);
300
- assert.calledOnceWithExactly(saveLatencySpy, key, 50, accumulate);
1476
+ assert.calledOnceWithExactly(saveLatencySpy, key, 50, {accumulate});
301
1477
  });
302
1478
  });
303
1479
 
@@ -406,14 +1582,16 @@ describe('internal-plugin-metrics', () => {
406
1582
  });
407
1583
 
408
1584
  it('calculates getShowInterstitialTime correctly', () => {
409
- cdl.saveTimestamp({key: 'client.interstitial-window.start-launch', value: 10});
1585
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 10});
410
1586
  cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 20});
411
1587
  assert.deepEqual(cdl.getShowInterstitialTime(), 10);
412
1588
  });
413
1589
 
414
1590
  it('calculates getCallInitJoinReq correctly', () => {
1591
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 5});
415
1592
  cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
416
1593
  cdl.saveTimestamp({key: 'client.locus.join.request', value: 20});
1594
+ // showedToJoinReq = 20-5 = 15, showInterstitialTime = 10-5 = 5, result = 15-5 = 10
417
1595
  assert.deepEqual(cdl.getCallInitJoinReq(), 10);
418
1596
  });
419
1597
 
@@ -509,16 +1687,60 @@ describe('internal-plugin-metrics', () => {
509
1687
 
510
1688
  it('calculates getStayLobbyTime correctly', () => {
511
1689
  cdl.saveTimestamp({
512
- key: 'client.locus.join.response',
1690
+ key: 'client.lobby.entered',
513
1691
  value: 10,
514
1692
  });
515
1693
  cdl.saveTimestamp({
516
- key: 'internal.host.meeting.participant.admitted',
1694
+ key: 'client.lobby.exited',
517
1695
  value: 20,
518
1696
  });
519
1697
  assert.deepEqual(cdl.getStayLobbyTime(), 10);
520
1698
  });
521
1699
 
1700
+ describe('getStayLobbyTimeCappedBy', () => {
1701
+ it('returns 0 when lobbyStartTimestamp is missing', () => {
1702
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 100});
1703
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 0);
1704
+ });
1705
+
1706
+ it('returns undefined when endTimestampKey is missing', () => {
1707
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 10});
1708
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), undefined);
1709
+ });
1710
+
1711
+ it('uses maximumEndTimestamp when lobby end does not exist', () => {
1712
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 10});
1713
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
1714
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 40);
1715
+ });
1716
+
1717
+ it('uses lobby end when it is before maximumEndTimestamp', () => {
1718
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 10});
1719
+ cdl.saveTimestamp({key: 'client.lobby.exited', value: 30});
1720
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
1721
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 20);
1722
+ });
1723
+
1724
+ it('uses maximumEndTimestamp when lobby end is after it', () => {
1725
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 10});
1726
+ cdl.saveTimestamp({key: 'client.lobby.exited', value: 60});
1727
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
1728
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 40);
1729
+ });
1730
+
1731
+ it('clamps to 0 when result would be negative', () => {
1732
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 100});
1733
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
1734
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 0);
1735
+ });
1736
+
1737
+ it('clamps to MAX_INTEGER when result is very large', () => {
1738
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 0});
1739
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 2147483648});
1740
+ assert.deepEqual(cdl.getStayLobbyTimeCappedBy('client.media-engine.ready'), 2147483647);
1741
+ });
1742
+ });
1743
+
522
1744
  it('calculates getPageJMT correctly', () => {
523
1745
  cdl.saveLatency('internal.client.pageJMT', 10);
524
1746
  assert.deepEqual(cdl.getPageJMT(), 10);
@@ -530,490 +1752,349 @@ describe('internal-plugin-metrics', () => {
530
1752
  });
531
1753
 
532
1754
  it('calculates getClickToInterstitial correctly', () => {
533
- cdl.saveTimestamp({
534
- key: 'internal.client.meeting.click.joinbutton',
535
- value: 10,
536
- });
537
- cdl.saveTimestamp({
538
- key: 'internal.client.meeting.interstitial-window.showed',
539
- value: 20,
540
- });
541
- assert.deepEqual(cdl.getClickToInterstitial(), 10);
542
- });
543
-
544
- it('calculates getClickToInterstitial without join button timestamp', () => {
545
1755
  cdl.saveLatency('internal.click.to.interstitial', 5);
546
- cdl.saveTimestamp({
547
- key: 'internal.client.meeting.interstitial-window.showed',
548
- value: 20,
549
- });
550
1756
  assert.deepEqual(cdl.getClickToInterstitial(), 5);
551
1757
  });
552
1758
 
553
- it('calculates getClickToInterstitial without join button timestamp when it is 0', () => {
1759
+ it('calculates getClickToInterstitial correctly when it is 0', () => {
554
1760
  cdl.saveLatency('internal.click.to.interstitial', 0);
555
- cdl.saveTimestamp({
556
- key: 'internal.client.meeting.interstitial-window.showed',
557
- value: 20,
558
- });
559
1761
  assert.deepEqual(cdl.getClickToInterstitial(), 0);
560
1762
  });
561
1763
 
562
- it('calculates getClickToInterstitial without join button timestamp when it is greater than MAX_INTEGER', () => {
1764
+ it('calculates getClickToInterstitial correctly when it is greater than MAX_INTEGER', () => {
563
1765
  cdl.saveLatency('internal.click.to.interstitial', 2147483648);
564
1766
  assert.deepEqual(cdl.getClickToInterstitial(), 2147483647);
565
1767
  });
566
1768
 
567
1769
  it('calculates getClickToInterstitialWithUserDelay correctly', () => {
568
- cdl.saveTimestamp({
569
- key: 'internal.client.meeting.click.joinbutton',
570
- value: 10,
571
- });
572
- cdl.saveTimestamp({
573
- key: 'internal.client.meeting.interstitial-window.showed',
574
- value: 20,
575
- });
576
- assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 10);
577
- });
578
-
579
- it('calculates getClickToInterstitialWithUserDelay without join button timestamp', () => {
580
1770
  cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 5);
581
- cdl.saveTimestamp({
582
- key: 'internal.client.meeting.interstitial-window.showed',
583
- value: 20,
584
- });
585
1771
  assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 5);
586
1772
  });
587
1773
 
588
- it('calculates getClickToInterstitialWithUserDelay without join button timestamp when it is 0', () => {
1774
+ it('calculates getClickToInterstitialWithUserDelay correctly when it is 0', () => {
589
1775
  cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
590
- cdl.saveTimestamp({
591
- key: 'internal.client.meeting.interstitial-window.showed',
592
- value: 20,
593
- });
594
- assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 0);
595
- });
596
-
597
- it('calculates getClickToInterstitialWithUserDelay without join button timestamp when it is greater than MAX_INTEGER', () => {
598
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 2147483648);
599
- assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 2147483647);
600
- });
601
-
602
- it('calculates getInterstitialToJoinOK correctly', () => {
603
- cdl.saveTimestamp({
604
- key: 'internal.client.interstitial-window.click.joinbutton',
605
- value: 10,
606
- });
607
- cdl.saveTimestamp({
608
- key: 'client.locus.join.response',
609
- value: 20,
610
- });
611
- assert.deepEqual(cdl.getInterstitialToJoinOK(), 10);
612
- });
613
-
614
- it('calculates getInterstitialToJoinOK correctly when one value is not a number', () => {
615
- cdl.saveTimestamp({
616
- key: 'internal.client.interstitial-window.click.joinbutton',
617
- value: 'ten' as unknown as number,
618
- });
619
- cdl.saveTimestamp({
620
- key: 'client.locus.join.response',
621
- value: 20,
622
- });
623
- assert.deepEqual(cdl.getInterstitialToJoinOK(), undefined);
624
- });
625
-
626
- it('calculates getCallInitMediaEngineReady correctly', () => {
627
- cdl.saveTimestamp({
628
- key: 'internal.client.interstitial-window.click.joinbutton',
629
- value: 10,
630
- });
631
- cdl.saveTimestamp({
632
- key: 'client.media-engine.ready',
633
- value: 20,
634
- });
635
- assert.deepEqual(cdl.getCallInitMediaEngineReady(), 10);
636
- });
637
-
638
- it('calculates getTotalJMT correctly', () => {
639
- cdl.saveTimestamp({
640
- key: 'internal.client.interstitial-window.click.joinbutton',
641
- value: 5,
642
- });
643
- cdl.saveTimestamp({
644
- key: 'internal.client.meeting.click.joinbutton',
645
- value: 10,
646
- });
647
- cdl.saveTimestamp({
648
- key: 'internal.client.meeting.interstitial-window.showed',
649
- value: 20,
650
- });
651
- cdl.saveTimestamp({
652
- key: 'client.locus.join.response',
653
- value: 40,
654
- });
655
- assert.deepEqual(cdl.getTotalJMT(), 45);
656
- });
657
-
658
- it('calculates getTotalJMT correctly when clickToInterstitial is 0', () => {
659
- cdl.saveLatency('internal.click.to.interstitial', 0);
660
- cdl.saveTimestamp({
661
- key: 'internal.client.interstitial-window.click.joinbutton',
662
- value: 20,
663
- });
664
- cdl.saveTimestamp({
665
- key: 'client.locus.join.response',
666
- value: 40,
667
- });
668
- assert.deepEqual(cdl.getTotalJMT(), 20);
669
- });
670
-
671
- it('calculates getTotalJMT correctly when interstitialToJoinOk is 0', () => {
672
- cdl.saveTimestamp({
673
- key: 'internal.client.interstitial-window.click.joinbutton',
674
- value: 40,
675
- });
676
- cdl.saveLatency('internal.click.to.interstitial', 12);
677
- cdl.saveTimestamp({
678
- key: 'client.locus.join.response',
679
- value: 40,
680
- });
681
- assert.deepEqual(cdl.getTotalJMT(), 12);
682
- });
683
-
684
- it('calculates getTotalJMT correctly when both clickToInterstitial and interstitialToJoinOk are 0', () => {
685
- cdl.saveTimestamp({
686
- key: 'internal.client.interstitial-window.click.joinbutton',
687
- value: 40,
688
- });
689
- cdl.saveLatency('internal.click.to.interstitial', 0);
690
- cdl.saveTimestamp({
691
- key: 'client.locus.join.response',
692
- value: 40,
693
- });
694
- assert.deepEqual(cdl.getTotalJMT(), 0);
695
- });
696
-
697
- it('calculates getTotalJMT correctly when both clickToInterstitial is not a number', () => {
698
- cdl.saveTimestamp({
699
- key: 'internal.client.interstitial-window.click.joinbutton',
700
- value: 40,
701
- });
702
- cdl.saveLatency('internal.click.to.interstitial', 'eleven' as unknown as number);
703
- cdl.saveTimestamp({
704
- key: 'client.locus.join.response',
705
- value: 40,
706
- });
707
- assert.deepEqual(cdl.getTotalJMT(), undefined);
708
- });
709
-
710
- it('calculates getTotalJMT correctly when it is greater than MAX_INTEGER', () => {
711
- cdl.saveTimestamp({
712
- key: 'internal.client.interstitial-window.click.joinbutton',
713
- value: 5,
714
- });
715
- cdl.saveTimestamp({
716
- key: 'client.locus.join.response',
717
- value: 40,
718
- });
719
- cdl.saveLatency('internal.click.to.interstitial', 2147483648);
720
- assert.deepEqual(cdl.getTotalJMT(), 2147483647);
721
- });
722
-
723
- it('calculates getTotalJMTWithUserDelay correctly', () => {
724
- cdl.saveTimestamp({
725
- key: 'internal.client.interstitial-window.click.joinbutton',
726
- value: 5,
727
- });
728
- cdl.saveTimestamp({
729
- key: 'internal.client.meeting.click.joinbutton',
730
- value: 10,
731
- });
732
- cdl.saveTimestamp({
733
- key: 'internal.client.meeting.interstitial-window.showed',
734
- value: 20,
735
- });
736
- cdl.saveTimestamp({
737
- key: 'client.locus.join.response',
738
- value: 40,
739
- });
740
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 45);
741
- });
742
-
743
- it('calculates getTotalJMTWithUserDelay correctly when clickToInterstitialWithUserDelay is 0', () => {
744
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
745
- cdl.saveTimestamp({
746
- key: 'internal.client.interstitial-window.click.joinbutton',
747
- value: 20,
748
- });
749
- cdl.saveTimestamp({
750
- key: 'client.locus.join.response',
751
- value: 40,
752
- });
753
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 20);
754
- });
755
-
756
- it('calculates getTotalJMTWithUserDelay correctly when interstitialToJoinOk is 0', () => {
757
- cdl.saveTimestamp({
758
- key: 'internal.client.interstitial-window.click.joinbutton',
759
- value: 40,
760
- });
761
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 12);
762
- cdl.saveTimestamp({
763
- key: 'client.locus.join.response',
764
- value: 40,
765
- });
766
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 12);
767
- });
768
-
769
- it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay and interstitialToJoinOk are 0', () => {
770
- cdl.saveTimestamp({
771
- key: 'internal.client.interstitial-window.click.joinbutton',
772
- value: 40,
773
- });
774
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
775
- cdl.saveTimestamp({
776
- key: 'client.locus.join.response',
777
- value: 40,
778
- });
779
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 0);
780
- });
781
-
782
- it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay is not a number', () => {
783
- cdl.saveTimestamp({
784
- key: 'internal.client.interstitial-window.click.joinbutton',
785
- value: 40,
786
- });
787
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 'eleven' as unknown as number);
788
- cdl.saveTimestamp({
789
- key: 'client.locus.join.response',
790
- value: 40,
791
- });
792
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), undefined);
793
- });
1776
+ assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 0);
1777
+ });
794
1778
 
795
- it('calculates getTotalJMTWithUserDelay correctly when it is greater than MAX_INTEGER', () => {
796
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 2147483648);
797
- cdl.saveTimestamp({
798
- key: 'internal.client.interstitial-window.click.joinbutton',
799
- value: 20,
800
- });
801
- cdl.saveTimestamp({
802
- key: 'client.locus.join.response',
803
- value: 40,
804
- });
805
- assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 2147483647);
806
- });
1779
+ it('calculates getClickToInterstitialWithUserDelay correctly when it is greater than MAX_INTEGER', () => {
1780
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 2147483648);
1781
+ assert.deepEqual(cdl.getClickToInterstitialWithUserDelay(), 2147483647);
1782
+ });
807
1783
 
808
- it('calculates getTotalMediaJMT correctly', () => {
809
- cdl.saveTimestamp({
810
- key: 'internal.client.meeting.click.joinbutton',
811
- value: 5,
812
- });
1784
+ it('calculates getInterstitialToJoinOK correctly', () => {
813
1785
  cdl.saveTimestamp({
814
1786
  key: 'internal.client.meeting.interstitial-window.showed',
815
- value: 8,
1787
+ value: 5,
816
1788
  });
817
1789
  cdl.saveTimestamp({
818
1790
  key: 'internal.client.interstitial-window.click.joinbutton',
819
1791
  value: 10,
820
1792
  });
821
- cdl.saveTimestamp({
822
- key: 'client.locus.join.request',
823
- value: 12,
824
- });
825
1793
  cdl.saveTimestamp({
826
1794
  key: 'client.locus.join.response',
827
1795
  value: 20,
828
1796
  });
829
- cdl.saveTimestamp({
830
- key: 'internal.host.meeting.participant.admitted',
831
- value: 24,
832
- });
833
- cdl.saveTimestamp({
834
- key: 'client.ice.start',
835
- value: 30,
836
- });
837
- cdl.saveTimestamp({
838
- key: 'client.ice.end',
839
- value: 40,
840
- });
841
- assert.deepEqual(cdl.getTotalMediaJMT(), 27);
1797
+ // showedToJoinResp = 20-5 = 15, showInterstitialTime = 10-5 = 5, result = 15-5 = 10
1798
+ assert.deepEqual(cdl.getInterstitialToJoinOK(), 10);
842
1799
  });
843
1800
 
844
- it('calculates getTotalMediaJMT correctly when it is greater than MAX_INTEGER', () => {
845
- cdl.saveTimestamp({
846
- key: 'internal.client.meeting.click.joinbutton',
847
- value: 5,
848
- });
1801
+ it('calculates getInterstitialToJoinOK correctly when one value is not a number', () => {
849
1802
  cdl.saveTimestamp({
850
1803
  key: 'internal.client.meeting.interstitial-window.showed',
851
- value: 8,
852
- });
853
- cdl.saveTimestamp({
854
- key: 'internal.client.interstitial-window.click.joinbutton',
855
- value: 10,
856
- });
857
- cdl.saveTimestamp({
858
- key: 'client.locus.join.request',
859
- value: 12,
1804
+ value: 'ten' as unknown as number,
860
1805
  });
861
1806
  cdl.saveTimestamp({
862
1807
  key: 'client.locus.join.response',
863
- value: 2147483700,
864
- });
865
- cdl.saveTimestamp({
866
- key: 'internal.host.meeting.participant.admitted',
867
- value: 2147483800,
868
- });
869
- cdl.saveTimestamp({
870
- key: 'client.ice.start',
871
- value: 30,
872
- });
873
- cdl.saveTimestamp({
874
- key: 'client.ice.end',
875
- value: 100,
1808
+ value: 20,
876
1809
  });
877
- assert.deepEqual(cdl.getTotalMediaJMT(), 2147483647);
1810
+ assert.deepEqual(cdl.getInterstitialToJoinOK(), undefined);
1811
+ });
1812
+
1813
+ it('calculates getCallInitMediaEngineReady correctly', () => {
1814
+ sinon.stub(cdl, 'getInterstitialToMediaOKJMT').returns(42);
1815
+ assert.deepEqual(cdl.getCallInitMediaEngineReady(), 42);
878
1816
  });
879
1817
 
880
- it('calculates getTotalMediaJMT correctly with allowMediaInLobby true', () => {
1818
+ it('calculates getTotalJMT correctly', () => {
1819
+ cdl.saveLatency('internal.click.to.interstitial', 10);
881
1820
  cdl.saveTimestamp({
882
1821
  key: 'internal.client.meeting.click.joinbutton',
883
- value: 5,
884
- options: {meetingId: 'meeting-id'},
1822
+ value: 10,
885
1823
  });
886
1824
  cdl.saveTimestamp({
887
1825
  key: 'internal.client.meeting.interstitial-window.showed',
888
- value: 8,
1826
+ value: 20,
889
1827
  });
890
1828
  cdl.saveTimestamp({
891
1829
  key: 'internal.client.interstitial-window.click.joinbutton',
892
- value: 10,
1830
+ value: 25,
893
1831
  });
894
1832
  cdl.saveTimestamp({
895
- key: 'client.locus.join.request',
896
- value: 12,
1833
+ key: 'client.locus.join.response',
1834
+ value: 40,
897
1835
  });
1836
+ // clickToInterstitial = 20-10 = 10
1837
+ // showedToJoinLocusResponse = 40-20 = 20
1838
+ // showInterstitialTime = 25-20 = 5
1839
+ // total = 10 + 20 - 5 = 25
1840
+ assert.deepEqual(cdl.getTotalJMT(), 25);
1841
+ });
1842
+
1843
+ it('calculates getTotalJMT correctly when clickToInterstitial is 0', () => {
1844
+ cdl.saveLatency('internal.click.to.interstitial', 0);
898
1845
  cdl.saveTimestamp({
899
- key: 'client.locus.join.response',
1846
+ key: 'internal.client.meeting.interstitial-window.showed',
900
1847
  value: 20,
901
1848
  });
902
1849
  cdl.saveTimestamp({
903
- key: 'internal.host.meeting.participant.admitted',
904
- value: 24,
1850
+ key: 'client.locus.join.response',
1851
+ value: 40,
905
1852
  });
1853
+ // showedToJoinLocusResponse = 40-20 = 20, showInterstitialTime = 0
1854
+ // total = 0 + 20 - 0 = 20
1855
+ assert.deepEqual(cdl.getTotalJMT(), 20);
1856
+ });
1857
+
1858
+ it('calculates getTotalJMT correctly when interstitialClickJoinToJoinLocusResponse is 0', () => {
906
1859
  cdl.saveTimestamp({
907
- key: 'client.ice.start',
908
- value: 30,
1860
+ key: 'internal.client.meeting.interstitial-window.showed',
1861
+ value: 40,
909
1862
  });
1863
+ cdl.saveLatency('internal.click.to.interstitial', 12);
910
1864
  cdl.saveTimestamp({
911
- key: 'client.ice.end',
1865
+ key: 'client.locus.join.response',
912
1866
  value: 40,
913
1867
  });
914
- assert.deepEqual(cdl.getTotalMediaJMT(), 31);
1868
+ // showedToJoinLocusResponse = 0, showInterstitialTime = 0
1869
+ // total = 12 + 0 - 0 = 12
1870
+ assert.deepEqual(cdl.getTotalJMT(), 12);
915
1871
  });
916
1872
 
917
- it('calculates getTotalMediaJMT correctly with allowMediaInLobby true and it is greater than MAX_INTEGER', () => {
918
- cdl.saveTimestamp({
919
- key: 'internal.client.meeting.click.joinbutton',
920
- value: 5,
921
- options: {meetingId: 'meeting-id'},
922
- });
1873
+ it('calculates getTotalJMT correctly when both clickToInterstitial and interstitialClickJoinToJoinLocusResponse are 0', () => {
923
1874
  cdl.saveTimestamp({
924
1875
  key: 'internal.client.meeting.interstitial-window.showed',
925
- value: 100,
1876
+ value: 40,
926
1877
  });
1878
+ cdl.saveLatency('internal.click.to.interstitial', 0);
927
1879
  cdl.saveTimestamp({
928
- key: 'internal.client.interstitial-window.click.joinbutton',
929
- value: 1000,
1880
+ key: 'client.locus.join.response',
1881
+ value: 40,
930
1882
  });
1883
+ assert.deepEqual(cdl.getTotalJMT(), 0);
1884
+ });
1885
+
1886
+ it('calculates getTotalJMT correctly when both clickToInterstitial is not a number', () => {
931
1887
  cdl.saveTimestamp({
932
- key: 'client.locus.join.request',
933
- value: 2000,
1888
+ key: 'internal.client.meeting.interstitial-window.showed',
1889
+ value: 40,
934
1890
  });
1891
+ cdl.saveLatency('internal.click.to.interstitial', 'eleven' as unknown as number);
935
1892
  cdl.saveTimestamp({
936
1893
  key: 'client.locus.join.response',
937
- value: 2147483700,
938
- });
939
- cdl.saveTimestamp({
940
- key: 'internal.host.meeting.participant.admitted',
941
- value: 2147483800,
1894
+ value: 40,
942
1895
  });
1896
+ assert.deepEqual(cdl.getTotalJMT(), undefined);
1897
+ });
1898
+
1899
+ it('calculates getTotalJMT correctly when it is greater than MAX_INTEGER', () => {
943
1900
  cdl.saveTimestamp({
944
- key: 'client.ice.start',
945
- value: 2147483900,
1901
+ key: 'internal.client.meeting.interstitial-window.showed',
1902
+ value: 5,
946
1903
  });
947
1904
  cdl.saveTimestamp({
948
- key: 'client.ice.end',
949
- value: 4294967400,
1905
+ key: 'client.locus.join.response',
1906
+ value: 40,
950
1907
  });
951
- assert.deepEqual(cdl.getTotalMediaJMT(), 2147483647);
1908
+ cdl.saveLatency('internal.click.to.interstitial', 2147483648);
1909
+ assert.deepEqual(cdl.getTotalJMT(), 2147483647);
952
1910
  });
953
1911
 
954
- it('calculates getTotalMediaJMTWithUserDelay correctly', () => {
955
- cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 7);
1912
+ it('calculates getTotalJMTWithUserDelay correctly', () => {
1913
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 10);
956
1914
  cdl.saveTimestamp({
957
- key: 'internal.client.interstitial-window.click.joinbutton',
958
- value: 10,
1915
+ key: 'internal.client.meeting.interstitial-window.showed',
1916
+ value: 20,
959
1917
  });
960
1918
  cdl.saveTimestamp({
961
- key: 'client.locus.join.request',
962
- value: 12,
1919
+ key: 'client.locus.join.response',
1920
+ value: 40,
963
1921
  });
1922
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 30);
1923
+ });
1924
+
1925
+ it('calculates getTotalJMTWithUserDelay correctly when clickToInterstitialWithUserDelay is 0', () => {
1926
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
964
1927
  cdl.saveTimestamp({
965
- key: 'client.locus.join.response',
1928
+ key: 'internal.client.meeting.interstitial-window.showed',
966
1929
  value: 20,
967
1930
  });
968
1931
  cdl.saveTimestamp({
969
- key: 'internal.host.meeting.participant.admitted',
970
- value: 24,
1932
+ key: 'client.locus.join.response',
1933
+ value: 40,
971
1934
  });
1935
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 20);
1936
+ });
1937
+
1938
+ it('calculates getTotalJMTWithUserDelay correctly when interstitialShowedToJoinLocusResponse is 0', () => {
972
1939
  cdl.saveTimestamp({
973
- key: 'client.ice.start',
974
- value: 30,
1940
+ key: 'internal.client.meeting.interstitial-window.showed',
1941
+ value: 40,
975
1942
  });
1943
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 12);
976
1944
  cdl.saveTimestamp({
977
- key: 'client.ice.end',
1945
+ key: 'client.locus.join.response',
978
1946
  value: 40,
979
1947
  });
980
- assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 35);
1948
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 12);
981
1949
  });
982
1950
 
983
- it('calculates getTotalMediaJMTWithUserDelay correctly for guest join', () => {
984
- cdl.saveTimestamp({
985
- key: 'internal.client.meeting.click.joinbutton',
986
- value: 5,
987
- });
1951
+ it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay and interstitialShowedToJoinLocusResponse are 0', () => {
988
1952
  cdl.saveTimestamp({
989
1953
  key: 'internal.client.meeting.interstitial-window.showed',
990
- value: 8,
1954
+ value: 40,
991
1955
  });
1956
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 0);
992
1957
  cdl.saveTimestamp({
993
- key: 'internal.client.interstitial-window.click.joinbutton',
994
- value: 10,
1958
+ key: 'client.locus.join.response',
1959
+ value: 40,
995
1960
  });
1961
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 0);
1962
+ });
1963
+
1964
+ it('calculates getTotalJMTWithUserDelay correctly when both clickToInterstitialWithUserDelay is not a number', () => {
996
1965
  cdl.saveTimestamp({
997
- key: 'client.locus.join.request',
998
- value: 12,
1966
+ key: 'internal.client.meeting.interstitial-window.showed',
1967
+ value: 40,
999
1968
  });
1969
+ cdl.saveLatency(
1970
+ 'internal.click.to.interstitial.with.user.delay',
1971
+ 'eleven' as unknown as number
1972
+ );
1000
1973
  cdl.saveTimestamp({
1001
1974
  key: 'client.locus.join.response',
1002
- value: 20,
1003
- });
1004
- cdl.saveTimestamp({
1005
- key: 'internal.host.meeting.participant.admitted',
1006
- value: 24,
1975
+ value: 40,
1007
1976
  });
1977
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), undefined);
1978
+ });
1979
+
1980
+ it('calculates getTotalJMTWithUserDelay correctly when it is greater than MAX_INTEGER', () => {
1981
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 2147483648);
1008
1982
  cdl.saveTimestamp({
1009
- key: 'client.ice.start',
1010
- value: 30,
1983
+ key: 'internal.client.meeting.interstitial-window.showed',
1984
+ value: 20,
1011
1985
  });
1012
1986
  cdl.saveTimestamp({
1013
- key: 'client.ice.end',
1987
+ key: 'client.locus.join.response',
1014
1988
  value: 40,
1015
1989
  });
1016
- assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 31);
1990
+ assert.deepEqual(cdl.getTotalJMTWithUserDelay(), 2147483647);
1991
+ });
1992
+
1993
+ it('calculates getTotalMediaJMT correctly with lobby exiting before media-engine.ready', () => {
1994
+ cdl.saveLatency('internal.click.to.interstitial', 3);
1995
+ // clickToInterstitial = 3
1996
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
1997
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
1998
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
1999
+ // interstitialShowedToMediaEngineReady = 50 - 8 = 42
2000
+ // showInterstitialTime = 10 - 8 = 2
2001
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 20});
2002
+ cdl.saveTimestamp({key: 'client.lobby.exited', value: 30});
2003
+ // stayLobbyTimeCappedByMediaEngineReady = min(30, 50) - 20 = 10
2004
+ // total = 3 + 42 - 2 - 10 = 33
2005
+ assert.deepEqual(cdl.getTotalMediaJMT(), 33);
2006
+ });
2007
+
2008
+ it('calculates getTotalMediaJMT correctly without lobby', () => {
2009
+ cdl.saveLatency('internal.click.to.interstitial', 3);
2010
+ // clickToInterstitial = 3
2011
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
2012
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
2013
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2014
+ // interstitialShowedToMediaEngineReady = 50 - 8 = 42
2015
+ // showInterstitialTime = 10 - 8 = 2
2016
+ // no client.lobby.entered → stayLobbyTimeCappedByMediaEngineReady = 0
2017
+ // total = 3 + 42 - 2 - 0 = 43
2018
+ assert.deepEqual(cdl.getTotalMediaJMT(), 43);
2019
+ });
2020
+
2021
+ it('calculates getTotalMediaJMT correctly with lobby exiting after media-engine.ready', () => {
2022
+ cdl.saveLatency('internal.click.to.interstitial', 3);
2023
+ // clickToInterstitial = 3
2024
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
2025
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
2026
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2027
+ // interstitialShowedToMediaEngineReady = 50 - 8 = 42
2028
+ // showInterstitialTime = 10 - 8 = 2
2029
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 20});
2030
+ cdl.saveTimestamp({key: 'client.lobby.exited', value: 60});
2031
+ // stayLobbyTimeCappedByMediaEngineReady = min(60, 50) - 20 = 30
2032
+ // total = 3 + 42 - 2 - 30 = 13
2033
+ assert.deepEqual(cdl.getTotalMediaJMT(), 13);
2034
+ });
2035
+
2036
+ it('calculates getTotalMediaJMT correctly when it is greater than MAX_INTEGER', () => {
2037
+ cdl.saveLatency('internal.click.to.interstitial', 5);
2038
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 10});
2039
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
2040
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 4294967400});
2041
+ cdl.saveTimestamp({key: 'client.lobby.entered', value: 28});
2042
+ cdl.saveTimestamp({key: 'client.lobby.exited', value: 30});
2043
+ assert.deepEqual(cdl.getTotalMediaJMT(), 2147483647);
2044
+ });
2045
+
2046
+ it('returns undefined for getTotalMediaJMT when media-engine.ready is missing', () => {
2047
+ cdl.saveLatency('internal.click.to.interstitial', 3);
2048
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
2049
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
2050
+ cdl.saveTimestamp({key: 'client.locus.join.response', value: 20});
2051
+ assert.deepEqual(cdl.getTotalMediaJMT(), undefined);
2052
+ });
2053
+
2054
+ it('calculates getTotalMediaJMT correctly when there is no lobby and stayLobbyTime defaults to 0', () => {
2055
+ cdl.saveLatency('internal.click.to.interstitial', 3);
2056
+ // clickToInterstitial = 3
2057
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
2058
+ cdl.saveTimestamp({key: 'internal.client.interstitial-window.click.joinbutton', value: 10});
2059
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2060
+ // interstitialShowedToMediaEngineReady = 50 - 8 = 42
2061
+ // showInterstitialTime = 10 - 8 = 2
2062
+ // no client.lobby.entered → stayLobbyTimeCappedByMediaEngineReady = 0
2063
+ // total = 3 + 42 - 2 - 0 = 43
2064
+ assert.deepEqual(cdl.getTotalMediaJMT(), 43);
2065
+ });
2066
+
2067
+ it('calculates getTotalMediaJMTWithUserDelay correctly', () => {
2068
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 7);
2069
+ // clickToInterstitialWithUserDelay = 7
2070
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 10});
2071
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2072
+ // interstitialShowedToMediaEngineReady = 50 - 10 = 40
2073
+ // total = 7 + 40 = 47
2074
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 47);
2075
+ });
2076
+
2077
+ it('calculates getTotalMediaJMTWithUserDelay correctly for guest join', () => {
2078
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 3);
2079
+ // clickToInterstitialWithUserDelay = 3
2080
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 8});
2081
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2082
+ // interstitialShowedToMediaEngineReady = 50 - 8 = 42
2083
+ // total = 3 + 42 = 45
2084
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 45);
2085
+ });
2086
+
2087
+ it('returns undefined for getTotalMediaJMTWithUserDelay when media-engine.ready is missing', () => {
2088
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 7);
2089
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 10});
2090
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), undefined);
2091
+ });
2092
+
2093
+ it('calculates getTotalMediaJMTWithUserDelay correctly when it is greater than MAX_INTEGER', () => {
2094
+ cdl.saveLatency('internal.click.to.interstitial.with.user.delay', 2147483648);
2095
+ cdl.saveTimestamp({key: 'internal.client.meeting.interstitial-window.showed', value: 10});
2096
+ cdl.saveTimestamp({key: 'client.media-engine.ready', value: 50});
2097
+ assert.deepEqual(cdl.getTotalMediaJMTWithUserDelay(), 2147483647);
1017
2098
  });
1018
2099
 
1019
2100
  it('calculates getJoinConfJMT correctly', () => {
@@ -1041,24 +2122,29 @@ describe('internal-plugin-metrics', () => {
1041
2122
  // the maximum possible sum is 2400000, which is less than MAX_INTEGER (2147483647).
1042
2123
  // This test should verify that the final clamping works by mocking the intermediate methods
1043
2124
  // to return values that would sum to more than MAX_INTEGER.
1044
-
2125
+
1045
2126
  const originalGetJoinReqResp = cdl.getJoinReqResp;
1046
2127
  const originalGetICESetupTime = cdl.getICESetupTime;
1047
-
2128
+
1048
2129
  // Mock the methods to return large values that would exceed MAX_INTEGER when summed
1049
2130
  cdl.getJoinReqResp = () => 1500000000;
1050
2131
  cdl.getICESetupTime = () => 1000000000;
1051
-
2132
+
1052
2133
  const result = cdl.getJoinConfJMT();
1053
-
2134
+
1054
2135
  // Restore original methods
1055
2136
  cdl.getJoinReqResp = originalGetJoinReqResp;
1056
2137
  cdl.getICESetupTime = originalGetICESetupTime;
1057
-
2138
+
1058
2139
  assert.deepEqual(result, 2147483647);
1059
2140
  });
1060
2141
 
1061
2142
  it('calculates getClientJMT correctly', () => {
2143
+ cdl.saveLatency('internal.click.to.interstitial.for.client.jmt', 5);
2144
+ cdl.saveTimestamp({
2145
+ key: 'internal.client.meeting.interstitial-window.showed',
2146
+ value: 1,
2147
+ });
1062
2148
  cdl.saveTimestamp({
1063
2149
  key: 'internal.client.interstitial-window.click.joinbutton',
1064
2150
  value: 2,
@@ -1067,19 +2153,30 @@ describe('internal-plugin-metrics', () => {
1067
2153
  key: 'client.locus.join.request',
1068
2154
  value: 6,
1069
2155
  });
2156
+ // showedToLocusJoinRequest = 6-1 = 5, showInterstitialTime = 2-1 = 1
2157
+ // clickToInterstitialForClientJmt (5) + 5 - 1 = 9
2158
+ assert.deepEqual(cdl.getClientJMT(), 9);
2159
+ });
2160
+
2161
+ it('returns undefined for getClientJMT when clickToInterstitialForClientJmt is missing', () => {
1070
2162
  cdl.saveTimestamp({
1071
- key: 'client.locus.join.response',
1072
- value: 8,
2163
+ key: 'internal.client.meeting.interstitial-window.showed',
2164
+ value: 1,
1073
2165
  });
1074
2166
  cdl.saveTimestamp({
1075
- key: 'client.ice.start',
1076
- value: 10,
2167
+ key: 'internal.client.interstitial-window.click.joinbutton',
2168
+ value: 2,
1077
2169
  });
1078
2170
  cdl.saveTimestamp({
1079
- key: 'client.ice.end',
1080
- value: 11,
2171
+ key: 'client.locus.join.request',
2172
+ value: 6,
1081
2173
  });
1082
- assert.deepEqual(cdl.getClientJMT(), 3);
2174
+ assert.deepEqual(cdl.getClientJMT(), undefined);
2175
+ });
2176
+
2177
+ it('returns undefined for getClientJMT when interstitialJoinToLocusJoinRequest is missing', () => {
2178
+ cdl.saveLatency('internal.click.to.interstitial.for.client.jmt', 5);
2179
+ assert.deepEqual(cdl.getClientJMT(), undefined);
1083
2180
  });
1084
2181
 
1085
2182
  it('calculates getAudioJoinRespRxStart correctly', () => {
@@ -1131,37 +2228,48 @@ describe('internal-plugin-metrics', () => {
1131
2228
  });
1132
2229
 
1133
2230
  it('calculates getInterstitialToMediaOKJMT correctly', () => {
2231
+ cdl.saveTimestamp({
2232
+ key: 'internal.client.meeting.interstitial-window.showed',
2233
+ value: 2,
2234
+ });
1134
2235
  cdl.saveTimestamp({
1135
2236
  key: 'internal.client.interstitial-window.click.joinbutton',
1136
2237
  value: 4,
1137
2238
  });
1138
2239
  cdl.saveTimestamp({
1139
- key: 'client.locus.join.response',
2240
+ key: 'client.lobby.entered',
1140
2241
  value: 10,
1141
2242
  });
1142
2243
  cdl.saveTimestamp({
1143
- key: 'internal.host.meeting.participant.admitted',
2244
+ key: 'client.lobby.exited',
1144
2245
  value: 12,
1145
2246
  });
1146
2247
  cdl.saveTimestamp({
1147
2248
  key: 'client.ice.end',
1148
2249
  value: 14,
1149
2250
  });
2251
+ // showedToIceEnd = 14-2 = 12, showInterstitialTime = 4-2 = 2
2252
+ // stayLobbyTimeCappedByIceEnd = min(12,14)-10 = 2
2253
+ // result = 12 - 2 - 2 = 8
1150
2254
  assert.deepEqual(cdl.getInterstitialToMediaOKJMT(), 8);
1151
2255
  });
1152
2256
 
1153
2257
  it('calculates getInterstitialToMediaOKJMT correctly when it is greater than MAX_INTEGER', () => {
2258
+ cdl.saveTimestamp({
2259
+ key: 'internal.client.meeting.interstitial-window.showed',
2260
+ value: 4,
2261
+ });
1154
2262
  cdl.saveTimestamp({
1155
2263
  key: 'internal.client.interstitial-window.click.joinbutton',
1156
2264
  value: 4,
1157
2265
  });
1158
2266
  cdl.saveTimestamp({
1159
- key: 'client.locus.join.response',
2267
+ key: 'client.lobby.entered',
1160
2268
  value: 10,
1161
2269
  });
1162
2270
  cdl.saveTimestamp({
1163
- key: 'internal.host.meeting.participant.admitted',
1164
- value: 12,
2271
+ key: 'client.lobby.exited',
2272
+ value: 10,
1165
2273
  });
1166
2274
  cdl.saveTimestamp({
1167
2275
  key: 'client.ice.end',
@@ -1171,6 +2279,29 @@ describe('internal-plugin-metrics', () => {
1171
2279
  });
1172
2280
 
1173
2281
  it('calculates getInterstitialToMediaOKJMT correctly without lobby', () => {
2282
+ cdl.saveTimestamp({
2283
+ key: 'internal.client.meeting.interstitial-window.showed',
2284
+ value: 2,
2285
+ });
2286
+ cdl.saveTimestamp({
2287
+ key: 'internal.client.interstitial-window.click.joinbutton',
2288
+ value: 4,
2289
+ });
2290
+ cdl.saveTimestamp({
2291
+ key: 'client.ice.end',
2292
+ value: 14,
2293
+ });
2294
+ // showedToIceEnd = 14-2 = 12, showInterstitialTime = 4-2 = 2
2295
+ // stayLobbyTimeCappedByIceEnd = 0 (no lobby)
2296
+ // result = 12 - 2 - 0 = 10
2297
+ assert.deepEqual(cdl.getInterstitialToMediaOKJMT(), 10);
2298
+ });
2299
+
2300
+ it('calculates getInterstitialToMediaOKJMT correctly when there is no lobby and stayLobbyTime defaults to 0', () => {
2301
+ cdl.saveTimestamp({
2302
+ key: 'internal.client.meeting.interstitial-window.showed',
2303
+ value: 2,
2304
+ });
1174
2305
  cdl.saveTimestamp({
1175
2306
  key: 'internal.client.interstitial-window.click.joinbutton',
1176
2307
  value: 4,
@@ -1179,6 +2310,9 @@ describe('internal-plugin-metrics', () => {
1179
2310
  key: 'client.ice.end',
1180
2311
  value: 14,
1181
2312
  });
2313
+ // showedToIceEnd = 14-2 = 12, showInterstitialTime = 4-2 = 2
2314
+ // stayLobbyTimeCappedByIceEnd = 0 (no lobby)
2315
+ // result = 12 - 2 - 0 = 10
1182
2316
  assert.deepEqual(cdl.getInterstitialToMediaOKJMT(), 10);
1183
2317
  });
1184
2318