@webex/internal-plugin-metrics 3.12.0-next.4 → 3.12.0-next.41

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 (65) 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 +638 -65
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +167 -76
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +5 -0
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  11. package/dist/call-diagnostic/config.js +16 -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/index.js +15 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/metrics.js +1 -1
  18. package/dist/metrics.types.js +4 -0
  19. package/dist/metrics.types.js.map +1 -1
  20. package/dist/new-metrics.js +60 -17
  21. package/dist/new-metrics.js.map +1 -1
  22. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  23. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  24. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  25. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  26. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  27. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  28. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  29. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  30. package/dist/types/automated-user.d.ts +2 -0
  31. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  32. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +67 -14
  33. package/dist/types/call-diagnostic/config.d.ts +4 -0
  34. package/dist/types/config.d.ts +1 -0
  35. package/dist/types/index.d.ts +5 -3
  36. package/dist/types/metrics.types.d.ts +7 -2
  37. package/dist/types/new-metrics.d.ts +17 -1
  38. package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
  39. package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
  40. package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
  41. package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
  42. package/package.json +12 -11
  43. package/src/automated-user.ts +16 -0
  44. package/src/batcher.js +4 -0
  45. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -73
  46. package/src/call-diagnostic/call-diagnostic-metrics.ts +101 -15
  47. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +5 -0
  48. package/src/call-diagnostic/config.ts +14 -0
  49. package/src/config.js +1 -0
  50. package/src/index.ts +7 -0
  51. package/src/metrics.types.ts +25 -3
  52. package/src/new-metrics.ts +53 -6
  53. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  54. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  55. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  56. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  57. package/test/unit/spec/automated-user.ts +43 -0
  58. package/test/unit/spec/batcher.js +43 -0
  59. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +14 -2
  60. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1434 -303
  61. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +852 -159
  62. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -0
  63. package/test/unit/spec/new-metrics.ts +183 -50
  64. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  65. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
@@ -460,6 +460,33 @@ describe('internal-plugin-metrics', () => {
460
460
  });
461
461
  });
462
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
+
463
490
  it('sets buildType and upgradeChannel correctly', () => {
464
491
  const item: any = {
465
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
  });