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

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 (57) 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 +69 -23
  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/types/automated-user.d.ts +2 -0
  27. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  28. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +79 -15
  29. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +5 -0
  30. package/dist/types/call-diagnostic/config.d.ts +5 -0
  31. package/dist/types/config.d.ts +1 -0
  32. package/dist/types/index.d.ts +6 -3
  33. package/dist/types/metrics.types.d.ts +6 -4
  34. package/dist/types/new-metrics.d.ts +16 -0
  35. package/dist/types/prelogin-metrics.d.ts +47 -0
  36. package/package.json +12 -11
  37. package/src/automated-user.ts +16 -0
  38. package/src/batcher.js +4 -0
  39. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +800 -75
  40. package/src/call-diagnostic/call-diagnostic-metrics.ts +102 -15
  41. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +22 -2
  42. package/src/call-diagnostic/config.ts +15 -0
  43. package/src/config.js +1 -0
  44. package/src/generic-metrics.ts +6 -6
  45. package/src/index.ts +7 -0
  46. package/src/metrics.types.ts +18 -5
  47. package/src/new-metrics.ts +54 -4
  48. package/src/prelogin-metrics.ts +94 -0
  49. package/test/unit/spec/automated-user.ts +43 -0
  50. package/test/unit/spec/batcher.js +43 -0
  51. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +47 -11
  52. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1550 -416
  53. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +887 -159
  54. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +61 -3
  55. package/test/unit/spec/new-metrics.ts +39 -2
  56. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  57. package/test/unit/spec/prelogin-metrics.ts +132 -0
@@ -0,0 +1,94 @@
1
+ import GenericMetrics from './generic-metrics';
2
+ import {BusinessEvent, EventPayload} from './metrics.types';
3
+ import PreLoginMetricsBatcher from './prelogin-metrics-batcher';
4
+
5
+ /**
6
+ * @description Util class to handle PreLogin Metrics
7
+ * @export
8
+ * @class PreLoginMetrics
9
+ */
10
+ export default class PreLoginMetrics extends GenericMetrics {
11
+ private preLoginMetricsBatcher: typeof PreLoginMetricsBatcher;
12
+
13
+ /**
14
+ * Constructor
15
+ * @param {PreLoginMetricsBatcher} preLoginMetricsBatcher - Pre-login metrics batcher
16
+ * @param {any} attrs - Attributes
17
+ * @param {any} options - Options
18
+ * @constructor
19
+ */
20
+ constructor(
21
+ preLoginMetricsBatcher: typeof PreLoginMetricsBatcher,
22
+ attrs: any = {},
23
+ options: {parent?: any} = {}
24
+ ) {
25
+ super(attrs, options);
26
+ this.preLoginMetricsBatcher = preLoginMetricsBatcher;
27
+ }
28
+
29
+ /**
30
+ * Submit a business metric to our metrics endpoint.
31
+ * Routes to the correct table with the correct schema payload by table.
32
+ * @see https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
33
+ * @param {Object} options - The options object
34
+ * @param {string} options.name - Name of the metric
35
+ * @param {string} options.preLoginId - ID to identify pre-login user
36
+ * @param {EventPayload} options.payload - User payload of the metric
37
+ * @param {EventPayload} [options.metadata] - Optional metadata to include outside of eventPayload.value
38
+ * @returns {Promise<void>} Promise that resolves when the metric is submitted
39
+ */
40
+ public submitPreLoginEvent({
41
+ name,
42
+ preLoginId,
43
+ payload,
44
+ metadata,
45
+ }: {
46
+ name: string;
47
+ preLoginId: string;
48
+ payload: EventPayload;
49
+ metadata?: EventPayload;
50
+ }): Promise<void> {
51
+ if (!metadata) {
52
+ metadata = {};
53
+ }
54
+ if (!metadata.appType) {
55
+ metadata.appType = 'Web Client';
56
+ }
57
+
58
+ const finalEvent = this.buildEvent(name, preLoginId, payload, metadata);
59
+
60
+ this.preLoginMetricsBatcher.savePreLoginId(preLoginId);
61
+
62
+ return this.preLoginMetricsBatcher.request(finalEvent);
63
+ }
64
+
65
+ /**
66
+ * Builds a formatted event object for metrics submission.
67
+ * @param {string} metricName - Metric name
68
+ * @param {string} preLoginId - Pre-login user identifier
69
+ * @param {EventPayload} payload - Metric payload data
70
+ * @param {EventPayload} metadata - Additional metadata to include in the event
71
+ * @returns {object} Formatted metrics event object with type, eventPayload, and timestamp
72
+ */
73
+ private buildEvent(
74
+ metricName: string,
75
+ preLoginId: string,
76
+ payload: EventPayload,
77
+ metadata: EventPayload
78
+ ): BusinessEvent {
79
+ return {
80
+ type: ['business'],
81
+ eventPayload: {
82
+ metricName,
83
+ browserDetails: this.getBrowserDetails(),
84
+ context: this.getContext(),
85
+ timestamp: new Date().getTime(),
86
+ value: {
87
+ preLoginId,
88
+ ...metadata,
89
+ ...payload,
90
+ },
91
+ },
92
+ };
93
+ }
94
+ }
@@ -0,0 +1,43 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+
3
+ import {isAutomatedUser, isAutomatedUserAgent} from '../../../src/automated-user';
4
+
5
+ describe('automated user detection', () => {
6
+ [
7
+ {userAgent: 'SkypeUriPreview', expected: true},
8
+ {userAgent: 'skypeuripreview', expected: true},
9
+ {userAgent: 'Mozilla/5.0 (compatible; SkypeUriPreview/0.1)', expected: true},
10
+ {userAgent: 'Googlebot/2.1 (+http://www.google.com/bot.html)', expected: true},
11
+ {
12
+ userAgent:
13
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36',
14
+ expected: false,
15
+ },
16
+ {userAgent: undefined, expected: false},
17
+ ].forEach(({userAgent, expected}) => {
18
+ it(`returns ${expected} for ${userAgent || 'an undefined user agent'}`, () => {
19
+ assert.equal(isAutomatedUserAgent(userAgent), expected);
20
+ });
21
+ });
22
+
23
+ it('returns the cached classification when navigator changes', () => {
24
+ const cachedResult = isAutomatedUser();
25
+ const originalDescriptor = Object.getOwnPropertyDescriptor(global, 'navigator');
26
+
27
+ Object.defineProperty(global, 'navigator', {
28
+ value: cachedResult
29
+ ? {userAgent: 'Mozilla/5.0', webdriver: false}
30
+ : {userAgent: 'SkypeUriPreview', webdriver: true},
31
+ configurable: true,
32
+ writable: true,
33
+ });
34
+
35
+ assert.equal(isAutomatedUser(), cachedResult);
36
+
37
+ if (originalDescriptor) {
38
+ Object.defineProperty(global, 'navigator', originalDescriptor);
39
+ } else {
40
+ delete (global as any).navigator;
41
+ }
42
+ });
43
+ });
@@ -177,6 +177,49 @@ describe('plugin-metrics', () => {
177
177
  assert.lengthOf(webex.internal.metrics.batcher.queue, 0);
178
178
  });
