@webex/internal-plugin-metrics 3.0.0-beta.40 → 3.0.0-beta.401

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 (73) hide show
  1. package/dist/batcher.js +40 -1
  2. package/dist/batcher.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js +65 -0
  4. package/dist/call-diagnostic/call-diagnostic-metrics-batcher.js.map +1 -0
  5. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +518 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -0
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +860 -0
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -0
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +368 -0
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -0
  11. package/dist/call-diagnostic/config.js +627 -0
  12. package/dist/call-diagnostic/config.js.map +1 -0
  13. package/dist/client-metrics-batcher.js +2 -1
  14. package/dist/client-metrics-batcher.js.map +1 -1
  15. package/dist/config.js +2 -1
  16. package/dist/config.js.map +1 -1
  17. package/dist/index.js +33 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/metrics.js +27 -28
  20. package/dist/metrics.js.map +1 -1
  21. package/dist/metrics.types.js +7 -0
  22. package/dist/metrics.types.js.map +1 -0
  23. package/dist/new-metrics.js +300 -0
  24. package/dist/new-metrics.js.map +1 -0
  25. package/dist/prelogin-metrics-batcher.js +82 -0
  26. package/dist/prelogin-metrics-batcher.js.map +1 -0
  27. package/dist/types/batcher.d.ts +7 -0
  28. package/dist/types/call-diagnostic/call-diagnostic-metrics-batcher.d.ts +2 -0
  29. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +222 -0
  30. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +421 -0
  31. package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +103 -0
  32. package/dist/types/call-diagnostic/config.d.ts +178 -0
  33. package/dist/types/client-metrics-batcher.d.ts +2 -0
  34. package/dist/types/config.d.ts +36 -0
  35. package/dist/types/index.d.ts +15 -0
  36. package/dist/types/metrics.d.ts +3 -0
  37. package/dist/types/metrics.types.d.ts +105 -0
  38. package/dist/types/new-metrics.d.ts +131 -0
  39. package/dist/types/prelogin-metrics-batcher.d.ts +2 -0
  40. package/dist/types/utils.d.ts +6 -0
  41. package/dist/utils.js +27 -0
  42. package/dist/utils.js.map +1 -0
  43. package/package.json +16 -8
  44. package/src/batcher.js +38 -0
  45. package/src/call-diagnostic/call-diagnostic-metrics-batcher.ts +72 -0
  46. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +476 -0
  47. package/src/call-diagnostic/call-diagnostic-metrics.ts +919 -0
  48. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +396 -0
  49. package/src/call-diagnostic/config.ts +685 -0
  50. package/src/client-metrics-batcher.js +1 -0
  51. package/src/config.js +1 -0
  52. package/src/index.ts +56 -0
  53. package/src/metrics.js +21 -24
  54. package/src/metrics.types.ts +171 -0
  55. package/src/new-metrics.ts +278 -0
  56. package/src/prelogin-metrics-batcher.ts +95 -0
  57. package/src/utils.ts +17 -0
  58. package/test/unit/spec/batcher.js +2 -0
  59. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +461 -0
  60. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +675 -0
  61. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +2303 -0
  62. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +635 -0
  63. package/test/unit/spec/client-metrics-batcher.js +2 -0
  64. package/test/unit/spec/metrics.js +74 -97
  65. package/test/unit/spec/new-metrics.ts +231 -0
  66. package/test/unit/spec/prelogin-metrics-batcher.ts +251 -0
  67. package/test/unit/spec/utils.ts +22 -0
  68. package/tsconfig.json +6 -0
  69. package/dist/call-diagnostic-events-batcher.js +0 -60
  70. package/dist/call-diagnostic-events-batcher.js.map +0 -1
  71. package/src/call-diagnostic-events-batcher.js +0 -62
  72. package/src/index.js +0 -17
  73. package/test/unit/spec/call-diagnostic-events-batcher.js +0 -195
@@ -8,6 +8,9 @@ import {Token, Credentials} from '@webex/webex-core';
8
8
  import FakeTimers from '@sinonjs/fake-timers';
9
9
  import sinon from 'sinon';
10
10
  import Metrics, {config} from '@webex/internal-plugin-metrics';
