@webex/internal-plugin-metrics 3.12.0-next.34 → 3.12.0-next.35
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/call-diagnostic/call-diagnostic-metrics-latencies.js +571 -15
- package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js +4 -0
- package/dist/metrics.types.js.map +1 -1
- package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +199 -5
- package/dist/types/index.d.ts +2 -2
- package/dist/types/metrics.types.d.ts +4 -2
- package/package.json +2 -2
- package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +661 -5
- package/src/index.ts +2 -0
- package/src/metrics.types.ts +15 -2
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1192 -16
|
@@ -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', () => {
|
|
@@ -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
|
|