@webex/internal-plugin-metrics 3.12.0-next.5 → 3.12.0-next.50

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 (84) hide show
  1. package/README.md +274 -0
  2. package/dist/automated-user.js +19 -0
  3. package/dist/automated-user.js.map +1 -0
  4. package/dist/batcher.js +3 -0
  5. package/dist/batcher.js.map +1 -1
  6. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js +635 -62
  7. package/dist/call-diagnostic/call-diagnostic-metrics-latencies.js.map +1 -1
  8. package/dist/call-diagnostic/call-diagnostic-metrics.js +188 -78
  9. package/dist/call-diagnostic/call-diagnostic-metrics.js.map +1 -1
  10. package/dist/call-diagnostic/call-diagnostic-metrics.util.js +5 -0
  11. package/dist/call-diagnostic/call-diagnostic-metrics.util.js.map +1 -1
  12. package/dist/call-diagnostic/config.js +16 -3
  13. package/dist/call-diagnostic/config.js.map +1 -1
  14. package/dist/config.js +8 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/index.js +25 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/metrics.js +118 -5
  19. package/dist/metrics.js.map +1 -1
  20. package/dist/metrics.types.js +4 -0
  21. package/dist/metrics.types.js.map +1 -1
  22. package/dist/network-telemetry.js +610 -0
  23. package/dist/network-telemetry.js.map +1 -0
  24. package/dist/new-metrics.js +63 -17
  25. package/dist/new-metrics.js.map +1 -1
  26. package/dist/privacy-and-security-permission-enricher/constants.js +18 -0
  27. package/dist/privacy-and-security-permission-enricher/constants.js.map +1 -0
  28. package/dist/privacy-and-security-permission-enricher/index.js +143 -0
  29. package/dist/privacy-and-security-permission-enricher/index.js.map +1 -0
  30. package/dist/privacy-and-security-permission-enricher/types.js +7 -0
  31. package/dist/privacy-and-security-permission-enricher/types.js.map +1 -0
  32. package/dist/privacy-and-security-permission-enricher/utils.js +71 -0
  33. package/dist/privacy-and-security-permission-enricher/utils.js.map +1 -0
  34. package/dist/types/automated-user.d.ts +2 -0
  35. package/dist/types/call-diagnostic/call-diagnostic-metrics-latencies.d.ts +208 -5
  36. package/dist/types/call-diagnostic/call-diagnostic-metrics.d.ts +73 -14
  37. package/dist/types/call-diagnostic/config.d.ts +4 -0
  38. package/dist/types/config.d.ts +9 -0
  39. package/dist/types/index.d.ts +5 -3
  40. package/dist/types/metrics.types.d.ts +7 -2
  41. package/dist/types/network-telemetry.d.ts +108 -0
  42. package/dist/types/new-metrics.d.ts +17 -1
  43. package/dist/types/privacy-and-security-permission-enricher/constants.d.ts +6 -0
  44. package/dist/types/privacy-and-security-permission-enricher/index.d.ts +40 -0
  45. package/dist/types/privacy-and-security-permission-enricher/types.d.ts +14 -0
  46. package/dist/types/privacy-and-security-permission-enricher/utils.d.ts +5 -0
  47. package/dist/types/unhandled-exception-telemetry/index.d.ts +60 -0
  48. package/dist/types/unhandled-exception-telemetry/utils.d.ts +6 -0
  49. package/dist/unhandled-exception-telemetry/index.js +330 -0
  50. package/dist/unhandled-exception-telemetry/index.js.map +1 -0
  51. package/dist/unhandled-exception-telemetry/utils.js +105 -0
  52. package/dist/unhandled-exception-telemetry/utils.js.map +1 -0
  53. package/package.json +12 -11
  54. package/src/automated-user.ts +16 -0
  55. package/src/batcher.js +4 -0
  56. package/src/call-diagnostic/call-diagnostic-metrics-latencies.ts +781 -71
  57. package/src/call-diagnostic/call-diagnostic-metrics.ts +119 -16
  58. package/src/call-diagnostic/call-diagnostic-metrics.util.ts +5 -0
  59. package/src/call-diagnostic/config.ts +14 -0
  60. package/src/config.js +8 -0
  61. package/src/index.ts +16 -0
  62. package/src/metrics.js +123 -5
  63. package/src/metrics.types.ts +25 -3
  64. package/src/network-telemetry.ts +757 -0
  65. package/src/new-metrics.ts +56 -6
  66. package/src/privacy-and-security-permission-enricher/constants.ts +33 -0
  67. package/src/privacy-and-security-permission-enricher/index.ts +142 -0
  68. package/src/privacy-and-security-permission-enricher/types.ts +21 -0
  69. package/src/privacy-and-security-permission-enricher/utils.ts +82 -0
  70. package/src/unhandled-exception-telemetry/index.ts +403 -0
  71. package/src/unhandled-exception-telemetry/utils.ts +101 -0
  72. package/test/unit/spec/automated-user.ts +43 -0
  73. package/test/unit/spec/batcher.js +43 -0
  74. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-batcher.ts +14 -2
  75. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics-latencies.ts +1424 -293
  76. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.ts +906 -159
  77. package/test/unit/spec/call-diagnostic/call-diagnostic-metrics.util.ts +27 -0
  78. package/test/unit/spec/metrics.js +14 -5
  79. package/test/unit/spec/network-telemetry.ts +610 -0
  80. package/test/unit/spec/new-metrics.ts +203 -50
  81. package/test/unit/spec/prelogin-metrics-batcher.ts +71 -36
  82. package/test/unit/spec/privacy-and-security-permission-enricher.ts +318 -0
  83. package/test/unit/spec/unhandled-exception-telemetry/utils.ts +109 -0
  84. package/test/unit/spec/unhandled-exception-telemetry.ts +688 -0
@@ -9,6 +9,7 @@ import {
9
9
  CallDiagnosticMetrics,
10
10
  getOSNameInternal,
11
11
  CallDiagnosticUtils,
12
+ AutomatedUserUtils,
12
13
  config,
13
14
  } from '@webex/internal-plugin-metrics';
14
15
  import uuid from 'uuid';
