@webex/plugin-meetings 3.0.0-beta.364 → 3.0.0-beta.365

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.
@@ -209,7 +209,7 @@ var Breakout = _webexCore.WebexPlugin.extend({
209
209
  sessionId: this.sessionId
210
210
  });
211
211
  },
212
- version: "3.0.0-beta.364"
212
+ version: "3.0.0-beta.365"
213
213
  });
214
214
  var _default = Breakout;
215
215
  exports.default = _default;
@@ -1041,7 +1041,7 @@ var Breakouts = _webexCore.WebexPlugin.extend({
1041
1041
  this.trigger(_constants.BREAKOUTS.EVENTS.ASK_RETURN_TO_MAIN);
1042
1042
  }
1043
1043
  },
1044
- version: "3.0.0-beta.364"
1044
+ version: "3.0.0-beta.365"
1045
1045
  });
1046
1046
  var _default = Breakouts;
1047
1047
  exports.default = _default;
@@ -359,7 +359,7 @@ var SimultaneousInterpretation = _webexCore.WebexPlugin.extend({
359
359
  throw error;
360
360
  });
361
361
  },
362
- version: "3.0.0-beta.364"
362
+ version: "3.0.0-beta.365"
363
363
  });
364
364
  var _default = SimultaneousInterpretation;
365
365
  exports.default = _default;
@@ -18,7 +18,7 @@ var SILanguage = _webexCore.WebexPlugin.extend({
18
18
  languageCode: 'number',
19
19
  languageName: 'string'
20
20
  },
21
- version: "3.0.0-beta.364"
21
+ version: "3.0.0-beta.365"
22
22
  });
23
23
  var _default = SILanguage;
24
24
  exports.default = _default;
@@ -11,8 +11,21 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/he
11
11
  var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
13
13
  var _internalPluginMetrics = require("@webex/internal-plugin-metrics");
14
+ var _uuid = _interopRequireDefault(require("uuid"));
14
15
  var _constants = _interopRequireDefault(require("./constants"));
15
16
  /* eslint-disable class-methods-use-this */
17
+
18
+ var parseJsonPayload = function parseJsonPayload(payload) {
19
+ try {
20
+ if (payload && payload[0]) {
21
+ return JSON.parse(payload[0]);
22
+ }
23
+ return null;
24
+ } catch (_) {
25
+ return null;
26
+ }
27
+ };
28
+
16
29
  /**
17
30
  * Rtc Metrics
18
31
  */
@@ -35,11 +48,13 @@ var RtcMetrics = /*#__PURE__*/function () {
35
48
  (0, _defineProperty2.default)(this, "webex", void 0);
36
49
  (0, _defineProperty2.default)(this, "meetingId", void 0);
37
50
  (0, _defineProperty2.default)(this, "correlationId", void 0);
51
+ (0, _defineProperty2.default)(this, "connectionId", void 0);
38
52
  // `window` is used to prevent typescript from returning a NodeJS.Timer.
39
53
  this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);
40
54
  this.meetingId = meetingId;
41
55
  this.webex = webex;
42
56
  this.correlationId = correlationId;
57
+ this.setNewConnectionId();
43
58
  // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.
44
59
  setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);
45
60
  }
@@ -73,6 +88,16 @@ var RtcMetrics = /*#__PURE__*/function () {
73
88
  data.payload = data.payload.map(this.anonymizeIp);
74
89
  }
75
90
  this.metricsQueue.push(data);
91
+ try {
92
+ // If a connection fails, send the rest of the metrics in queue and get a new connection id.
93
+ var parsedPayload = parseJsonPayload(data.payload);
94
+ if (data.name === 'onconnectionstatechange' && parsedPayload && parsedPayload.value === 'failed') {
95
+ this.sendMetricsInQueue();
96
+ this.setNewConnectionId();
97
+ }
98
+ } catch (e) {
99
+ console.error(e);
100
+ }
76
101
  }
77
102
  }
78
103
 
@@ -107,6 +132,17 @@ var RtcMetrics = /*#__PURE__*/function () {
107
132
  return (0, _stringify.default)(data);
108
133
  }
109
134
 
