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