179
179
  });
180
+
181
+ it('rejects the deferred without reenqueuing when batcherRetryOnNetworkError is false', () => {
182
+ webex.config.metrics = {...config.metrics, batcherRetryOnNetworkError: false};
183
+
184
+ webex.request = function () {
185
+ // noop
186
+ };
187
+
188
+ sinon.stub(webex, 'request').callsFake((options) => {
189
+ options.headers = {
190
+ trackingid: 'test-no-retry',
191
+ };
192
+
193
+ return Promise.reject(
194
+ new WebexHttpError.NetworkOrCORSError({
195
+ statusCode: 0,
196
+ options,
197
+ })
198
+ );
199
+ });
200
+
201
+ const promise = webex.internal.metrics.batcher.request({
202
+ key: 'testMetric',
203
+ });
204
+
205
+ return promiseTick(50)
206
+ .then(() => assert.lengthOf(webex.internal.metrics.batcher.queue, 1))
207
+ .then(() => clock.tick(config.metrics.batcherWait))
208
+ .then(() => assert.calledOnce(webex.request))
209
+ .then(() => promiseTick(50))
210
+ .then(() =>
211
+ promise.then(
212
+ () => {
213
+ assert.fail('promise should have been rejected');
214
+ },
215
+ (reason) => {
216
+ assert.instanceOf(reason, WebexHttpError.NetworkOrCORSError);
217
+ assert.lengthOf(webex.internal.metrics.batcher.queue, 0);
218
+ assert.calledOnce(webex.request);
219
+ }
220
+ )
221
+ );
222
+ });
180
223
  });
181
224
  });
