@webex/internal-plugin-metrics 3.0.0-beta.374 → 3.0.0-beta.376

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.
@@ -1,15 +1,16 @@
1
1
  import sinon from 'sinon';
2
2
  import {assert} from '@webex/test-helper-chai';
3
3
  import {WebexHttpError} from '@webex/webex-core';
4
-
5
- import CallDiagnosticMetrics from '../../../../src/call-diagnostic/call-diagnostic-metrics';
6
- import CallDiagnosticLatencies from '../../../../src/call-diagnostic/call-diagnostic-metrics-latencies';
7
- import * as Utils from '../../../../src/call-diagnostic/call-diagnostic-metrics.util';
8
- import {BrowserDetection, getBrowserSerial} from '@webex/common';
9
- import {getOSNameInternal} from '@webex/internal-plugin-metrics';
4
+ import {BrowserDetection} from '@webex/common';
5
+ import {
6
+ CallDiagnosticLatencies,
7
+ CallDiagnosticMetrics,
8
+ getOSNameInternal,
9
+ CallDiagnosticUtils,
10
+ config,
11
+ } from '@webex/internal-plugin-metrics';
10
12
  import uuid from 'uuid';
11
13
  import {omit} from 'lodash';
12
- import CONFIG from '../../../../src/config';
13
14
 
14
15
  //@ts-ignore
15
16
  global.window = {location: {hostname: 'whatever'}};
