@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
@@ -27,6 +27,7 @@ const {
27
27
  isUnauthorizedError,
28
28
  generateClientErrorCodeForIceFailure,
29
29
  isSdpOfferCreationError,
30
+ isWebrtcApiNotAvailableError,
30
31
  } = CallDiagnosticUtils;
31
32
 
32
33
  describe('internal-plugin-metrics', () => {
@@ -206,6 +207,29 @@ describe('internal-plugin-metrics', () => {
206
207
  });
207
208
  });
208
209
 
210
+ describe('isWebrtcApiNotAvailableError', () => {
211
+ type TestWebrtcApiNotAvailableError = {
212
+ code: number;
213
+ message: string;
214
+ name: string;
215
+ };
216
+
217
+ const error: TestWebrtcApiNotAvailableError = {
218
+ code: 30007,
219
+ name: 'WebrtcApiNotAvailableError',
220
+ message: 'RTCPeerConnection API is not available in this environment',
221
+ };
222
+
223
+ [
224
+ ['WebrtcApiNotAvailableError', error, true],
225
+ ['generic error', new Error('this is an error'), false],
226
+ ].forEach(([errorType, rawError, expected]) => {
227
+ it(`for ${errorType} rawError returns the correct result`, () => {
228
+ assert.strictEqual(isWebrtcApiNotAvailableError(rawError), expected);
229
+ });
230
+ });
231
+ });
232
+
209
233
  describe('isBrowserMediaErrorName', () => {
210
234
  [
211
235
  ['PermissionDeniedError', true],
@@ -287,7 +311,7 @@ describe('internal-plugin-metrics', () => {
287
311
  origin: {
288
312
  buildType: 'prod',
289
313
  networkType: 'unknown',
290
- upgradeChannel: expectedUpgradeChannel
314
+ upgradeChannel: expectedUpgradeChannel,
291
315
  },
292
316
  event: {name: eventName, ...expectedEvent},
293
317
  },
@@ -369,7 +393,7 @@ describe('internal-plugin-metrics', () => {
369
393
  totalJmt: undefined,
370
394
  clientJmt: undefined,
371
395
  downloadTime: undefined,
372
- clickToInterstitialWithUserDelay: undefined,
396
+ clickToInterstitialWithUserDelay: undefined,
373
397
  totalJMTWithUserDelay: undefined,
374
398
  },
375
399
  },
@@ -406,7 +430,6 @@ describe('internal-plugin-metrics', () => {
406
430
  totalMediaJMT: undefined,
407
431
  interstitialToMediaOKJMT: undefined,
408
432
  callInitMediaEngineReady: undefined,
409
- stayLobbyTime: undefined,
410
433
  totalMediaJMTWithUserDelay: undefined,
411
434
  totalJMTWithUserDelay: undefined,
412
435
  },
@@ -423,12 +446,47 @@ describe('internal-plugin-metrics', () => {
423
446
  },
424
447
  },
425
448
  ],
449
+ [
450
+ 'client.lobby.exited',
451
+ {
452
+ joinTimes: {
453
+ stayLobbyTime: undefined,
454
+ },
455
+ },
456
+ ],
426
457
  ].forEach(([eventName, expectedEvent]) => {
427
458
  it(`returns expected result for ${eventName}`, () => {
428
459
  check(eventName as string, expectedEvent, 'gold');
429
460
  });
430
461
  });
431
462
 
463
+ it('logs a Milestone entry when event name is present', () => {
464
+ const logSpy = sinon.spy(webex.logger, 'log');
465
+ const eventName = 'client.call.initiated';
466
+ const eventPayload = {event: {name: eventName}};
467
+
468
+ prepareDiagnosticMetricItem(webex, {eventPayload, type: ['diagnostic-event']});
469
+
470
+ assert.isTrue(
471
+ logSpy.calledWith('Milestone,CallDiagnostic', eventName),
472
+ 'expected logger.log to be called with Milestone,CallDiagnostic and the event name'
473
+ );
474
+ sinon.restore();
475
+ });
476
+
477
+ it('does not log a Milestone entry when event name is absent', () => {
478
+ const logSpy = sinon.spy(webex.logger, 'log');
479
+ const eventPayload = {event: {}};
480
+
481
+ prepareDiagnosticMetricItem(webex, {eventPayload, type: ['diagnostic-event']});
482
+
483
+ assert.isFalse(
484
+ logSpy.calledWith('Milestone,CallDiagnostic', sinon.match.any),
485
+ 'expected logger.log not to be called with Milestone,CallDiagnostic when event name is absent'
486
+ );
487
+ sinon.restore();
488
+ });
489
+
432
490
  it('sets buildType and upgradeChannel correctly', () => {
433
491
  const item: any = {
434
492
  eventPayload: {
@@ -1,23 +1,31 @@
1
1
  import {assert} from '@webex/test-helper-chai';
2
- import {NewMetrics, CallDiagnosticLatencies} from '@webex/internal-plugin-metrics';
2
+ import {
3
+ NewMetrics,
4
+ CallDiagnosticLatencies,
5
+ AutomatedUserUtils,
6
+ Utils,
7
+ } from '@webex/internal-plugin-metrics';
3
8
  import MockWebex from '@webex/test-helper-mock-webex';
4
9
  import sinon from 'sinon';
5
- import {Utils} from '@webex/internal-plugin-metrics';
6
10
 
7
11
  describe('internal-plugin-metrics', () => {
8
-
9
- const mockWebex = () => new MockWebex({
10
- children: {
11
- newMetrics: NewMetrics,
12
- },
13
- meetings: {
14
- },
15
- request: sinon.stub().resolves({}),
16
- logger: {
17
- log: sinon.stub(),
18
- error: sinon.stub(),
19
- }
20
- });
12
+ const mockWebex = () =>
13
+ new MockWebex({
14
+ children: {
15
+ newMetrics: NewMetrics,
16
+ },
17
+ meetings: {
18
+ getBasicMeetingInformation: sinon.stub().callsFake((meetingId) => ({
19
+ id: meetingId,
20
+ correlationId: `correlation-${meetingId}`,
21
+ })),
22
+ },
23
+ request: sinon.stub().resolves({}),
24
+ logger: {
25
+ log: sinon.stub(),
26
+ error: sinon.stub(),
27
+ },
28
+ });
21
29
 
22
30
  describe('check submitClientEvent, submitFeatureEvent when webex is not ready', () => {
23
31
  let webex;
@@ -46,12 +54,14 @@ describe('internal-plugin-metrics', () => {
46
54
  payload: {
47
55
  meetingSummaryInfo: {
48
56
  featureName: 'syncSystemMuteStatus',
49
- featureActions: [{
50
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
51
- actionId: '14200',
52
- isInitialValue: false,
53
- clickCount: '1'
54
- }]
57
+ featureActions: [
58
+ {
59
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
60
+ actionId: '14200',
61
+ isInitialValue: false,
62
+ clickCount: '1',
63
+ },
64
+ ],
55
65
  },
56
66
  },
57
67
  });
@@ -64,11 +74,36 @@ describe('internal-plugin-metrics', () => {
64
74
 
65
75
  describe('new-metrics contstructor', () => {
66
76
  it('checks callDiagnosticLatencies is defined before ready emit', () => {
67
-
68
77
  const webex = mockWebex();
69
78
 
70
79
  assert.instanceOf(webex.internal.newMetrics.callDiagnosticLatencies, CallDiagnosticLatencies);
71
80
  });
81
+
82
+ it('checks callDiagnosticMetrics is defined before ready emit', () => {
83
+ const webex = mockWebex();
84
+
85
+ assert.isDefined(webex.internal.newMetrics.callDiagnosticMetrics);
86
+ });
87
+
88
+ it('can call buildClientEventFetchRequestOptions before ready', async () => {
89
+ const webex = mockWebex();
90
+ const stub = sinon.stub(
91
+ webex.internal.newMetrics.callDiagnosticMetrics,
92
+ 'buildClientEventFetchRequestOptions'
93
+ ).resolves({url: 'https://metrics.example.com'});
94
+
95
+ const result = await webex.internal.newMetrics.buildClientEventFetchRequestOptions({
96
+ name: 'client.alert.displayed',
97
+ options: {correlationId: 'test-id'},
98
+ });
99
+
100
+ assert.calledOnceWithExactly(stub, {
101
+ name: 'client.alert.displayed',
102
+ payload: undefined,
103
+ options: {correlationId: 'test-id'},
104
+ });
105
+ assert.deepEqual(result, {url: 'https://metrics.example.com'});
106
+ });
72
107
  });
73
108
 
74
109
  describe('new-metrics', () => {
@@ -94,7 +129,7 @@ describe('internal-plugin-metrics', () => {
94
129
 
95
130
  afterEach(() => {
96
131
  sinon.restore();
97
- })
132
+ });
98
133
 
99
134
  it('lazy metrics backend initialization when checking if backend ready', () => {
100
135
  assert.isUndefined(webex.internal.newMetrics.behavioralMetrics);
@@ -105,13 +140,20 @@ describe('internal-plugin-metrics', () => {
105
140
  webex.internal.newMetrics.isReadyToSubmitOperationalEvents();
106
141
  assert.isDefined(webex.internal.newMetrics.operationalMetrics);
107
142
 
108
- assert.isUndefined(webex.internal.newMetrics.businessMetrics)
143
+ assert.isUndefined(webex.internal.newMetrics.businessMetrics);
109
144
  webex.internal.newMetrics.isReadyToSubmitBusinessEvents();
110
145
  assert.isDefined(webex.internal.newMetrics.businessMetrics);
111
- })
146
+ });
147
+
148
+ it('returns the automated user classification', () => {
149
+ assert.strictEqual(
150
+ webex.internal.newMetrics.isAutomatedUser(),
151
+ AutomatedUserUtils.isAutomatedUser()
152
+ );
153
+ });
112
154
 
113
155
  it('passes the table through to the business metrics', () => {
114
- assert.isUndefined(webex.internal.newMetrics.businessMetrics)
156
+ assert.isUndefined(webex.internal.newMetrics.businessMetrics);
115
157
  webex.internal.newMetrics.isReadyToSubmitBusinessEvents();
116
158
  assert.isDefined(webex.internal.newMetrics.businessMetrics);
117
159
  webex.internal.newMetrics.businessMetrics.submitBusinessEvent = sinon.stub();
@@ -119,14 +161,14 @@ describe('internal-plugin-metrics', () => {
119
161
  name: 'foobar',
120
162
  payload: {},
121
163
  table: 'test',
122
- metadata: { foo: 'bar' },
164
+ metadata: {foo: 'bar'},
123
165
  });
124
166
 
125
167
  assert.calledWith(webex.internal.newMetrics.businessMetrics.submitBusinessEvent, {
126
168
  name: 'foobar',
127
169
  payload: {},
128
170
  table: 'test',
129
- metadata: { foo: 'bar' },
171
+ metadata: {foo: 'bar'},
130
172
  });
131
173
  });
132
174
 
@@ -150,6 +192,87 @@ describe('internal-plugin-metrics', () => {
150
192
  });
151
193
  });
152
194
 
195
+ describe('privacy and security permission enrichment', () => {
196
+ const permission = {
197
+ camera: {status: 'GRANTED' as const},
198
+ microphone: {status: 'DENIED' as const, reason: 'DENIED_BY_USER' as const},
199
+ contentShare: {status: 'REQUESTING' as const},
200
+ };
201
+
202
+ it('enriches an eligible client event through the public metrics API', () => {
203
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
204
+ webex.internal.newMetrics.submitClientEvent({name: 'client.call.initiated'});
205
+
206
+ const submittedPayload =
207
+ webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.firstCall.args[0]
208
+ .payload;
209
+
210
+ assert.deepEqual(submittedPayload.privacyAndSecurityPermission, {
211
+ camera: permission.camera,
212
+ microphone: permission.microphone,
213
+ });
214
+ });
215
+
216
+ it('uses the meeting correlation id to preserve history across identifier transitions', () => {
217
+ webex.meetings.getBasicMeetingInformation
218
+ .withArgs('meeting-1')
219
+ .returns({id: 'meeting-1', correlationId: 'correlation-1'});
220
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
221
+
222
+ webex.internal.newMetrics.submitClientEvent({
223
+ name: 'client.call.initiated',
224
+ options: {correlationId: 'correlation-1'},
225
+ });
226
+ webex.internal.newMetrics.submitClientEvent({
227
+ name: 'client.ice.end',
228
+ payload: {},
229
+ options: {meetingId: 'meeting-1'},
230
+ });
231
+
232
+ const submissions = webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.args;
233
+
234
+ assert.property(submissions[0][0].payload, 'privacyAndSecurityPermission');
235
+ assert.notProperty(submissions[1][0].payload, 'privacyAndSecurityPermission');
236
+ });
237
+
238
+ it('uses the default scope when no correlation id can be resolved', () => {
239
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
240
+
241
+ webex.internal.newMetrics.submitClientEvent({
242
+ name: 'client.call.initiated',
243
+ options: {sessionCorrelationId: 'session-1'},
244
+ });
245
+ webex.internal.newMetrics.submitClientEvent({
246
+ name: 'client.ice.end',
247
+ payload: {},
248
+ options: {sessionCorrelationId: 'session-2'},
249
+ });
250
+
251
+ const submissions = webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.args;
252
+
253
+ assert.property(submissions[0][0].payload, 'privacyAndSecurityPermission');
254
+ assert.notProperty(submissions[1][0].payload, 'privacyAndSecurityPermission');
255
+ });
256
+
257
+ it('captures the permission snapshot before a delayed event is queued', () => {
258
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission(permission);
259
+ webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: true});
260
+ webex.internal.newMetrics.submitClientEvent({name: 'client.call.initiated'});
261
+ webex.internal.newMetrics.setPrivacyAndSecurityPermission({
262
+ camera: {status: 'DENIED' as const},
263
+ });
264
+
265
+ const submission =
266
+ webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent.firstCall.args[0];
267
+
268
+ assert.isTrue(submission.delaySubmitEvent);
269
+ assert.deepEqual(submission.payload.privacyAndSecurityPermission, {
270
+ camera: permission.camera,
271
+ microphone: permission.microphone,
272
+ });
273
+ });
274
+ });
275
+
153
276
  it('submits feature Event successfully', () => {
154
277
  webex.internal.newMetrics.submitFeatureEvent({
155
278
  name: 'client.feature.meeting.summary',
@@ -159,12 +282,14 @@ describe('internal-plugin-metrics', () => {
159
282
  payload: {
160
283
  meetingSummaryInfo: {
161
284
  featureName: 'syncSystemMuteStatus',
162
- featureActions: [{
163
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
164
- actionId: '14200',
165
- isInitialValue: false,
166
- clickCount: '1'
167
- }]
285
+ featureActions: [
286
+ {
287
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
288
+ actionId: '14200',
289
+ isInitialValue: false,
290
+ clickCount: '1',
291
+ },
292
+ ],
168
293
  },
169
294
  },
170
295
  });
@@ -178,12 +303,14 @@ describe('internal-plugin-metrics', () => {
178
303
  payload: {
179
304
  meetingSummaryInfo: {
180
305
  featureName: 'syncSystemMuteStatus',
181
- featureActions: [{
182
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
183
- actionId: '14200',
184
- isInitialValue: false,
185
- clickCount: '1'
186
- }]
306
+ featureActions: [
307
+ {
308
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
309
+ actionId: '14200',
310
+ isInitialValue: false,
311
+ clickCount: '1',
312
+ },
313
+ ],
187
314
  },
188
315
  },
189
316
  options: {meetingId: '123'},
@@ -244,9 +371,9 @@ describe('internal-plugin-metrics', () => {
244
371
  method: 'POST',
245
372
  api: 'metrics',
246
373
  resource: 'clientmetrics',
247
- headers: { 'x-prelogin-userid': 'my-id' },
374
+ headers: {'x-prelogin-userid': 'my-id'},
248
375
  body: {},
249
- qs: { alias: true },
376
+ qs: {alias: true},
250
377
  });
251
378
  assert.calledWith(
252
379
  webex.logger.log,
@@ -255,8 +382,8 @@ describe('internal-plugin-metrics', () => {
255
382
  });
256
383
 
257
384
  it('handles failed request correctly', async () => {
258
- webex.request.rejects(new Error("test error"));
259
- sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError')
385
+ webex.request.rejects(new Error('test error'));
386
+ sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError');
260
387
  try {
261
388
  await webex.internal.newMetrics.clientMetricsAliasUser({event: 'test'}, 'my-id');
262
389
  } catch (err) {
@@ -338,19 +465,26 @@ describe('internal-plugin-metrics', () => {
338
465
  sinon.assert.match(webex.internal.newMetrics.delaySubmitClientEvents, true);
339
466
  sinon.assert.match(webex.internal.newMetrics.delayedClientEventsOverrides, {});
340
467
 
341
- webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: false, overrides: {foo: 'bar'}});
468
+ webex.internal.newMetrics.setDelaySubmitClientEvents({
469
+ shouldDelay: false,
470
+ overrides: {foo: 'bar'},
471
+ });
342
472
 
343
- assert.calledOnce(webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents);
344
- assert.calledWith(webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents, {foo: 'bar'});
473
+ assert.calledOnce(
474
+ webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents
475
+ );
476
+ assert.calledWith(
477
+ webex.internal.newMetrics.callDiagnosticMetrics.submitDelayedClientEvents,
478
+ {foo: 'bar'}
479
+ );
345
480
 
346
481
  sinon.assert.match(webex.internal.newMetrics.delaySubmitClientEvents, false);
347
482
  sinon.assert.match(webex.internal.newMetrics.delayedClientEventsOverrides, {foo: 'bar'});
348
483
  });
349
484
 
350
485
  it('should not fail when called before webex is ready', () => {
351
-
352
486
  // Create mock
353
- webex = mockWebex()
487
+ webex = mockWebex();
354
488
 
355
489
  webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
356
490
  webex.internal.newMetrics.callDiagnosticLatencies.clearTimestamps = sinon.stub();
@@ -365,7 +499,6 @@ describe('internal-plugin-metrics', () => {
365
499
  webex.internal.newMetrics.setDelaySubmitClientEvents({shouldDelay: false});
366
500
  // Webex is ready
367
501
  webex.emit('ready');
368
-
369
502
  });
370
503
  });
371
504
  });
@@ -64,45 +64,36 @@ describe('internal-plugin-metrics', () => {
64
64
  //@ts-ignore
65
65
  assert.calledOnce(webex.request);
66
66
 
67
- // matching because the request includes a symbol key: value pair and sinon cannot handle to compare it..
68
- assert.match(webexRequestArgs, {
69
- //@ts-ignore
70
- body: {
71
- metrics: [
72
- {
73
- eventPayload: {
74
- event: {
75
- joinTimes: {
76
- meetingInfoReqResp: undefined,
77
- clickToInterstitial: undefined,
78
- refreshCaptchaServiceReqResp: undefined,
79
- downloadIntelligenceModelsReqResp: undefined,
80
- clickToInterstitialWithUserDelay: undefined,
81
- },
82
- name: 'client.interstitial-window.launched',
83
- },
84
- origin: {
85
- buildType: 'test',
86
- networkType: 'unknown',
87
- upgradeChannel: 'test',
88
- },
89
- originTime: {
90
- sent: dateAfterBatcherWait.toISOString(),
91
- },
92
- },
93
- type: ['diagnostic-event'],
94
- },
95
- ],
67
+ assert.deepEqual(webexRequestArgs.headers, {
68
+ authorization: false,
69
+ 'x-prelogin-userid': preLoginId,
70
+ });
71
+ assert.equal(webexRequestArgs.method, 'POST');
72
+ assert.equal(webexRequestArgs.resource, 'clientmetrics-prelogin');
73
+ assert.equal(webexRequestArgs.service, 'metrics');
74
+ assert.equal(webexRequestArgs.waitForServiceTimeout, 30);
75
+
76
+ assert.deepEqual(webexRequestArgs.body.metrics[0].eventPayload, {
77
+ event: {
78
+ joinTimes: {
79
+ meetingInfoReqResp: undefined,
80
+ clickToInterstitial: undefined,
81
+ refreshCaptchaServiceReqResp: undefined,
82
+ downloadIntelligenceModelsReqResp: undefined,
83
+ clickToInterstitialWithUserDelay: undefined,
84
+ },
85
+ name: 'client.interstitial-window.launched',
96
86
  },
97
- headers: {
98
- authorization: false,
99
- 'x-prelogin-userid': preLoginId,
87
+ origin: {
88
+ buildType: 'test',
89
+ networkType: 'unknown',
90
+ upgradeChannel: 'test',
91
+ },
92
+ originTime: {
93
+ sent: dateAfterBatcherWait.toISOString(),
100
94
  },
101
- method: 'POST',
102
- resource: 'clientmetrics-prelogin',
103
- service: 'metrics',
104
- waitForServiceTimeout: 30,
105
95
  });
96
+ assert.deepEqual(webexRequestArgs.body.metrics[0].type, ['diagnostic-event']);
106
97
  assert.lengthOf(
107
98
  webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.queue,
108
99
  0
@@ -320,5 +311,49 @@ describe('internal-plugin-metrics', () => {
320
311
  );
321
312
  });
322
313
  });
314
+
315
+ describe('#submitHttpRequest', () => {
316
+ it('calls webex.request with the correct parameters', async () => {
317
+ const payload = [
318
+ {
319
+ eventPayload: {event: 'my.event'},
320
+ type: ['diagnostic-event'],
321
+ },
322
+ ];
323
+
324
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.savePreLoginId(
325
+ preLoginId
326
+ );
327
+ webex.request = sinon.stub().resolves({statusCode: 200});
328
+
329
+ const promise =
330
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.submitHttpRequest(
331
+ payload
332
+ );
333
+
334
+ await flushPromises();
335
+
336
+ clock.tick(config.metrics.batcherWait);
337
+
338
+ await promise;
339
+
340
+ const webexRequestArgs = webex.request.args[0][0];
341
+
342
+ assert.match(webexRequestArgs, {
343
+ //@ts-ignore
344
+ body: {
345
+ metrics: payload,
346
+ },
347
+ headers: {
348
+ authorization: false,
349
+ 'x-prelogin-userid': preLoginId,
350
+ },
351
+ method: 'POST',
352
+ resource: 'clientmetrics-prelogin',
353
+ service: 'metrics',
354
+ waitForServiceTimeout: 30,
355
+ });
356
+ });
357
+ });
323
358
  });
324
359
  });