@webex/internal-plugin-metrics 3.12.0-next.9 → 3.12.0-webex-services-ready.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 (38) hide show
  1. package/dist/batcher.js +3 -0
  2. package/dist/batcher.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js +23 -0
  4. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +29 -25
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +55 -8
  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 +14 -2
  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/metrics.js +1 -1
  16. package/dist/metrics.types.js.map +1 -1
  17. package/dist/prelogin-metrics-batcher.js +23 -0
  18. package/dist/prelogin-metrics-batcher.js.map +1 -1
  19. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +23 -0
  20. package/dist/types/call-diagnostic/config.d.ts +4 -0
  21. package/dist/types/config.d.ts +1 -0
  22. package/dist/types/metrics.types.d.ts +2 -2
  23. package/package.json +11 -11
  24. package/src/batcher.js +4 -0
  25. package/src/call-diagnostic/call-diagnostic-metrics-batcher.ts +26 -0
  26. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +54 -38
  27. package/src/call-diagnostic/call-diagnostic-metrics.ts +46 -1
  28. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +5 -0
  29. package/src/call-diagnostic/config.ts +13 -0
  30. package/src/config.js +1 -0
  31. package/src/metrics.types.ts +1 -1
  32. package/src/prelogin-metrics-batcher.ts +26 -0
  33. package/test/unit/spec/batcher.js +43 -0
  34. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +145 -0
  35. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +105 -95
  36. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +680 -159
  37. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -0
  38. package/test/unit/spec/prelogin-metrics-batcher.ts +190 -36
@@ -78,6 +78,8 @@ const PreLoginMetricsBatcher = Batcher.extend({
78
78
  `PreLoginMetricsBatcher: @submitHttpRequest#${batchId}. Request successful.`
79
79
  );
80
80
 
81
+ this.handleHttpResponseStatus(res?.statusCode, payload);
82
+
81
83
  return res;
82
84
  })
83
85
  .catch((err) => {
@@ -87,9 +89,33 @@ const PreLoginMetricsBatcher = Batcher.extend({
87
89
  `error: ${generateCommonErrorMetadata(err)}`
88
90
  );
89
91
 
92
+ this.handleHttpResponseStatus(err?.statusCode, payload);
93
+
90
94
  return Promise.reject(err);
91
95
  });
92
96
  },
97
+
98
+ /**
99
+ * React to the HTTP status code returned by the prelogin metrics endpoint.
100
+ * Only items submitted with `markTelemetryOptOutOnResponse: true` opt into
101
+ * this behavior.
102
+ * @param {number | undefined} statusCode
103
+ * @param {any[]} payload Items flushed in this HTTP batch.
104
+ * @returns {void}
105
+ */
106
+ handleHttpResponseStatus(statusCode: number | undefined, payload: any[]) {
107
+ const shouldMark =
108
+ Array.isArray(payload) &&
109
+ payload.some((item) => item?.markTelemetryOptOutOnResponse === true);
110
+
111
+ if (!shouldMark) {
112
+ return;
113
+ }
114
+
115
+ if (statusCode === 200) {
116
+ this.webex.internal.newMetrics?.callDiagnosticMetrics?.setIsTelemetryOptOutAutomatic(true);
117
+ }
118
+ },
93
119
  });
94
120
 
95
121
  export default PreLoginMetricsBatcher;
@@ -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
  });