182
225
  });
@@ -142,9 +142,7 @@ describe('plugin-metrics', () => {
142
142
  webex.internal.newMetrics.callDiagnosticLatencies.getDiffBetweenTimestamps = sinon
143
143
  .stub()
144
144
  .returns(10);
145
- webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon
146
- .stub()
147
- .returns(20);
145
+ webex.internal.newMetrics.callDiagnosticLatencies.getU2CTime = sinon.stub().returns(20);
148
146
  webex.internal.newMetrics.callDiagnosticLatencies.getReachabilityClustersReqResp = sinon
149
147
  .stub()
150
148
  .returns(10);
@@ -165,7 +163,7 @@ describe('plugin-metrics', () => {
165
163
  registerWDMDeviceJMT: 10,
166
164
  showInterstitialTime: 10,
167
165
  getU2CTime: 20,
168
- getReachabilityClustersReqResp: 10
166
+ getReachabilityClustersReqResp: 10,
169
167
  },
170
168
  });
171
169
  assert.lengthOf(
@@ -189,12 +187,17 @@ describe('plugin-metrics', () => {
189
187
  webex.internal.newMetrics.callDiagnosticLatencies.getDownloadTimeJMT = sinon
190
188
  .stub()
191
189
  .returns(100);
192
- webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay = sinon
193
- .stub()
194
- .returns(43);
190
+ webex.internal.newMetrics.callDiagnosticLatencies.getClickToInterstitialWithUserDelay =
191
+ sinon.stub().returns(43);
195
192
  webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMTWithUserDelay = sinon
196
193
  .stub()
197
194
  .returns(64);
195
+ webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToJoinOK = sinon
196
+ .stub()
197
+ .returns(10);
198
+ webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMT = sinon
199
+ .stub()
200
+ .returns(20);
198
201
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
199
202
  //@ts-ignore
200
203
  {event: {name: 'client.locus.join.response'}}
@@ -346,9 +349,15 @@ describe('plugin-metrics', () => {
346
349
  webex.internal.newMetrics.callDiagnosticLatencies.getInterstitialToJoinOK = sinon
347
350
  .stub()
348
351
  .returns(7);
349
- webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
352
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
353
+ .stub()
354
+ .returns(1);
355
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTimeCappedBy = sinon
350
356
  .stub()
351
357
  .returns(1);
358
+ webex.internal.newMetrics.callDiagnosticLatencies.getTotalMediaJMT = sinon
359
+ .stub()
360
+ .returns(44);
352
361
  webex.internal.newMetrics.callDiagnosticLatencies.getTotalMediaJMTWithUserDelay = sinon
353
362
  .stub()
354
363
  .returns(43);
@@ -369,10 +378,9 @@ describe('plugin-metrics', () => {
369
378
  assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
370
379
  name: 'client.media-engine.ready',
371
380
  joinTimes: {
372
- totalMediaJMT: 61,
381
+ totalMediaJMT: 44,
373
382
  interstitialToMediaOKJMT: 22,
374
- callInitMediaEngineReady: 10,
375
- stayLobbyTime: 1,
383
+ callInitMediaEngineReady: 22,
376
384
  totalMediaJMTWithUserDelay: 43,
377
385
  totalJMTWithUserDelay: 64,
378
386
  },
@@ -382,6 +390,34 @@ describe('plugin-metrics', () => {
382
390
  0
383
391
  );
384
392
  });
393
+
394
+ it('appends the correct join times to the request for client.lobby.exited', async () => {
395
+ webex.internal.newMetrics.callDiagnosticLatencies.getStayLobbyTime = sinon
396
+ .stub()
397
+ .returns(10);
398
+
399
+ const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
400
+ //@ts-ignore
401
+ {event: {name: 'client.lobby.exited'}}
402
+ );
403
+ await flushPromises();
404
+ clock.tick(config.metrics.batcherWait);
405
+
406
+ await promise;
407
+
408
+ //@ts-ignore
409
+ assert.calledOnce(webex.request);
410
+ assert.deepEqual(webex.request.getCalls()[0].args[0].body.metrics[0].eventPayload.event, {
411
+ name: 'client.lobby.exited',
412
+ joinTimes: {
413
+ stayLobbyTime: 10,
414
+ },
415
+ });
416
+ assert.lengthOf(
417
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.queue,
418
+ 0
419
+ );
420
+ });
385
421
  });
386
422
 
387
423
  describe('when the request fails', () => {