@webex/internal-plugin-metrics 3.7.0-next.1 → 3.7.0-next.11

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 (32) hide show
  1. package/dist/business-metrics.js +74 -100
  2. package/dist/business-metrics.js.map +1 -1
  3. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +5 -1
  4. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  5. package/dist/call-diagnostic/call-diagnostic-metrics.js +9 -2
  6. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  7. package/dist/call-diagnostic/config.js +17 -11
  8. package/dist/call-diagnostic/config.js.map +1 -1
  9. package/dist/generic-metrics.js +2 -2
  10. package/dist/generic-metrics.js.map +1 -1
  11. package/dist/metrics.js +1 -1
  12. package/dist/metrics.types.js.map +1 -1
  13. package/dist/new-metrics.js +6 -4
  14. package/dist/new-metrics.js.map +1 -1
  15. package/dist/types/business-metrics.d.ts +10 -28
  16. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +4 -0
  17. package/dist/types/call-diagnostic/config.d.ts +2 -0
  18. package/dist/types/generic-metrics.d.ts +2 -2
  19. package/dist/types/metrics.types.d.ts +3 -0
  20. package/dist/types/new-metrics.d.ts +4 -3
  21. package/package.json +12 -12
  22. package/src/business-metrics.ts +66 -76
  23. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +6 -1
  24. package/src/call-diagnostic/call-diagnostic-metrics.ts +10 -2
  25. package/src/call-diagnostic/config.ts +7 -0
  26. package/src/generic-metrics.ts +2 -2
  27. package/src/metrics.types.ts +3 -0
  28. package/src/new-metrics.ts +5 -3
  29. package/test/unit/spec/business/business-metrics.ts +2 -2
  30. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +12 -0
  31. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +60 -2
  32. package/test/unit/spec/new-metrics.ts +2 -0
@@ -17,7 +17,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
17
17
  */
18
18
  constructor(...args: any[]);
19
19
  /**
20
- * Submit a buisness metric to our metrics endpoint.
20
+ * Submit a business metric to our metrics endpoint.
21
21
  * @param {string} kind of metric for logging
22
22
  * @param {string} name of the metric
23
23
  * @param {object} event
@@ -44,7 +44,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
44
44
  */
45
45
  protected getBrowserDetails(): object;
46
46
  /**
47
- * Returns true once we have the deviceId we need to submit behavioral/operational/buisness events
47
+ * Returns true once we have the deviceId we need to submit behavioral/operational/business events
48
48
  * @returns {boolean}
49
49
  */
50
50
  isReadyToSubmitEvents(): boolean;
@@ -11,6 +11,7 @@ export type MetricEventProduct = 'webex' | 'wxcc_desktop';
11
11
  export type MetricEventAgent = 'user' | 'browser' | 'system' | 'sdk' | 'redux' | 'service' | 'api';
12
12
  export type MetricEventVerb = 'abort' | 'accept' | 'activate' | 'apply' | 'answer' | 'authorize' | 'build' | 'cancel' | 'change' | 'click' | 'close' | 'complete' | 'connect' | 'create' | 'deactivate' | 'decrypt' | 'delete' | 'deliver' | 'destroy' | 'disable' | 'disconnect' | 'dismiss' | 'display' | 'download' | 'edit' | 'enable' | 'encrypt' | 'end' | 'expire' | 'fail' | 'fetch' | 'fire' | 'generate' | 'get' | 'hide' | 'hover' | 'ignore' | 'initialize' | 'initiate' | 'invalidate' | 'join' | 'list' | 'load' | 'login' | 'logout' | 'notify' | 'offer' | 'open' | 'press' | 'receive' | 'refer' | 'refresh' | 'register' | 'release' | 'reload' | 'reject' | 'request' | 'reset' | 'resize' | 'respond' | 'retry' | 'revoke' | 'save' | 'search' | 'select' | 'send' | 'set' | 'sign' | 'start' | 'submit' | 'switch' | 'sync' | 'toggle' | 'transfer' | 'unregister' | 'update' | 'upload' | 'use' | 'validate' | 'view' | 'visit' | 'wait' | 'warn' | 'exit';
