@webex/internal-plugin-metrics 3.4.0 → 3.5.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/dist/behavioral-metrics.js +63 -0
- package/dist/behavioral-metrics.js.map +1 -0
- package/dist/business-metrics.js +62 -0
- package/dist/business-metrics.js.map +1 -0
- package/dist/call-diagnostic/call-diagnostic-metrics.js +12 -4
- package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js +8 -3
- package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
- package/dist/generic-metrics.js +184 -0
- package/dist/generic-metrics.js.map +1 -0
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/metrics.js +1 -1
- package/dist/metrics.types.js.map +1 -1
- package/dist/new-metrics.js +122 -24
- package/dist/new-metrics.js.map +1 -1
- package/dist/operational-metrics.js +56 -0
- package/dist/operational-metrics.js.map +1 -0
- package/dist/types/behavioral-metrics.d.ts +25 -0
- package/dist/types/business-metrics.d.ts +19 -0
- package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +21 -5
- package/dist/types/call-diagnostic/call-diagnostic-metrics.util.d.ts +2 -1
- package/dist/types/generic-metrics.d.ts +63 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/metrics.types.d.ts +26 -14
- package/dist/types/new-metrics.d.ts +41 -9
- package/dist/types/operational-metrics.d.ts +19 -0
- package/package.json +12 -12
- package/src/behavioral-metrics.ts +40 -0
- package/src/business-metrics.ts +30 -0
- package/src/call-diagnostic/call-diagnostic-metrics.ts +17 -2
- package/src/call-diagnostic/call-diagnostic-metrics.util.ts +7 -0
- package/src/generic-metrics.ts +146 -0
- package/src/index.ts +5 -1
- package/src/metrics.types.ts +30 -16
- package/src/new-metrics.ts +95 -17
- package/src/operational-metrics.ts +24 -0
- package/test/unit/spec/behavioral/behavioral-metrics.ts +51 -10
- package/test/unit/spec/business/business-metrics.ts +120 -0
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +13 -1
- package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +15 -5
- package/test/unit/spec/new-metrics.ts +14 -0
- package/test/unit/spec/operational/operational-metrics.ts +115 -0
- package/src/behavioral/behavioral-metrics.ts +0 -179
- package/src/behavioral/config.ts +0 -3
package/src/metrics.types.ts
CHANGED
|
@@ -61,6 +61,7 @@ export type SubmitClientEventOptions = {
|
|
|
61
61
|
mediaConnections?: any[];
|
|
62
62
|
rawError?: any;
|
|
63
63
|
correlationId?: string;
|
|
64
|
+
sessionCorrelationId?: string;
|
|
64
65
|
preLoginId?: string;
|
|
65
66
|
environment?: EnvironmentType;
|
|
66
67
|
newEnvironmentType?: NewEnvironmentType;
|
|
@@ -102,7 +103,7 @@ export interface ClientEvent {
|
|
|
102
103
|
options?: SubmitClientEventOptions;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
export interface
|
|
106
|
+
export interface DeviceContext {
|
|
106
107
|
app: {version: string};
|
|
107
108
|
device: {id: string};
|
|
108
109
|
locale: string;
|
|
@@ -112,23 +113,36 @@ export interface BehavioralEventContext {
|
|
|
112
113
|
};
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
export
|
|
116
|
-
|
|
116
|
+
export type MetricType = 'behavioral' | 'operational' | 'business';
|
|
117
|
+
|
|
118
|
+
type InternalEventPayload = string | number | boolean;
|
|
119
|
+
export type EventPayload = Record<string, InternalEventPayload>;
|
|
120
|
+
export type BehavioralEventPayload = EventPayload; // for compatibilty, can be remove after wxcc-desktop did change their imports.
|
|
121
|
+
|
|
122
|
+
export interface BusinessEventPayload {
|
|
117
123
|
metricName: string;
|
|
118
|
-
tags: Record<string, string | number | boolean>;
|
|
119
124
|
timestamp: number;
|
|
120
|
-
|
|
125
|
+
context: DeviceContext;
|
|
126
|
+
browserDetails: EventPayload;
|
|
127
|
+
value: EventPayload;
|
|
121
128
|
}
|
|
122
129
|
|
|
123
|
-
export
|
|
130
|
+
export interface BusinessEvent {
|
|
131
|
+
type: string[];
|
|
132
|
+
eventPayload: BusinessEventPayload;
|
|
133
|
+
}
|
|
124
134
|
|
|
125
|
-
export interface
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
export interface TaggedEvent {
|
|
136
|
+
context: DeviceContext;
|
|
137
|
+
metricName: string;
|
|
138
|
+
tags: EventPayload;
|
|
139
|
+
timestamp: number;
|
|
140
|
+
type: [MetricType];
|
|
130
141
|
}
|
|
131
142
|
|
|
143
|
+
export type BehavioralEvent = TaggedEvent;
|
|
144
|
+
export type OperationalEvent = TaggedEvent;
|
|
145
|
+
|
|
132
146
|
export interface FeatureEvent {
|
|
133
147
|
// TODO: not implemented
|
|
134
148
|
name: never;
|
|
@@ -154,7 +168,8 @@ export type MetricEventNames =
|
|
|
154
168
|
| InternalEvent['name']
|
|
155
169
|
| ClientEvent['name']
|
|
156
170
|
| BehavioralEvent['metricName']
|
|
157
|
-
| OperationalEvent['
|
|
171
|
+
| OperationalEvent['metricName']
|
|
172
|
+
| BusinessEvent['eventPayload']['metricName']
|
|
158
173
|
| FeatureEvent['name']
|
|
159
174
|
| MediaQualityEvent['name'];
|
|
160
175
|
|
|
@@ -190,7 +205,7 @@ export type SubmitBehavioralEvent = (args: {
|
|
|
190
205
|
agent: MetricEventAgent;
|
|
191
206
|
target: string;
|
|
192
207
|
verb: MetricEventVerb;
|
|
193
|
-
payload?:
|
|
208
|
+
payload?: EventPayload;
|
|
194
209
|
}) => void;
|
|
195
210
|
|
|
196
211
|
export type SubmitClientEvent = (args: {
|
|
@@ -200,9 +215,8 @@ export type SubmitClientEvent = (args: {
|
|
|
200
215
|
}) => Promise<any>;
|
|
201
216
|
|
|
202
217
|
export type SubmitOperationalEvent = (args: {
|
|
203
|
-
name: OperationalEvent['
|
|
204
|
-
payload
|
|
205
|
-
options?: any;
|
|
218
|
+
name: OperationalEvent['metricName'];
|
|
219
|
+
payload: EventPayload;
|
|
206
220
|
}) => void;
|
|
207
221
|
|
|
208
222
|
export type SubmitMQE = (args: {
|
package/src/new-metrics.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
import {WebexPlugin} from '@webex/webex-core';
|
|
7
7
|
|
|
8
8
|
import CallDiagnosticMetrics from './call-diagnostic/call-diagnostic-metrics';
|
|
9
|
-
import BehavioralMetrics from './behavioral
|
|
9
|
+
import BehavioralMetrics from './behavioral-metrics';
|
|
10
|
+
import OperationalMetrics from './operational-metrics';
|
|
11
|
+
import BusinessMetrics from './business-metrics';
|
|
10
12
|
import {
|
|
11
13
|
RecursivePartial,
|
|
12
14
|
MetricEventProduct,
|
|
@@ -14,7 +16,7 @@ import {
|
|
|
14
16
|
MetricEventVerb,
|
|
15
17
|
ClientEvent,
|
|
16
18
|
FeatureEvent,
|
|
17
|
-
|
|
19
|
+
EventPayload,
|
|
18
20
|
OperationalEvent,
|
|
19
21
|
MediaQualityEvent,
|
|
20
22
|
InternalEvent,
|
|
@@ -37,6 +39,9 @@ class Metrics extends WebexPlugin {
|
|
|
37
39
|
// Helper classes to handle the different types of metrics
|
|
38
40
|
callDiagnosticMetrics: CallDiagnosticMetrics;
|
|
39
41
|
behavioralMetrics: BehavioralMetrics;
|
|
42
|
+
operationalMetrics: OperationalMetrics;
|
|
43
|
+
businessMetrics: BusinessMetrics;
|
|
44
|
+
isReady = false;
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
47
|
* Constructor
|
|
@@ -61,8 +66,7 @@ class Metrics extends WebexPlugin {
|
|
|
61
66
|
this.webex.once('ready', () => {
|
|
62
67
|
// @ts-ignore
|
|
63
68
|
this.callDiagnosticMetrics = new CallDiagnosticMetrics({}, {parent: this.webex});
|
|
64
|
-
|
|
65
|
-
this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
|
|
69
|
+
this.isReady = true;
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -86,11 +90,61 @@ class Metrics extends WebexPlugin {
|
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
|
|
93
|
+
/**
|
|
94
|
+
* if webex metrics is ready, build behavioral metric backend if not already done.
|
|
95
|
+
*/
|
|
96
|
+
private lazyBuildBehavioralMetrics() {
|
|
97
|
+
if (this.isReady && !this.behavioralMetrics) {
|
|
98
|
+
// @ts-ignore
|
|
99
|
+
this.behavioralMetrics = new BehavioralMetrics({}, {parent: this.webex});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* if webex metrics is ready, build operational metric backend if not already done.
|
|
105
|
+
*/
|
|
106
|
+
private lazyBuildOperationalMetrics() {
|
|
107
|
+
if (this.isReady && !this.operationalMetrics) {
|
|
108
|
+
// @ts-ignore
|
|
109
|
+
this.operationalMetrics = new OperationalMetrics({}, {parent: this.webex});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* if webex metrics is ready, build business metric backend if not already done.
|
|
115
|
+
*/
|
|
116
|
+
private lazyBuildBusinessMetrics() {
|
|
117
|
+
if (this.isReady && !this.businessMetrics) {
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
this.businessMetrics = new BusinessMetrics({}, {parent: this.webex});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
89
123
|
/**
|
|
90
124
|
* @returns true once we have the deviceId we need to submit behavioral events to Amplitude
|
|
91
125
|
*/
|
|
92
126
|
isReadyToSubmitBehavioralEvents() {
|
|
93
|
-
|
|
127
|
+
this.lazyBuildBehavioralMetrics();
|
|
128
|
+
|
|
129
|
+
return this.behavioralMetrics?.isReadyToSubmitEvents() ?? false;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @returns true once we have the deviceId we need to submit operational events
|
|
134
|
+
*/
|
|
135
|
+
isReadyToSubmitOperationalEvents() {
|
|
136
|
+
this.lazyBuildOperationalMetrics();
|
|
137
|
+
|
|
138
|
+
return this.operationalMetrics?.isReadyToSubmitEvents() ?? false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @returns true once we have the deviceId we need to submit buisness events
|
|
143
|
+
*/
|
|
144
|
+
isReadyToSubmitBusinessEvents() {
|
|
145
|
+
this.lazyBuildBusinessMetrics();
|
|
146
|
+
|
|
147
|
+
return this.businessMetrics?.isReadyToSubmitEvents() ?? false;
|
|
94
148
|
}
|
|
95
149
|
|
|
96
150
|
/**
|
|
@@ -108,9 +162,9 @@ class Metrics extends WebexPlugin {
|
|
|
108
162
|
agent: MetricEventAgent;
|
|
109
163
|
target: string;
|
|
110
164
|
verb: MetricEventVerb;
|
|
111
|
-
payload?:
|
|
165
|
+
payload?: EventPayload;
|
|
112
166
|
}) {
|
|
113
|
-
if (!this.
|
|
167
|
+
if (!this.isReady) {
|
|
114
168
|
// @ts-ignore
|
|
115
169
|
this.webex.logger.log(
|
|
116
170
|
`NewMetrics: @submitBehavioralEvent. Attempted to submit before webex.ready: ${product}.${agent}.${target}.${verb}`
|
|
@@ -119,6 +173,8 @@ class Metrics extends WebexPlugin {
|
|
|
119
173
|
return Promise.resolve();
|
|
120
174
|
}
|
|
121
175
|
|
|
176
|
+
this.lazyBuildBehavioralMetrics();
|
|
177
|
+
|
|
122
178
|
return this.behavioralMetrics.submitBehavioralEvent({product, agent, target, verb, payload});
|
|
123
179
|
}
|
|
124
180
|
|
|
@@ -126,16 +182,38 @@ class Metrics extends WebexPlugin {
|
|
|
126
182
|
* Operational event
|
|
127
183
|
* @param args
|
|
128
184
|
*/
|
|
129
|
-
submitOperationalEvent({
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
185
|
+
submitOperationalEvent({name, payload}: {name: string; payload?: EventPayload}) {
|
|
186
|
+
if (!this.isReady) {
|
|
187
|
+
// @ts-ignore
|
|
188
|
+
this.webex.logger.log(
|
|
189
|
+
`NewMetrics: @submitOperationalEvent. Attempted to submit before webex.ready: ${name}`
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
return Promise.resolve();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.lazyBuildOperationalMetrics();
|
|
196
|
+
|
|
197
|
+
return this.operationalMetrics.submitOperationalEvent({name, payload});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Buisness event
|
|
202
|
+
* @param args
|
|
203
|
+
*/
|
|
204
|
+
submitBusinessEvent({name, payload}: {name: string; payload: EventPayload}) {
|
|
205
|
+
if (!this.isReady) {
|
|
206
|
+
// @ts-ignore
|
|
207
|
+
this.webex.logger.log(
|
|
208
|
+
`NewMetrics: @submitBusinessEvent. Attempted to submit before webex.ready: ${name}`
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
return Promise.resolve();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.lazyBuildBusinessMetrics();
|
|
215
|
+
|
|
216
|
+
return this.businessMetrics.submitBusinessEvent({name, payload});
|
|
139
217
|
}
|
|
140
218
|
|
|
141
219
|
/**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import GenericMetrics from './generic-metrics';
|
|
2
|
+
import {EventPayload} from './metrics.types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description Util class to handle Operational Metrics
|
|
6
|
+
* @export
|
|
7
|
+
* @class OperationalMetrics
|
|
8
|
+
*/
|
|
9
|
+
export default class OperationalMetrics extends GenericMetrics {
|
|
10
|
+
/**
|
|
11
|
+
* Submit an operational metric to our metrics endpoint.
|
|
12
|
+
* @param {string} name of the metric
|
|
13
|
+
* @param {EventPayload} user payload of the metric
|
|
14
|
+
* @returns {Promise<any>}
|
|
15
|
+
*/
|
|
16
|
+
public submitOperationalEvent({name, payload}: {name: string; payload: EventPayload}) {
|
|
17
|
+
const event = this.createTaggedEventObject({
|
|
18
|
+
type: ['operational'],
|
|
19
|
+
name,
|
|
20
|
+
payload,
|
|
21
|
+
});
|
|
22
|
+
this.submitEvent({kind: 'operational-events -> ', name, event});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -74,6 +74,45 @@ describe('internal-plugin-metrics', () => {
|
|
|
74
74
|
sinon.restore();
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
+
describe('#sendEvent', () => {
|
|
78
|
+
it('should send correctly shaped behavioral event (check name building and internal tagged event building)', () => {
|
|
79
|
+
// For some reasons `jest` isn't available when testing form build server - so can't use `jest.fn()` here...
|
|
80
|
+
const requestCalls = [];
|
|
81
|
+
const request = function(arg) { requestCalls.push(arg) }
|
|
82
|
+
|
|
83
|
+
behavioralMetrics.clientMetricsBatcher.request = request;
|
|
84
|
+
|
|
85
|
+
assert.equal(requestCalls.length, 0)
|
|
86
|
+
behavioralMetrics.submitBehavioralEvent({ product: "webex", agent: "user", target: "foo", verb: "get", payload: {bar:"gee"} })
|
|
87
|
+
assert.equal(requestCalls.length, 1)
|
|
88
|
+
assert.deepEqual(requestCalls[0], {
|
|
89
|
+
context: {
|
|
90
|
+
app: {version: 'webex-version'},
|
|
91
|
+
device: {id: 'deviceId'},
|
|
92
|
+
locale: 'language',
|
|
93
|
+
os: {
|
|
94
|
+
name: getOSNameInternal(),
|
|
95
|
+
version: getOSVersion(),
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
metricName: 'webex.user.foo.get',
|
|
99
|
+
tags: {
|
|
100
|
+
browser: getBrowserName(),
|
|
101
|
+
browserHeight: window.innerHeight,
|
|
102
|
+
browserVersion: getBrowserVersion(),
|
|
103
|
+
browserWidth: window.innerWidth,
|
|
104
|
+
domain: window.location.hostname,
|
|
105
|
+
inIframe: false,
|
|
106
|
+
locale: window.navigator.language,
|
|
107
|
+
os: getOSNameInternal(),
|
|
108
|
+
bar:"gee"
|
|
109
|
+
},
|
|
110
|
+
timestamp: requestCalls[0].timestamp, // This is to bypass time check, which is correctly tested below.
|
|
111
|
+
type: ['behavioral'],
|
|
112
|
+
});
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
77
116
|
describe('#getContext', () => {
|
|
78
117
|
it('should build context correctly', () => {
|
|
79
118
|
const res = behavioralMetrics.getContext();
|
|
@@ -96,7 +135,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
96
135
|
|
|
97
136
|
describe('#getDefaultTags', () => {
|
|
98
137
|
it('should build tags correctly', () => {
|
|
99
|
-
const res = behavioralMetrics.
|
|
138
|
+
const res = behavioralMetrics.getBrowserDetails();
|
|
100
139
|
|
|
101
140
|
assert.deepEqual(res, {
|
|
102
141
|
browser: getBrowserName(),
|
|
@@ -111,25 +150,27 @@ describe('internal-plugin-metrics', () => {
|
|
|
111
150
|
});
|
|
112
151
|
});
|
|
113
152
|
|
|
114
|
-
describe('#
|
|
153
|
+
describe('#isReadyToSubmitEvents', () => {
|
|
115
154
|
it('should return true when we have a deviceId, false when deviceId is empty or undefined', async () => {
|
|
116
|
-
|
|
155
|
+
let deviceIdUrl = webex.internal.device.url;
|
|
117
156
|
|
|
157
|
+
// testing case w/o device id url first, as the internal deviceId cache would bypass that flow.
|
|
118
158
|
webex.internal.device.url = "";
|
|
119
|
-
assert.equal(false, behavioralMetrics.
|
|
159
|
+
assert.equal(false, behavioralMetrics.isReadyToSubmitEvents());
|
|
120
160
|
|
|
121
161
|
delete webex.internal.device.url;
|
|
122
|
-
assert.equal(false, behavioralMetrics.
|
|
162
|
+
assert.equal(false, behavioralMetrics.isReadyToSubmitEvents());
|
|
163
|
+
|
|
164
|
+
webex.internal.device.url = deviceIdUrl;
|
|
165
|
+
assert.equal(true, behavioralMetrics.isReadyToSubmitEvents());
|
|
123
166
|
});
|
|
124
167
|
});
|
|
125
168
|
|
|
126
169
|
describe('#createEventObject', () => {
|
|
127
170
|
it('should build event object correctly', async () => {
|
|
128
|
-
const res = behavioralMetrics.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
target: 'target',
|
|
132
|
-
verb: 'create',
|
|
171
|
+
const res = behavioralMetrics.createTaggedEventObject({
|
|
172
|
+
type:['behavioral'],
|
|
173
|
+
name:'webex.user.target.create',
|
|
133
174
|
payload: tags,
|
|
134
175
|
});
|
|
135
176
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import {assert} from '@webex/test-helper-chai';
|
|
3
|
+
import {BrowserDetection} from '@webex/common';
|
|
4
|
+
import {BusinessMetrics, config, getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
5
|
+
import uuid from 'uuid';
|
|
6
|
+
|
|
7
|
+
//@ts-ignore
|
|
8
|
+
global.window = {location: {hostname: 'whatever'}, navigator: {language: 'language'}};
|
|
9
|
+
process.env.NODE_ENV = 'test';
|
|
10
|
+
|
|
11
|
+
const {getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
12
|
+
|
|
13
|
+
describe('internal-plugin-metrics', () => {
|
|
14
|
+
describe('BusinessMetrics', () => {
|
|
15
|
+
let webex;
|
|
16
|
+
let now;
|
|
17
|
+
let businessMetrics: BusinessMetrics;
|
|
18
|
+
|
|
19
|
+
const tags = {key: 'val'};
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
now = new Date();
|
|
23
|
+
|
|
24
|
+
webex = {
|
|
25
|
+
canAuthorize: true,
|
|
26
|
+
version: 'webex-version',
|
|
27
|
+
internal: {
|
|
28
|
+
services: {
|
|
29
|
+
get: () => 'locus-url',
|
|
30
|
+
},
|
|
31
|
+
metrics: {
|
|
32
|
+
submitClientMetrics: sinon.stub(),
|
|
33
|
+
config: {...config.metrics},
|
|
34
|
+
},
|
|
35
|
+
newMetrics: {},
|
|
36
|
+
device: {
|
|
37
|
+
userId: 'userId',
|
|
38
|
+
url: 'https://wdm-intb.ciscospark.com/wdm/api/v1/devices/deviceId',
|
|
39
|
+
orgId: 'orgId',
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
meetings: {
|
|
43
|
+
config: {
|
|
44
|
+
metrics: {
|
|
45
|
+
clientType: 'TEAMS_CLIENT',
|
|
46
|
+
subClientType: 'WEB_APP',
|
|
47
|
+
clientName: 'Cantina',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
geoHintInfo: {
|
|
51
|
+
clientAddress: '1.3.4.5',
|
|
52
|
+
countryCode: 'UK',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
credentials: {
|
|
56
|
+
isUnverifiedGuest: false,
|
|
57
|
+
},
|
|
58
|
+
prepareFetchOptions: sinon.stub().callsFake((opts: any) => ({...opts, foo: 'bar'})),
|
|
59
|
+
request: sinon.stub().resolves({body: {}}),
|
|
60
|
+
logger: {
|
|
61
|
+
log: sinon.stub(),
|
|
62
|
+
error: sinon.stub(),
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
sinon.createSandbox();
|
|
67
|
+
sinon.useFakeTimers(now.getTime());
|
|
68
|
+
businessMetrics = new BusinessMetrics({}, {parent: webex});
|
|
69
|
+
sinon.stub(uuid, 'v4').returns('my-fake-id');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
afterEach(() => {
|
|
73
|
+
sinon.restore();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('#sendEvent', () => {
|
|
77
|
+
it('should send correctly shaped business event (check name building and internal tagged event building)', () => {
|
|
78
|
+
// For some reasons `jest` isn't available when testing form build server - so can't use `jest.fn()` here...
|
|
79
|
+
const requestCalls = [];
|
|
80
|
+
const request = function(arg) { requestCalls.push(arg) }
|
|
81
|
+
|
|
82
|
+
businessMetrics.clientMetricsBatcher.request = request;
|
|
83
|
+
|
|
84
|
+
assert.equal(requestCalls.length, 0)
|
|
85
|
+
businessMetrics.submitBusinessEvent({ name: "foobar", payload: {bar:"gee"} })
|
|
86
|
+
assert.equal(requestCalls.length, 1)
|
|
87
|
+
assert.deepEqual(requestCalls[0], {
|
|
88
|
+
eventPayload: {
|
|
89
|
+
context: {
|
|
90
|
+
app: {version: 'webex-version'},
|
|
91
|
+
device: {id: 'deviceId'},
|
|
92
|
+
locale: 'language',
|
|
93
|
+
os: {
|
|
94
|
+
name: getOSNameInternal(),
|
|
95
|
+
version: getOSVersion(),
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
key: 'foobar',
|
|
99
|
+
browserDetails: {
|
|
100
|
+
browser: getBrowserName(),
|
|
101
|
+
browserHeight: window.innerHeight,
|
|
102
|
+
browserVersion: getBrowserVersion(),
|
|
103
|
+
browserWidth: window.innerWidth,
|
|
104
|
+
domain: window.location.hostname,
|
|
105
|
+
inIframe: false,
|
|
106
|
+
locale: window.navigator.language,
|
|
107
|
+
os: getOSNameInternal(),
|
|
108
|
+
},
|
|
109
|
+
client_timestamp: requestCalls[0].eventPayload.client_timestamp, // This is to bypass time check, which is checked below.
|
|
110
|
+
value: {
|
|
111
|
+
bar: "gee"
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
type: ['business'],
|
|
115
|
+
});
|
|
116
|
+
assert.isNumber(requestCalls[0].eventPayload.client_timestamp)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -372,6 +372,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
372
372
|
{mediaAgentAlias: 'mediaAgentAlias', mediaAgentGroupId: 'mediaAgentGroupId'},
|
|
373
373
|
],
|
|
374
374
|
webexConferenceIdStr: 'webexConferenceIdStr',
|
|
375
|
+
sessionCorrelationId: 'sessionCorrelationId',
|
|
375
376
|
globalMeetingId: 'globalMeetingId',
|
|
376
377
|
meeting: {
|
|
377
378
|
...fakeMeeting,
|
|
@@ -386,6 +387,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
386
387
|
assert.deepEqual(res, {
|
|
387
388
|
correlationId: 'correlationId',
|
|
388
389
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
390
|
+
sessionCorrelationId: 'sessionCorrelationId',
|
|
389
391
|
globalMeetingId: 'globalMeetingId1',
|
|
390
392
|
deviceId: 'deviceUrl',
|
|
391
393
|
locusId: 'url',
|
|
@@ -608,6 +610,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
608
610
|
meeting: fakeMeeting,
|
|
609
611
|
mediaConnections: [{mediaAgentAlias: 'alias', mediaAgentGroupId: '1'}],
|
|
610
612
|
webexConferenceIdStr: undefined,
|
|
613
|
+
sessionCorrelationId: undefined,
|
|
611
614
|
globalMeetingId: undefined,
|
|
612
615
|
});
|
|
613
616
|
assert.notCalled(generateClientEventErrorPayloadSpy);
|
|
@@ -762,7 +765,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
762
765
|
]);
|
|
763
766
|
});
|
|
764
767
|
|
|
765
|
-
it('should submit client event successfully with correlationId, webexConferenceIdStr and globalMeetingId', () => {
|
|
768
|
+
it('should submit client event successfully with correlationId, webexConferenceIdStr, sessionCorrelationId, and globalMeetingId', () => {
|
|
766
769
|
const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
|
|
767
770
|
const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
|
|
768
771
|
const generateClientEventErrorPayloadSpy = sinon.spy(cd, 'generateClientEventErrorPayload');
|
|
@@ -773,6 +776,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
773
776
|
correlationId: 'correlationId',
|
|
774
777
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
775
778
|
globalMeetingId: 'globalMeetingId1',
|
|
779
|
+
sessionCorrelationId: 'sessionCorrelationId1'
|
|
776
780
|
};
|
|
777
781
|
|
|
778
782
|
cd.submitClientEvent({
|
|
@@ -784,6 +788,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
784
788
|
correlationId: 'correlationId',
|
|
785
789
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
786
790
|
globalMeetingId: 'globalMeetingId1',
|
|
791
|
+
sessionCorrelationId: 'sessionCorrelationId1',
|
|
787
792
|
preLoginId: undefined,
|
|
788
793
|
});
|
|
789
794
|
|
|
@@ -798,6 +803,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
798
803
|
identifiers: {
|
|
799
804
|
correlationId: 'correlationId',
|
|
800
805
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
806
|
+
sessionCorrelationId: 'sessionCorrelationId1',
|
|
801
807
|
globalMeetingId: 'globalMeetingId1',
|
|
802
808
|
deviceId: 'deviceUrl',
|
|
803
809
|
locusUrl: 'locus-url',
|
|
@@ -818,6 +824,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
818
824
|
identifiers: {
|
|
819
825
|
correlationId: 'correlationId',
|
|
820
826
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
827
|
+
sessionCorrelationId: 'sessionCorrelationId1',
|
|
821
828
|
globalMeetingId: 'globalMeetingId1',
|
|
822
829
|
deviceId: 'deviceUrl',
|
|
823
830
|
locusUrl: 'locus-url',
|
|
@@ -863,6 +870,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
863
870
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
864
871
|
globalMeetingId: 'globalMeetingId1',
|
|
865
872
|
preLoginId: 'myPreLoginId',
|
|
873
|
+
sessionCorrelationId: 'sessionCorrelationId1'
|
|
866
874
|
};
|
|
867
875
|
|
|
868
876
|
cd.submitClientEvent({
|
|
@@ -875,6 +883,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
875
883
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
876
884
|
globalMeetingId: 'globalMeetingId1',
|
|
877
885
|
preLoginId: 'myPreLoginId',
|
|
886
|
+
sessionCorrelationId: 'sessionCorrelationId1'
|
|
878
887
|
});
|
|
879
888
|
|
|
880
889
|
assert.notCalled(generateClientEventErrorPayloadSpy);
|
|
@@ -887,6 +896,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
887
896
|
},
|
|
888
897
|
identifiers: {
|
|
889
898
|
correlationId: 'correlationId',
|
|
899
|
+
sessionCorrelationId: 'sessionCorrelationId1',
|
|
890
900
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
891
901
|
globalMeetingId: 'globalMeetingId1',
|
|
892
902
|
deviceId: 'deviceUrl',
|
|
@@ -913,6 +923,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
913
923
|
canProceed: true,
|
|
914
924
|
identifiers: {
|
|
915
925
|
correlationId: 'correlationId',
|
|
926
|
+
sessionCorrelationId: 'sessionCorrelationId1',
|
|
916
927
|
userId: 'myPreLoginId',
|
|
917
928
|
deviceId: 'deviceUrl',
|
|
918
929
|
orgId: 'orgId',
|
|
@@ -1417,6 +1428,7 @@ describe('internal-plugin-metrics', () => {
|
|
|
1417
1428
|
meetingId: fakeMeeting.id,
|
|
1418
1429
|
webexConferenceIdStr: 'webexConferenceIdStr1',
|
|
1419
1430
|
globalMeetingId: 'globalMeetingId1',
|
|
1431
|
+
sessionCorrelationId: 'sessionCorrelationId1'
|
|
1420
1432
|
};
|
|
1421
1433
|
|
|
1422
1434
|
cd.submitMQE({
|
|
@@ -235,6 +235,8 @@ describe('internal-plugin-metrics', () => {
|
|
|
235
235
|
});
|
|
236
236
|
|
|
237
237
|
describe('getBuildType', () => {
|
|
238
|
+
const webex = {internal: {metrics: {config: {}}}};
|
|
239
|
+
|
|
238
240
|
beforeEach(() => {
|
|
239
241
|
process.env.NODE_ENV = 'production';
|
|
240
242
|
});
|
|
@@ -246,18 +248,26 @@ describe('internal-plugin-metrics', () => {
|
|
|
246
248
|
['https://web.webex.com', true, 'test'],
|
|
247
249
|
].forEach(([webClientDomain, markAsTestEvent, expected]) => {
|
|
248
250
|
it(`returns expected result for ${webClientDomain}`, () => {
|
|
249
|
-
assert.deepEqual(getBuildType(webClientDomain, markAsTestEvent as any), expected);
|
|
251
|
+
assert.deepEqual(getBuildType(webex, webClientDomain, markAsTestEvent as any), expected);
|
|
250
252
|
});
|
|
251
253
|
});
|
|
252
254
|
|
|
253
255
|
it('returns "test" for NODE_ENV "foo"', () => {
|
|
254
256
|
process.env.NODE_ENV = 'foo';
|
|
255
|
-
assert.deepEqual(getBuildType('production'), 'test');
|
|
257
|
+
assert.deepEqual(getBuildType(webex, 'production'), 'test');
|
|
256
258
|
});
|
|
257
259
|
|
|
258
260
|
it('returns "test" for NODE_ENV "production" and markAsTestEvent = true', () => {
|
|
259
261
|
process.env.NODE_ENV = 'production';
|
|
260
|
-
assert.deepEqual(getBuildType('my.domain', true), 'test');
|
|
262
|
+
assert.deepEqual(getBuildType(webex, 'my.domain', true), 'test');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('returns "test" for NODE_ENV "production" when webex.caBuildType = "test"', () => {
|
|
266
|
+
process.env.NODE_ENV = 'production';
|
|
267
|
+
assert.deepEqual(
|
|
268
|
+
getBuildType({internal: {metrics: {config: {caBuildType: 'test'}}}}, 'my.domain'),
|
|
269
|
+
'test'
|
|
270
|
+
);
|
|
261
271
|
});
|
|
262
272
|
});
|
|
263
273
|
|
|
@@ -418,8 +428,8 @@ describe('internal-plugin-metrics', () => {
|
|
|
418
428
|
name: 'client.exit.app',
|
|
419
429
|
eventData: {
|
|
420
430
|
markAsTestEvent: true,
|
|
421
|
-
webClientDomain: 'https://web.webex.com'
|
|
422
|
-
}
|
|
431
|
+
webClientDomain: 'https://web.webex.com',
|
|
432
|
+
},
|
|
423
433
|
},
|
|
424
434
|
},
|
|
425
435
|
type: ['diagnostic-event'],
|
|
@@ -73,6 +73,20 @@ describe('internal-plugin-metrics', () => {
|
|
|
73
73
|
sinon.restore();
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
+
it('lazy metrics backend initialization when checking if backend ready', () => {
|
|
77
|
+
assert.isUndefined(webex.internal.newMetrics.behavioralMetrics);
|
|
78
|
+
webex.internal.newMetrics.isReadyToSubmitBehavioralEvents();
|
|
79
|
+
assert.isDefined(webex.internal.newMetrics.behavioralMetrics);
|
|
80
|
+
|
|
81
|
+
assert.isUndefined(webex.internal.newMetrics.operationalMetrics);
|
|
82
|
+
webex.internal.newMetrics.isReadyToSubmitOperationalEvents();
|
|
83
|
+
assert.isDefined(webex.internal.newMetrics.operationalMetrics);
|
|
84
|
+
|
|
85
|
+
assert.isUndefined(webex.internal.newMetrics.businessMetrics)
|
|
86
|
+
webex.internal.newMetrics.isReadyToSubmitBusinessEvents();
|
|
87
|
+
assert.isDefined(webex.internal.newMetrics.businessMetrics);
|
|
88
|
+
})
|
|
89
|
+
|
|
76
90
|
it('submits Client Event successfully', () => {
|
|
77
91
|
webex.internal.newMetrics.submitClientEvent({
|
|
78
92
|
name: 'client.alert.displayed',
|