@@ -67,11 +68,9 @@ describe('internal-plugin-metrics', () => {
67
68
  },
68
69
  metrics: {
69
70
  submitClientMetrics: sinon.stub(),
70
- config: {...CONFIG.metrics},
71
- },
72
- newMetrics: {
73
- postPreLoginMetric: sinon.stub(),
71
+ config: {...config.metrics},
74
72
  },
73
+ newMetrics: {},
75
74
  device: {
76
75
  userId: 'userId',
77
76
  url: 'deviceUrl',
@@ -128,7 +127,7 @@ describe('internal-plugin-metrics', () => {
128
127
 
129
128
  describe('#getOrigin', () => {
130
129
  it('should build origin correctly', () => {
131
- sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
130
+ sinon.stub(CallDiagnosticUtils, 'anonymizeIPAddress').returns('1.1.1.1');
132
131
  //@ts-ignore
133
132
  const res = cd.getOrigin(
134
133
  {subClientType: 'WEB_APP', clientType: 'TEAMS_CLIENT'},
@@ -155,7 +154,7 @@ describe('internal-plugin-metrics', () => {
155
154
  });
156
155
 
157
156
  it('should build origin correctly with newEnvironment and createLaunchMethod', () => {
158
- sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
157
+ sinon.stub(CallDiagnosticUtils, 'anonymizeIPAddress').returns('1.1.1.1');
159
158
 
160
159
  //@ts-ignore
161
160
  const res = cd.getOrigin(
@@ -190,7 +189,7 @@ describe('internal-plugin-metrics', () => {
190
189
  });
191
190
 
192
191
  it('should build origin correctly and environment can be passed in options', () => {
193
- sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
192
+ sinon.stub(CallDiagnosticUtils, 'anonymizeIPAddress').returns('1.1.1.1');
194
193
 
195
194
  //@ts-ignore
196
195
  const res = cd.getOrigin(
@@ -224,7 +223,7 @@ describe('internal-plugin-metrics', () => {
224
223
  });
225
224
 
226
225
  it('should build origin correctly with no meeting', () => {
227
- sinon.stub(Utils, 'anonymizeIPAddress').returns('1.1.1.1');
226
+ sinon.stub(CallDiagnosticUtils, 'anonymizeIPAddress').returns('1.1.1.1');
228
227
 
229
228
  //@ts-ignore
230
229
  const res = cd.getOrigin();
@@ -498,7 +497,7 @@ describe('internal-plugin-metrics', () => {
498
497
  it('should prepare diagnostic event successfully', () => {
499
498
  const options = {meetingId: fakeMeeting.id};
500
499
  const getOriginStub = sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
501
- const clearEmptyKeysRecursivelyStub = sinon.stub(Utils, 'clearEmptyKeysRecursively');
500
+ const clearEmptyKeysRecursivelyStub = sinon.stub(CallDiagnosticUtils, 'clearEmptyKeysRecursively');
502
501
 
503
502
  const res = cd.prepareDiagnosticEvent(
504
503
  {
@@ -854,32 +853,27 @@ describe('internal-plugin-metrics', () => {
854
853
  );
855
854
  assert.notCalled(submitToCallDiagnosticsSpy);
856
855
  assert.calledWith(submitToCallDiagnosticsPreLoginSpy, {
857
- event: {
858
- canProceed: true,
859
- eventData: {
860
- webClientDomain: 'whatever',
861
- },
862
- identifiers: {
863
- correlationId: 'correlationId',
864
- webexConferenceIdStr: 'webexConferenceIdStr1',
865
- globalMeetingId: 'globalMeetingId1',
866
- deviceId: 'deviceUrl',
867
- locusUrl: 'locus-url',
868
- orgId: 'orgId',
869
- userId: 'myPreLoginId',
856
+ eventId: 'my-fake-id',
857
+ version: 1,
858
+ origin: { origin: 'fake-origin' },
859
+ originTime: { triggered: now.toISOString(), sent: 'not_defined_yet' },
860
+ senderCountryCode: 'UK',
861
+ event: {
862
+ name: 'client.alert.displayed',
863
+ canProceed: true,
864
+ identifiers: {
865
+ correlationId: 'correlationId',
866
+ userId: 'myPreLoginId',
867
+ deviceId: 'deviceUrl',
868
+ orgId: 'orgId',
869
+ locusUrl: 'locus-url',
870
+ webexConferenceIdStr: 'webexConferenceIdStr1',
871
+ globalMeetingId: 'globalMeetingId1'
872
+ },
873
+ eventData: { webClientDomain: 'whatever' },
874
+ loginType: 'login-ci'
870
875
  },
871
- loginType: 'login-ci',
872
- name: 'client.alert.displayed',
873
- },
874
- eventId: 'my-fake-id',
875
- origin: {buildType: 'test', networkType: 'unknown', origin: 'fake-origin'},
876
- originTime: {
877
- triggered: now.toISOString(),
878
- sent: now.toISOString(),
879
- },
880
- senderCountryCode: 'UK',
881
- version: 1,
882
- });
876
+ }, options.preLoginId);
883
877
  });
884
878
 
885
879
  it('should use meeting loginType if present and meetingId provided', () => {
@@ -1030,8 +1024,6 @@ describe('internal-plugin-metrics', () => {
1030
1024
  options,
1031
1025
  });
1032
1026
 
1033
- console.log(submitToCallDiagnosticsSpy.getCalls()[0].args[0].event.errors);
1034
-
1035
1027
  assert.calledWith(submitToCallDiagnosticsSpy, {
1036
1028
  event: {
1037
1029
  canProceed: true,
@@ -1346,14 +1338,16 @@ describe('internal-plugin-metrics', () => {
1346
1338
  });
1347
1339
  });
1348
1340
 
1349
- it('should send request to call diagnostic batcher', () => {
1350
- const requestStub = sinon.stub();
1351
- //@ts-ignore
1352
- cd.callDiagnosticEventsBatcher = {request: requestStub};
1353
- //@ts-ignore
1354
- cd.submitToCallDiagnostics({event: 'test'});
1355
- assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
1356
- });
1341
+ describe("#submitToCallDiagnostics", () => {
1342
+ it('should send request to call diagnostic batcher', () => {
1343
+ const requestStub = sinon.stub();
1344
+ //@ts-ignore
1345
+ cd.callDiagnosticEventsBatcher = {request: requestStub};
1346
+ //@ts-ignore
1347
+ cd.submitToCallDiagnostics({event: 'test'});
1348
+ assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
1349
+ });
1350
+ })
1357
1351
 
1358
1352
  describe('#submitMQE', () => {
1359
1353
  it('submits the event correctly', () => {
@@ -2083,7 +2077,7 @@ describe('internal-plugin-metrics', () => {
2083
2077
  method: 'POST',
2084
2078
  resource: 'clientmetrics-prelogin',
2085
2079
  service: 'metrics',
2086
- waitForServiceTimeout: CONFIG.metrics.waitForServiceTimeout,
2080
+ waitForServiceTimeout: config.metrics.waitForServiceTimeout,
2087
2081
  headers: {
2088
2082
  authorization: false,
2089
2083
  'x-prelogin-userid': preLoginId,
@@ -2096,7 +2090,7 @@ describe('internal-plugin-metrics', () => {
2096
2090
  resource: 'clientmetrics',
2097
2091
  service: 'metrics',
2098
2092
  headers: {},
2099
- waitForServiceTimeout: CONFIG.metrics.waitForServiceTimeout,
2093
+ waitForServiceTimeout: config.metrics.waitForServiceTimeout,
2100
2094
  });
2101
2095
  }
2102
2096
 
@@ -2111,51 +2105,20 @@ describe('internal-plugin-metrics', () => {
2111
2105
  });
2112
2106
  });
2113
2107
 
2114
- describe('#submitToCallDiagnosticsPreLogin', async () => {
2115
- it('should call webex.request with expected options', async () => {
2116
- sinon.spy(Utils, 'prepareDiagnosticMetricItem');
2117
- await cd.submitToCallDiagnosticsPreLogin(
2118
- {
2119
- //@ts-ignore
2120
- event: {name: 'client.alert.displayed', canProceed: true},
2121
- //@ts-ignore
2122
- originTime: {triggered: 'now'},
2123
- },
2124
- 'my-id'
2125
- );
2126
-
2127
- assert.calledWith(Utils.prepareDiagnosticMetricItem, webex, {
2128
- eventPayload: {
2129
- event: {name: 'client.alert.displayed', canProceed: true},
2130
- originTime: {triggered: 'now', sent: now.toISOString()},
2131
- origin: {buildType: 'test', networkType: 'unknown'},
2132
- },
2133
- type: ['diagnostic-event'],
2134
- });
2135
-
2136
- assert.calledWith(
2137
- webex.internal.newMetrics.postPreLoginMetric,
2138
- {
2139
- eventPayload: {
2140
- event: {
2141
- name: 'client.alert.displayed',
2142
- canProceed: true,
2143
- },
2144
- originTime: {
2145
- sent: now.toISOString(),
2146
- triggered: 'now',
2147
- },
2148
- origin: {
2149
- buildType: 'test',
2150
- networkType: 'unknown',
2151
- },
2152
- },
2153
- type: ['diagnostic-event'],
2154
- },
2155
- 'my-id'
2156
- );
2108
+ describe("#submitToCallDiagnosticsPreLogin", () => {
2109
+ it('should send request to call diagnostic batcher and saves preLoginId', () => {
2110
+ const requestStub = sinon.stub();
2111
+ //@ts-ignore
2112
+ const preLoginId = '123';
2113
+ //@ts-ignore
2114
+ cd.preLoginMetricsBatcher = {request: requestStub, savePreLoginId: sinon.stub()};
2115
+ //@ts-ignore
2116
+ cd.submitToCallDiagnosticsPreLogin({event: 'test'}, preLoginId);
2117
+ //@ts-ignore
2118
+ assert.calledWith(cd.preLoginMetricsBatcher.savePreLoginId, preLoginId);
2119
+ assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
2157
2120
  });
2158
- });
2121
+ })
2159
2122
 
2160
2123
  describe('#isServiceErrorExpected', () => {
2161
2124
  it('returns true for code mapped to "expected"', () => {
@@ -67,7 +67,6 @@ describe('internal-plugin-metrics', () => {
67
67
  webex.internal.newMetrics.callDiagnosticMetrics.submitClientEvent = sinon.stub();
68
68
  webex.internal.newMetrics.callDiagnosticMetrics.submitMQE = sinon.stub();
69
69
  webex.internal.newMetrics.callDiagnosticMetrics.clientMetricsAliasUser = sinon.stub();
70
- webex.internal.newMetrics.callDiagnosticMetrics.postPreLoginMetric = sinon.stub();
71
70
  webex.internal.newMetrics.callDiagnosticMetrics.buildClientEventFetchRequestOptions =
72
71
  sinon.stub();
73
72
  webex.setTimingsAndFetch = sinon.stub();
@@ -175,38 +174,6 @@ describe('internal-plugin-metrics', () => {
175
174
  });
176
175
  });
177
176
 
178
- describe('#postPreLoginMetric', () => {
179
- it('sends the request correctly', async () => {
180
- webex.request.resolves({response: 'abc'});
181
- await webex.internal.newMetrics.postPreLoginMetric({event: 'test'}, 'my-id');
182
- assert.calledWith(webex.request, {
183
- method: 'POST',
184
- api: 'metrics',
185
- resource: 'clientmetrics-prelogin',
186
- headers: { 'x-prelogin-userid': 'my-id', authorization: false },
187
- body: {metrics: [{event: 'test'}]},
188
- });
189
- assert.calledWith(
190
- webex.logger.log,
191
- 'NewMetrics: @postPreLoginMetric. Request successful.'
192
- );
193
- });
194
-
195
- it('handles failed request correctly', async () => {
196
- webex.request.rejects(new Error("test error"));
197
- sinon.stub(Utils, 'generateCommonErrorMetadata').returns('formattedError')
198
- try {
199
- await webex.internal.newMetrics.postPreLoginMetric({event: 'test'}, 'my-id');
200
- } catch (err) {
201
- assert.calledWith(
202
- webex.logger.error,
203
- 'NewMetrics: @postPreLoginMetric. Request failed:',
204
- `err: formattedError`
205
- );
206
- }
207
- });
208
- })
209
-
210
177
  describe('#buildClientEventFetchRequestOptions', () => {
211
178
  it('builds client event fetch options successfully', () => {
212
179
  webex.internal.newMetrics.buildClientEventFetchRequestOptions({
@@ -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
+ });