@@ -34,6 +35,7 @@ describe('internal-plugin-metrics', () => {
34
35
  var now = new Date();
35
36
 
36
37
  let cd: CallDiagnosticMetrics;
38
+ let isAutomatedUserStub: sinon.SinonStub;
37
39
 
38
40
  const fakeMeeting = {
39
41
  id: '1',
@@ -155,6 +157,7 @@ describe('internal-plugin-metrics', () => {
155
157
  sinon.useFakeTimers(now.getTime());
156
158
  cd = new CallDiagnosticMetrics({}, {parent: webex});
157
159
  sinon.stub(uuid, 'v4').returns('my-fake-id');
160
+ isAutomatedUserStub = sinon.stub(AutomatedUserUtils, 'isAutomatedUser').returns(false);
158
161
  cd.setDeviceInfo(webex.internal.device);
159
162
  });
160
163
 
@@ -361,6 +364,23 @@ describe('internal-plugin-metrics', () => {
361
364
  });
362
365
  });
363
366
 
367
+ it('should build origin correctly when the meetings plugin is not available (before webex is ready)', () => {
368
+ // meetings plugin, geoHintInfo and meetingCollection are all absent before webex.ready
369
+ webex.meetings = undefined;
370
+
371
+ //@ts-ignore
372
+ const res = cd.getOrigin(
373
+ {subClientType: 'WEB_APP', clientType: 'TEAMS_CLIENT'},
374
+ fakeMeeting.id
375
+ );
376
+
377
+ assert.equal(res.clientInfo.clientType, 'TEAMS_CLIENT');
378
+ assert.equal(res.clientInfo.subClientType, 'WEB_APP');
379
+ assert.isUndefined(res.clientInfo.publicNetworkPrefix);
380
+ assert.isUndefined(res.clientInfo.localNetworkPrefix);
381
+ assert.equal(res.name, 'endpoint');
382
+ });
383
+
364
384
  it('builds origin correctly, when overriding clientVersion', () => {
365
385
  webex.meetings.config.metrics.clientVersion = '43.9.0.1234';
366
386
 
@@ -391,6 +411,64 @@ describe('internal-plugin-metrics', () => {
391
411
  });
392
412
  });
393
413
 
414
+ it('builds origin correctly with browser details provided by the host client', () => {
415
+ // host resolves wrapper browsers (WebOS, Electron) to the engine that determines capability
416
+ webex.meetings.config.metrics.browser = 'WebOS Browser';
417
+ webex.meetings.config.metrics.browserVersion = '108.0.0.0';
418
+
419
+ //@ts-ignore
420
+ const res = cd.getOrigin(
421
+ {subClientType: 'WEB_APP', clientType: 'TEAMS_CLIENT'},
422
+ fakeMeeting.id
423
+ );
424
+
425
+ assert.equal(res.clientInfo.browser, 'WebOS Browser');
426
+ assert.equal(res.clientInfo.browserVersion, '108.0.0.0');
427
+ });
428
+
429
+ it('falls back to SDK browser detection when the host provides nothing', () => {
430
+ //@ts-ignore
431
+ const res = cd.getOrigin(
432
+ {subClientType: 'WEB_APP', clientType: 'TEAMS_CLIENT'},
433
+ fakeMeeting.id
434
+ );
435
+
436
+ assert.equal(res.clientInfo.browser, getBrowserName());
437
+ assert.equal(res.clientInfo.browserVersion, getBrowserVersion());
438
+ });
439
+
440
+ it('builds origin correctly with the browser support flags from config', () => {
441
+ // `false` is the meaningful "unsupported family" signal, so it must survive a truthy check
442
+ webex.meetings.config.metrics.isSupportedBrowserFamily = false;
443
+ webex.meetings.config.metrics.isOutdatedBrowserVersion = true;
444
+
445
+ //@ts-ignore
446
+ const res = cd.getOrigin(
447
+ {subClientType: 'WEB_APP', clientType: 'TEAMS_CLIENT'},
448
+ fakeMeeting.id
449
+ );
450
+
451
+ assert.deepEqual(res, {
452
+ clientInfo: {
453
+ browser: getBrowserName(),
454
+ browserVersion: getBrowserVersion(),
455
+ clientType: 'TEAMS_CLIENT',
456
+ clientVersion: 'webex-js-sdk/webex-version',
457
+ publicNetworkPrefix: '1.3.4.0',
458
+ localNetworkPrefix: '192.168.1.80',
459
+ os: getOSNameInternal(),
460
+ osVersion: getOSVersion() || 'unknown',
461
+ subClientType: 'WEB_APP',
462
+ isSupportedBrowserFamily: false,
463
+ isOutdatedBrowserVersion: true,
464
+ },
465
+ environment: 'meeting_evn',
466
+ name: 'endpoint',
467
+ networkType: 'unknown',
468
+ userAgent,
469
+ });
470
+ });
471
+
394
472
  it('should build origin correctly with no meeting or stats analyzer', () => {
395
473
  //@ts-ignore
396
474
  const res = cd.getOrigin();
@@ -763,6 +841,60 @@ describe('internal-plugin-metrics', () => {
763
841
  userId: 'preLoginId',
764
842
  });
765
843
  });
844
+
845
+ it('should use the userId from credentials when no device userId is available', () => {
846
+ cd.device.userId = undefined;
847
+ webex.credentials.getUserId = sinon.stub().returns('credentials-user-id');
848
+
849
+ const res = cd.getIdentifiers({
850
+ correlationId: 'correlationId',
851
+ });
852
+
853
+ assert.deepEqual(res, {
854
+ correlationId: 'correlationId',
855
+ locusUrl: 'locus-url',
856
+ deviceId: 'deviceUrl',
857
+ orgId: 'orgId',
858
+ userId: 'credentials-user-id',
859
+ });
860
+ });
861
+
862
+ it('should prefer the device userId over the credentials userId', () => {
863
+ webex.credentials.getUserId = sinon.stub().returns('credentials-user-id');
864
+
865
+ const res = cd.getIdentifiers({
866
+ correlationId: 'correlationId',
867
+ });
868
+
869
+ assert.equal(res.userId, 'userId');
870
+ assert.notCalled(webex.credentials.getUserId);
871
+ });
872
+
873
+ it('should fall back to preLoginId when neither the device nor credentials provide a userId', () => {
874
+ cd.device.userId = undefined;
875
+ webex.credentials.getUserId = sinon.stub().throws(new Error('no user token available'));
876
+
877
+ const res = cd.getIdentifiers({
878
+ correlationId: 'correlationId',
879
+ preLoginId: 'preLoginId',
880
+ });
881
+
882
+ assert.equal(res.userId, 'preLoginId');
883
+ });
884
+ });
885
+
886
+ describe('#getUserIdFromCredentials', () => {
887
+ it('should return the userId from credentials', () => {
888
+ webex.credentials.getUserId = sinon.stub().returns('credentials-user-id');
889
+
890
+ assert.equal(cd.getUserIdFromCredentials(), 'credentials-user-id');
891
+ });
892
+
893
+ it('should return undefined when credentials cannot provide a userId', () => {
894
+ webex.credentials.getUserId = sinon.stub().throws(new Error('no user token available'));
895
+
896
+ assert.isUndefined(cd.getUserIdFromCredentials());
897
+ });
766
898
  });
767
899
 
768
900
  it('should prepare diagnostic event successfully', () => {
@@ -857,6 +989,103 @@ describe('internal-plugin-metrics', () => {
857
989
  });
858
990
  });
859
991
 