135
+ /**
136
+ * Set a new connection id.
137
+ *
138
+ * @returns {void}
139
+ */
140
+ }, {
141
+ key: "setNewConnectionId",
142
+ value: function setNewConnectionId() {
143
+ this.connectionId = _uuid.default.v4();
144
+ }
145
+
110
146
  /**
111
147
  * Send metrics to the metrics service.
112
148
  *
@@ -126,10 +162,11 @@ var RtcMetrics = /*#__PURE__*/function () {
126
162
  body: {
127
163
  metrics: [{
128
164
  type: 'webrtc',
129
- version: '1.0.1',
165
+ version: '1.1.0',
130
166
  userId: this.webex.internal.device.userId,
131
167
  meetingId: this.meetingId,
132
168
  correlationId: this.correlationId,
169
+ connectionId: this.connectionId,
133
170
  data: this.metricsQueue
134
171
  }]
135
172
  }
@@ -1 +1 @@
1
- {"version":3,"names":["RtcMetrics","webex","meetingId","correlationId","intervalId","window","setInterval","sendMetricsInQueue","bind","setTimeout","metricsQueue","length","sendMetrics","data","payload","name","map","anonymizeIp","push","clearInterval","stats","JSON","parse","type","ip","CallDiagnosticUtils","anonymizeIPAddress","undefined","address","relatedAddress","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics","version","userId","internal","device"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';\nimport RTC_METRICS from './constants';\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId: string;\n\n correlationId: string;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {string} meetingId - The meeting id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, meetingId, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.webex = webex;\n this.correlationId = correlationId;\n // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.\n setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n this.metricsQueue.push(data);\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [\n {\n type: 'webrtc',\n version: '1.0.1',\n userId: this.webex.internal.device.userId,\n meetingId: this.meetingId,\n correlationId: this.correlationId,\n data: this.metricsQueue,\n },\n ],\n },\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["parseJsonPayload","payload","JSON","parse","_","RtcMetrics","webex","meetingId","correlationId","intervalId","window","setInterval","sendMetricsInQueue","bind","setNewConnectionId","setTimeout","metricsQueue","length","sendMetrics","data","name","map","anonymizeIp","push","parsedPayload","value","e","console","error","clearInterval","stats","type","ip","CallDiagnosticUtils","anonymizeIPAddress","undefined","address","relatedAddress","connectionId","uuid","v4","request","method","service","resource","headers","appId","RTC_METRICS","APP_ID","body","metrics","version","userId","internal","device"],"sources":["index.ts"],"sourcesContent":["/* eslint-disable class-methods-use-this */\nimport {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';\nimport uuid from 'uuid';\nimport RTC_METRICS from './constants';\n\nconst parseJsonPayload = (payload: any[]): any | null => {\n try {\n if (payload && payload[0]) {\n return JSON.parse(payload[0]);\n }\n\n return null;\n } catch (_) {\n return null;\n }\n};\n\n/**\n * Rtc Metrics\n */\nexport default class RtcMetrics {\n /**\n * Array of MetricData items to be sent to the metrics service.\n */\n metricsQueue = [];\n\n intervalId: number;\n\n webex: any;\n\n meetingId: string;\n\n correlationId: string;\n\n connectionId: string;\n\n /**\n * Initialize the interval.\n *\n * @param {object} webex - The main `webex` object.\n * @param {string} meetingId - The meeting id.\n * @param {string} correlationId - The correlation id.\n */\n constructor(webex, meetingId, correlationId) {\n // `window` is used to prevent typescript from returning a NodeJS.Timer.\n this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);\n this.meetingId = meetingId;\n this.webex = webex;\n this.correlationId = correlationId;\n this.setNewConnectionId();\n // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.\n setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);\n }\n\n /**\n * Check to see if the metrics queue has any items.\n *\n * @returns {void}\n */\n public sendMetricsInQueue() {\n if (this.metricsQueue.length) {\n this.sendMetrics();\n this.metricsQueue = [];\n }\n }\n\n /**\n * Add metrics items to the metrics queue.\n *\n * @param {object} data - An object with a payload array of metrics items.\n *\n * @returns {void}\n */\n addMetrics(data) {\n if (data.payload.length) {\n if (data.name === 'stats-report') {\n data.payload = data.payload.map(this.anonymizeIp);\n }\n\n this.metricsQueue.push(data);\n\n try {\n // If a connection fails, send the rest of the metrics in queue and get a new connection id.\n const parsedPayload = parseJsonPayload(data.payload);\n if (\n data.name === 'onconnectionstatechange' &&\n parsedPayload &&\n parsedPayload.value === 'failed'\n ) {\n this.sendMetricsInQueue();\n this.setNewConnectionId();\n }\n } catch (e) {\n console.error(e);\n }\n }\n }\n\n /**\n * Clear the metrics interval.\n *\n * @returns {void}\n */\n closeMetrics() {\n this.sendMetricsInQueue();\n clearInterval(this.intervalId);\n }\n\n /**\n * Anonymize IP addresses.\n *\n * @param {array} stats - An RTCStatsReport organized into an array of strings.\n * @returns {string}\n */\n anonymizeIp(stats: string): string {\n const data = JSON.parse(stats);\n // on local and remote candidates, anonymize the last 4 bits.\n if (data.type === 'local-candidate' || data.type === 'remote-candidate') {\n data.ip = CallDiagnosticUtils.anonymizeIPAddress(data.ip) || undefined;\n data.address = CallDiagnosticUtils.anonymizeIPAddress(data.address) || undefined;\n data.relatedAddress =\n CallDiagnosticUtils.anonymizeIPAddress(data.relatedAddress) || undefined;\n }\n\n return JSON.stringify(data);\n }\n\n /**\n * Set a new connection id.\n *\n * @returns {void}\n */\n private setNewConnectionId() {\n this.connectionId = uuid.v4();\n }\n\n /**\n * Send metrics to the metrics service.\n *\n * @returns {void}\n */\n private sendMetrics() {\n this.webex.request({\n method: 'POST',\n service: 'unifiedTelemetry',\n resource: 'metric/v2',\n headers: {\n type: 'webrtcMedia',\n appId: RTC_METRICS.APP_ID,\n },\n body: {\n metrics: [\n {\n type: 'webrtc',\n version: '1.1.0',\n userId: this.webex.internal.device.userId,\n meetingId: this.meetingId,\n correlationId: this.correlationId,\n connectionId: this.connectionId,\n data: this.metricsQueue,\n },\n ],\n },\n });\n }\n}\n"],"mappings":"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"}
@@ -10,6 +10,7 @@ export default class RtcMetrics {
10
10
  webex: any;
11
11
  meetingId: string;
12
12
  correlationId: string;
13
+ connectionId: string;
13
14
  /**
14
15
  * Initialize the interval.
15
16
  *
@@ -45,6 +46,12 @@ export default class RtcMetrics {
45
46
  * @returns {string}
46
47
  */
47
48
  anonymizeIp(stats: string): string;
49
+ /**
50
+ * Set a new connection id.
51
+ *
52
+ * @returns {void}
53
+ */
54
+ private setNewConnectionId;
48
55
  /**
49
56
  * Send metrics to the metrics service.
50
57
  *
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.0.0-beta.364"
65
+ version: "3.0.0-beta.365"
66
66
  });
67
67
  var _default = Webinar;
68
68
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.364",
3
+ "version": "3.0.0-beta.365",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -33,12 +33,12 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@peculiar/webcrypto": "^1.4.3",
36
- "@webex/plugin-meetings": "3.0.0-beta.364",
37
- "@webex/test-helper-chai": "3.0.0-beta.364",
38
- "@webex/test-helper-mocha": "3.0.0-beta.364",
39
- "@webex/test-helper-mock-webex": "3.0.0-beta.364",
40
- "@webex/test-helper-retry": "3.0.0-beta.364",
41
- "@webex/test-helper-test-users": "3.0.0-beta.364",
36
+ "@webex/plugin-meetings": "3.0.0-beta.365",
37
+ "@webex/test-helper-chai": "3.0.0-beta.365",
38
+ "@webex/test-helper-mocha": "3.0.0-beta.365",
39
+ "@webex/test-helper-mock-webex": "3.0.0-beta.365",
40
+ "@webex/test-helper-retry": "3.0.0-beta.365",
41
+ "@webex/test-helper-test-users": "3.0.0-beta.365",
42
42
  "chai": "^4.3.4",
43
43
  "chai-as-promised": "^7.1.1",
44
44
  "jsdom-global": "3.0.2",
@@ -47,19 +47,19 @@
47
47
  "typescript": "^4.7.4"
48
48
  },
49
49
  "dependencies": {
50
- "@webex/common": "3.0.0-beta.364",
50
+ "@webex/common": "3.0.0-beta.365",
51
51
  "@webex/internal-media-core": "2.2.7",
52
- "@webex/internal-plugin-conversation": "3.0.0-beta.364",
53
- "@webex/internal-plugin-device": "3.0.0-beta.364",
54
- "@webex/internal-plugin-llm": "3.0.0-beta.364",
55
- "@webex/internal-plugin-mercury": "3.0.0-beta.364",
56
- "@webex/internal-plugin-metrics": "3.0.0-beta.364",
57
- "@webex/internal-plugin-support": "3.0.0-beta.364",
58
- "@webex/internal-plugin-user": "3.0.0-beta.364",
59
- "@webex/media-helpers": "3.0.0-beta.364",
60
- "@webex/plugin-people": "3.0.0-beta.364",
61
- "@webex/plugin-rooms": "3.0.0-beta.364",
62
- "@webex/webex-core": "3.0.0-beta.364",
52
+ "@webex/internal-plugin-conversation": "3.0.0-beta.365",
53
+ "@webex/internal-plugin-device": "3.0.0-beta.365",
54
+ "@webex/internal-plugin-llm": "3.0.0-beta.365",
55
+ "@webex/internal-plugin-mercury": "3.0.0-beta.365",
56
+ "@webex/internal-plugin-metrics": "3.0.0-beta.365",
57
+ "@webex/internal-plugin-support": "3.0.0-beta.365",
58
+ "@webex/internal-plugin-user": "3.0.0-beta.365",
59
+ "@webex/media-helpers": "3.0.0-beta.365",
60
+ "@webex/plugin-people": "3.0.0-beta.365",
61
+ "@webex/plugin-rooms": "3.0.0-beta.365",
62
+ "@webex/webex-core": "3.0.0-beta.365",
63
63
  "ampersand-collection": "^2.0.2",
64
64
  "bowser": "^2.11.0",
65
65
  "btoa": "^1.2.1",
@@ -1,7 +1,20 @@
1
1
  /* eslint-disable class-methods-use-this */
2
2
  import {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';
3
+ import uuid from 'uuid';
3
4
  import RTC_METRICS from './constants';
4
5
 
6
+ const parseJsonPayload = (payload: any[]): any | null => {
7
+ try {
8
+ if (payload && payload[0]) {
9
+ return JSON.parse(payload[0]);
10
+ }
11
+
12
+ return null;
13
+ } catch (_) {
14
+ return null;
15
+ }
16
+ };
17
+
5
18
  /**
6
19
  * Rtc Metrics
7
20
  */
@@ -19,6 +32,8 @@ export default class RtcMetrics {
19
32
 
20
33
  correlationId: string;
21
34
 
35
+ connectionId: string;
36
+
22
37
  /**
23
38
  * Initialize the interval.
24
39
  *
@@ -32,6 +47,7 @@ export default class RtcMetrics {
32
47
  this.meetingId = meetingId;
33
48
  this.webex = webex;
34
49
  this.correlationId = correlationId;
50
+ this.setNewConnectionId();
35
51
  // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.
36
52
  setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);
37
53
  }
@@ -60,7 +76,23 @@ export default class RtcMetrics {
60
76
  if (data.name === 'stats-report') {
61
77
  data.payload = data.payload.map(this.anonymizeIp);
62
78
  }
79
+
63
80
  this.metricsQueue.push(data);
81
+
82
+ try {
83
+ // If a connection fails, send the rest of the metrics in queue and get a new connection id.
84
+ const parsedPayload = parseJsonPayload(data.payload);
85
+ if (
86
+ data.name === 'onconnectionstatechange' &&
87
+ parsedPayload &&
88
+ parsedPayload.value === 'failed'
89
+ ) {
90
+ this.sendMetricsInQueue();
91
+ this.setNewConnectionId();
92
+ }
93
+ } catch (e) {
94
+ console.error(e);
95
+ }
64
96
  }
65
97
  }
66
98
 
@@ -93,6 +125,15 @@ export default class RtcMetrics {
93
125
  return JSON.stringify(data);
94
126
  }
95
127
 
128
+ /**
129
+ * Set a new connection id.
130
+ *
131
+ * @returns {void}
132
+ */
133
+ private setNewConnectionId() {
134
+ this.connectionId = uuid.v4();
135
+ }
136
+
96
137
  /**
97
138
  * Send metrics to the metrics service.
98
139
  *
@@ -111,10 +152,11 @@ export default class RtcMetrics {
111
152
  metrics: [
112
153
  {
113
154
  type: 'webrtc',
114
- version: '1.0.1',
155
+ version: '1.1.0',
115
156
  userId: this.webex.internal.device.userId,
116
157
  meetingId: this.meetingId,
117
158
  correlationId: this.correlationId,
159
+ connectionId: this.connectionId,
118
160
  data: this.metricsQueue,
119
161
  },
120
162
  ],
@@ -4,10 +4,15 @@ import {assert} from '@webex/test-helper-chai';
4
4
  import sinon from 'sinon';
5
5
  import RTC_METRICS from '../../../../src/rtcMetrics/constants';
6
6
 
7
- const FAKE_METRICS_ITEM = {payload: ['fake-metrics']};
7
+ const FAKE_METRICS_ITEM = {payload: ['{"type":"string","value":"fake-metrics","id":""}']};
8
+ const FAILURE_METRICS_ITEM = {
9
+ name: "onconnectionstatechange",
10
+ payload: ['{"type":"string","value":"failed","id":""}'],
11
+ timestamp: 1707929986667
12
+ };
8
13
 
9
- const STATS_WITH_IP = '{\"id\":\"RTCIceCandidate_/kQs0ZNU\",\"type\":\"remote-candidate\",\"transportId\":\"RTCTransport_0_1\",\"isRemote\":true,\"ip\":\"11.22.111.255\",\"address\":\"11.22.111.255\",\"port\":5004,\"protocol\":\"udp\",\"candidateType\":\"host\",\"priority\":2130706431}';
10
- const STATS_WITH_IP_RESULT = '{\"id\":\"RTCIceCandidate_/kQs0ZNU\",\"type\":\"remote-candidate\",\"transportId\":\"RTCTransport_0_1\",\"isRemote\":true,\"ip\":\"11.22.111.240\",\"address\":\"11.22.111.240\",\"port\":5004,\"protocol\":\"udp\",\"candidateType\":\"host\",\"priority\":2130706431}';
14
+ const STATS_WITH_IP = '{"id":"RTCIceCandidate_/kQs0ZNU","type":"remote-candidate","transportId":"RTCTransport_0_1","isRemote":true,"ip":"11.22.111.255","address":"11.22.111.255","port":5004,"protocol":"udp","candidateType":"host","priority":2130706431}';
15
+ const STATS_WITH_IP_RESULT = '{"id":"RTCIceCandidate_/kQs0ZNU","type":"remote-candidate","transportId":"RTCTransport_0_1","isRemote":true,"ip":"11.22.111.240","address":"11.22.111.240","port":5004,"protocol":"udp","candidateType":"host","priority":2130706431}';
11
16
 
12
17
  describe('RtcMetrics', () => {
13
18
  let metrics: RtcMetrics;
@@ -82,6 +87,30 @@ describe('RtcMetrics', () => {
82
87
  assert.callCount(webex.request, 1);
83
88
  });
84
89
 
90
+ it('should clear out metrics on failure', () => {
91
+ assert.notCalled(webex.request);
92
+
93
+ metrics.addMetrics(FAILURE_METRICS_ITEM);
94
+
95
+ assert.callCount(webex.request, 1);
96
+ });
97
+
98
+ it('should have the same connectionId on success', () => {
99
+ const originalId = metrics.connectionId;
100
+
101
+ metrics.addMetrics(FAKE_METRICS_ITEM);
102
+
103
+ assert.strictEqual(originalId, metrics.connectionId);
104
+ });
105
+
106
+ it('should have a new connectionId on failure', () => {
107
+ const originalId = metrics.connectionId;
108
+
109
+ metrics.addMetrics(FAILURE_METRICS_ITEM);
110
+
111
+ assert.notEqual(originalId, metrics.connectionId);
112
+ });
113
+
85
114
  it('should anonymize IP addresses', () => {
86
115
  assert.strictEqual(metrics.anonymizeIp(STATS_WITH_IP), STATS_WITH_IP_RESULT);
87
116
  });