@webex/internal-plugin-metrics 3.0.0-beta.42 → 3.0.0-beta.420

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 +552 -0
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -0
  7. package/dist/call-diagnostic/call-diagnostic-metrics.js +863 -0
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -0
  9. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +371 -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 +237 -0
  30. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +425 -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 +107 -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 +15 -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 +511 -0
  47. package/src/call-diagnostic/call-diagnostic-metrics.ts +925 -0
  48. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +399 -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 +179 -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 +469 -0
  60. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +718 -0
  61. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +2371 -0
  62. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +637 -0
  63. package/test/unit/spec/client-metrics-batcher.js +2 -0
  64. package/test/unit/spec/metrics.js +77 -98
  65. package/test/unit/spec/new-metrics.ts +231 -0
  66. package/test/unit/spec/prelogin-metrics-batcher.ts +253 -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,7 +8,12 @@ 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';
11
12
 
13
+ const {getOSVersion} = BrowserDetection();
14
+
15
+ //@ts-ignore
16
+ global.window = {location: {hostname: 'whatever'}};
12
17
  function promiseTick(count) {
13
18
  let promise = Promise.resolve();
14
19
 
@@ -82,6 +87,7 @@ describe('plugin-metrics', () => {
82
87
  return Promise.resolve({
83
88
  statusCode: 204,
84
89
  body: undefined,
90
+ waitForServiceTimeout: 30,
85
91
  options,
86
92
  });
87
93
  };
@@ -89,7 +95,7 @@ describe('plugin-metrics', () => {
89
95
  webex.credentials = new Credentials(undefined, {parent: webex});
90
96
  sinon.stub(webex.credentials, 'getClientToken').returns(Promise.resolve('token'));
91
97
 
92
- webex.internal = {...webex.internal, device: {userId: 'userId'}};
98
+ webex.internal = {...webex.internal};
93
99
  webex.config = {
94
100
  ...webex.config,
95
101
  appName: 'appName',
@@ -98,11 +104,17 @@ describe('plugin-metrics', () => {
98
104
  };
99
105
  webex.config.metrics.type = ['operational'];
100
106
  webex.config.metrics.appType = 'sdk';
107
+ webex.meetings = {
108
+ config: {
109
+ metrics: {
110
+ clientVersion: '43.0.105'
111
+ }
112
+ }
113
+ }
101
114
 
102
115
  sinon.spy(webex, 'request');
103
116
  sinon.spy(metrics, 'postPreLoginMetric');
104
117
  sinon.spy(metrics, 'aliasUser');
105
- sinon.spy(metrics, 'submitCallDiagnosticEvents');
106
118
  });
107
119
 
108
120
  describe('#submit()', () => {
@@ -131,6 +143,68 @@ describe('plugin-metrics', () => {
131
143
  });
132
144
  });
133
145
 
146
+ describe('#getClientMetricsPayload()', () => {
147
+ it('returns the expected payload', () => {
148
+ webex.credentials.supertoken = new Token(
149
+ {
150
+ access_token: 'a_b_orgid',
151
+ },
152
+ {parent: webex}
153
+ );
154
+
155
+ const testPayload = {
156
+ tags: {success: true},
157
+ fields: {perceivedDurationInMillis: 314},
158
+ context: {},
159
+ eventPayload: {value: 'splunk business metric payload'},
160
+ };
161
+ const date = clock.now;
162
+
163
+ const result = metrics.getClientMetricsPayload('test', testPayload);
164
+
165
+ assert.deepEqual(result, {
166
+ context: {
167
+ app: {
168
+ version: undefined,
169
+ },
170
+ locale: 'en-US',
171
+ os: {
172
+ name: 'other',
173
+ version: getOSVersion(),
174
+ },
175
+ },
176
+ eventPayload: {
177
+ value: 'splunk business metric payload',
178
+ },
179
+ fields: {
180
+ browser_version: '',
181
+ client_id: 'fake',
182
+ os_version: getOSVersion(),
183
+ perceivedDurationInMillis: 314,
184
+ platform: 'Web',
185
+ sdk_version: undefined,
186
+ spark_user_agent: 'webex-js-sdk appName/appVersion appPlatform',
187
+ },
188
+ metricName: 'test',
189
+ tags: {
190
+ appVersion: '43.0.105',
191
+ browser: '',
192
+ domain: 'whatever',
193
+ os: 'other',
194
+ success: true,
195
+ },
196
+ timestamp: 0,
197
+ type: ['operational'],
198
+ });
199
+ });
200
+
201
+ it('throws when no event name is specified', () => {
202
+ assert.throws(() => {
203
+ metrics.getClientMetricsPayload();
204
+ }, 'Missing behavioral metric name. Please provide one');
205
+ });
206
+ });
207
+
134
208
  describe('#submitClientMetrics()', () => {
135
209
  describe('before login', () => {
136
210
  it('posts pre-login metric', () => {
@@ -199,17 +273,15 @@ describe('plugin-metrics', () => {
199
273
  assert.property(metric, 'eventPayload');
200
274
 
201
275
  assert.property(metric.tags, 'browser');
202
- assert.property(metric.tags, 'org_id');
203
276
  assert.property(metric.tags, 'os');
204
277
  assert.property(metric.tags, 'domain');
205
- assert.property(metric.tags, 'client_id');
206
- assert.property(metric.tags, 'user_id');
207
278
 
208
279
  assert.property(metric.fields, 'browser_version');
209
280
  assert.property(metric.fields, 'os_version');
210
281
  assert.property(metric.fields, 'sdk_version');
211
282
  assert.property(metric.fields, 'platform');
212
283
  assert.property(metric.fields, 'spark_user_agent');
284
+ assert.property(metric.fields, 'client_id');
213
285
 
214
286
  assert.property(metric.context, 'app');
215
287
  assert.property(metric.context, 'locale');
@@ -269,98 +341,5 @@ describe('plugin-metrics', () => {
269
341
  assert.match(params, {alias: true});
270
342
  }));
271
343
  });
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
344
  });
366
345
  });
@@ -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
+ });