992
+ describe('#prepareDiagnosticEvent isAutomatedUser field', () => {
993
+ it('should set isAutomatedUser to false when window is not defined', () => {
994
+ const options = {meetingId: fakeMeeting.id};
995
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
996
+
997
+ const res = cd.prepareDiagnosticEvent(
998
+ {
999
+ canProceed: true,
1000
+ identifiers: {correlationId: 'test-id'},
1001
+ name: 'client.alert.displayed',
1002
+ isAutomatedUser: false,
1003
+ userActivation: undefined,
1004
+ },
1005
+ options
1006
+ );
1007
+
1008
+ // In the test environment, isAutomatedUser should be false since we're not in a webdriver environment
1009
+ assert.isFalse(
1010
+ res.event.isAutomatedUser,
1011
+ 'isAutomatedUser should be false in non-webdriver test environment'
1012
+ );
1013
+ });
1014
+
1015
+ it('should include isAutomatedUser field in the returned event', () => {
1016
+ const options = {meetingId: fakeMeeting.id};
1017
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
1018
+
1019
+ const res = cd.prepareDiagnosticEvent(
1020
+ {
1021
+ canProceed: true,
1022
+ identifiers: {correlationId: 'test-id'},
1023
+ name: 'client.alert.displayed',
1024
+ isAutomatedUser: false,
1025
+ userActivation: undefined,
1026
+ },
1027
+ options
1028
+ );
1029
+
1030
+ // Verify the isAutomatedUser field is present in the event
1031
+ assert.isDefined(res.event.isAutomatedUser, 'isAutomatedUser field should be defined');
1032
+ assert.isBoolean(res.event.isAutomatedUser, 'isAutomatedUser should be a boolean');
1033
+ });
1034
+
1035
+ it('should set isAutomatedUser to true when the user is automated', () => {
1036
+ isAutomatedUserStub.returns(true);
1037
+ const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
1038
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
1039
+ cd.setMercuryConnectedStatus(true);
1040
+
1041
+ cd.submitClientEvent({
1042
+ name: 'client.alert.displayed',
1043
+ options: {correlationId: 'correlationId'},
1044
+ });
1045
+
1046
+ assert.isTrue(
1047
+ prepareDiagnosticEventSpy.firstCall.args[0].isAutomatedUser,
1048
+ 'isAutomatedUser should be true for an automated user'
1049
+ );
1050
+ });
1051
+ });
1052
+
1053
+ describe('#getUserActivation', () => {
1054
+ let originalDescriptor;
1055
+
1056
+ beforeEach(() => {
1057
+ originalDescriptor = Object.getOwnPropertyDescriptor(global, 'navigator');
1058
+ });
1059
+
1060
+ afterEach(() => {
1061
+ if (originalDescriptor) {
1062
+ Object.defineProperty(global, 'navigator', originalDescriptor);
1063
+ } else {
1064
+ delete (global as any).navigator;
1065
+ }
1066
+ });
1067
+
1068
+ it('should return the userActivation state when navigator.userActivation is available', () => {
1069
+ Object.defineProperty(global, 'navigator', {
1070
+ value: {userActivation: {hasBeenActive: true, isActive: false}},
1071
+ configurable: true,
1072
+ writable: true,
1073
+ });
1074
+
1075
+ assert.deepEqual(cd.getUserActivation(), {hasBeenActive: true, isActive: false});
1076
+ });
1077
+
1078
+ it('should return undefined when navigator.userActivation is not available', () => {
1079
+ Object.defineProperty(global, 'navigator', {
1080
+ value: {},
1081
+ configurable: true,
1082
+ writable: true,
1083
+ });
1084
+
1085
+ assert.isUndefined(cd.getUserActivation());
1086
+ });
1087
+ });
1088
+
860
1089
  describe('#submitClientEvent', () => {
861
1090
  it('should submit client event successfully with meetingId', () => {
862
1091
  const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
@@ -907,11 +1136,15 @@ describe('internal-plugin-metrics', () => {
907
1136
  userId: 'userId',
908
1137
  },
909
1138
  loginType: 'login-ci',
1139
+ telemetryOptOut: undefined,
910
1140
  name: 'client.alert.displayed',
911
1141
  userType: 'host',
912
1142
  isConvergedArchitectureEnabled: undefined,
913
1143
  webexSubServiceType: undefined,
914
1144
  webClientPreload: undefined,
1145
+ isVipMeeting: false,
1146
+ isAutomatedUser: false,
1147
+ userActivation: undefined,
915
1148
  },
916
1149
  options
917
1150
  );
@@ -935,11 +1168,15 @@ describe('internal-plugin-metrics', () => {
935
1168
  userId: 'userId',
936
1169
  },
937
1170
  loginType: 'login-ci',
1171
+ telemetryOptOut: undefined,
938
1172
  name: 'client.alert.displayed',
939
1173
  userType: 'host',
940
1174
  isConvergedArchitectureEnabled: undefined,
941
1175
  webexSubServiceType: undefined,
942
1176
  webClientPreload: undefined,
1177
+ isVipMeeting: false,
1178
+ isAutomatedUser: false,
1179
+ userActivation: undefined,
943
1180
  },
944
1181
  eventId: 'my-fake-id',
945
1182
  origin: {
@@ -974,11 +1211,15 @@ describe('internal-plugin-metrics', () => {
974
1211
  userId: 'userId',
975
1212
  },
976
1213
  loginType: 'login-ci',
1214
+ telemetryOptOut: undefined,
977
1215
  name: 'client.alert.displayed',
978
1216
  userType: 'host',
979
1217
  isConvergedArchitectureEnabled: undefined,
980
1218
  webexSubServiceType: undefined,
981
1219
  webClientPreload: undefined,
1220
+ isVipMeeting: false,
1221
+ isAutomatedUser: false,
1222
+ userActivation: undefined,
982
1223
  },
983
1224
  eventId: 'my-fake-id',
984
1225
  origin: {
@@ -1049,11 +1290,15 @@ describe('internal-plugin-metrics', () => {
1049
1290
  userId: 'userId',
1050
1291
  },
1051
1292
  loginType: 'login-ci',
1293
+ telemetryOptOut: undefined,
1052
1294
  name: 'client.alert.displayed',
1053
1295
  userType: 'host',
1054
1296
  isConvergedArchitectureEnabled: undefined,
1055
1297
  webexSubServiceType: undefined,
1056
1298
  webClientPreload: undefined,
1299
+ isVipMeeting: false,
1300
+ isAutomatedUser: false,
1301
+ userActivation: undefined,
1057
1302
  },
1058
1303
  options
1059
1304
  );
@@ -1077,11 +1322,15 @@ describe('internal-plugin-metrics', () => {
1077
1322
  userId: 'userId',
1078
1323
  },
1079
1324
  loginType: 'login-ci',
1325
+ telemetryOptOut: undefined,
1080
1326
  name: 'client.alert.displayed',
1081
1327
  userType: 'host',
1082
1328
  isConvergedArchitectureEnabled: undefined,
1083
1329
  webexSubServiceType: undefined,
1084
1330
  webClientPreload: undefined,
1331
+ isVipMeeting: false,
1332
+ isAutomatedUser: false,
1333
+ userActivation: undefined,
1085
1334
  },
1086
1335
  eventId: 'my-fake-id',
1087
1336
  origin: {
@@ -1116,11 +1365,15 @@ describe('internal-plugin-metrics', () => {
1116
1365
  userId: 'userId',
1117
1366
  },
1118
1367
  loginType: 'login-ci',
1368
+ telemetryOptOut: undefined,
1119
1369
  name: 'client.alert.displayed',
1120
1370
  userType: 'host',
1121
1371
  isConvergedArchitectureEnabled: undefined,
1122
1372
  webexSubServiceType: undefined,
1123
1373
  webClientPreload: undefined,
1374
+ isVipMeeting: false,
1375
+ isAutomatedUser: false,
1376
+ userActivation: undefined,
1124
1377
  },
1125
1378
  eventId: 'my-fake-id',
1126
1379
  origin: {
@@ -1192,11 +1445,15 @@ describe('internal-plugin-metrics', () => {
1192
1445
  userId: 'userId',
1193
1446
  },
1194
1447
  loginType: 'login-ci',
1448
+ telemetryOptOut: undefined,
1195
1449
  name: 'client.alert.displayed',
1196
1450
  userType: 'host',
1197
1451
  isConvergedArchitectureEnabled: undefined,
1198
1452
  webexSubServiceType: undefined,
1199
1453
  webClientPreload: undefined,
1454
+ isVipMeeting: false,
1455
+ isAutomatedUser: false,
1456
+ userActivation: undefined,
1200
1457
  },
1201
1458
  options
1202
1459
  );
@@ -1221,11 +1478,15 @@ describe('internal-plugin-metrics', () => {
1221
1478
  userId: 'userId',
1222
1479
  },
1223
1480
  loginType: 'login-ci',
1481
+ telemetryOptOut: undefined,
1224
1482
  name: 'client.alert.displayed',
1225
1483
  userType: 'host',
1226
1484
  isConvergedArchitectureEnabled: undefined,
1227
1485
  webexSubServiceType: undefined,
1228
1486
  webClientPreload: undefined,
1487
+ isVipMeeting: false,
1488
+ isAutomatedUser: false,
1489
+ userActivation: undefined,
1229
1490
  },
1230
1491
  eventId: 'my-fake-id',
1231
1492
  origin: {
@@ -1261,11 +1522,15 @@ describe('internal-plugin-metrics', () => {
1261
1522
  userId: 'userId',
1262
1523
  },
1263
1524
  loginType: 'login-ci',
1525
+ telemetryOptOut: undefined,
1264
1526
  name: 'client.alert.displayed',
1265
1527
  userType: 'host',
1266
1528
  isConvergedArchitectureEnabled: undefined,
1267
1529
  webexSubServiceType: undefined,
1268
1530
  webClientPreload: undefined,
1531
+ isVipMeeting: false,
1532
+ isAutomatedUser: false,
1533
+ userActivation: undefined,
1269
1534
  },
1270
1535
  eventId: 'my-fake-id',
1271
1536
  origin: {
@@ -1336,11 +1601,15 @@ describe('internal-plugin-metrics', () => {
1336
1601
  userId: 'userId',
1337
1602
  },
1338
1603
  loginType: 'login-ci',
1604
+ telemetryOptOut: undefined,
1339
1605
  webClientPreload: undefined,
1340
1606
  name: 'client.alert.displayed',
1341
1607
  userType: 'host',
1342
1608
  isConvergedArchitectureEnabled: undefined,
1343
1609
  webexSubServiceType: undefined,
1610
+ isVipMeeting: false,
1611
+ isAutomatedUser: false,
1612
+ userActivation: undefined,
1344
1613
  },
1345
1614
  options
1346
1615
  );
@@ -1365,11 +1634,15 @@ describe('internal-plugin-metrics', () => {
1365
1634
  userId: 'userId',
1366
1635
  },
1367
1636
  loginType: 'login-ci',
1637
+ telemetryOptOut: undefined,
1368
1638
  webClientPreload: undefined,
1369
1639
  name: 'client.alert.displayed',
1370
1640
  userType: 'host',
1371
1641
  isConvergedArchitectureEnabled: undefined,
1372
1642
  webexSubServiceType: undefined,
1643
+ isVipMeeting: false,
1644
+ isAutomatedUser: false,
1645
+ userActivation: undefined,
1373
1646
  },
1374
1647
  eventId: 'my-fake-id',
1375
1648
  origin: {
@@ -1405,11 +1678,15 @@ describe('internal-plugin-metrics', () => {
1405
1678
  userId: 'userId',
1406
1679
  },
1407
1680
  loginType: 'login-ci',
1681
+ telemetryOptOut: undefined,
1408
1682
  webClientPreload: undefined,
1409
1683
  name: 'client.alert.displayed',
1410
1684
  userType: 'host',
1411
1685
  isConvergedArchitectureEnabled: undefined,
1412
1686
  webexSubServiceType: undefined,
1687
+ isVipMeeting: false,
1688
+ isAutomatedUser: false,
1689
+ userActivation: undefined,
1413
1690
  },
1414
1691
  eventId: 'my-fake-id',
1415
1692
  origin: {
@@ -1480,6 +1757,7 @@ describe('internal-plugin-metrics', () => {
1480
1757
  userId: 'userId',
1481
1758
  },
1482
1759
  loginType: 'login-ci',
1760
+ telemetryOptOut: undefined,
1483
1761
  name: 'client.alert.displayed',
1484
1762
  userType: 'host',
1485
1763
  userNameInput: 'test',
@@ -1487,6 +1765,9 @@ describe('internal-plugin-metrics', () => {
1487
1765
  isConvergedArchitectureEnabled: undefined,
1488
1766
  webexSubServiceType: undefined,
1489
1767
  webClientPreload: undefined,
1768
+ isVipMeeting: false,
1769
+ isAutomatedUser: false,
1770
+ userActivation: undefined,
1490
1771
  },
1491
1772
  options
1492
1773
  );
@@ -1511,6 +1792,7 @@ describe('internal-plugin-metrics', () => {
1511
1792
  userId: 'userId',
1512
1793
  },
1513
1794
  loginType: 'login-ci',
1795
+ telemetryOptOut: undefined,
1514
1796
  name: 'client.alert.displayed',
1515
1797
  userType: 'host',
1516
1798
  userNameInput: 'test',
@@ -1518,6 +1800,9 @@ describe('internal-plugin-metrics', () => {
1518
1800
  isConvergedArchitectureEnabled: undefined,
1519
1801
  webexSubServiceType: undefined,
1520
1802
  webClientPreload: undefined,
1803
+ isVipMeeting: false,
1804
+ isAutomatedUser: false,
1805
+ userActivation: undefined,
1521
1806
  },
1522
1807
  eventId: 'my-fake-id',
1523
1808
  origin: {
@@ -1553,6 +1838,7 @@ describe('internal-plugin-metrics', () => {
1553
1838
  userId: 'userId',
1554
1839
  },
1555
1840
  loginType: 'login-ci',
1841
+ telemetryOptOut: undefined,
1556
1842
  name: 'client.alert.displayed',
1557
1843
  userType: 'host',
1558
1844
  userNameInput: 'test',
@@ -1560,6 +1846,9 @@ describe('internal-plugin-metrics', () => {
1560
1846
  isConvergedArchitectureEnabled: undefined,
1561
1847
  webexSubServiceType: undefined,
1562
1848
  webClientPreload: undefined,
1849
+ isVipMeeting: false,
1850
+ isAutomatedUser: false,
1851
+ userActivation: undefined,
1563
1852
  },
1564
1853
  eventId: 'my-fake-id',
1565
1854
  origin: {
@@ -1684,8 +1973,11 @@ describe('internal-plugin-metrics', () => {
1684
1973
  userId: 'userId',
1685
1974
  },
1686
1975
  loginType: 'login-ci',
1976
+ telemetryOptOut: undefined,
1687
1977
  name: 'client.alert.displayed',
1688
1978
  webClientPreload: undefined,
1979
+ isAutomatedUser: false,
1980
+ userActivation: undefined,
1689
1981
  },
1690
1982
  options
1691
1983
  );
@@ -1707,8 +1999,11 @@ describe('internal-plugin-metrics', () => {
1707
1999
  userId: 'userId',
1708
2000
  },
1709
2001
  loginType: 'login-ci',
2002
+ telemetryOptOut: undefined,
1710
2003
  name: 'client.alert.displayed',
1711
2004
  webClientPreload: undefined,
2005
+ isAutomatedUser: false,
2006
+ userActivation: undefined,
1712
2007
  },
1713
2008
  eventId: 'my-fake-id',
1714
2009
  origin: {
@@ -1782,8 +2077,11 @@ describe('internal-plugin-metrics', () => {
1782
2077
  userId: 'myPreLoginId',
1783
2078
  },
1784
2079
  loginType: 'login-ci',
2080
+ telemetryOptOut: undefined,
1785
2081
  name: 'client.alert.displayed',
1786
2082
  webClientPreload: undefined,
2083
+ isAutomatedUser: false,
2084
+ userActivation: undefined,
1787
2085
  },
1788
2086
  options
1789
2087
  );
@@ -1811,7 +2109,10 @@ describe('internal-plugin-metrics', () => {
1811
2109
  },
1812
2110
  eventData: {webClientDomain: 'whatever', isMercuryConnected: true},
1813
2111
  loginType: 'login-ci',
2112
+ telemetryOptOut: undefined,
1814
2113
  webClientPreload: undefined,
2114
+ isAutomatedUser: false,
2115
+ userActivation: undefined,
1815
2116
  },
1816
2117
  },
1817
2118
  options.preLoginId
@@ -1873,8 +2174,11 @@ describe('internal-plugin-metrics', () => {
1873
2174
  userNameInput: 'current',
1874
2175
  emailInput: 'current',
1875
2176
  loginType: 'login-ci',
2177
+ telemetryOptOut: undefined,
1876
2178
  name: 'client.alert.displayed',
1877
2179
  webClientPreload: undefined,
2180
+ isAutomatedUser: false,
2181
+ userActivation: undefined,
1878
2182
  },
1879
2183
  options
1880
2184
  );
@@ -1902,9 +2206,12 @@ describe('internal-plugin-metrics', () => {
1902
2206
  },
1903
2207
  eventData: {webClientDomain: 'whatever', isMercuryConnected: true},
1904
2208
  loginType: 'login-ci',
2209
+ telemetryOptOut: undefined,
1905
2210
  userNameInput: 'current',
1906
2211
  emailInput: 'current',
1907
2212
  webClientPreload: undefined,
2213
+ isAutomatedUser: false,
2214
+ userActivation: undefined,
1908
2215
  },
1909
2216
  },
1910
2217
  options.preLoginId
@@ -1944,12 +2251,16 @@ describe('internal-plugin-metrics', () => {
1944
2251
  userId: 'userId',
1945
2252
  },
1946
2253
  loginType: 'fakeLoginType',
2254
+ telemetryOptOut: undefined,
1947
2255
  name: 'client.alert.displayed',
1948
2256
  userType: 'host',
1949
2257
  joinFlowVersion: 'Other',
1950
2258
  isConvergedArchitectureEnabled: undefined,
1951
2259
  webexSubServiceType: undefined,
1952
2260
  webClientPreload: undefined,
2261
+ isVipMeeting: false,
2262
+ isAutomatedUser: false,
2263
+ userActivation: undefined,
1953
2264
  },
1954
2265
  eventId: 'my-fake-id',
1955
2266
  origin: {
@@ -1999,12 +2310,16 @@ describe('internal-plugin-metrics', () => {
1999
2310
  userId: 'userId',
2000
2311
  },
2001
2312
  loginType: 'fakeLoginType',
2313
+ telemetryOptOut: undefined,
2002
2314
  name: 'client.alert.displayed',
2003
2315
  userType: 'host',
2004
2316
  joinFlowVersion: 'Other',
2005
2317
  isConvergedArchitectureEnabled: undefined,
2006
2318
  webexSubServiceType: undefined,
2007
2319
  webClientPreload: undefined,
2320
+ isVipMeeting: false,
2321
+ isAutomatedUser: false,
2322
+ userActivation: undefined,
2008
2323
  },
2009
2324
  eventId: 'my-fake-id',
2010
2325
  origin: {
@@ -2059,8 +2374,11 @@ describe('internal-plugin-metrics', () => {
2059
2374
  userId: 'userId',
2060
2375
  },
2061
2376
  loginType: 'login-ci',
2377
+ telemetryOptOut: undefined,
2062
2378
  name: 'client.alert.displayed',
2063
2379
  webClientPreload: true,
2380
+ isAutomatedUser: false,
2381
+ userActivation: undefined,
2064
2382
  },
2065
2383
  options
2066
2384
  );
@@ -2082,8 +2400,221 @@ describe('internal-plugin-metrics', () => {
2082
2400
  userId: 'userId',
2083
2401
  },
2084
2402
  loginType: 'login-ci',
2403
+ telemetryOptOut: undefined,
2085
2404
  name: 'client.alert.displayed',
2086
2405
  webClientPreload: true,
2406
+ isAutomatedUser: false,
2407
+ userActivation: undefined,
2408
+ },
2409
+ eventId: 'my-fake-id',
2410
+ origin: {
2411
+ origin: 'fake-origin',
2412
+ },
2413
+ originTime: {
2414
+ sent: 'not_defined_yet',
2415
+ triggered: now.toISOString(),
2416
+ },
2417
+ senderCountryCode: 'UK',
2418
+ version: 1,
2419
+ });
2420
+ });
2421
+
2422
+ it('should submit client event with isVipMeeting: false when vipMeeting is false', () => {
2423
+ const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
2424
+ const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
2425
+ const generateClientEventErrorPayloadSpy = sinon.spy(cd, 'generateClientEventErrorPayload');
2426
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
2427
+
2428
+ webex.meetings.getBasicMeetingInformation = sinon.stub().returns({
2429
+ ...fakeMeeting,
2430
+ meetingInfo: {
2431
+ vipmeeting: false,
2432
+ },
2433
+ });
2434
+
2435
+ const options = {
2436
+ correlationId: 'correlationId',
2437
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2438
+ globalMeetingId: 'globalMeetingId1',
2439
+ sessionCorrelationId: 'sessionCorrelationId1',
2440
+ meetingId: fakeMeeting.id,
2441
+ };
2442
+ cd.setMercuryConnectedStatus(true);
2443
+ cd.submitClientEvent({
2444
+ name: 'client.alert.displayed',
2445
+ options,
2446
+ });
2447
+
2448
+ assert.notCalled(generateClientEventErrorPayloadSpy);
2449
+ assert.calledWith(
2450
+ prepareDiagnosticEventSpy,
2451
+ {
2452
+ canProceed: true,
2453
+ eventData: {
2454
+ webClientDomain: 'whatever',
2455
+ isMercuryConnected: true,
2456
+ },
2457
+ identifiers: {
2458
+ correlationId: 'correlationId',
2459
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2460
+ globalMeetingId: 'globalMeetingId1',
2461
+ sessionCorrelationId: 'sessionCorrelationId1',
2462
+ deviceId: 'deviceUrl',
2463
+ locusId: 'url',
2464
+ locusSessionId: 'locusSessionId',
2465
+ locusStartTime: 'lastActive',
2466
+ locusUrl: 'locus/url',
2467
+ orgId: 'orgId',
2468
+ userId: 'userId',
2469
+ },
2470
+ loginType: 'login-ci',
2471
+ telemetryOptOut: undefined,
2472
+ name: 'client.alert.displayed',
2473
+ userType: 'host',
2474
+ isConvergedArchitectureEnabled: undefined,
2475
+ webexSubServiceType: undefined,
2476
+ webClientPreload: undefined,
2477
+ isVipMeeting: false,
2478
+ isAutomatedUser: false,
2479
+ userActivation: undefined,
2480
+ },
2481
+ options
2482
+ );
2483
+ assert.calledWith(submitToCallDiagnosticsSpy, {
2484
+ event: {
2485
+ canProceed: true,
2486
+ eventData: {
2487
+ webClientDomain: 'whatever',
2488
+ isMercuryConnected: true,
2489
+ },
2490
+ identifiers: {
2491
+ correlationId: 'correlationId',
2492
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2493
+ globalMeetingId: 'globalMeetingId1',
2494
+ sessionCorrelationId: 'sessionCorrelationId1',
2495
+ deviceId: 'deviceUrl',
2496
+ locusId: 'url',
2497
+ locusSessionId: 'locusSessionId',
2498
+ locusStartTime: 'lastActive',
2499
+ locusUrl: 'locus/url',
2500
+ orgId: 'orgId',
2501
+ userId: 'userId',
2502
+ },
2503
+ loginType: 'login-ci',
2504
+ telemetryOptOut: undefined,
2505
+ name: 'client.alert.displayed',
2506
+ userType: 'host',
2507
+ isConvergedArchitectureEnabled: undefined,
2508
+ webexSubServiceType: undefined,
2509
+ webClientPreload: undefined,
2510
+ isVipMeeting: false,
2511
+ isAutomatedUser: false,
2512
+ userActivation: undefined,
2513
+ },
2514
+ eventId: 'my-fake-id',
2515
+ origin: {
2516
+ origin: 'fake-origin',
2517
+ },
2518
+ originTime: {
2519
+ sent: 'not_defined_yet',
2520
+ triggered: now.toISOString(),
2521
+ },
2522
+ senderCountryCode: 'UK',
2523
+ version: 1,
2524
+ });
2525
+ });
2526
+
2527
+ it('should submit client event with isVipMeeting: true when vipMeeting is true', () => {
2528
+ const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
2529
+ const submitToCallDiagnosticsSpy = sinon.spy(cd, 'submitToCallDiagnostics');
2530
+ const generateClientEventErrorPayloadSpy = sinon.spy(cd, 'generateClientEventErrorPayload');
2531
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
2532
+
2533
+ webex.meetings.getBasicMeetingInformation = sinon.stub().returns({
2534
+ ...fakeMeeting,
2535
+ meetingInfo: {
2536
+ vipmeeting: true,
2537
+ },
2538
+ });
2539
+
2540
+ const options = {
2541
+ correlationId: 'correlationId',
2542
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2543
+ globalMeetingId: 'globalMeetingId1',
2544
+ sessionCorrelationId: 'sessionCorrelationId1',
2545
+ meetingId: fakeMeeting.id,
2546
+ };
2547
+ cd.setMercuryConnectedStatus(true);
2548
+ cd.submitClientEvent({
2549
+ name: 'client.alert.displayed',
2550
+ options,
2551
+ });
2552
+
2553
+ assert.notCalled(generateClientEventErrorPayloadSpy);
2554
+ assert.calledWith(
2555
+ prepareDiagnosticEventSpy,
2556
+ {
2557
+ canProceed: true,
2558
+ eventData: {
2559
+ webClientDomain: 'whatever',
2560
+ isMercuryConnected: true,
2561
+ },
2562
+ identifiers: {
2563
+ correlationId: 'correlationId',
2564
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2565
+ globalMeetingId: 'globalMeetingId1',
2566
+ sessionCorrelationId: 'sessionCorrelationId1',
2567
+ deviceId: 'deviceUrl',
2568
+ locusId: 'url',
2569
+ locusSessionId: 'locusSessionId',
2570
+ locusStartTime: 'lastActive',
2571
+ locusUrl: 'locus/url',
2572
+ orgId: 'orgId',
2573
+ userId: 'userId',
2574
+ },
2575
+ loginType: 'login-ci',
2576
+ telemetryOptOut: undefined,
2577
+ name: 'client.alert.displayed',
2578
+ userType: 'host',
2579
+ isConvergedArchitectureEnabled: undefined,
2580
+ webexSubServiceType: undefined,
2581
+ webClientPreload: undefined,
2582
+ isVipMeeting: true,
2583
+ isAutomatedUser: false,
2584
+ userActivation: undefined,
2585
+ },
2586
+ options
2587
+ );
2588
+ assert.calledWith(submitToCallDiagnosticsSpy, {
2589
+ event: {
2590
+ canProceed: true,
2591
+ eventData: {
2592
+ webClientDomain: 'whatever',
2593
+ isMercuryConnected: true,
2594
+ },
2595
+ identifiers: {
2596
+ correlationId: 'correlationId',
2597
+ webexConferenceIdStr: 'webexConferenceIdStr1',
2598
+ globalMeetingId: 'globalMeetingId1',
2599
+ sessionCorrelationId: 'sessionCorrelationId1',
2600
+ deviceId: 'deviceUrl',
2601
+ locusId: 'url',
2602
+ locusSessionId: 'locusSessionId',
2603
+ locusStartTime: 'lastActive',
2604
+ locusUrl: 'locus/url',
2605
+ orgId: 'orgId',
2606
+ userId: 'userId',
2607
+ },
2608
+ loginType: 'login-ci',
2609
+ telemetryOptOut: undefined,
2610
+ name: 'client.alert.displayed',
2611
+ userType: 'host',
2612
+ isConvergedArchitectureEnabled: undefined,
2613
+ webexSubServiceType: undefined,
2614
+ webClientPreload: undefined,
2615
+ isVipMeeting: true,
2616
+ isAutomatedUser: false,
2617
+ userActivation: undefined,
2087
2618
  },
2088
2619
  eventId: 'my-fake-id',
2089
2620
  origin: {
@@ -2153,11 +2684,15 @@ describe('internal-plugin-metrics', () => {
2153
2684
  },
2154
2685
  ],
2155
2686
  loginType: 'login-ci',
2687
+ telemetryOptOut: undefined,
2156
2688
  name: 'client.alert.displayed',
2157
2689
  userType: 'host',
2158
2690
  isConvergedArchitectureEnabled: undefined,
2159
2691
  webexSubServiceType: undefined,
2160
2692
  webClientPreload: undefined,
2693
+ isVipMeeting: false,
2694
+ isAutomatedUser: false,
2695
+ userActivation: undefined,
2161
2696
  },
2162
2697
  eventId: 'my-fake-id',
2163
2698
  origin: {
@@ -2235,11 +2770,15 @@ describe('internal-plugin-metrics', () => {
2235
2770
  },
2236
2771
  ],
2237
2772
  loginType: 'login-ci',
2773
+ telemetryOptOut: undefined,
2238
2774
  name: 'client.alert.displayed',
2239
2775
  userType: 'host',
2240
2776
  isConvergedArchitectureEnabled: undefined,
2241
2777
  webexSubServiceType: undefined,
2242
2778
  webClientPreload: undefined,
2779
+ isVipMeeting: false,
2780
+ isAutomatedUser: false,
2781
+ userActivation: undefined,
2243
2782
  },
2244
2783
  eventId: 'my-fake-id',
2245
2784
  origin: {
@@ -2311,8 +2850,11 @@ describe('internal-plugin-metrics', () => {
2311
2850
  },
2312
2851
  ],
2313
2852
  loginType: 'login-ci',
2853
+ telemetryOptOut: undefined,
2314
2854
  name: 'client.alert.displayed',
2315
2855
  webClientPreload: undefined,
2856
+ isAutomatedUser: false,
2857
+ userActivation: undefined,
2316
2858
  },
2317
2859
  eventId: 'my-fake-id',
2318
2860
  origin: {
@@ -2386,8 +2928,11 @@ describe('internal-plugin-metrics', () => {
2386
2928
  },
2387
2929
  ],
2388
2930
  loginType: 'login-ci',
2931
+ telemetryOptOut: undefined,
2389
2932
  name: 'client.alert.displayed',
2390
2933
  webClientPreload: undefined,
2934
+ isAutomatedUser: false,
2935
+ userActivation: undefined,
2391
2936
  },
2392
2937
  eventId: 'my-fake-id',
2393
2938
  origin: {
@@ -2468,11 +3013,15 @@ describe('internal-plugin-metrics', () => {
2468
3013
  },
2469
3014
  ],
2470
3015
  loginType: 'login-ci',
3016
+ telemetryOptOut: undefined,
2471
3017
  name: 'client.alert.displayed',
2472
3018
  userType: 'host',
2473
3019
  isConvergedArchitectureEnabled: undefined,
2474
3020
  webexSubServiceType: undefined,
2475
3021
  webClientPreload: undefined,
3022
+ isVipMeeting: false,
3023
+ isAutomatedUser: false,
3024
+ userActivation: undefined,
2476
3025
  },
2477
3026
  eventId: 'my-fake-id',
2478
3027
  origin: {
@@ -2563,16 +3112,18 @@ describe('internal-plugin-metrics', () => {
2563
3112
  });
2564
3113
 
2565
3114
  assert.calledThrice(submitToCallDiagnosticsStub);
2566
- });
3115
+ });
2567
3116
 
2568
- ([
2569
- ['client.media.render.start'],
2570
- ['client.media.render.stop'],
2571
- ['client.media.rx.start'],
2572
- ['client.media.rx.stop'],
2573
- ['client.media.tx.start'],
2574
- ['client.media.tx.stop']
2575
- ] as const).forEach(([name]) => {
3117
+ (
3118
+ [
3119
+ ['client.media.render.start'],
3120
+ ['client.media.render.stop'],
3121
+ ['client.media.rx.start'],
3122
+ ['client.media.rx.stop'],
3123
+ ['client.media.tx.start'],
3124
+ ['client.media.tx.stop'],
3125
+ ] as const
3126
+ ).forEach(([name]) => {
2576
3127
  it(`should only send ${name} once per mediaType`, () => {
2577
3128
  const options = {
2578
3129
  meetingId: fakeMeeting.id,
@@ -2616,7 +3167,8 @@ describe('internal-plugin-metrics', () => {
2616
3167
  });
2617
3168
 
2618
3169
  assert.notCalled(submitToCallDiagnosticsStub);
2619
- assert.neverCalledWithMatch(webex.logger.log,
3170
+ assert.neverCalledWithMatch(
3171
+ webex.logger.log,
2620
3172
  'call-diagnostic-events -> ',
2621
3173
  sinon.match(createEventLimitRegex(name, 'mediaType video'))
2622
3174
  );
@@ -2659,7 +3211,7 @@ describe('internal-plugin-metrics', () => {
2659
3211
  // Send event with different shareInstanceId
2660
3212
  cd.submitClientEvent({
2661
3213
  name,
2662
- payload: { ...payload, shareInstanceId: 'instance-2' },
3214
+ payload: {...payload, shareInstanceId: 'instance-2'},
2663
3215
  options,
2664
3216
  });
2665
3217
 
@@ -2667,89 +3219,88 @@ describe('internal-plugin-metrics', () => {
2667
3219
  });
2668
3220
  });
2669
3221
 
2670
- ([
2671
- ['client.roap-message.received'],
2672
- ['client.roap-message.sent']
2673
- ] as const).forEach(([name]) => {
2674
- it(`should not send third event of same type and not log warning again for ${name}`, () => {
2675
- const options = {
2676
- meetingId: fakeMeeting.id,
2677
- };
2678
- const payload = {
2679
- roap: {
2680
- messageType: 'OFFER' as const,
2681
- },
2682
- };
2683
- const submitToCallDiagnosticsStub = sinon.stub(cd, 'submitToCallDiagnostics');
2684
-
2685
- // Clear any existing call history to get accurate counts
2686
- webex.logger.log.resetHistory();
2687
-
2688
- // Send first event
2689
- cd.submitClientEvent({
2690
- name,
2691
- payload,
2692
- options,
2693
- });
2694
-
2695
- assert.calledOnce(submitToCallDiagnosticsStub);
2696
- submitToCallDiagnosticsStub.resetHistory();
2697
-
2698
- // Send second event (should trigger warning)
2699
- cd.submitClientEvent({
2700
- name,
2701
- payload,
2702
- options,
2703
- });
2704
-
2705
- assert.notCalled(submitToCallDiagnosticsStub);
2706
- assert.calledWith(
2707
- webex.logger.log,
2708
- 'call-diagnostic-events -> ',
2709
- sinon.match(createEventLimitRegex(name, 'ROAP type OFFER'))
2710
- );
2711
- webex.logger.log.resetHistory();
2712
-
2713
- cd.submitClientEvent({
2714
- name,
2715
- payload,
2716
- options,
3222
+ ([['client.roap-message.received'], ['client.roap-message.sent']] as const).forEach(
3223
+ ([name]) => {
3224
+ it(`should not send third event of same type and not log warning again for ${name}`, () => {
3225
+ const options = {
3226
+ meetingId: fakeMeeting.id,
3227
+ };
3228
+ const payload = {
3229
+ roap: {
3230
+ messageType: 'OFFER' as const,
3231
+ },
3232
+ };
3233
+ const submitToCallDiagnosticsStub = sinon.stub(cd, 'submitToCallDiagnostics');
3234
+
3235
+ // Clear any existing call history to get accurate counts
3236
+ webex.logger.log.resetHistory();
3237
+
3238
+ // Send first event
3239
+ cd.submitClientEvent({
3240
+ name,
3241
+ payload,
3242
+ options,
3243
+ });
3244
+
3245
+ assert.calledOnce(submitToCallDiagnosticsStub);
3246
+ submitToCallDiagnosticsStub.resetHistory();
3247
+
3248
+ // Send second event (should trigger warning)
3249
+ cd.submitClientEvent({
3250
+ name,
3251
+ payload,
3252
+ options,
3253
+ });
3254
+
3255
+ assert.notCalled(submitToCallDiagnosticsStub);
3256
+ assert.calledWith(
3257
+ webex.logger.log,
3258
+ 'call-diagnostic-events -> ',
3259
+ sinon.match(createEventLimitRegex(name, 'ROAP type OFFER'))
3260
+ );
3261
+ webex.logger.log.resetHistory();
3262
+
3263
+ cd.submitClientEvent({
3264
+ name,
3265
+ payload,
3266
+ options,
3267
+ });
3268
+
3269
+ assert.notCalled(submitToCallDiagnosticsStub);
3270
+ assert.neverCalledWithMatch(
3271
+ webex.logger.log,
3272
+ 'call-diagnostic-events -> ',
3273
+ sinon.match(createEventLimitRegex(name, 'ROAP type OFFER'))
3274
+ );
2717
3275
  });
2718
3276
 
2719
- assert.notCalled(submitToCallDiagnosticsStub);
2720
- assert.neverCalledWithMatch(
2721
- webex.logger.log,
2722
- 'call-diagnostic-events -> ',
2723
- sinon.match(createEventLimitRegex(name, 'ROAP type OFFER'))
2724
- );
2725
- });
3277
+ it(`should handle roap.type instead of roap.messageType for ${name}`, () => {
3278
+ const options = {
3279
+ meetingId: fakeMeeting.id,
3280
+ };
3281
+ const payload = {
3282
+ roap: {
3283
+ type: 'ANSWER' as const,
3284
+ },
3285
+ };
3286
+ const submitToCallDiagnosticsStub = sinon.stub(cd, 'submitToCallDiagnostics');
2726
3287
 
2727
- it(`should handle roap.type instead of roap.messageType for ${name}`, () => {
2728
- const options = {
2729
- meetingId: fakeMeeting.id,
2730
- };
2731
- const payload = {
2732
- roap: {
2733
- type: 'ANSWER' as const,
2734
- },
2735
- };
2736
- const submitToCallDiagnosticsStub = sinon.stub(cd, 'submitToCallDiagnostics');
3288
+ cd.submitClientEvent({
3289
+ name,
3290
+ payload,
3291
+ options,
3292
+ });
2737
3293
 
2738
- cd.submitClientEvent({
2739
- name,
2740
- payload,
2741
- options,
2742
- });
3294
+ cd.submitClientEvent({
3295
+ name,
3296
+ payload,
3297
+ options,
3298
+ });
2743
3299
 
2744
- cd.submitClientEvent({
2745
- name,
2746
- payload,
2747
- options,
3300
+ assert.calledOnce(submitToCallDiagnosticsStub);
2748
3301
  });
2749
-
2750
- assert.calledOnce(submitToCallDiagnosticsStub);
2751
- });
2752
- });
3302
+ }
3303
+ );
2753
3304
  });
2754
3305
  });
2755
3306
 
@@ -2760,7 +3311,10 @@ describe('internal-plugin-metrics', () => {
2760
3311
  cd.callDiagnosticEventsBatcher = {request: requestStub};
2761
3312
  //@ts-ignore
2762
3313
  cd.submitToCallDiagnostics({event: 'test'});
2763
- assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
3314
+ assert.calledWith(requestStub, {
3315
+ eventPayload: {event: 'test'},
3316
+ type: ['diagnostic-event'],
3317
+ });
2764
3318
  });
2765
3319
  });
2766
3320
 
@@ -2829,6 +3383,7 @@ describe('internal-plugin-metrics', () => {
2829
3383
  mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
2830
3384
  startTime: now.toISOString(),
2831
3385
  },
3386
+ webexSubServiceType: undefined,
2832
3387
  },
2833
3388
  options
2834
3389
  );
@@ -2869,6 +3424,7 @@ describe('internal-plugin-metrics', () => {
2869
3424
  mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
2870
3425
  startTime: now.toISOString(),
2871
3426
  },
3427
+ webexSubServiceType: undefined,
2872
3428
  },
2873
3429
  },
2874
3430
  });
@@ -2907,10 +3463,48 @@ describe('internal-plugin-metrics', () => {
2907
3463
  mediaEngineSoftwareVersion: getOSVersion() || 'unknown',
2908
3464
  startTime: now.toISOString(),
2909
3465
  },
3466
+ webexSubServiceType: undefined,
2910
3467
  },
2911
3468
  });
2912
3469
  });
2913
3470
 
3471
+ it('includes webexSubServiceType in the media quality event payload', () => {
3472
+ const meeting = {
3473
+ ...fakeMeeting,
3474
+ meetingInfo: {
3475
+ enableConvergedArchitecture: true,
3476
+ enableEvent: true,
3477
+ enableConvergedWebinarLargeScale: true,
3478
+ },
3479
+ };
3480
+ const prepareDiagnosticEventSpy = sinon.spy(cd, 'prepareDiagnosticEvent');
3481
+ sinon.stub(cd, 'getOrigin').returns({origin: 'fake-origin'});
3482
+ webex.meetings.getBasicMeetingInformation = sinon.stub().returns(meeting);
3483
+
3484
+ const options = {
3485
+ networkType: 'wifi' as const,
3486
+ meetingId: fakeMeeting.id,
3487
+ };
3488
+
3489
+ cd.submitMQE({
3490
+ name: 'client.mediaquality.event',
3491
+ payload: {
3492
+ //@ts-ignore
3493
+ intervals: [{}],
3494
+ },
3495
+ options,
3496
+ });
3497
+
3498
+ assert.calledOnceWithExactly(
3499
+ prepareDiagnosticEventSpy,
3500
+ sinon.match({
3501
+ name: 'client.mediaquality.event',
3502
+ webexSubServiceType: 'LargeScaleWebinar',
3503
+ }),
3504
+ options
3505
+ );
3506
+ });
3507
+
2914
3508
  it('throws if meeting id not provided', () => {
2915
3509
  assert.throws(() =>
2916
3510
  cd.submitMQE({
@@ -3631,6 +4225,97 @@ describe('internal-plugin-metrics', () => {
3631
4225
  });
3632
4226
  });
3633
4227
 
4228
+ describe('#getTelemetryOptOut', () => {
4229
+ it('returns "manual" when manual telemetry opt-out is enabled', () => {
4230
+ cd.setIsTelemetryOptOutManual(true);
4231
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4232
+ });
4233
+
4234
+ it('returns "automatic" when automatic telemetry opt-out is enabled', () => {
4235
+ cd.setIsTelemetryOptOutAutomatic(true);
4236
+ assert.equal(cd.getTelemetryOptOut(), 'automatic');
4237
+ });
4238
+
4239
+ it('returns "manual" when manual opt-out takes precedence over automatic', () => {
4240
+ cd.setIsTelemetryOptOutManual(true);
4241
+ cd.setIsTelemetryOptOutAutomatic(true);
4242
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4243
+ });
4244
+
4245
+ it('returns undefined when neither manual nor automatic opt-out is set', () => {
4246
+ assert.isUndefined(cd.getTelemetryOptOut());
4247
+ });
4248
+
4249
+ it('returns undefined after disabling manual opt-out', () => {
4250
+ cd.setIsTelemetryOptOutManual(true);
4251
+ cd.setIsTelemetryOptOutManual(false);
4252
+ assert.isUndefined(cd.getTelemetryOptOut());
4253
+ });
4254
+ });
4255
+
4256
+ describe('#setIsTelemetryOptOutManual', () => {
4257
+ it('sets manual telemetry opt-out to true', () => {
4258
+ cd.setIsTelemetryOptOutManual(true);
4259
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4260
+ });
4261
+
4262
+ it('sets manual telemetry opt-out to false', () => {
4263
+ cd.setIsTelemetryOptOutManual(true);
4264
+ cd.setIsTelemetryOptOutManual(false);
4265
+ assert.isUndefined(cd.getTelemetryOptOut());
4266
+ });
4267
+
4268
+ it('can toggle manual telemetry opt-out multiple times', () => {
4269
+ cd.setIsTelemetryOptOutManual(true);
4270
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4271
+
4272
+ cd.setIsTelemetryOptOutManual(false);
4273
+ assert.isUndefined(cd.getTelemetryOptOut());
4274
+
4275
+ cd.setIsTelemetryOptOutManual(true);
4276
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4277
+ });
4278
+
4279
+ it('manual opt-out takes precedence when automatic is also set', () => {
4280
+ cd.setIsTelemetryOptOutAutomatic(true);
4281
+ cd.setIsTelemetryOptOutManual(true);
4282
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4283
+ });
4284
+ });
4285
+
4286
+ describe('#setIsTelemetryOptOutAutomatic', () => {
4287
+ it('sets automatic telemetry opt-out to true', () => {
4288
+ cd.setIsTelemetryOptOutAutomatic(true);
4289
+ assert.equal(cd.getTelemetryOptOut(), 'automatic');
4290
+ });
4291
+
4292
+ it('sets automatic telemetry opt-out to false', () => {
4293
+ cd.setIsTelemetryOptOutAutomatic(true);
4294
+ cd.setIsTelemetryOptOutAutomatic(false);
4295
+ assert.isUndefined(cd.getTelemetryOptOut());
4296
+ });
4297
+
4298
+ it('can toggle automatic telemetry opt-out multiple times', () => {
4299
+ cd.setIsTelemetryOptOutAutomatic(true);
4300
+ assert.equal(cd.getTelemetryOptOut(), 'automatic');
4301
+
4302
+ cd.setIsTelemetryOptOutAutomatic(false);
4303
+ assert.isUndefined(cd.getTelemetryOptOut());
4304
+
4305
+ cd.setIsTelemetryOptOutAutomatic(true);
4306
+ assert.equal(cd.getTelemetryOptOut(), 'automatic');
4307
+ });
4308
+
4309
+ it('does not override manual opt-out', () => {
4310
+ cd.setIsTelemetryOptOutManual(true);
4311
+ cd.setIsTelemetryOptOutAutomatic(true);
4312
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4313
+
4314
+ cd.setIsTelemetryOptOutAutomatic(false);
4315
+ assert.equal(cd.getTelemetryOptOut(), 'manual');
4316
+ });
4317
+ });
4318
+
3634
4319
  describe('#getSubServiceType', () => {
3635
4320
  it('returns subServicetype as PMR when PMR meeting', () => {
3636
4321
  fakeMeeting.meetingInfo = {
@@ -3680,6 +4365,15 @@ describe('internal-plugin-metrics', () => {
3680
4365
  assert.deepEqual(cd.getSubServiceType(fakeMeeting), 'Webcast');
3681
4366
  });
3682
4367
 
4368
+ it('returns subServicetype as LargeScaleWebinar when meeting is converged Webinar and enable large scale', () => {
4369
+ fakeMeeting.meetingInfo = {
4370
+ enableEvent: true,
4371
+ enableConvergedArchitecture: true,
4372
+ enableConvergedWebinarLargeScale: true,
4373
+ };
4374
+ assert.deepEqual(cd.getSubServiceType(fakeMeeting), 'LargeScaleWebinar');
4375
+ });
4376
+
3683
4377
  it('returns subServicetype as undefined when correct parameters are not found', () => {
3684
4378
  fakeMeeting.meetingInfo = {};
3685
4379
  assert.deepEqual(cd.getSubServiceType(fakeMeeting), undefined);
@@ -3740,12 +4434,16 @@ describe('internal-plugin-metrics', () => {
3740
4434
  userId: 'userId',
3741
4435
  },
3742
4436
  loginType: 'login-ci',
4437
+ telemetryOptOut: undefined,
3743
4438
  name: 'client.exit.app',
3744
4439
  trigger: 'user-interaction',
3745
4440
  userType: 'host',
3746
4441
  isConvergedArchitectureEnabled: undefined,
3747
4442
  webexSubServiceType: undefined,
3748
4443
  webClientPreload: undefined,
4444
+ isVipMeeting: false,
4445
+ isAutomatedUser: false,
4446
+ userActivation: undefined,
3749
4447
  },
3750
4448
  eventId: 'my-fake-id',
3751
4449
  origin: {
@@ -3900,6 +4598,30 @@ describe('internal-plugin-metrics', () => {
3900
4598
  options.meetingJoinPhase
3901
4599
  );
3902
4600
  });
4601
+
4602
+ it('builds request options before webex is ready (no meetings plugin or internal metrics config)', async () => {
4603
+ // before webex.ready the meetings plugin and internal metrics config are not available
4604
+ webex.meetings = undefined;
4605
+ webex.internal.metrics = undefined;
4606
+
4607
+ const options = {
4608
+ correlationId: 'myCorrelationId',
4609
+ clientType: 'TEAMS_CLIENT',
4610
+ subClientType: 'WEB_APP',
4611
+ };
4612
+
4613
+ const fetchOptions = await cd.buildClientEventFetchRequestOptions({
4614
+ name: 'client.exit.app',
4615
+ payload: {trigger: 'user-interaction', canProceed: false},
4616
+ options,
4617
+ });
4618
+
4619
+ const eventPayload = fetchOptions.body.metrics[0].eventPayload;
4620
+ assert.equal(eventPayload.event.name, 'client.exit.app');
4621
+ assert.isUndefined(eventPayload.senderCountryCode);
4622
+ assert.isUndefined(fetchOptions.waitForServiceTimeout);
4623
+ assert.equal(fetchOptions.resource, 'clientmetrics');
4624
+ });
3903
4625
  });
3904
4626
 
3905
4627
  describe('#submitToCallDiagnosticsPreLogin', () => {
@@ -3913,7 +4635,10 @@ describe('internal-plugin-metrics', () => {
3913
4635
  cd.submitToCallDiagnosticsPreLogin({event: 'test'}, preLoginId);
3914
4636
  //@ts-ignore
3915
4637
  assert.calledWith(cd.preLoginMetricsBatcher.savePreLoginId, preLoginId);
3916
- assert.calledWith(requestStub, {eventPayload: {event: 'test'}, type: ['diagnostic-event']});
4638
+ assert.calledWith(requestStub, {
4639
+ eventPayload: {event: 'test'},
4640
+ type: ['diagnostic-event'],
4641
+ });
3917
4642
  });
3918
4643
  });
3919
4644
 
@@ -4114,12 +4839,14 @@ describe('internal-plugin-metrics', () => {
4114
4839
  payload: {
4115
4840
  meetingSummaryInfo: {
4116
4841
  featureName: 'syncSystemMuteStatus',
4117
- featureActions: [{
4118
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
4119
- actionId: '14200',
4120
- isInitialValue: false,
4121
- clickCount: '1'
4122
- }]
4842
+ featureActions: [
4843
+ {
4844
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
4845
+ actionId: '14200',
4846
+ isInitialValue: false,
4847
+ clickCount: '1',
4848
+ },
4849
+ ],
4123
4850
  },
4124
4851
  },
4125
4852
  options,
@@ -4140,22 +4867,28 @@ describe('internal-plugin-metrics', () => {
4140
4867
  locusSessionId: 'locusSessionId',
4141
4868
  locusStartTime: 'lastActive',
4142
4869
  },
4143
- eventData: { webClientDomain: 'whatever'},
4870
+ eventData: {webClientDomain: 'whatever'},
4144
4871
  userType: 'host',
4145
4872
  loginType: 'login-ci',
4873
+ telemetryOptOut: undefined,
4146
4874
  isConvergedArchitectureEnabled: undefined,
4147
4875
  webexSubServiceType: undefined,
4148
4876
  webClientPreload: undefined,
4877
+ isVipMeeting: false,
4878
+ isAutomatedUser: false,
4879
+ userActivation: undefined,
4149
4880
  meetingSummaryInfo: {
4150
4881
  featureName: 'syncSystemMuteStatus',
4151
- featureActions: [{
4152
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
4153
- actionId: '14200',
4154
- isInitialValue: false,
4155
- clickCount: '1'
4156
- }]
4882
+ featureActions: [
4883
+ {
4884
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
4885
+ actionId: '14200',
4886
+ isInitialValue: false,
4887
+ clickCount: '1',
4888
+ },
4889
+ ],
4157
4890
  },
4158
- key: "UcfFeatureUsage",
4891
+ key: 'UcfFeatureUsage',
4159
4892
  },
4160
4893
  options
4161
4894
  );
@@ -4168,7 +4901,7 @@ describe('internal-plugin-metrics', () => {
4168
4901
  },
4169
4902
  event: {
4170
4903
  canProceed: true,
4171
- eventData: { webClientDomain: 'whatever'},
4904
+ eventData: {webClientDomain: 'whatever'},
4172
4905
  identifiers: {
4173
4906
  correlationId: 'correlationId',
4174
4907
  deviceId: 'deviceUrl',
@@ -4180,21 +4913,27 @@ describe('internal-plugin-metrics', () => {
4180
4913
  userId: 'userId',
4181
4914
  },
4182
4915
  loginType: 'login-ci',
4916
+ telemetryOptOut: undefined,
4183
4917
  name: 'client.feature.meeting.summary',
4184
4918
  userType: 'host',
4185
4919
  isConvergedArchitectureEnabled: undefined,
4186
4920
  webexSubServiceType: undefined,
4187
4921
  webClientPreload: undefined,
4922
+ isVipMeeting: false,
4923
+ isAutomatedUser: false,
4924
+ userActivation: undefined,
4188
4925
  meetingSummaryInfo: {
4189
4926
  featureName: 'syncSystemMuteStatus',
4190
- featureActions: [{
4191
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
4192
- actionId: '14200',
4193
- isInitialValue: false,
4194
- clickCount: '1'
4195
- }]
4927
+ featureActions: [
4928
+ {
4929
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
4930
+ actionId: '14200',
4931
+ isInitialValue: false,
4932
+ clickCount: '1',
4933
+ },
4934
+ ],
4196
4935
  },
4197
- key: "UcfFeatureUsage",
4936
+ key: 'UcfFeatureUsage',
4198
4937
  },
4199
4938
  originTime: {
4200
4939
  sent: 'not_defined_yet',
@@ -4235,12 +4974,14 @@ describe('internal-plugin-metrics', () => {
4235
4974
  payload: {
4236
4975
  meetingSummaryInfo: {
4237
4976
  featureName: 'syncSystemMuteStatus',
4238
- featureActions: [{
4239
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
4240
- actionId: '14200',
4241
- isInitialValue: false,
4242
- clickCount: '1'
4243
- }]
4977
+ featureActions: [
4978
+ {
4979
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
4980
+ actionId: '14200',
4981
+ isInitialValue: false,
4982
+ clickCount: '1',
4983
+ },
4984
+ ],
4244
4985
  },
4245
4986
  },
4246
4987
  delaySubmitEvent: true,
@@ -4252,12 +4993,14 @@ describe('internal-plugin-metrics', () => {
4252
4993
  payload: {
4253
4994
  meetingSummaryInfo: {
4254
4995
  featureName: 'syncSystemVideoStatus',
4255
- featureActions: [{
4256
- actionName: 'syncMeetingVideoUnmuteStatusToSystem',
4257
- actionId: '13400',
4258
- isInitialValue: false,
4259
- clickCount: '1'
4260
- }]
4996
+ featureActions: [
4997
+ {
4998
+ actionName: 'syncMeetingVideoUnmuteStatusToSystem',
4999
+ actionId: '13400',
5000
+ isInitialValue: false,
5001
+ clickCount: '1',
5002
+ },
5003
+ ],
4261
5004
  },
4262
5005
  },
4263
5006
  delaySubmitEvent: true,
@@ -4275,12 +5018,14 @@ describe('internal-plugin-metrics', () => {
4275
5018
  payload: {
4276
5019
  meetingSummaryInfo: {
4277
5020
  featureName: 'syncSystemMuteStatus',
4278
- featureActions: [{
4279
- actionName: 'syncMeetingMicUnmuteStatusToSystem',
4280
- actionId: '14200',
4281
- isInitialValue: false,
4282
- clickCount: '1'
4283
- }]
5021
+ featureActions: [
5022
+ {
5023
+ actionName: 'syncMeetingMicUnmuteStatusToSystem',
5024
+ actionId: '14200',
5025
+ isInitialValue: false,
5026
+ clickCount: '1',
5027
+ },
5028
+ ],
4284
5029
  },
4285
5030
  },
4286
5031
  options: {
@@ -4293,12 +5038,14 @@ describe('internal-plugin-metrics', () => {
4293
5038
  payload: {
4294
5039
  meetingSummaryInfo: {
4295
5040
  featureName: 'syncSystemVideoStatus',
4296
- featureActions: [{
4297
- actionName: 'syncMeetingVideoUnmuteStatusToSystem',
4298
- actionId: '13400',
4299
- isInitialValue: false,
4300
- clickCount: '1'
4301
- }]
5041
+ featureActions: [
5042
+ {
5043
+ actionName: 'syncMeetingVideoUnmuteStatusToSystem',
5044
+ actionId: '13400',
5045
+ isInitialValue: false,
5046
+ clickCount: '1',
5047
+ },
5048
+ ],
4302
5049
  },
4303
5050
  },
4304
5051
  options: {
@@ -4322,17 +5069,17 @@ describe('internal-plugin-metrics', () => {
4322
5069
 
4323
5070
  it('should clear event limits for specific correlationId only', () => {
4324
5071
  // Use the actual correlationIds from our fakeMeeting fixtures
4325
- const correlationId1 = fakeMeeting.correlationId; // e.g. 'correlationId1'
4326
- const correlationId2 = fakeMeeting2.correlationId; // e.g. 'correlationId2'
4327
- const options1 = { meetingId: fakeMeeting.id };
4328
- const options2 = { meetingId: fakeMeeting2.id };
4329
- const payload = { mediaType: 'video' as const };
5072
+ const correlationId1 = fakeMeeting.correlationId; // e.g. 'correlationId1'
5073
+ const correlationId2 = fakeMeeting2.correlationId; // e.g. 'correlationId2'
5074
+ const options1 = {meetingId: fakeMeeting.id};
5075
+ const options2 = {meetingId: fakeMeeting2.id};
5076
+ const payload = {mediaType: 'video' as const};
4330
5077
 
4331
5078
  // Set up events for both correlations to trigger limits
4332
- cd.submitClientEvent({ name: 'client.media.render.start', payload, options: options1 });
4333
- cd.submitClientEvent({ name: 'client.media.render.start', payload, options: options2 });
4334
- cd.submitClientEvent({ name: 'client.media.render.start', payload, options: options1 });
4335
- cd.submitClientEvent({ name: 'client.media.render.start', payload, options: options2 });
5079
+ cd.submitClientEvent({name: 'client.media.render.start', payload, options: options1});
5080
+ cd.submitClientEvent({name: 'client.media.render.start', payload, options: options2});
5081
+ cd.submitClientEvent({name: 'client.media.render.start', payload, options: options1});
5082
+ cd.submitClientEvent({name: 'client.media.render.start', payload, options: options2});
4336
5083
  assert.isTrue(cd.eventLimitTracker.size > 0);
4337
5084
  assert.isTrue(cd.eventLimitWarningsLogged.size > 0);
4338
5085
 
@@ -4343,17 +5090,17 @@ describe('internal-plugin-metrics', () => {
4343
5090
  const remainingWarningKeys = Array.from(cd.eventLimitWarningsLogged.keys());
4344
5091
 
4345
5092
  // Should have no keys with correlationId1
4346
- assert.isFalse(remainingTrackerKeys.some(key => key.split(':')[1] === correlationId1));
4347
- assert.isFalse(remainingWarningKeys.some(key => key.split(':')[1] === correlationId1));
5093
+ assert.isFalse(remainingTrackerKeys.some((key) => key.split(':')[1] === correlationId1));
5094
+ assert.isFalse(remainingWarningKeys.some((key) => key.split(':')[1] === correlationId1));
4348
5095
 
4349
5096
  // Should still have keys with correlationId2
4350
- assert.isTrue(remainingTrackerKeys.some(key => key.split(':')[1] === correlationId2));
4351
- assert.isTrue(remainingWarningKeys.some(key => key.split(':')[1] === correlationId2));
5097
+ assert.isTrue(remainingTrackerKeys.some((key) => key.split(':')[1] === correlationId2));
5098
+ assert.isTrue(remainingWarningKeys.some((key) => key.split(':')[1] === correlationId2));
4352
5099
  });
4353
5100
 
4354
5101
  it('should handle empty correlationId gracefully', () => {
4355
- const options = { meetingId: fakeMeeting.id };
4356
- const payload = { mediaType: 'video' as const };
5102
+ const options = {meetingId: fakeMeeting.id};
5103
+ const payload = {mediaType: 'video' as const};
4357
5104
 
4358
5105
  // Set up some tracking data
4359
5106
  cd.submitClientEvent({
@@ -4381,8 +5128,8 @@ describe('internal-plugin-metrics', () => {
4381
5128
  });
4382
5129
 
4383
5130
  it('should handle non-existent correlationId gracefully', () => {
4384
- const options = { meetingId: fakeMeeting.id };
4385
- const payload = { mediaType: 'video' as const };
5131
+ const options = {meetingId: fakeMeeting.id};
5132
+ const payload = {mediaType: 'video' as const};
4386
5133
 
4387
5134
  // Set up some tracking data
4388
5135
  cd.submitClientEvent({
@@ -4403,10 +5150,10 @@ describe('internal-plugin-metrics', () => {
4403
5150
 
4404
5151
  it('should clear multiple event types for the same correlationId', () => {
4405
5152
  const correlationId = fakeMeeting.correlationId;
4406
- const options = { meetingId: fakeMeeting.id };
4407
- const videoPayload = { mediaType: 'video' as const };
4408
- const audioPayload = { mediaType: 'audio' as const };
4409
- const roapPayload = { roap: { messageType: 'OFFER' as const } };
5153
+ const options = {meetingId: fakeMeeting.id};
5154
+ const videoPayload = {mediaType: 'video' as const};
5155
+ const audioPayload = {mediaType: 'audio' as const};
5156
+ const roapPayload = {roap: {messageType: 'OFFER' as const}};
4410
5157
 
4411
5158
  // Set up multiple event types for the same correlation
4412
5159
  cd.submitClientEvent({
@@ -4459,8 +5206,8 @@ describe('internal-plugin-metrics', () => {
4459
5206
 
4460
5207
  it('should allow events to be sent again after clearing limits for correlationId', () => {
4461
5208
  const correlationId = fakeMeeting.correlationId;
4462
- const options = { meetingId: fakeMeeting.id };
4463
- const payload = { mediaType: 'video' as const };
5209
+ const options = {meetingId: fakeMeeting.id};
5210
+ const payload = {mediaType: 'video' as const};
4464
5211
  const submitToCallDiagnosticsStub = sinon.stub(cd, 'submitToCallDiagnostics');
4465
5212
 
4466
5213
  // Send first event (should succeed)