@@ -192,6 +192,12 @@ describe('plugin-metrics', () => {
192
192
  webex.internal.newMetrics.callDiagnosticLatencies.getTotalJMTWithUserDelay = sinon
193
193
  .stub()
194
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);
195
201
  const promise = webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnostics(
196
202
  //@ts-ignore
197
203
  {event: {name: 'client.locus.join.response'}}
@@ -349,6 +355,9 @@ describe('plugin-metrics', () => {
349
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);
@@ -507,5 +516,141 @@ describe('plugin-metrics', () => {
507
516
  assert.deepEqual(prepareDiagnosticMetricItemCalls[0].args[1].type, ['diagnostic-event']);
508
517
  });
509
518
  });
519
+
520
+ describe('#submitHttpRequest', () => {
521
+ it('calls handleHttpResponseStatus with response status on success', async () => {
522
+ const payload = [
523
+ {
524
+ eventPayload: {event: 'my.event'},
525
+ type: ['diagnostic-event'],
526
+ },
527
+ ];
528
+
529
+ webex.request = sinon.stub().resolves({statusCode: 200});
530
+
531
+ const handleHttpResponseStatusSpy = sinon.spy(
532
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher,
533
+ 'handleHttpResponseStatus'
534
+ );
535
+
536
+ const promise =
537
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.submitHttpRequest(
538
+ payload
539
+ );
540
+
541
+ assert.deepEqual(handleHttpResponseStatusSpy.getCalls().length, 0);
542
+
543
+ await flushPromises();
544
+ clock.tick(config.metrics.batcherWait);
545
+
546
+ await promise;
547
+
548
+ assert.calledOnce(webex.request);
549
+ assert.deepEqual(handleHttpResponseStatusSpy.getCalls().length, 1);
550
+ assert.deepEqual(handleHttpResponseStatusSpy.args[0][0], 200);
551
+ assert.deepEqual(handleHttpResponseStatusSpy.args[0][1], payload);
552
+ });
553
+
554
+ it('calls handleHttpResponseStatus with error status on failure', async () => {
555
+ const payload = [
556
+ {
557
+ eventPayload: {event: 'my.event'},
558
+ type: ['diagnostic-event'],
559
+ },
560
+ ];
561
+
562
+ webex.request = sinon.stub().rejects({statusCode: 503});
563
+
564
+ const handleHttpResponseStatusSpy = sinon.spy(
565
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher,
566
+ 'handleHttpResponseStatus'
567
+ );
568
+
569
+ const promise =
570
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.submitHttpRequest(
571
+ payload
572
+ );
573
+
574
+ assert.deepEqual(handleHttpResponseStatusSpy.getCalls().length, 0);
575
+
576
+ await flushPromises();
577
+ clock.tick(config.metrics.batcherWait);
578
+
579
+ let error: any;
580
+
581
+ try {
582
+ await promise;
583
+ } catch (err) {
584
+ error = err;
585
+ }
586
+
587
+ assert.deepEqual(error.statusCode, 503);
588
+ assert.calledOnce(webex.request);
589
+ assert.deepEqual(handleHttpResponseStatusSpy.getCalls().length, 1);
590
+ assert.deepEqual(handleHttpResponseStatusSpy.args[0][0], 503);
591
+ assert.deepEqual(handleHttpResponseStatusSpy.args[0][1], payload);
592
+ });
593
+ });
594
+
595
+ describe('#handleHttpResponseStatus', () => {
596
+ let setIsTelemetryOptOutAutomaticStub;
597
+
598
+ beforeEach(() => {
599
+ setIsTelemetryOptOutAutomaticStub = sinon.stub(
600
+ webex.internal.newMetrics.callDiagnosticMetrics,
601
+ 'setIsTelemetryOptOutAutomatic'
602
+ );
603
+ });
604
+
605
+ [201, 400, 503, undefined].forEach((statusCode) => {
606
+ it(`does not call setIsTelemetryOptOutAutomatic() when statusCode is ${statusCode} and markTelemetryOptOutOnResponse is true`, () => {
607
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.handleHttpResponseStatus(
608
+ statusCode,
609
+ [{markTelemetryOptOutOnResponse: true}]
610
+ );
611
+
612
+ assert.notCalled(setIsTelemetryOptOutAutomaticStub);
613
+ });
614
+ });
615
+
616
+ it('calls setIsTelemetryOptOutAutomatic(true) when statusCode is 200 and markTelemetryOptOutOnResponse is true', () => {
617
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.handleHttpResponseStatus(
618
+ 200,
619
+ [{markTelemetryOptOutOnResponse: true}]
620
+ );
621
+
622
+ assert.calledOnce(setIsTelemetryOptOutAutomaticStub);
623
+ assert.calledWithExactly(setIsTelemetryOptOutAutomaticStub, true);
624
+ });
625
+
626
+ [200, 201, 400, 503, undefined].forEach((statusCode) => {
627
+ it(`does not call setIsTelemetryOptOutAutomatic when shouldMark is false (statusCode: ${statusCode})`, () => {
628
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.handleHttpResponseStatus(
629
+ statusCode,
630
+ [{markTelemetryOptOutOnResponse: false}]
631
+ );
632
+
633
+ assert.notCalled(setIsTelemetryOptOutAutomaticStub);
634
+ });
635
+ });
636
+
637
+ it('does not call setIsTelemetryOptOutAutomatic when payload is empty', () => {
638
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.handleHttpResponseStatus(
639
+ 200,
640
+ []
641
+ );
642
+
643
+ assert.notCalled(setIsTelemetryOptOutAutomaticStub);
644
+ });
645
+
646
+ it('does not call setIsTelemetryOptOutAutomatic when payload is not an array', () => {
647
+ webex.internal.newMetrics.callDiagnosticMetrics.callDiagnosticEventsBatcher.handleHttpResponseStatus(
648
+ 200,
649
+ null
650
+ );
651
+
652
+ assert.notCalled(setIsTelemetryOptOutAutomaticStub);
653
+ });
654
+ });
510
655
  });
511
656
  });