13
13
  export type MetricEventJoinFlowVersion = 'Other' | 'NewFTE';
14
+ export type MetricEventMeetingJoinPhase = 'pre-join' | 'join' | 'in-meeting';
14
15
  export type SubmitClientEventOptions = {
15
16
  meetingId?: string;
16
17
  mediaConnections?: any[];
@@ -25,6 +26,8 @@ export type SubmitClientEventOptions = {
25
26
  webexConferenceIdStr?: string;
26
27
  globalMeetingId?: string;
27
28
  joinFlowVersion?: MetricEventJoinFlowVersion;
29
+ meetingJoinPhase?: MetricEventMeetingJoinPhase;
30
+ triggeredTime?: string;
28
31
  };
29
32
  export type SubmitMQEOptions = {
30
33
  meetingId: string;
@@ -60,7 +60,7 @@ declare class Metrics extends WebexPlugin {
60
60
  */
61
61
  isReadyToSubmitOperationalEvents(): boolean;
62
62
  /**
63
- * @returns true once we have the deviceId we need to submit buisness events
63
+ * @returns true once we have the deviceId we need to submit business events
64
64
  */
65
65
  isReadyToSubmitBusinessEvents(): boolean;
66
66
  /**
@@ -83,13 +83,14 @@ declare class Metrics extends WebexPlugin {
83
83
  payload?: EventPayload;
84
84
  }): void | Promise<void>;
85
85
  /**
86
- * Buisness event
86
+ * Business event
87
87
  * @param args
88
88
  */
89
- submitBusinessEvent({ name, payload, table, }: {
89
+ submitBusinessEvent({ name, payload, table, metadata, }: {
90
90
  name: string;
91
91
  payload: EventPayload;
92
92
  table?: Table;
93
+ metadata?: EventPayload;
93
94
  }): Promise<void>;
94
95
  /**
95
96
  * Call Analyzer: Media Quality Event
package/package.json CHANGED
@@ -26,22 +26,22 @@
26
26
  "@webex/eslint-config-legacy": "0.0.0",
27
27
  "@webex/jest-config-legacy": "0.0.0",
28
28
  "@webex/legacy-tools": "0.0.0",
29
- "@webex/test-helper-chai": "3.7.0-next.1",
30
- "@webex/test-helper-mocha": "3.7.0-next.1",
31
- "@webex/test-helper-mock-webex": "3.7.0-next.1",
32
- "@webex/test-helper-test-users": "3.7.0-next.1",
29
+ "@webex/test-helper-chai": "3.7.0-next.11",
30
+ "@webex/test-helper-mocha": "3.7.0-next.11",
31
+ "@webex/test-helper-mock-webex": "3.7.0-next.11",
32
+ "@webex/test-helper-test-users": "3.7.0-next.11",
33
33
  "eslint": "^8.24.0",
34
34
  "prettier": "^2.7.1",
35
35
  "sinon": "^9.2.4"
36
36
  },
37
37
  "dependencies": {
38
- "@webex/common": "3.7.0-next.1",
39
- "@webex/common-timers": "3.7.0-next.1",
40
- "@webex/event-dictionary-ts": "^1.0.1594",
41
- "@webex/internal-plugin-metrics": "3.7.0-next.1",
42
- "@webex/test-helper-chai": "3.7.0-next.1",
43
- "@webex/test-helper-mock-webex": "3.7.0-next.1",
44
- "@webex/webex-core": "3.7.0-next.1",
38
+ "@webex/common": "3.7.0-next.11",
39
+ "@webex/common-timers": "3.7.0-next.11",
40
+ "@webex/event-dictionary-ts": "^1.0.1643",
41
+ "@webex/internal-plugin-metrics": "3.7.0-next.11",
42
+ "@webex/test-helper-chai": "3.7.0-next.11",
43
+ "@webex/test-helper-mock-webex": "3.7.0-next.11",
44
+ "@webex/webex-core": "3.7.0-next.11",
45
45
  "ip-anonymize": "^0.1.0",
46
46
  "lodash": "^4.17.21",
47
47
  "uuid": "^3.3.2"
@@ -54,5 +54,5 @@
54
54
  "test:style": "eslint ./src/**/*.*",
55
55
  "test:unit": "webex-legacy-tools test --unit --runner mocha"
56
56
  },
57
- "version": "3.7.0-next.1"
57
+ "version": "3.7.0-next.11"
58
58
  }
@@ -2,121 +2,111 @@ import GenericMetrics from './generic-metrics';
2
2
  import {EventPayload, Table} from './metrics.types';
3
3
 
4
4
  /**
5
- * @description Util class to handle Buisness Metrics
5
+ * @description Util class to handle Business Metrics
6
6
  * @export
7
7
  * @class BusinessMetrics
8
8
  */
9
9
  export default class BusinessMetrics extends GenericMetrics {
10
10
  /**
11
- * unfortunately, the pinot team does not allow changes to the schema of wbxapp_callend_metrics
12
- * so we have to shim this layer specifically for this
13
- * https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table+wbxapp_callend_metrics
14
- * @param {EventPayload} payload payload of the metric
15
- * @returns {Promise<any>}
16
- */
17
- private submitCallEndEvent({payload}: {payload: EventPayload}) {
18
- const event = {
19
- type: ['business'],
20
- eventPayload: {
21
- key: 'callEnd',
22
- client_timestamp: new Date().toISOString(),
23
- appType: 'Web Client',
24
- value: {
25
- ...payload,
26
- },
27
- },
28
- };
29
-
30
- return this.submitEvent({
31
- kind: 'buisness-events:wbxapp_callend_metrics -> ',
32
- name: 'wbxapp_callend_metrics',
33
- event,
34
- });
35
- }
36
-
37
- /**
38
- * Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
39
- * all event payload keys are converted into a hex string value
40
- * unfortunately, the pinot team does not allow changes to the schema of business_metrics
41
- * so we have to shim this layer specifically for this
42
- * https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table%3A+business_metrics
11
+ * Build the metric event to submit.
43
12
  * @param {string} name of the metric
44
- * @param {EventPayload} payload payload of the metric
45
- * @returns {Promise<any>}
46
- */
47
- private submitBusinessMetricsEvent({name, payload}: {name: string; payload: EventPayload}) {
48
- const event = {
49
- type: ['business'],
50
- eventPayload: {
51
- key: name,
52
- client_timestamp: new Date().toISOString(),
53
- appType: 'Web Client',
54
- value: {
55
- ...this.getContext(),
56
- ...this.getBrowserDetails(),
57
- ...payload,
58
- },
59
- },
60
- };
61
-
62
- return this.submitEvent({kind: 'buisness-events:business_metrics -> ', name, event});
63
- }
64
-
65
- /**
66
- * Submit a buisness metric to our metrics endpoint, going to the default business_ucf table
67
- * all event payload keys are converted into a hex string value
68
- * https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
69
- * @param {string} name of the metric
70
- * @param {EventPayload} user payload of the metric
71
- * @returns {Promise<any>}
13
+ * @param {EventPayload} payload user payload of the metric
14
+ * @param {EventPayload} metadata to include outside of eventPayload.value
15
+ * @returns {MetricEvent} The constructed metric event
72
16
  */
73
- private submitDefaultEvent({name, payload}: {name: string; payload: EventPayload}) {
74
- const event = {
17
+ private buildEvent({name, payload, metadata}: {name: string; payload: object; metadata: object}) {
18
+ return {
75
19
  type: ['business'],
76
20
  eventPayload: {
77
21
  key: name,
78
- appType: 'Web Client',
79
22
  client_timestamp: new Date().toISOString(),
80
- context: this.getContext(),
81
- browserDetails: this.getBrowserDetails(),
23
+ ...metadata,
82
24
  value: payload,
83
25
  },
84
26
  };
85
-
86
- return this.submitEvent({kind: 'buisness-events:default -> ', name, event});
87
27
  }
88
28
 
89
29
  /**
90
- * Submit a buisness metric to our metrics endpoint.
30
+ * Submit a business metric to our metrics endpoint.
91
31
  * routes to the correct table with the correct schema payload by table
92
32
  * https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
93
33
  * @param {string} name of the metric, ignored if going to wbxapp_callend_metrics
94
34
  * @param {EventPayload} payload user payload of the metric
95
35
  * @param {Table} table optional - to submit the metric to and adapt the sent schema
36
+ * @param {EventPayload} metadata optional - to include outside of eventPayload.value
96
37
  * @returns {Promise<any>}
97
38
  */
98
39
  public submitBusinessEvent({
99
40
  name,
100
41
  payload,
101
42
  table,
43
+ metadata,
102
44
  }: {
103
45
  name: string;
104
46
  payload: EventPayload;
105
47
  table?: Table;
48
+ metadata?: EventPayload;
106
49
  }): Promise<void> {
107
50
  if (!table) {
108
51
  table = 'default';
109
52
  }
53
+ if (!metadata) {
54
+ metadata = {};
55
+ }
56
+ if (!metadata.appType) {
57
+ metadata.appType = 'Web Client';
58
+ }
110
59
  switch (table) {
111
- case 'wbxapp_callend_metrics':
112
- return this.submitCallEndEvent({payload});
113
- case 'business_metrics':
114
- return this.submitBusinessMetricsEvent({name, payload});
60
+ case 'wbxapp_callend_metrics': {
61
+ // https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table+wbxapp_callend_metrics
62
+ const callEndEvent = this.buildEvent({name: 'callEnd', payload, metadata});
63
+
64
+ return this.submitEvent({
65
+ kind: 'business-events:wbxapp_callend_metrics -> ',
66
+ name: 'wbxapp_callend_metrics',
67
+ event: callEndEvent,
68
+ });
69
+ }
70
+
71
+ case 'business_metrics': {
72
+ // all event payload keys are converted into a hex string value
73
+ // unfortunately, the pinot team does not allow changes to the schema of business_metrics
74
+ // so we have to shim this layer specifically for this
75
+ // https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Table%3A+business_metrics
76
+ const businessEvent = this.buildEvent({
77
+ name,
78
+ payload: {
79
+ ...this.getContext(),
80
+ ...this.getBrowserDetails(),
81
+ ...payload,
82
+ },
83
+ metadata,
84
+ });
85
+
86
+ return this.submitEvent({
87
+ kind: 'business-events:business_metrics -> ',
88
+ name,
89
+ event: businessEvent,
90
+ });
91
+ }
92
+
115
93
  case 'business_ucf':
116
- return this.submitDefaultEvent({name, payload});
117
94
  case 'default':
118
- default:
119
- return this.submitDefaultEvent({name, payload});
95
+ default: {
96
+ // all event payload keys are converted into a hex string value
97
+ // https://confluence-eng-gpk2.cisco.com/conf/display/WAP/Business+metrics++-%3E+ROMA
98
+ const defaultEvent = this.buildEvent({
99
+ name,
100
+ payload,
101
+ metadata: {
102
+ context: this.getContext(),
103
+ browserDetails: this.getBrowserDetails(),
104
+ ...metadata,
105
+ },
106
+ });
107
+
108
+ return this.submitEvent({kind: 'business-events:default -> ', name, event: defaultEvent});
109
+ }
120
110
  }
121
111
  }
122
112
  }
@@ -83,11 +83,16 @@ export default class CallDiagnosticLatencies extends WebexPlugin {
83
83
  key === 'client.media.rx.start' ||
84
84
  key === 'client.media.tx.start' ||
85
85
  key === 'internal.client.meetinginfo.request' ||
86
- key === 'internal.client.meetinginfo.response'
86
+ key === 'internal.client.meetinginfo.response' ||
87
+ key === 'client.media-engine.remote-sdp-received'
87
88
  ) {
88
89
  this.saveFirstTimestampOnly(key, value);
89
90
  } else {
90
91
  this.latencyTimestamps.set(key, value);
92
+ // new offer/answer so reset the remote SDP timestamp
93
+ if (key === 'client.media-engine.local-sdp-generated') {
94
+ this.latencyTimestamps.delete('client.media-engine.remote-sdp-received');
95
+ }
91
96
  }
92
97
  }
93
98
 
@@ -377,7 +377,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
377
377
  * @returns
378
378
  */
379
379
  prepareDiagnosticEvent(eventData: Event['event'], options: any) {
380
- const {meetingId} = options;
380
+ const {meetingId, triggeredTime} = options;
381
381
  const origin = this.getOrigin(options, meetingId);
382
382
 
383
383
  const event: Event = {
@@ -385,7 +385,7 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
385
385
  version: 1,
386
386
  origin,
387
387
  originTime: {
388
- triggered: new Date().toISOString(),
388
+ triggered: triggeredTime || new Date().toISOString(),
389
389
  // is overridden in prepareRequest batcher
390
390
  sent: 'not_defined_yet',
391
391
  },
@@ -723,6 +723,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
723
723
  clientEventObject.joinFlowVersion = joinFlowVersion;
724
724
  }
725
725
 
726
+ if (options.meetingJoinPhase) {
727
+ clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
728
+ }
729
+
726
730
  return clientEventObject;
727
731
  }
728
732
 
@@ -770,6 +774,10 @@ export default class CallDiagnosticMetrics extends StatelessWebexPlugin {
770
774
  clientEventObject.joinFlowVersion = options.joinFlowVersion;
771
775
  }
772
776
 
777
+ if (options.meetingJoinPhase) {
778
+ clientEventObject.meetingJoinPhase = options.meetingJoinPhase;
779
+ }
780
+
773
781
  return clientEventObject;
774
782
  }
775
783
 
@@ -17,6 +17,7 @@ export const DTLS_HANDSHAKE_FAILED_CLIENT_CODE = 2008;
17
17
  export const ICE_FAILED_WITH_TURN_TLS_CLIENT_CODE = 2010;
18
18
  export const ICE_FAILED_WITHOUT_TURN_TLS_CLIENT_CODE = 2009;
19
19
  export const ICE_AND_REACHABILITY_FAILED_CLIENT_CODE = 2011;
20
+ export const MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE = 2012;
20
21
  export const WBX_APP_API_URL = 'wbxappapi'; // MeetingInfo WebexAppApi response object normally contains a body.url that includes the string 'wbxappapi'
21
22
 
22
23
  export const WEBEX_SUB_SERVICE_TYPES: Record<string, ClientSubServiceType> = {
@@ -127,6 +128,7 @@ export const ERROR_DESCRIPTIONS = {
127
128
  ICE_FAILED_WITHOUT_TURN_TLS: 'ICEFailedWithoutTURN_TLS',
128
129
  ICE_FAILED_WITH_TURN_TLS: 'ICEFailedWithTURN_TLS',
129
130
  ICE_AND_REACHABILITY_FAILED: 'ICEAndReachabilityFailed',
131
+ MULTISTREAM_NOT_AVAILABLE: 'MultistreamNotAvailable',
130
132
  SDP_OFFER_CREATION_ERROR: 'SdpOfferCreationError',
131
133
  SDP_OFFER_CREATION_ERROR_MISSING_CODEC: 'SdpOfferCreationErrorMissingCodec',
132
134
  WDM_RESTRICTED_REGION: 'WdmRestrictedRegion',
@@ -409,6 +411,11 @@ export const CLIENT_ERROR_CODE_TO_ERROR_PAYLOAD: Record<number, Partial<ClientEv
409
411
  category: 'expected',
410
412
  fatal: true,
411
413
  },
414
+ [MULTISTREAM_NOT_AVAILABLE_CLIENT_CODE]: {
415
+ errorDescription: ERROR_DESCRIPTIONS.MULTISTREAM_NOT_AVAILABLE,
416
+ category: 'expected',
417
+ fatal: false,
418
+ },
412
419
  2050: {
413
420
  errorDescription: ERROR_DESCRIPTIONS.SDP_OFFER_CREATION_ERROR,
414
421
  category: 'media',
@@ -37,7 +37,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
37
37
  }
38
38
 
39
39
  /**
40
- * Submit a buisness metric to our metrics endpoint.
40
+ * Submit a business metric to our metrics endpoint.
41
41
  * @param {string} kind of metric for logging
42
42
  * @param {string} name of the metric
43
43
  * @param {object} event
@@ -105,7 +105,7 @@ export default abstract class GenericMetrics extends StatelessWebexPlugin {
105
105
  }
106
106
 
107
107
  /**
108
- * Returns true once we have the deviceId we need to submit behavioral/operational/buisness events
108
+ * Returns true once we have the deviceId we need to submit behavioral/operational/business events
109
109
  * @returns {boolean}
110
110
  */
111
111
  public isReadyToSubmitEvents(): boolean {
@@ -111,6 +111,7 @@ export type MetricEventVerb =
111
111
  | 'exit';
112
112
 
113
113
  export type MetricEventJoinFlowVersion = 'Other' | 'NewFTE';
114
+ export type MetricEventMeetingJoinPhase = 'pre-join' | 'join' | 'in-meeting';
114
115
 
115
116
  export type SubmitClientEventOptions = {
116
117
  meetingId?: string;
@@ -126,6 +127,8 @@ export type SubmitClientEventOptions = {
126
127
  webexConferenceIdStr?: string;
127
128
  globalMeetingId?: string;
128
129
  joinFlowVersion?: MetricEventJoinFlowVersion;
130
+ meetingJoinPhase?: MetricEventMeetingJoinPhase;
131
+ triggeredTime?: string;
129
132
  };
130
133
 
131
134
  export type SubmitMQEOptions = {
@@ -141,7 +141,7 @@ class Metrics extends WebexPlugin {
141
141
  }
142
142
 
143
143
  /**
144
- * @returns true once we have the deviceId we need to submit buisness events
144
+ * @returns true once we have the deviceId we need to submit business events
145
145
  */
146
146
  isReadyToSubmitBusinessEvents() {
147
147
  this.lazyBuildBusinessMetrics();
@@ -200,17 +200,19 @@ class Metrics extends WebexPlugin {
200
200
  }
201
201
 
202
202
  /**
203
- * Buisness event
203
+ * Business event
204
204
  * @param args
205
205
  */
206
206
  submitBusinessEvent({
207
207
  name,
208
208
  payload,
209
209
  table,
210
+ metadata,
210
211
  }: {
211
212
  name: string;
212
213
  payload: EventPayload;
213
214
  table?: Table;
215
+ metadata?: EventPayload;
214
216
  }) {
215
217
  if (!this.isReady) {
216
218
  // @ts-ignore
@@ -223,7 +225,7 @@ class Metrics extends WebexPlugin {
223
225
 
224
226
  this.lazyBuildBusinessMetrics();
225
227
 
226
- return this.businessMetrics.submitBusinessEvent({name, payload, table});
228
+ return this.businessMetrics.submitBusinessEvent({name, payload, table, metadata});
227
229
  }
228
230
 
229
231
  /**
@@ -154,11 +154,12 @@ describe('internal-plugin-metrics', () => {
154
154
  businessMetrics.clientMetricsBatcher.request = request;
155
155
 
156
156
  assert.equal(requestCalls.length, 0)
157
- businessMetrics.submitBusinessEvent({ name: "foobar", payload: {bar:"gee"}, table: 'business_metrics' })
157
+ businessMetrics.submitBusinessEvent({ name: "foobar", payload: {bar: "gee"}, table: 'business_metrics', metadata: {asdf: 'hjkl'} })
158
158
  assert.equal(requestCalls.length, 1)
159
159
  assert.deepEqual(requestCalls[0], {
160
160
  eventPayload: {
161
161
  key: 'foobar',
162
+ asdf: 'hjkl',
162
163
  appType: 'Web Client',
163
164
  client_timestamp: requestCalls[0].eventPayload.client_timestamp, // This is to bypass time check, which is checked below.
164
165
  value: {
@@ -173,7 +174,6 @@ describe('internal-plugin-metrics', () => {
173
174
  os: getOSNameInternal(),
174
175
  app: {version: 'webex-version'},
175
176
  device: {id: 'deviceId'},
176
- locale: 'language',
177
177
  }
178
178
  },
179
179
  type: ['business'],
@@ -283,6 +283,18 @@ describe('internal-plugin-metrics', () => {
283
283
  cdl.saveTimestamp({key: 'internal.client.meetinginfo.response', value: 20});
284
284
  assert.deepEqual(saveFirstTimestamp.callCount, 1);
285
285
  });
286
+
287
+ it('calls saveFirstTimestamp for remote SDP received', () => {
288
+ const saveFirstTimestamp = sinon.stub(cdl, 'saveFirstTimestampOnly');
289
+ cdl.saveTimestamp({key: 'client.media-engine.remote-sdp-received', value: 10});
290
+ assert.deepEqual(saveFirstTimestamp.callCount, 1);
291
+ });
292
+
293
+ it('clears timestamp for remote SDP received when local SDP generated', () => {
294
+ cdl.saveTimestamp({key: 'client.media-engine.remote-sdp-received', value: 10});
295
+ cdl.saveTimestamp({key: 'client.media-engine.local-sdp-generated', value: 20});
296
+ assert.isUndefined(cdl.latencyTimestamps.get('client.media-engine.remote-sdp-received'));
297
+ });
286
298
  });
287
299
 
288
300
  it('calculates getShowInterstitialTime correctly', () => {
@@ -745,6 +745,52 @@ describe('internal-plugin-metrics', () => {
745
745
  });
746
746
  });
747
747
 
748
+ it('should prepare diagnostic event successfully when triggeredTime is supplied in the options object', () => {
749
+ const options = {meetingId: fakeMeeting.id, triggeredTime: 'fake-triggered-time'};
750
+ const getOriginStub = sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
751
+ const clearEmptyKeysRecursivelyStub = sinon.stub(
752
+ CallDiagnosticUtils,
753
+ 'clearEmptyKeysRecursively'
754
+ );
755
+
756
+ const res = cd.prepareDiagnosticEvent(
757
+ {
758
+ canProceed: false,
759
+ identifiers: {
760
+ correlationId: 'id',
761
+ webexConferenceIdStr: 'webexConferenceIdStr1',
762
+ globalMeetingId: 'globalMeetingId1',
763
+ },
764
+ name: 'client.alert.displayed',
765
+ },
766
+ options
767
+ );
768
+
769
+ assert.calledWith(getOriginStub, options, options.meetingId);
770
+ assert.calledOnce(clearEmptyKeysRecursivelyStub);
771
+ assert.deepEqual(res, {
772
+ event: {
773
+ canProceed: false,
774
+ identifiers: {
775
+ correlationId: 'id',
776
+ webexConferenceIdStr: 'webexConferenceIdStr1',
777
+ globalMeetingId: 'globalMeetingId1',
778
+ },
779
+ name: 'client.alert.displayed',
780
+ },
781
+ eventId: 'my-fake-id',
782
+ origin: {
783
+ origin: 'fake-origin',
784
+ },
785
+ originTime: {
786
+ sent: 'not_defined_yet',
787
+ triggered: 'fake-triggered-time',
788
+ },
789
+ senderCountryCode: 'UK',
790
+ version: 1,
791
+ });
792
+ });
793
+
748
794
  describe('#submitClientEvent', () => {
749
795
  it('should submit client event successfully with meetingId', () => {
750
796
  const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
@@ -2759,11 +2805,12 @@ describe('internal-plugin-metrics', () => {
2759
2805
  });
2760
2806
  });
2761
2807
 
2762
- it('includes expected joinFlowVersion from options when in-meeting', async () => {
2808
+ it('includes expected joinFlowVersion and meetingJoinPhase from options when in-meeting', async () => {
2763
2809
  // meetingId means in-meeting
2764
2810
  const options = {
2765
2811
  meetingId: fakeMeeting.id,
2766
2812
  joinFlowVersion: 'NewFTE',
2813
+ meetingJoinPhase: 'join',
2767
2814
  };
2768
2815
 
2769
2816
  const triggered = new Date();
@@ -2777,6 +2824,11 @@ describe('internal-plugin-metrics', () => {
2777
2824
  fetchOptions.body.metrics[0].eventPayload.event.joinFlowVersion,
2778
2825
  options.joinFlowVersion
2779
2826
  );
2827
+
2828
+ assert.equal(
2829
+ fetchOptions.body.metrics[0].eventPayload.event.meetingJoinPhase,
2830
+ options.meetingJoinPhase
2831
+ );
2780
2832
  });
2781
2833
 
2782
2834
  it('includes expected joinFlowVersion from meeting callStateForMetrics when in-meeting', async () => {
@@ -2815,12 +2867,13 @@ describe('internal-plugin-metrics', () => {
2815
2867
  );
2816
2868
  });
2817
2869
 
2818
- it('includes expected joinFlowVersion from options during prejoin', async () => {
2870
+ it('includes expected joinFlowVersion and meetingJoinPhase from options during prejoin', async () => {
2819
2871
  // correlationId and no meeting id means prejoin
2820
2872
  const options = {
2821
2873
  correlationId: 'myCorrelationId',
2822
2874
  preLoginId: 'myPreLoginId',
2823
2875
  joinFlowVersion: 'NewFTE',
2876
+ meetingJoinPhase: 'pre-join',
2824
2877
  };
2825
2878
 
2826
2879
  const triggered = new Date();
@@ -2834,6 +2887,11 @@ describe('internal-plugin-metrics', () => {
2834
2887
  fetchOptions.body.metrics[0].eventPayload.event.joinFlowVersion,
2835
2888
  options.joinFlowVersion
2836
2889
  );
2890
+
2891
+ assert.equal(
2892
+ fetchOptions.body.metrics[0].eventPayload.event.meetingJoinPhase,
2893
+ options.meetingJoinPhase
2894
+ );
2837
2895
  });
2838
2896
  });
2839
2897
 
@@ -93,12 +93,14 @@ describe('internal-plugin-metrics', () => {
93
93
  name: 'foobar',
94
94
  payload: {},
95
95
  table: 'test',
96
+ metadata: { foo: 'bar' },
96
97
  });
97
98
 
98
99
  assert.calledWith(webex.internal.newMetrics.businessMetrics.submitBusinessEvent, {
99
100
  name: 'foobar',
100
101
  payload: {},
101
102
  table: 'test',
103
+ metadata: { foo: 'bar' },
102
104
  });
103
105
  });
104
106