11
+ import {BrowserDetection} from '@webex/common';
12
+
13
+ const {getOSVersion} = BrowserDetection();
11
14
 
12
15
  function promiseTick(count) {
13
16
  let promise = Promise.resolve();
@@ -82,6 +85,7 @@ describe('plugin-metrics', () => {
82
85
  return Promise.resolve({
83
86
  statusCode: 204,
84
87
  body: undefined,
88
+ waitForServiceTimeout: 30,
85
89
  options,
86
90
  });
87
91
  };
@@ -98,11 +102,17 @@ describe('plugin-metrics', () => {
98
102
  };
99
103
  webex.config.metrics.type = ['operational'];
100
104
  webex.config.metrics.appType = 'sdk';
105
+ webex.meetings = {
106
+ config: {
107
+ metrics: {
108
+ clientVersion: '43.0.105'
109
+ }
110
+ }
111
+ }
101
112
 
102
113
  sinon.spy(webex, 'request');
103
114
  sinon.spy(metrics, 'postPreLoginMetric');
104
115
  sinon.spy(metrics, 'aliasUser');
105
- sinon.spy(metrics, 'submitCallDiagnosticEvents');
106
116
  });
107
117
 
108
118
  describe('#submit()', () => {
@@ -131,6 +141,68 @@ describe('plugin-metrics', () => {
131
141
  });
132
142
  });
133
143
 
144
+ describe('#getClientMetricsPayload()', () => {
145
+ it('returns the expected payload', () => {
146
+ webex.credentials.supertoken = new Token(
147
+ {
148
+ access_token: 'a_b_orgid',
149
+ },
150
+ {parent: webex}
151
+ );
152
+
153
+ const testPayload = {
154
+ tags: {success: true},
155
+ fields: {perceivedDurationInMillis: 314},
156
+ context: {},
157
+ eventPayload: {value: 'splunk business metric payload'},
158
+ };
159
+ const date = clock.now;
160
+
161
+ const result = metrics.getClientMetricsPayload('test', testPayload);
162
+
163
+ assert.deepEqual(result, {
164
+ context: {
165
+ app: {
166
+ version: undefined,
167
+ },
168
+ locale: 'en-US',
169
+ os: {
170
+ name: 'other',
171
+ version: getOSVersion(),
172
+ },
173
+ },
174
+ eventPayload: {
175
+ value: 'splunk business metric payload',
176
+ },
177
+ fields: {
178
+ browser_version: '',
179
+ client_id: 'fake',
180
+ os_version: getOSVersion(),
181
+ perceivedDurationInMillis: 314,
182
+ platform: 'Web',
183
+ sdk_version: undefined,
184
+ spark_user_agent: 'webex-js-sdk appName/appVersion appPlatform',
185
+ },
186
+ metricName: 'test',
187
+ tags: {
188
+ appVersion: '43.0.105',
189
+ browser: '',
190
+ domain: 'whatever',
191
+ os: 'other',
192
+ success: true,
193
+ },
194
+ timestamp: 0,
195
+ type: ['operational'],
196
+ });
197
+ });
198
+
199
+ it('throws when no event name is specified', () => {
200
+ assert.throws(() => {
201
+ metrics.getClientMetricsPayload();
202
+ }, 'Missing behavioral metric name. Please provide one');
203
+ });
204
+ });
205
+
134
206
  describe('#submitClientMetrics()', () => {
135
207
  describe('before login', () => {
136
208
  it('posts pre-login metric', () => {
@@ -199,17 +271,15 @@ describe('plugin-metrics', () => {
199
271
  assert.property(metric, 'eventPayload');
200
272
 
201
273
  assert.property(metric.tags, 'browser');
202
- assert.property(metric.tags, 'org_id');
203
274
  assert.property(metric.tags, 'os');
204
275
  assert.property(metric.tags, 'domain');
205
- assert.property(metric.tags, 'client_id');
206
- assert.property(metric.tags, 'user_id');
207
276
 
208
277
  assert.property(metric.fields, 'browser_version');
209
278
  assert.property(metric.fields, 'os_version');
210
279
  assert.property(metric.fields, 'sdk_version');
211
280
  assert.property(metric.fields, 'platform');
212
281
  assert.property(metric.fields, 'spark_user_agent');
282
+ assert.property(metric.fields, 'client_id');
213
283
 
214
284
  assert.property(metric.context, 'app');
215
285
  assert.property(metric.context, 'locale');
@@ -269,98 +339,5 @@ describe('plugin-metrics', () => {
269
339
  assert.match(params, {alias: true});
270
340
  }));
271
341
  });
272
-
273
- describe('#submitCallDiagnosticEvents()', () => {
274
- it('submits a call diagnostic event', () => {
275
- const promise = metrics.submitCallDiagnosticEvents(mockCallDiagnosticEvent);
276
-
277
- return promiseTick(50)
278
- .then(() => clock.tick(config.metrics.batcherWait))
279
- .then(() => promise)
280
- .then(() => {
281
- assert.calledOnce(webex.request);
282
- const req = webex.request.args[0][0];
283
- const metric = req.body.metrics[0];
284
-
285
- assert.property(metric.eventPayload, 'origin');
286
- assert.property(metric.eventPayload, 'originTime');
287
- assert.property(metric.eventPayload.origin, 'buildType');
288
- assert.property(metric.eventPayload.origin, 'networkType');
289
- assert.property(metric.eventPayload.originTime, 'sent');
290
- assert.equal(metric.eventPayload.origin.buildType, 'test');
291
- });
292
- });
293
-
294
- it('submits a call diagnostic event with buildType set in the payload', () => {
295
- const promise = metrics.submitCallDiagnosticEvents({
296
- ...mockCallDiagnosticEvent,
297
- origin: {
298
- buildType: 'prod',
299
- },
300
- });
301
-
302
- return promiseTick(50)
303
- .then(() => clock.tick(config.metrics.batcherWait))
304
- .then(() => promise)
305
- .then(() => {
306
- assert.calledOnce(webex.request);
307
- const req = webex.request.args[0][0];
308
- const metric = req.body.metrics[0];
309
-
310
- assert.property(metric.eventPayload, 'origin');
311
- assert.property(metric.eventPayload, 'originTime');
312
- assert.property(metric.eventPayload.origin, 'buildType');
313
- assert.property(metric.eventPayload.origin, 'networkType');
314
- assert.property(metric.eventPayload.originTime, 'sent');
315
- assert.equal(metric.eventPayload.origin.buildType, 'prod');
316
- });
317
- });
318
-
319
- xit('submits a call diagnostic event with a test domain', () => {
320
- global.window.location.hostname = 'test.webex.com';
321
-
322
- const promise = metrics.submitCallDiagnosticEvents(mockCallDiagnosticEvent);
323
-
324
- return promiseTick(50)
325
- .then(() => clock.tick(config.metrics.batcherWait))
326
- .then(() => promise)
327
- .then(() => {
328
- assert.calledOnce(webex.request);
329
- const req = webex.request.args[0][0];
330
- const metric = req.body.metrics[0];
331
-
332
- assert.property(metric.eventPayload, 'origin');
333
- assert.property(metric.eventPayload, 'originTime');
334
- assert.property(metric.eventPayload.origin, 'buildType');
335
- assert.property(metric.eventPayload.origin, 'networkType');
336
- assert.property(metric.eventPayload.originTime, 'sent');
337
- assert.equal(metric.eventPayload.origin.buildType, 'test');
338
- });
339
- });
340
-
341
- // Skip because it's current unable to overwrite NODE_ENV
342
- // However doing `NODE_ENV=test npm run test ...` will get this test case to pass
343
- xit('submits a call diagnostic event with a NODE_ENV=production', () => {
344
- process.env.NODE_ENV = 'production';
345
-
346
- const promise = metrics.submitCallDiagnosticEvents(mockCallDiagnosticEvent);
347
-
348
- return promiseTick(50)
349
- .then(() => clock.tick(config.metrics.batcherWait))
350
- .then(() => promise)
351
- .then(() => {
352
- assert.calledOnce(webex.request);
353
- const req = webex.request.args[0][0];
354
- const metric = req.body.metrics[0];
355
-
356
- assert.property(metric.eventPayload, 'origin');
357
- assert.property(metric.eventPayload, 'originTime');
358
- assert.property(metric.eventPayload.origin, 'buildType');
359
- assert.property(metric.eventPayload.origin, 'networkType');
360
- assert.property(metric.eventPayload.originTime, 'sent');
361
- assert.equal(metric.eventPayload.origin.buildType, 'prod');
362
- });
363
- });
364
- });
365
342
  });
366
343
  });
@@ -0,0 +1,231 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+ import {NewMetrics, CallDiagnosticLatencies} from '@webex/internal-plugin-metrics';
3
+ import MockWebex from '@webex/test-helper-mock-webex';
4
+ import sinon from 'sinon';
5
+ import {Utils} from '@webex/internal-plugin-metrics';
6
+
7
+ describe('internal-plugin-metrics', () => {
8
+
9
+ const mockWebex = () => new MockWebex({
10
+ children: {
11
+ newMetrics: NewMetrics,
12
+ },
13
+ meetings: {
14
+ meetingCollection: {
15
+ get: sinon.stub(),
16
+ },
17
+ },
18
+ request: sinon.stub().resolves({}),
19
+ logger: {
20
+ log: sinon.stub(),
21
+ error: sinon.stub(),
22
+ }
23
+ });
24
+
25
+ describe('check submitClientEvent when webex is not ready', () => {
26
+ let webex;
27
+ //@ts-ignore
28
+ webex = mockWebex();
29
+
30
+ it('checks the log', () => {
31
+ webex.internal.newMetrics.submitClientEvent({
32
+ name: 'client.alert.displayed',
33
+ options: {
34
+ meetingId: '123',
35
+ },
36
+ });
37
+ assert.calledWith(
38
+ webex.logger.log,
39
+ 'NewMetrics: @submitClientEvent. Attempted to submit before webex.ready. Event name: client.alert.displayed'
40
+ );
41
+ });
42
+ });
43
+
44
+ describe('new-metrics contstructor', () => {
45
+ it('checks callDiagnosticLatencies is defined before ready emit', () => {
46
+
47
+ const webex = mockWebex();
48
+
49
+ assert.instanceOf(webex.internal.newMetrics.callDiagnosticLatencies, CallDiagnosticLatencies);
50
+ });
51
+ });
52
+
53
+ describe('new-metrics', () => {
54
+ let webex;
55
+
56
+ beforeEach(() => {
57
+ //@ts-ignore
58
+ webex = mockWebex();
59
+
60
+ webex.emit('ready');
61
+
62
+ webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp = sinon.stub();
63
+ webex.internal.newMetrics.callDiagnosticLatencies.clearTimestamps = sinon.stub();
64
+ webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent = sinon.stub();
65
+ webex.internal.newMetrics.callDiagnosticMetrics.submitMQE = sinon.stub();
66
+ webex.internal.newMetrics.callDiagnosticMetrics.clientMetricsAliasUser = sinon.stub();
67
+ webex.internal.newMetrics.callDiagnosticMetrics.buildClientEventFetchRequestOptions =
68
+ sinon.stub();
69
+ webex.setTimingsAndFetch = sinon.stub();
70
+ });
71
+
72
+ afterEach(() => {
73
+ sinon.restore();
74
+ })
75
+
76
+ it('submits Client Event successfully', () => {
77
+ webex.internal.newMetrics.submitClientEvent({
78
+ name: 'client.alert.displayed',
79
+ options: {
80
+ meetingId: '123',
81
+ },
82
+ });
83
+
84
+ assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
85
+ key: 'client.alert.displayed',
86
+ options: {meetingId: '123'},
87
+ });
88
+ assert.calledWith(webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent, {
89
+ name: 'client.alert.displayed',
90
+ payload: undefined,
91
+ options: {meetingId: '123'},
92
+ });
93
+ });
94
+
95
+
96
+ it('submits MQE successfully', () => {
97
+ webex.internal.newMetrics.submitMQE({
98
+ name: 'client.mediaquality.event',
99
+ //@ts-ignore
100
+ payload: {intervals: [{}]},
101
+ options: {
102
+ meetingId: '123',
103
+ networkType: 'wifi',
104
+ },
105
+ });
106
+
107
+ assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
108
+ key: 'client.mediaquality.event',
109
+ });
110
+ assert.calledWith(webex.internal.newMetrics.callDiagnosticMetrics.submitMQE, {
111
+ name: 'client.mediaquality.event',
112
+ //@ts-ignore
113
+ payload: {intervals: [{}]},
114
+ options: {
115
+ meetingId: '123',
116
+ networkType: 'wifi',
117
+ },
118
+ });
119
+ });
120
+
121
+ it('submits Internal Event successfully', () => {
122
+ webex.internal.newMetrics.submitInternalEvent({
123
+ name: 'client.mediaquality.event',
124
+ });
125
+
126
+ assert.calledWith(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp, {
127
+ key: 'client.mediaquality.event',
128
+ });
129
+ assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.clearTimestamps);
130
+ });
131
+
132
+ it('submits Internal Event successfully for clearing the join latencies', () => {
133
+ webex.internal.newMetrics.submitInternalEvent({
134
+ name: 'internal.reset.join.latencies',
135
+ });
136
+
137
+ assert.notCalled(webex.internal.newMetrics.callDiagnosticLatencies.saveTimestamp);
138
+ assert.calledOnce(webex.internal.newMetrics.callDiagnosticLatencies.clearTimestamps);
139
+ });
140
+
141
+ describe('#clientMetricsAliasUser', () => {
142
+ it('aliases the user correctly', async () => {
143
+ webex.request.resolves({response: 'abc'});
144
+ await webex.internal.newMetrics.clientMetricsAliasUser('my-id');
145
+ assert.calledWith(webex.request, {
146
+ method: 'POST',
147
+ api: 'metrics',
148
+ resource: 'clientmetrics',
149
+ headers: { 'x-prelogin-userid': 'my-id' },
150
+ body: {},
151
+ qs: { alias: true },
152
+ });
153
+ assert.calledWith(
154
+ webex.logger.log,
155
+ 'NewMetrics: @clientMetricsAliasUser. Request successful.'
156
+ );
157
+ });
158
+
159
+ it('handles failed request correctly', async () => {
160
+ webex.request.rejects(new Error("test error"));
161
+ sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError')
162
+ try {
163
+ await webex.internal.newMetrics.clientMetricsAliasUser({event: 'test'}, 'my-id');
164
+ } catch (err) {
165
+ assert.calledWith(
166
+ webex.logger.error,
167
+ 'NewMetrics: @clientMetricsAliasUser. Request failed:',
168
+ `err: formattedError`
169
+ );
170
+ }
171
+ });
172
+ });
173
+
174
+ describe('#buildClientEventFetchRequestOptions', () => {
175
+ it('builds client event fetch options successfully', () => {
176
+ webex.internal.newMetrics.buildClientEventFetchRequestOptions({
177
+ name: 'client.alert.displayed',
178
+ options: {
179
+ meetingId: '123',
180
+ },
181
+ });
182
+
183
+ assert.calledWith(
184
+ webex.internal.newMetrics.callDiagnosticMetrics.buildClientEventFetchRequestOptions,
185
+ {
186
+ name: 'client.alert.displayed',
187
+ payload: undefined,
188
+ options: {meetingId: '123'},
189
+ }
190
+ );
191
+ });
192
+ });
193
+
194
+ describe('#setMetricTimingsAndFetch', () => {
195
+ beforeEach(() => {
196
+ global.fetch = sinon.stub();
197
+ });
198
+
199
+ it('calls fetch with the expected options', () => {
200
+ const now = new Date();
201
+ sinon.useFakeTimers(now.getTime());
202
+
203
+ webex.internal.newMetrics.setMetricTimingsAndFetch({
204
+ json: true,
205
+ body: JSON.stringify({metrics: [{eventPayload: {}}]}),
206
+ });
207
+
208
+ const expected = {
209
+ json: true,
210
+ body: JSON.stringify({
211
+ metrics: [
212
+ {
213
+ eventPayload: {
214
+ originTime: {
215
+ triggered: now.toISOString(),
216
+ sent: now.toISOString(),
217
+ },
218
+ },
219
+ },
220
+ ],
221
+ }),
222
+ };
223
+
224
+ sinon.assert.calledOnce(webex.setTimingsAndFetch);
225
+ sinon.assert.calledWith(webex.setTimingsAndFetch, expected);
226
+
227
+ sinon.restore();
228
+ });
229
+ });
230
+ });
231
+ });
@@ -0,0 +1,251 @@
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {assert} from '@webex/test-helper-chai';
6
+ import {config, Utils} from '@webex/internal-plugin-metrics';
7
+ import {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';
8
+ import MockWebex from '@webex/test-helper-mock-webex';
9
+ import sinon from 'sinon';
10
+ import FakeTimers from '@sinonjs/fake-timers';
11
+ import {NewMetrics} from '@webex/internal-plugin-metrics';
12
+ import {uniqueId} from 'lodash';
13
+
14
+ const flushPromises = () => new Promise(setImmediate);
15
+
16
+ describe('internal-plugin-metrics', () => {
17
+ describe('PreLoginMetricsBatcher', () => {
18
+ let webex;
19
+ let clock;
20
+ let now;
21
+
22
+ const preLoginId = 'my_prelogin_id';
23
+
24
+ beforeEach(() => {
25
+ now = new Date();
26
+ clock = FakeTimers.install({now});
27
+
28
+ //@ts-ignore
29
+ webex = new MockWebex({
30
+ children: {
31
+ newMetrics: NewMetrics,
32
+ },
33
+ });
34
+
35
+ webex.request = (options) =>
36
+ Promise.resolve({body: {items: []}, waitForServiceTimeout: 15, options});
37
+
38
+ sinon.spy(webex, 'request');
39
+ webex.emit('ready');
40
+ webex.config.metrics = config.metrics;
41
+ });
42
+
43
+ afterEach(() => {
44
+ sinon.restore();
45
+ clock.uninstall();
46
+ });
47
+
48
+ describe('#request()', () => {
49
+ it('when the request completes successfully, clears the queue', async () => {
50
+ const promise =
51
+ webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnosticsPreLogin(
52
+ //@ts-ignore
53
+ {event: {name: 'client.interstitial-window.launched'}},
54
+ preLoginId
55
+ );
56
+ await flushPromises();
57
+ clock.tick(config.metrics.batcherWait);
58
+
59
+ await promise;
60
+
61
+ const webexRequestArgs = webex.request.args[0][0];
62
+
63
+ const dateAfterBatcherWait = new Date(now.getTime() + config.metrics.batcherWait);
64
+ //@ts-ignore
65
+ assert.calledOnce(webex.request);
66
+
67
+ // matching because the request includes a symbol key: value pair and sinon cannot handle to compare it..
68
+ assert.match(webexRequestArgs, {
69
+ body: {
70
+ metrics: [
71
+ {
72
+ eventPayload: {
73
+ event: {
74
+ joinTimes: {
75
+ meetingInfoReqResp: undefined,
76
+ clickToInterstitial: undefined,
77
+ refreshCaptchaServiceReqResp: undefined,
78
+ },
79
+ name: 'client.interstitial-window.launched',
80
+ },
81
+ origin: {
82
+ buildType: 'test',
83
+ networkType: 'unknown',
84
+ },
85
+ originTime: {
86
+ sent: dateAfterBatcherWait.toISOString(),
87
+ },
88
+ },
89
+ type: ['diagnostic-event'],
90
+ },
91
+ ],
92
+ },
93
+ headers: {
94
+ authorization: false,
95
+ 'x-prelogin-userid': preLoginId,
96
+ },
97
+ method: 'POST',
98
+ resource: 'clientmetrics-prelogin',
99
+ service: 'metrics',
100
+ waitForServiceTimeout: 30,
101
+ });
102
+ assert.lengthOf(
103
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.queue,
104
+ 0
105
+ );
106
+ });
107
+
108
+ it('when the request fails, does not clear the queue', async () => {
109
+ webex.request = sinon.stub().rejects(new Error('my_error'));
110
+
111
+ webex.logger.error = sinon.stub();
112
+ webex.logger.log = sinon.stub();
113
+ sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError');
114
+
115
+ const promise =
116
+ webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnosticsPreLogin(
117
+ {
118
+ event: 'my.event',
119
+ },
120
+ preLoginId
121
+ );
122
+
123
+ await flushPromises();
124
+ clock.tick(config.metrics.batcherWait);
125
+
126
+ let error;
127
+
128
+ // catch the expected error and store it
129
+ try {
130
+ await promise;
131
+ } catch (err) {
132
+ error = err;
133
+ }
134
+
135
+ // This is horrific, but stubbing lodash is proving difficult
136
+ const expectedBatchId = parseInt(uniqueId()) - 1;
137
+
138
+ assert.equal(error.message, 'my_error');
139
+ assert.calledOnceWithExactly(
140
+ webex.logger.error,
141
+ 'Pre Login Metrics -->',
142
+ `PreLoginMetricsBatcher: @submitHttpRequest#prelogin-ca-batch-${expectedBatchId}. Request failed:`,
143
+ `error: formattedError`
144
+ );
145
+ assert.lengthOf(
146
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.queue,
147
+ 0
148
+ );
149
+ });
150
+
151
+ it('fails if preLoinId is not set', async () => {
152
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId = undefined;
153
+
154
+ const promise =
155
+ webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnosticsPreLogin(
156
+ {
157
+ event: 'my.event',
158
+ },
159
+ undefined
160
+ );
161
+
162
+ await flushPromises();
163
+ clock.tick(config.metrics.batcherWait);
164
+
165
+ let error;
166
+
167
+ // catch the expected error and store it
168
+ try {
169
+ await promise;
170
+ } catch (err) {
171
+ error = err;
172
+ }
173
+
174
+ assert.equal(error.message, 'PreLoginId is not set.');
175
+ });
176
+ });
177
+
178
+ describe('prepareItem', () => {
179
+ it('calls prepareDiagnosticMetricItem correctly', async () => {
180
+ // avoid setting .sent timestamp
181
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.prepareRequest = (q) =>
182
+ Promise.resolve(q);
183
+
184
+ const prepareItemSpy = sinon.spy(
185
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher,
186
+ 'prepareItem'
187
+ );
188
+ const prepareDiagnosticMetricItemSpy = sinon.spy(
189
+ CallDiagnosticUtils,
190
+ 'prepareDiagnosticMetricItem'
191
+ );
192
+
193
+ const promise =
194
+ webex.internal.newMetrics.callDiagnosticMetrics.submitToCallDiagnosticsPreLogin(
195
+ {
196
+ event: 'my.event',
197
+ },
198
+ preLoginId
199
+ );
200
+
201
+ await flushPromises();
202
+
203
+ clock.tick(config.metrics.batcherWait);
204
+
205
+ await promise;
206
+
207
+ const calls = prepareItemSpy.getCalls()[0];
208
+
209
+ // item also gets assigned a delay property but the key is a Symbol and haven't been able to test that..
210
+ assert.deepEqual(calls.args[0].eventPayload, {
211
+ event: 'my.event',
212
+ origin: {buildType: 'test', networkType: 'unknown'},
213
+ });
214
+
215
+ assert.deepEqual(calls.args[0].type, ['diagnostic-event']);
216
+
217
+ const prepareDiagnosticMetricItemCalls = prepareDiagnosticMetricItemSpy.getCalls();
218
+
219
+ // second argument (item) also gets assigned a delay property but the key is a Symbol and haven't been able to test that..
220
+ assert.deepEqual(prepareDiagnosticMetricItemCalls[0].args[0], webex);
221
+ assert.deepEqual(prepareDiagnosticMetricItemCalls[0].args[1].eventPayload, {
222
+ event: 'my.event',
223
+ origin: {
224
+ buildType: 'test',
225
+ networkType: 'unknown',
226
+ },
227
+ });
228
+ assert.deepEqual(prepareDiagnosticMetricItemCalls[0].args[1].type, ['diagnostic-event']);
229
+ });
230
+ });
231
+
232
+ describe('savePreLoginId', () => {
233
+ it('saves the preLoginId', () => {
234
+ const preLoginId = 'my_prelogin_id';
235
+
236
+ assert.isUndefined(
237
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId
238
+ );
239
+
240
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.savePreLoginId(
241
+ preLoginId
242
+ );
243
+
244
+ assert.equal(
245
+ webex.internal.newMetrics.callDiagnosticMetrics.preLoginMetricsBatcher.preLoginId,
246
+ preLoginId
247
+ );
248
+ });
249
+ });
250
+ });
251
+ });