@webex/plugin-meetings 3.0.0-beta.22 → 3.0.0-beta.221

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 (419) hide show
  1. package/README.md +46 -8
  2. package/dist/annotation/annotation.types.js +7 -0
  3. package/dist/annotation/annotation.types.js.map +1 -0
  4. package/dist/annotation/constants.js +49 -0
  5. package/dist/annotation/constants.js.map +1 -0
  6. package/dist/annotation/index.js +342 -0
  7. package/dist/annotation/index.js.map +1 -0
  8. package/dist/breakouts/breakout.js +114 -14
  9. package/dist/breakouts/breakout.js.map +1 -1
  10. package/dist/breakouts/edit-lock-error.js +52 -0
  11. package/dist/breakouts/edit-lock-error.js.map +1 -0
  12. package/dist/breakouts/events.js +45 -0
  13. package/dist/breakouts/events.js.map +1 -0
  14. package/dist/breakouts/index.js +841 -19
  15. package/dist/breakouts/index.js.map +1 -1
  16. package/dist/breakouts/request.js +78 -0
  17. package/dist/breakouts/request.js.map +1 -0
  18. package/dist/breakouts/utils.js +67 -0
  19. package/dist/breakouts/utils.js.map +1 -0
  20. package/dist/common/errors/webex-errors.js +3 -2
  21. package/dist/common/errors/webex-errors.js.map +1 -1
  22. package/dist/common/logs/logger-proxy.js +1 -1
  23. package/dist/common/logs/logger-proxy.js.map +1 -1
  24. package/dist/common/queue.js +24 -9
  25. package/dist/common/queue.js.map +1 -1
  26. package/dist/config.js +3 -8
  27. package/dist/config.js.map +1 -1
  28. package/dist/constants.js +188 -30
  29. package/dist/constants.js.map +1 -1
  30. package/dist/controls-options-manager/constants.js +14 -0
  31. package/dist/controls-options-manager/constants.js.map +1 -0
  32. package/dist/controls-options-manager/enums.js +27 -0
  33. package/dist/controls-options-manager/enums.js.map +1 -0
  34. package/dist/controls-options-manager/index.js +297 -0
  35. package/dist/controls-options-manager/index.js.map +1 -0
  36. package/dist/controls-options-manager/types.js +7 -0
  37. package/dist/controls-options-manager/types.js.map +1 -0
  38. package/dist/controls-options-manager/util.js +319 -0
  39. package/dist/controls-options-manager/util.js.map +1 -0
  40. package/dist/index.js +106 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/interpretation/collection.js +23 -0
  43. package/dist/interpretation/collection.js.map +1 -0
  44. package/dist/interpretation/index.js +366 -0
  45. package/dist/interpretation/index.js.map +1 -0
  46. package/dist/interpretation/siLanguage.js +25 -0
  47. package/dist/interpretation/siLanguage.js.map +1 -0
  48. package/dist/locus-info/controlsUtils.js +91 -2
  49. package/dist/locus-info/controlsUtils.js.map +1 -1
  50. package/dist/locus-info/index.js +357 -62
  51. package/dist/locus-info/index.js.map +1 -1
  52. package/dist/locus-info/infoUtils.js +7 -1
  53. package/dist/locus-info/infoUtils.js.map +1 -1
  54. package/dist/locus-info/mediaSharesUtils.js +43 -1
  55. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  56. package/dist/locus-info/parser.js +219 -63
  57. package/dist/locus-info/parser.js.map +1 -1
  58. package/dist/locus-info/selfUtils.js +89 -14
  59. package/dist/locus-info/selfUtils.js.map +1 -1
  60. package/dist/media/index.js +49 -106
  61. package/dist/media/index.js.map +1 -1
  62. package/dist/media/properties.js +29 -90
  63. package/dist/media/properties.js.map +1 -1
  64. package/dist/mediaQualityMetrics/config.js +505 -493
  65. package/dist/mediaQualityMetrics/config.js.map +1 -1
  66. package/dist/meeting/in-meeting-actions.js +90 -2
  67. package/dist/meeting/in-meeting-actions.js.map +1 -1
  68. package/dist/meeting/index.js +2587 -2560
  69. package/dist/meeting/index.js.map +1 -1
  70. package/dist/meeting/locusMediaRequest.js +292 -0
  71. package/dist/meeting/locusMediaRequest.js.map +1 -0
  72. package/dist/meeting/muteState.js +228 -123
  73. package/dist/meeting/muteState.js.map +1 -1
  74. package/dist/meeting/request.js +244 -194
  75. package/dist/meeting/request.js.map +1 -1
  76. package/dist/meeting/util.js +568 -414
  77. package/dist/meeting/util.js.map +1 -1
  78. package/dist/meeting-info/index.js +48 -7
  79. package/dist/meeting-info/index.js.map +1 -1
  80. package/dist/meeting-info/meeting-info-v2.js +171 -51
  81. package/dist/meeting-info/meeting-info-v2.js.map +1 -1
  82. package/dist/meeting-info/utilv2.js +20 -5
  83. package/dist/meeting-info/utilv2.js.map +1 -1
  84. package/dist/meetings/collection.js +22 -0
  85. package/dist/meetings/collection.js.map +1 -1
  86. package/dist/meetings/index.js +361 -84
  87. package/dist/meetings/index.js.map +1 -1
  88. package/dist/meetings/meetings.types.js +7 -0
  89. package/dist/meetings/meetings.types.js.map +1 -0
  90. package/dist/meetings/request.js +2 -0
  91. package/dist/meetings/request.js.map +1 -1
  92. package/dist/meetings/util.js +88 -1
  93. package/dist/meetings/util.js.map +1 -1
  94. package/dist/member/index.js +49 -0
  95. package/dist/member/index.js.map +1 -1
  96. package/dist/member/types.js +25 -0
  97. package/dist/member/types.js.map +1 -0
  98. package/dist/member/util.js +121 -25
  99. package/dist/member/util.js.map +1 -1
  100. package/dist/members/collection.js +10 -0
  101. package/dist/members/collection.js.map +1 -1
  102. package/dist/members/index.js +86 -5
  103. package/dist/members/index.js.map +1 -1
  104. package/dist/members/request.js +106 -38
  105. package/dist/members/request.js.map +1 -1
  106. package/dist/members/types.js +15 -0
  107. package/dist/members/types.js.map +1 -0
  108. package/dist/members/util.js +316 -233
  109. package/dist/members/util.js.map +1 -1
  110. package/dist/metrics/constants.js +3 -5
  111. package/dist/metrics/constants.js.map +1 -1
  112. package/dist/metrics/index.js +1 -468
  113. package/dist/metrics/index.js.map +1 -1
  114. package/dist/multistream/mediaRequestManager.js +238 -49
  115. package/dist/multistream/mediaRequestManager.js.map +1 -1
  116. package/dist/multistream/receiveSlot.js +49 -16
  117. package/dist/multistream/receiveSlot.js.map +1 -1
  118. package/dist/multistream/receiveSlotManager.js +52 -34
  119. package/dist/multistream/receiveSlotManager.js.map +1 -1
  120. package/dist/multistream/remoteMedia.js +44 -18
  121. package/dist/multistream/remoteMedia.js.map +1 -1
  122. package/dist/multistream/remoteMediaGroup.js +60 -3
  123. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  124. package/dist/multistream/remoteMediaManager.js +173 -59
  125. package/dist/multistream/remoteMediaManager.js.map +1 -1
  126. package/dist/networkQualityMonitor/index.js +4 -2
  127. package/dist/networkQualityMonitor/index.js.map +1 -1
  128. package/dist/reachability/index.js +90 -30
  129. package/dist/reachability/index.js.map +1 -1
  130. package/dist/reachability/request.js +16 -7
  131. package/dist/reachability/request.js.map +1 -1
  132. package/dist/reconnection-manager/index.js +196 -155
  133. package/dist/reconnection-manager/index.js.map +1 -1
  134. package/dist/recording-controller/index.js +21 -2
  135. package/dist/recording-controller/index.js.map +1 -1
  136. package/dist/recording-controller/util.js +9 -8
  137. package/dist/recording-controller/util.js.map +1 -1
  138. package/dist/roap/index.js +25 -29
  139. package/dist/roap/index.js.map +1 -1
  140. package/dist/roap/request.js +111 -89
  141. package/dist/roap/request.js.map +1 -1
  142. package/dist/roap/turnDiscovery.js +97 -36
  143. package/dist/roap/turnDiscovery.js.map +1 -1
  144. package/dist/rtcMetrics/constants.js +12 -0
  145. package/dist/rtcMetrics/constants.js.map +1 -0
  146. package/dist/rtcMetrics/index.js +117 -0
  147. package/dist/rtcMetrics/index.js.map +1 -0
  148. package/dist/statsAnalyzer/global.js +1 -93
  149. package/dist/statsAnalyzer/global.js.map +1 -1
  150. package/dist/statsAnalyzer/index.js +326 -311
  151. package/dist/statsAnalyzer/index.js.map +1 -1
  152. package/dist/statsAnalyzer/mqaUtil.js +90 -53
  153. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  154. package/dist/types/annotation/annotation.types.d.ts +42 -0
  155. package/dist/types/annotation/constants.d.ts +31 -0
  156. package/dist/types/annotation/index.d.ts +117 -0
  157. package/dist/types/breakouts/breakout.d.ts +8 -0
  158. package/dist/types/breakouts/collection.d.ts +5 -0
  159. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  160. package/dist/types/breakouts/events.d.ts +8 -0
  161. package/dist/types/breakouts/index.d.ts +5 -0
  162. package/dist/types/breakouts/request.d.ts +22 -0
  163. package/dist/types/breakouts/utils.d.ts +15 -0
  164. package/dist/types/common/browser-detection.d.ts +9 -0
  165. package/dist/types/common/collection.d.ts +48 -0
  166. package/dist/types/common/config.d.ts +2 -0
  167. package/dist/types/common/errors/captcha-error.d.ts +15 -0
  168. package/dist/types/common/errors/intent-to-join.d.ts +16 -0
  169. package/dist/types/common/errors/join-meeting.d.ts +17 -0
  170. package/dist/types/common/errors/media.d.ts +15 -0
  171. package/dist/types/common/errors/parameter.d.ts +15 -0
  172. package/dist/types/common/errors/password-error.d.ts +15 -0
  173. package/dist/types/common/errors/permission.d.ts +14 -0
  174. package/dist/types/common/errors/reconnection-in-progress.d.ts +9 -0
  175. package/dist/types/common/errors/reconnection.d.ts +15 -0
  176. package/dist/types/common/errors/stats.d.ts +15 -0
  177. package/dist/types/common/errors/webex-errors.d.ts +69 -0
  178. package/dist/types/common/errors/webex-meetings-error.d.ts +20 -0
  179. package/dist/types/common/events/events-scope.d.ts +17 -0
  180. package/dist/types/common/events/events.d.ts +12 -0
  181. package/dist/types/common/events/trigger-proxy.d.ts +2 -0
  182. package/dist/types/common/events/util.d.ts +2 -0
  183. package/dist/types/common/logs/logger-config.d.ts +2 -0
  184. package/dist/types/common/logs/logger-proxy.d.ts +2 -0
  185. package/dist/types/common/logs/request.d.ts +34 -0
  186. package/dist/types/common/queue.d.ts +34 -0
  187. package/dist/types/config.d.ts +72 -0
  188. package/dist/types/constants.d.ts +1028 -0
  189. package/dist/types/controls-options-manager/constants.d.ts +4 -0
  190. package/dist/types/controls-options-manager/enums.d.ts +15 -0
  191. package/dist/types/controls-options-manager/index.d.ts +136 -0
  192. package/dist/types/controls-options-manager/types.d.ts +43 -0
  193. package/dist/types/controls-options-manager/util.d.ts +1 -0
  194. package/dist/types/index.d.ts +7 -0
  195. package/dist/types/interpretation/collection.d.ts +5 -0
  196. package/dist/types/interpretation/index.d.ts +5 -0
  197. package/dist/types/interpretation/siLanguage.d.ts +5 -0
  198. package/dist/types/locus-info/controlsUtils.d.ts +2 -0
  199. package/dist/types/locus-info/embeddedAppsUtils.d.ts +2 -0
  200. package/dist/types/locus-info/fullState.d.ts +2 -0
  201. package/dist/types/locus-info/hostUtils.d.ts +2 -0
  202. package/dist/types/locus-info/index.d.ts +322 -0
  203. package/dist/types/locus-info/infoUtils.d.ts +2 -0
  204. package/dist/types/locus-info/mediaSharesUtils.d.ts +2 -0
  205. package/dist/types/locus-info/parser.d.ts +271 -0
  206. package/dist/types/locus-info/selfUtils.d.ts +2 -0
  207. package/dist/types/media/index.d.ts +34 -0
  208. package/dist/types/media/properties.d.ts +93 -0
  209. package/dist/types/media/util.d.ts +2 -0
  210. package/dist/types/mediaQualityMetrics/config.d.ts +365 -0
  211. package/dist/types/meeting/in-meeting-actions.d.ts +163 -0
  212. package/dist/types/meeting/index.d.ts +1512 -0
  213. package/dist/types/meeting/locusMediaRequest.d.ts +75 -0
  214. package/dist/types/meeting/muteState.d.ts +184 -0
  215. package/dist/types/meeting/request.d.ts +289 -0
  216. package/dist/types/meeting/request.type.d.ts +11 -0
  217. package/dist/types/meeting/state.d.ts +9 -0
  218. package/dist/types/meeting/util.d.ts +94 -0
  219. package/dist/types/meeting-info/collection.d.ts +20 -0
  220. package/dist/types/meeting-info/index.d.ts +62 -0
  221. package/dist/types/meeting-info/meeting-info-v2.d.ts +122 -0
  222. package/dist/types/meeting-info/request.d.ts +22 -0
  223. package/dist/types/meeting-info/util.d.ts +2 -0
  224. package/dist/types/meeting-info/utilv2.d.ts +2 -0
  225. package/dist/types/meetings/collection.d.ts +31 -0
  226. package/dist/types/meetings/index.d.ts +361 -0
  227. package/dist/types/meetings/meetings.types.d.ts +4 -0
  228. package/dist/types/meetings/request.d.ts +27 -0
  229. package/dist/types/meetings/util.d.ts +18 -0
  230. package/dist/types/member/index.d.ts +159 -0
  231. package/dist/types/member/types.d.ts +32 -0
  232. package/dist/types/member/util.d.ts +2 -0
  233. package/dist/types/members/collection.d.ts +29 -0
  234. package/dist/types/members/index.d.ts +353 -0
  235. package/dist/types/members/request.d.ts +114 -0
  236. package/dist/types/members/types.d.ts +24 -0
  237. package/dist/types/members/util.d.ts +210 -0
  238. package/dist/types/metrics/constants.d.ts +55 -0
  239. package/dist/types/metrics/index.d.ts +45 -0
  240. package/dist/types/multistream/mediaRequestManager.d.ts +118 -0
  241. package/dist/types/multistream/receiveSlot.d.ts +68 -0
  242. package/dist/types/multistream/receiveSlotManager.d.ts +56 -0
  243. package/dist/types/multistream/remoteMedia.d.ts +72 -0
  244. package/dist/types/multistream/remoteMediaGroup.d.ts +47 -0
  245. package/dist/types/multistream/remoteMediaManager.d.ts +277 -0
  246. package/dist/types/networkQualityMonitor/index.d.ts +70 -0
  247. package/dist/types/personal-meeting-room/index.d.ts +47 -0
  248. package/dist/types/personal-meeting-room/request.d.ts +14 -0
  249. package/dist/types/personal-meeting-room/util.d.ts +2 -0
  250. package/dist/types/reachability/index.d.ts +158 -0
  251. package/dist/types/reachability/request.d.ts +39 -0
  252. package/dist/types/reactions/constants.d.ts +3 -0
  253. package/dist/types/reactions/reactions.d.ts +4 -0
  254. package/dist/types/reactions/reactions.type.d.ts +52 -0
  255. package/dist/types/reconnection-manager/index.d.ts +126 -0
  256. package/dist/types/recording-controller/enums.d.ts +7 -0
  257. package/dist/types/recording-controller/index.d.ts +207 -0
  258. package/dist/types/recording-controller/util.d.ts +14 -0
  259. package/dist/types/roap/index.d.ts +77 -0
  260. package/dist/types/roap/request.d.ts +38 -0
  261. package/dist/types/roap/turnDiscovery.d.ts +91 -0
  262. package/dist/types/rtcMetrics/constants.d.ts +4 -0
  263. package/dist/types/rtcMetrics/index.d.ts +47 -0
  264. package/dist/types/statsAnalyzer/global.d.ts +36 -0
  265. package/dist/types/statsAnalyzer/index.d.ts +200 -0
  266. package/dist/types/statsAnalyzer/mqaUtil.d.ts +24 -0
  267. package/dist/types/transcription/index.d.ts +64 -0
  268. package/package.json +23 -20
  269. package/src/annotation/annotation.types.ts +50 -0
  270. package/src/annotation/constants.ts +36 -0
  271. package/src/annotation/index.ts +328 -0
  272. package/src/breakouts/README.md +44 -14
  273. package/src/breakouts/breakout.ts +87 -9
  274. package/src/breakouts/edit-lock-error.ts +25 -0
  275. package/src/breakouts/events.ts +56 -0
  276. package/src/breakouts/index.ts +710 -10
  277. package/src/breakouts/request.ts +55 -0
  278. package/src/breakouts/utils.ts +57 -0
  279. package/src/common/errors/webex-errors.ts +6 -2
  280. package/src/common/logs/logger-proxy.ts +1 -1
  281. package/src/common/queue.ts +22 -8
  282. package/src/config.ts +2 -7
  283. package/src/constants.ts +175 -21
  284. package/src/controls-options-manager/constants.ts +5 -0
  285. package/src/controls-options-manager/enums.ts +18 -0
  286. package/src/controls-options-manager/index.ts +278 -0
  287. package/src/controls-options-manager/types.ts +59 -0
  288. package/src/controls-options-manager/util.ts +300 -0
  289. package/src/index.ts +39 -0
  290. package/src/interpretation/README.md +60 -0
  291. package/src/interpretation/collection.ts +19 -0
  292. package/src/interpretation/index.ts +332 -0
  293. package/src/interpretation/siLanguage.ts +18 -0
  294. package/src/locus-info/controlsUtils.ts +108 -0
  295. package/src/locus-info/index.ts +381 -59
  296. package/src/locus-info/infoUtils.ts +10 -2
  297. package/src/locus-info/mediaSharesUtils.ts +48 -0
  298. package/src/locus-info/parser.ts +224 -39
  299. package/src/locus-info/selfUtils.ts +81 -5
  300. package/src/media/index.ts +89 -109
  301. package/src/media/properties.ts +49 -90
  302. package/src/mediaQualityMetrics/config.ts +379 -377
  303. package/src/meeting/in-meeting-actions.ts +179 -3
  304. package/src/meeting/index.ts +2062 -2137
  305. package/src/meeting/locusMediaRequest.ts +314 -0
  306. package/src/meeting/muteState.ts +227 -130
  307. package/src/meeting/request.ts +157 -116
  308. package/src/meeting/util.ts +555 -396
  309. package/src/meeting-info/index.ts +54 -8
  310. package/src/meeting-info/meeting-info-v2.ts +148 -14
  311. package/src/meeting-info/utilv2.ts +13 -3
  312. package/src/meetings/collection.ts +20 -0
  313. package/src/meetings/index.ts +397 -102
  314. package/src/meetings/meetings.types.ts +12 -0
  315. package/src/meetings/request.ts +2 -0
  316. package/src/meetings/util.ts +103 -4
  317. package/src/member/index.ts +49 -0
  318. package/src/member/types.ts +38 -0
  319. package/src/member/util.ts +127 -25
  320. package/src/members/collection.ts +8 -0
  321. package/src/members/index.ts +107 -6
  322. package/src/members/request.ts +97 -17
  323. package/src/members/types.ts +28 -0
  324. package/src/members/util.ts +319 -240
  325. package/src/metrics/constants.ts +2 -4
  326. package/src/metrics/index.ts +1 -490
  327. package/src/multistream/mediaRequestManager.ts +289 -79
  328. package/src/multistream/receiveSlot.ts +55 -18
  329. package/src/multistream/receiveSlotManager.ts +46 -24
  330. package/src/multistream/remoteMedia.ts +27 -2
  331. package/src/multistream/remoteMediaGroup.ts +59 -0
  332. package/src/multistream/remoteMediaManager.ts +113 -32
  333. package/src/networkQualityMonitor/index.ts +6 -6
  334. package/src/reachability/index.ts +76 -18
  335. package/src/reachability/request.ts +16 -7
  336. package/src/reconnection-manager/index.ts +68 -43
  337. package/src/recording-controller/index.ts +20 -3
  338. package/src/recording-controller/util.ts +26 -9
  339. package/src/roap/index.ts +25 -30
  340. package/src/roap/request.ts +103 -95
  341. package/src/roap/turnDiscovery.ts +51 -25
  342. package/src/rtcMetrics/constants.ts +3 -0
  343. package/src/rtcMetrics/index.ts +100 -0
  344. package/src/statsAnalyzer/global.ts +1 -94
  345. package/src/statsAnalyzer/index.ts +376 -386
  346. package/src/statsAnalyzer/mqaUtil.ts +100 -99
  347. package/test/integration/spec/converged-space-meetings.js +233 -0
  348. package/test/integration/spec/journey.js +336 -259
  349. package/test/integration/spec/space-meeting.js +77 -4
  350. package/test/unit/spec/annotation/index.ts +418 -0
  351. package/test/unit/spec/breakouts/breakout.ts +142 -24
  352. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  353. package/test/unit/spec/breakouts/events.ts +89 -0
  354. package/test/unit/spec/breakouts/index.ts +1545 -48
  355. package/test/unit/spec/breakouts/request.ts +104 -0
  356. package/test/unit/spec/breakouts/utils.js +72 -0
  357. package/test/unit/spec/common/queue.js +31 -2
  358. package/test/unit/spec/controls-options-manager/index.js +287 -0
  359. package/test/unit/spec/controls-options-manager/util.js +582 -0
  360. package/test/unit/spec/fixture/locus.js +1 -0
  361. package/test/unit/spec/interpretation/collection.ts +15 -0
  362. package/test/unit/spec/interpretation/index.ts +589 -0
  363. package/test/unit/spec/interpretation/siLanguage.ts +28 -0
  364. package/test/unit/spec/locus-info/controlsUtils.js +316 -43
  365. package/test/unit/spec/locus-info/index.js +1169 -36
  366. package/test/unit/spec/locus-info/infoUtils.js +37 -15
  367. package/test/unit/spec/locus-info/mediaSharesUtils.ts +22 -0
  368. package/test/unit/spec/locus-info/parser.js +62 -22
  369. package/test/unit/spec/locus-info/selfConstant.js +27 -4
  370. package/test/unit/spec/locus-info/selfUtils.js +208 -17
  371. package/test/unit/spec/media/index.ts +138 -28
  372. package/test/unit/spec/meeting/in-meeting-actions.ts +89 -3
  373. package/test/unit/spec/meeting/index.js +3510 -1747
  374. package/test/unit/spec/meeting/locusMediaRequest.ts +443 -0
  375. package/test/unit/spec/meeting/muteState.js +370 -208
  376. package/test/unit/spec/meeting/request.js +417 -45
  377. package/test/unit/spec/meeting/utils.js +601 -53
  378. package/test/unit/spec/meeting-info/index.js +181 -0
  379. package/test/unit/spec/meeting-info/meetinginfov2.js +383 -5
  380. package/test/unit/spec/meeting-info/utilv2.js +21 -0
  381. package/test/unit/spec/meetings/collection.js +14 -0
  382. package/test/unit/spec/meetings/index.js +874 -150
  383. package/test/unit/spec/meetings/utils.js +206 -2
  384. package/test/unit/spec/member/index.js +58 -4
  385. package/test/unit/spec/member/util.js +479 -35
  386. package/test/unit/spec/members/index.js +319 -1
  387. package/test/unit/spec/members/request.js +206 -27
  388. package/test/unit/spec/members/utils.js +184 -0
  389. package/test/unit/spec/metrics/index.js +1 -50
  390. package/test/unit/spec/multistream/mediaRequestManager.ts +803 -162
  391. package/test/unit/spec/multistream/receiveSlot.ts +72 -13
  392. package/test/unit/spec/multistream/receiveSlotManager.ts +58 -28
  393. package/test/unit/spec/multistream/remoteMedia.ts +30 -0
  394. package/test/unit/spec/multistream/remoteMediaGroup.ts +266 -0
  395. package/test/unit/spec/multistream/remoteMediaManager.ts +318 -0
  396. package/test/unit/spec/networkQualityMonitor/index.js +4 -4
  397. package/test/unit/spec/reachability/index.ts +185 -7
  398. package/test/unit/spec/reachability/request.js +68 -0
  399. package/test/unit/spec/reconnection-manager/index.js +59 -6
  400. package/test/unit/spec/recording-controller/index.js +294 -218
  401. package/test/unit/spec/recording-controller/util.js +223 -96
  402. package/test/unit/spec/roap/index.ts +27 -51
  403. package/test/unit/spec/roap/request.ts +202 -85
  404. package/test/unit/spec/roap/turnDiscovery.ts +36 -8
  405. package/test/unit/spec/rtcMetrics/index.ts +68 -0
  406. package/test/unit/spec/stats-analyzer/index.js +92 -41
  407. package/test/utils/constants.js +9 -0
  408. package/test/utils/integrationTestUtils.js +46 -0
  409. package/test/utils/testUtils.js +0 -45
  410. package/test/utils/webex-config.js +4 -0
  411. package/test/utils/webex-test-users.js +6 -3
  412. package/dist/meeting/effectsState.js +0 -262
  413. package/dist/meeting/effectsState.js.map +0 -1
  414. package/dist/metrics/config.js +0 -299
  415. package/dist/metrics/config.js.map +0 -1
  416. package/src/index.js +0 -16
  417. package/src/meeting/effectsState.ts +0 -211
  418. package/src/metrics/config.ts +0 -495
  419. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -11,6 +11,7 @@ import sinon from 'sinon';
11
11
  import uuid from 'uuid';
12
12
  import StaticConfig from '@webex/plugin-meetings/src/common/config';
13
13
  import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
14
+ import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
14
15
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
15
16
  import Meeting from '@webex/plugin-meetings/src/meeting';
16
17
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
@@ -29,6 +30,11 @@ import {
29
30
  LOCUSINFO,
30
31
  EVENT_TRIGGERS,
31
32
  } from '../../../../src/constants';
33
+ import CaptchaError from '@webex/plugin-meetings/src/common/errors/captcha-error';
34
+ import { forEach } from 'lodash';
35
+ import PasswordError from '@webex/plugin-meetings/src/common/errors/password-error';
36
+ import PermissionError from '@webex/plugin-meetings/src/common/errors/permission';
37
+ import {NoiseReductionEffect,VirtualBackgroundEffect} from '@webex/media-helpers';
32
38
 
33
39
  describe('plugin-meetings', () => {
34
40
  const logger = {
@@ -51,7 +57,7 @@ describe('plugin-meetings', () => {
51
57
  verboseEvents: true,
52
58
  enable: false,
53
59
  });
54
- TriggerProxy.trigger = sinon.stub().returns(true);
60
+ sinon.stub(TriggerProxy, 'trigger').returns(true);
55
61
  });
56
62
 
57
63
  let webex;
@@ -60,15 +66,20 @@ describe('plugin-meetings', () => {
60
66
  let url1;
61
67
  let test1;
62
68
  let test2;
69
+ let locusInfo;
63
70
 
64
71
  describe('meetings index', () => {
65
72
  beforeEach(() => {
66
73
  MeetingsUtil.checkH264Support = sinon.stub();
67
- uuid1 = uuid.v4();
74
+ uuid1 = uuid.v4();
68
75
  url1 = `https://example.com/${uuid.v4()}`;
69
76
  uri1 = `test-${uuid.v4()}@example.com`;
70
77
  test1 = `test-${uuid.v4()}`;
71
78
  test2 = `test2-${uuid.v4()}`;
79
+ locusInfo = {
80
+ parse: sinon.stub().returns(true),
81
+ updateMainSessionLocusCache: sinon.stub(),
82
+ };
72
83
  webex = new MockWebex({
73
84
  children: {
74
85
  device: Device,
@@ -151,6 +162,10 @@ describe('plugin-meetings', () => {
151
162
  webex.emit('ready');
152
163
  });
153
164
 
165
+ afterEach(() => {
166
+ sinon.restore();
167
+ });
168
+
154
169
  it('has a webex instance with a meetings property', () => {
155
170
  assert.exists(webex, 'webex was initialized with children');
156
171
  assert.exists(webex.meetings, 'meetings child was set up on the webex instance');
@@ -338,37 +353,113 @@ describe('plugin-meetings', () => {
338
353
  });
339
354
  });
340
355
 
356
+ describe('virtual background effect', () => {
357
+ beforeEach(() => {
358
+ webex.credentials = {
359
+ supertoken: {
360
+ access_token: "fake_token"
361
+ }
362
+ };
363
+ })
364
+
365
+ it('creates background effect', async () => {
366
+ const result = await webex.meetings.createVirtualBackgroundEffect();
367
+
368
+ assert.exists(result);
369
+ assert.instanceOf(result, VirtualBackgroundEffect);
370
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
371
+ assert.deepEqual(result.options, {
372
+ mode: 'BLUR',
373
+ blurStrength: 'STRONG',
374
+ generator: 'worker',
375
+ quality: 'LOW',
376
+ authToken: 'fake_token',
377
+ mirror: false
378
+ });
379
+ assert.exists(result.enable);
380
+ assert.exists(result.disable);
381
+ assert.exists(result.dispose);
382
+ });
383
+
384
+ it('creates background effect with custom options passed', async () => {
385
+ const effectOptions = {
386
+ generator: "local",
387
+ frameRate: 45,
388
+ mode: "IMAGE",
389
+ mirror: false,
390
+ quality: "HIGH",
391
+ blurStrength: "STRONG",
392
+ bgImageUrl: "https://test.webex.com/landscape.5a535788.jpg",
393
+ };
394
+
395
+ const result = await webex.meetings.createVirtualBackgroundEffect(effectOptions);
396
+
397
+ assert.exists(result);
398
+ assert.instanceOf(result, VirtualBackgroundEffect);
399
+ assert.containsAllKeys(result, ['loadModel', 'isEnabled', 'isLoaded', 'options']);
400
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
401
+ assert.exists(result.enable);
402
+ assert.exists(result.disable);
403
+ assert.exists(result.dispose);
404
+ });
405
+ })
406
+
407
+ describe('noise reduction effect', () => {
408
+ beforeEach(() => {
409
+ webex.credentials = {
410
+ supertoken: {
411
+ access_token: "fake_token"
412
+ }
413
+ };
414
+ })
415
+
416
+ it('creates noise reduction effect', async () => {
417
+ const result = await webex.meetings.createNoiseReductionEffect({audioContext: {}});
418
+
419
+ assert.exists(result);
420
+ assert.instanceOf(result, NoiseReductionEffect);
421
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
422
+ assert.deepEqual(result.options, {
423
+ authToken: 'fake_token',
424
+ audioContext: {}
425
+ });
426
+ assert.exists(result.enable);
427
+ assert.exists(result.disable);
428
+ assert.exists(result.dispose);
429
+ });
430
+
431
+ it('creates noise reduction effect with custom options passed', async () => {
432
+ const effectOptions = {
433
+ audioContext: {},
434
+ mode: "WORKLET",
435
+ env: "prod"
436
+ };
437
+
438
+ const result = await webex.meetings.createNoiseReductionEffect(effectOptions);
439
+
440
+ assert.exists(result);
441
+ assert.instanceOf(result, NoiseReductionEffect);
442
+ assert.containsAllKeys(result, ['audioContext', 'isEnabled', 'isReady', 'options']);
443
+ assert.deepEqual(result.options, {...effectOptions, authToken: "fake_token"});
444
+ assert.exists(result.enable);
445
+ assert.exists(result.disable);
446
+ assert.exists(result.dispose);
447
+ });
448
+ })
449
+
341
450
  describe('gets', () => {
342
451
  describe('#getReachability', () => {
343
452
  it('should have #getReachability', () => {
344
453
  assert.exists(webex.meetings.getReachability);
345
454
  });
346
- describe('before #setReachability', () => {
347
- it('does not get a reachability instance', () => {
348
- const reachability = webex.meetings.getReachability();
455
+ it('gets the reachability data instance from webex.meetings', () => {
456
+ const reachability = webex.meetings.getReachability();
349
457
 
350
- assert.notExists(
351
- reachability,
352
- 'reachability is undefined because #setReachability has not been called'
353
- );
354
- });
355
- });
356
- describe('after #setReachability', () => {
357
- beforeEach(() => {
358
- webex.meetings.setReachability();
359
- const reachabilityMocker = webex.meetings.getReachability();
360
-
361
- sinon.stub(reachabilityMocker, 'gatherReachability').returns(true);
362
- });
363
- it('gets the reachability data instance from webex.meetings', () => {
364
- const reachability = webex.meetings.getReachability();
365
-
366
- assert.exists(
367
- reachability,
368
- 'reachability is defined because #setReachability has been called'
369
- );
370
- assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
371
- });
458
+ assert.exists(
459
+ reachability,
460
+ 'reachability is defined'
461
+ );
462
+ assert.instanceOf(reachability, Reachability, 'should be a reachability instance');
372
463
  });
373
464
  });
374
465
  describe('#getPersonalMeetingRoom', () => {
@@ -443,21 +534,17 @@ describe('plugin-meetings', () => {
443
534
  );
444
535
  });
445
536
  describe('when meeting is returned', () => {
446
- let parse;
447
537
 
448
538
  beforeEach(() => {
449
- parse = sinon.stub().returns(true);
450
539
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
451
- locusInfo: {
452
- parse,
453
- },
540
+ locusInfo,
454
541
  });
455
542
  });
456
543
  it('tests the sync meeting calls for existing meeting', async () => {
457
544
  await webex.meetings.syncMeetings();
458
545
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
459
546
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
460
- assert.calledOnce(parse);
547
+ assert.calledOnce(locusInfo.parse);
461
548
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
462
549
  });
463
550
  });
@@ -470,6 +557,7 @@ describe('plugin-meetings', () => {
470
557
  webex.meetings.create = sinon.stub().returns(
471
558
  Promise.resolve({
472
559
  locusInfo: {
560
+ ...locusInfo,
473
561
  initialSetup,
474
562
  },
475
563
  })
@@ -478,7 +566,7 @@ describe('plugin-meetings', () => {
478
566
  it('tests the sync meeting calls for not existing meeting', async () => {
479
567
  await webex.meetings.syncMeetings();
480
568
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
481
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
569
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
482
570
  assert.calledOnce(initialSetup);
483
571
  assert.calledOnce(webex.meetings.create);
484
572
  assert.calledWith(webex.meetings.request.getActiveMeetings);
@@ -502,12 +590,9 @@ describe('plugin-meetings', () => {
502
590
 
503
591
  beforeEach(() => {
504
592
  destroySpy = sinon.spy(webex.meetings, 'destroy');
505
- parse = sinon.stub().returns(true);
506
593
  initialSetup = sinon.stub().returns(true);
507
594
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
508
- locusInfo: {
509
- parse,
510
- },
595
+ locusInfo,
511
596
  sendCallAnalyzerMetrics: sinon.stub(),
512
597
  });
513
598
  webex.meetings.meetingCollection.getAll = sinon.stub().returns({
@@ -576,12 +661,26 @@ describe('plugin-meetings', () => {
576
661
 
577
662
  it('calls createMeeting and returns its promise', async () => {
578
663
  const FAKE_USE_RANDOM_DELAY = true;
579
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY);
664
+ const correlationId = 'my-correlationId';
665
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
580
666
 
581
667
  assert.exists(create.then);
582
668
  await create;
583
669
  assert.calledOnce(webex.meetings.createMeeting);
584
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
670
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
671
+ });
672
+
673
+ it('calls createMeeting with extra info params and returns its promise', async () => {
674
+ const FAKE_USE_RANDOM_DELAY = false;
675
+ const correlationId = 'my-correlationId';
676
+
677
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
678
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
679
+
680
+ assert.exists(create.then);
681
+ await create;
682
+ assert.calledOnce(webex.meetings.createMeeting);
683
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
585
684
  });
586
685
 
587
686
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -677,45 +776,52 @@ describe('plugin-meetings', () => {
677
776
  });
678
777
  describe('#handleLocusEvent', () => {
679
778
  describe('there was a meeting', () => {
680
- let parse;
681
779
 
682
780
  beforeEach(() => {
683
- parse = sinon.stub().returns(true);
684
781
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
685
- locusInfo: {
686
- parse,
687
- },
782
+ locusInfo,
688
783
  });
689
784
  });
690
- it('should parse the meeting info', () => {
785
+ it('should parse the meeting info and update main session locus cache', () => {
786
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(false);
691
787
  webex.meetings.handleLocusEvent({
692
788
  locusUrl: url1,
693
789
  });
694
790
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
695
791
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
696
- assert.calledOnce(parse);
792
+ assert.calledOnce(locusInfo.parse);
793
+ assert.calledOnce(locusInfo.updateMainSessionLocusCache);
697
794
  assert.calledWith(
698
- parse,
795
+ locusInfo.parse,
699
796
  {
700
- locusInfo: {
701
- parse,
702
- },
797
+ locusInfo,
703
798
  },
704
799
  {
705
800
  locusUrl: url1,
706
801
  }
707
802
  );
708
803
  });
804
+
805
+ it('should not update main session locus cache', () => {
806
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(true);
807
+ webex.meetings.handleLocusEvent({
808
+ locusUrl: url1,
809
+ });
810
+ assert.notCalled(locusInfo.updateMainSessionLocusCache);
811
+ });
709
812
  });
710
813
  describe('there was not a meeting', () => {
711
814
  let initialSetup;
815
+ const webExMeetingId = '123456';
712
816
 
713
817
  beforeEach(() => {
714
818
  initialSetup = sinon.stub().returns(true);
715
819
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
716
820
  webex.meetings.create = sinon.stub().returns(
717
821
  Promise.resolve({
822
+ id: 'meeting-id',
718
823
  locusInfo: {
824
+ ...locusInfo,
719
825
  initialSetup,
720
826
  },
721
827
  })
@@ -735,12 +841,16 @@ describe('plugin-meetings', () => {
735
841
  callbackAddress: uri1,
736
842
  },
737
843
  },
844
+ info: {
845
+ webExMeetingId
846
+ },
738
847
  },
739
848
  eventType: 'locus.difference',
740
849
  locusUrl: url1,
741
850
  });
742
- assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
851
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 6);
743
852
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
853
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
744
854
  assert.calledOnce(initialSetup);
745
855
  assert.calledWith(initialSetup, {
746
856
  id: uuid1,
@@ -754,6 +864,9 @@ describe('plugin-meetings', () => {
754
864
  callbackAddress: uri1,
755
865
  },
756
866
  },
867
+ info: {
868
+ webExMeetingId
869
+ },
757
870
  });
758
871
  });
759
872
  it('should setup the meeting by difference event without replaces', async () => {
@@ -765,12 +878,16 @@ describe('plugin-meetings', () => {
765
878
  callbackAddress: uri1,
766
879
  },
767
880
  },
881
+ info: {
882
+ webExMeetingId
883
+ },
768
884
  },
769
885
  eventType: 'locus.difference',
770
886
  locusUrl: url1,
771
887
  });
772
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
888
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
773
889
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
890
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
774
891
  assert.calledOnce(initialSetup);
775
892
  assert.calledWith(initialSetup, {
776
893
  id: uuid1,
@@ -779,8 +896,44 @@ describe('plugin-meetings', () => {
779
896
  callbackAddress: uri1,
780
897
  },
781
898
  },
899
+ info: {
900
+ webExMeetingId
901
+ },
782
902
  });
783
903
  });
904
+
905
+ it('sends client event correctly on finally', async () => {
906
+ webex.meetings.getMeetingByType = sinon.stub().returns(true);
907
+
908
+ await webex.meetings.handleLocusEvent({
909
+ locus: {
910
+ id: uuid1,
911
+ self: {
912
+ callBackInfo: {
913
+ callbackAddress: uri1,
914
+ },
915
+ },
916
+ info: {
917
+ webExMeetingId,
918
+ },
919
+ },
920
+ eventType: 'locus.difference',
921
+ locusUrl: url1,
922
+ });
923
+
924
+ await testUtils.flushPromises();
925
+
926
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
927
+ name: 'client.call.remote-started',
928
+ payload: {
929
+ trigger: 'mercury-event',
930
+ },
931
+ options: {
932
+ meetingId: 'meeting-id',
933
+ },
934
+ });
935
+ });
936
+
784
937
  it('should setup the meeting by a not difference event', async () => {
785
938
  await webex.meetings.handleLocusEvent({
786
939
  locus: {
@@ -790,12 +943,16 @@ describe('plugin-meetings', () => {
790
943
  callbackAddress: uri1,
791
944
  },
792
945
  },
946
+ info: {
947
+ webExMeetingId
948
+ },
793
949
  },
794
950
  eventType: test1,
795
951
  locusUrl: url1,
796
952
  });
797
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
953
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
798
954
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
955
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
799
956
  assert.calledOnce(initialSetup);
800
957
  assert.calledWith(initialSetup, {
801
958
  id: uuid1,
@@ -804,6 +961,9 @@ describe('plugin-meetings', () => {
804
961
  callbackAddress: uri1,
805
962
  },
806
963
  },
964
+ info: {
965
+ webExMeetingId
966
+ },
807
967
  });
808
968
  });
809
969
 
@@ -826,7 +986,7 @@ describe('plugin-meetings', () => {
826
986
 
827
987
  it('should not try to match USM meetings by conversation url', async () => {
828
988
  await webex.meetings.handleLocusEvent(generateFakeLocusData(true));
829
- assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
989
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
830
990
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
831
991
  'locusUrl',
832
992
  url1,
@@ -843,7 +1003,7 @@ describe('plugin-meetings', () => {
843
1003
  });
844
1004
  it('should try to match non-USM meetings by conversation url', async () => {
845
1005
  await webex.meetings.handleLocusEvent(generateFakeLocusData(false));
846
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1006
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
847
1007
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
848
1008
  'locusUrl',
849
1009
  url1,
@@ -874,6 +1034,7 @@ describe('plugin-meetings', () => {
874
1034
  });
875
1035
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
876
1036
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1037
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
877
1038
 
878
1039
  beforeEach(() => {
879
1040
  clock = sinon.useFakeTimers();
@@ -903,13 +1064,14 @@ describe('plugin-meetings', () => {
903
1064
  meeting,
904
1065
  destination,
905
1066
  type,
1067
+ extraParams = {},
906
1068
  expectedMeetingData = {}
907
1069
  ) => {
908
1070
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
909
1071
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
910
1072
  assert.notCalled(setTimeoutSpy);
911
- assert.calledThrice(TriggerProxy.trigger);
912
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
1073
+ assert.callCount(TriggerProxy.trigger, 5);
1074
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
913
1075
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
914
1076
 
915
1077
  if (expectedMeetingData.permissionToken) {
@@ -918,6 +1080,9 @@ describe('plugin-meetings', () => {
918
1080
  if (expectedMeetingData.meetingJoinUrl) {
919
1081
  assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
920
1082
  }
1083
+ if(expectedMeetingData.correlationId) {
1084
+ assert.equal(meeting.correlationId, expectedMeetingData.correlationId);
1085
+ }
921
1086
  assert.equal(meeting.destination, destination);
922
1087
  assert.equal(meeting.destinationType, type);
923
1088
  assert.calledWith(
@@ -947,108 +1112,119 @@ describe('plugin-meetings', () => {
947
1112
  const expectedMeetingData = {
948
1113
  permissionToken: 'PT',
949
1114
  meetingJoinUrl: 'meetingJoinUrl',
1115
+ correlationId: meeting.id,
950
1116
  };
951
1117
 
952
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
1118
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
953
1119
  });
954
1120
 
955
- it('creates the meeting from a successful meeting info fetch meeting resolve testing', async () => {
956
- const meeting = await webex.meetings.createMeeting('test destination', 'test type');
957
- const expectedMeetingData = {
958
- permissionToken: 'PT',
959
- meetingJoinUrl: 'meetingJoinUrl',
960
- };
1121
+ [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1122
+ const infoExtraParamsProvided = infoExtraParams !== undefined;
961
1123
 
962
- assert.instanceOf(
963
- meeting,
964
- Meeting,
965
- 'createMeeting should eventually resolve to a Meeting Object'
966
- );
967
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
968
- });
1124
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1125
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1126
+ const expectedMeetingData = {
1127
+ permissionToken: 'PT',
1128
+ meetingJoinUrl: 'meetingJoinUrl',
1129
+ };
969
1130
 
970
- it('creates the meeting from a successful meeting info fetch with random delay', async () => {
971
- const FAKE_LOCUS_MEETING = {
972
- conversationUrl: 'locusConvURL',
973
- url: 'locusUrl',
974
- info: {
975
- webExMeetingId: 'locusMeetingId',
976
- sipUri: 'locusSipUri',
977
- owner: 'locusOwner',
978
- },
979
- meeting: {
980
- startTime: fakeMeetingStartTimeString,
981
- },
982
- fullState: {
983
- active: false,
984
- },
985
- };
1131
+ assert.instanceOf(
1132
+ meeting,
1133
+ Meeting,
1134
+ 'createMeeting should eventually resolve to a Meeting Object'
1135
+ );
1136
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
1137
+ });
986
1138
 
987
- const meeting = await webex.meetings.createMeeting(
988
- FAKE_LOCUS_MEETING,
989
- 'test type',
990
- true
991
- );
1139
+ it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1140
+ const FAKE_LOCUS_MEETING = {
1141
+ conversationUrl: 'locusConvURL',
1142
+ url: 'locusUrl',
1143
+ info: {
1144
+ webExMeetingId: 'locusMeetingId',
1145
+ sipUri: 'locusSipUri',
1146
+ owner: 'locusOwner',
1147
+ },
1148
+ meeting: {
1149
+ startTime: fakeMeetingStartTimeString,
1150
+ },
1151
+ fullState: {
1152
+ active: false,
1153
+ },
1154
+ };
992
1155
 
993
- assert.instanceOf(
994
- meeting,
995
- Meeting,
996
- 'createMeeting should eventually resolve to a Meeting Object'
997
- );
998
- assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
999
- assert.calledOnce(setTimeoutSpy);
1000
-
1001
- // Parse meeting info with locus object
1002
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1003
- assert.equal(meeting.locusUrl, 'locusUrl');
1004
- assert.equal(meeting.sipUri, 'locusSipUri');
1005
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1006
- assert.isUndefined(meeting.meetingJoinUrl);
1007
- assert.equal(meeting.owner, 'locusOwner');
1008
- assert.isUndefined(meeting.permissionToken);
1009
-
1010
- // Add meeting and send trigger
1011
- assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1012
- assert.calledTwice(TriggerProxy.trigger);
1013
- assert.calledWith(
1014
- TriggerProxy.trigger,
1015
- sinon.match.instanceOf(Meetings),
1016
- {
1017
- file: 'meetings',
1018
- function: 'createMeeting',
1019
- },
1020
- 'meeting:added',
1021
- {
1022
- meeting: sinon.match.instanceOf(Meeting),
1023
- type: 'test meeting added type',
1024
- }
1025
- );
1156
+ const meeting = await webex.meetings.createMeeting(
1157
+ FAKE_LOCUS_MEETING,
1158
+ 'test type',
1159
+ true,
1160
+ infoExtraParams
1161
+ );
1026
1162
 
1027
- // When timer expires
1028
- clock.tick(FAKE_TIME_TO_START);
1029
- assert.calledWith(
1030
- webex.meetings.meetingInfo.fetchMeetingInfo,
1031
- FAKE_LOCUS_MEETING,
1032
- 'test type'
1033
- );
1163
+ assert.instanceOf(
1164
+ meeting,
1165
+ Meeting,
1166
+ 'createMeeting should eventually resolve to a Meeting Object'
1167
+ );
1168
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1169
+ assert.calledOnce(setTimeoutSpy);
1170
+
1171
+ // Parse meeting info with locus object
1172
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1173
+ assert.equal(meeting.locusUrl, 'locusUrl');
1174
+ assert.equal(meeting.sipUri, 'locusSipUri');
1175
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1176
+ assert.isUndefined(meeting.meetingJoinUrl);
1177
+ assert.equal(meeting.owner, 'locusOwner');
1178
+ assert.isUndefined(meeting.permissionToken);
1179
+
1180
+ // Add meeting and send trigger
1181
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1182
+ assert.calledTwice(TriggerProxy.trigger);
1183
+ assert.calledWith(
1184
+ TriggerProxy.trigger,
1185
+ sinon.match.instanceOf(Meetings),
1186
+ {
1187
+ file: 'meetings',
1188
+ function: 'createMeeting',
1189
+ },
1190
+ 'meeting:added',
1191
+ {
1192
+ meeting: sinon.match.instanceOf(Meeting),
1193
+ type: 'test meeting added type',
1194
+ }
1195
+ );
1034
1196
 
1035
- // Parse meeting info is called again with new meeting info
1036
- await testUtils.flushPromises();
1037
- assert.equal(meeting.conversationUrl, 'locusConvURL');
1038
- assert.equal(meeting.locusUrl, 'locusUrl');
1039
- assert.equal(meeting.sipUri, 'locusSipUri');
1040
- assert.equal(meeting.meetingNumber, 'locusMeetingId');
1041
- assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1042
- assert.equal(meeting.owner, 'locusOwner');
1043
- assert.equal(meeting.permissionToken, 'PT');
1197
+ // When timer expires
1198
+ clock.tick(FAKE_TIME_TO_START);
1199
+ assert.calledWith(
1200
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1201
+ FAKE_LOCUS_MEETING,
1202
+ 'test type',
1203
+ null,
1204
+ null,
1205
+ undefined,
1206
+ undefined,
1207
+ infoExtraParamsProvided ? infoExtraParams : {}
1208
+ );
1044
1209
 
1045
- assert.calledWith(
1046
- TriggerProxy.trigger,
1047
- meeting,
1048
- {file: 'meetings', function: 'fetchMeetingInfo'},
1049
- 'meeting:meetingInfoAvailable'
1050
- );
1051
- });
1210
+ // Parse meeting info is called again with new meeting info
1211
+ await testUtils.flushPromises();
1212
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1213
+ assert.equal(meeting.locusUrl, 'locusUrl');
1214
+ assert.equal(meeting.sipUri, 'locusSipUri');
1215
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1216
+ assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1217
+ assert.equal(meeting.owner, 'locusOwner');
1218
+ assert.equal(meeting.permissionToken, 'PT');
1219
+
1220
+ assert.calledWith(
1221
+ TriggerProxy.trigger,
1222
+ meeting,
1223
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1224
+ 'meeting:meetingInfoAvailable'
1225
+ );
1226
+ });
1227
+ })
1052
1228
 
1053
1229
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
1054
1230
  const FAKE_LOCUS_MEETING = {
@@ -1147,6 +1323,16 @@ describe('plugin-meetings', () => {
1147
1323
  );
1148
1324
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
1149
1325
  });
1326
+
1327
+ it('creates meeting with the correlationId provided', async () => {
1328
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, {}, 'my-correlationId');
1329
+
1330
+ const expectedMeetingData = {
1331
+ correlationId: 'my-correlationId',
1332
+ };
1333
+
1334
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
1335
+ })
1150
1336
  });
1151
1337
 
1152
1338
  describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
@@ -1167,7 +1353,7 @@ describe('plugin-meetings', () => {
1167
1353
  );
1168
1354
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1169
1355
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1170
- assert.calledTwice(TriggerProxy.trigger);
1356
+ assert.calledThrice(TriggerProxy.trigger);
1171
1357
  assert.calledWith(
1172
1358
  webex.meetings.meetingInfo.fetchMeetingInfo,
1173
1359
  'test destination',
@@ -1189,6 +1375,63 @@ describe('plugin-meetings', () => {
1189
1375
  );
1190
1376
  });
1191
1377
  });
1378
+
1379
+ describe('rejected MeetingInfo.#fetchMeetingInfo - does not log for known Error types', () => {
1380
+ forEach(
1381
+ [
1382
+ {
1383
+ error: new CaptchaError(),
1384
+ debugLogMessage:
1385
+ 'Meetings:index#createMeeting --> Debug CaptchaError: Captcha is required. fetching /meetingInfo for creation.',
1386
+ },
1387
+ {
1388
+ error: new PasswordError(),
1389
+ debugLogMessage:
1390
+ 'Meetings:index#createMeeting --> Debug PasswordError: Password is required, please use verifyPassword() fetching /meetingInfo for creation.',
1391
+ },
1392
+ {
1393
+ error: new PermissionError(),
1394
+ debugLogMessage:
1395
+ 'Meetings:index#createMeeting --> Debug PermissionError: Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action. fetching /meetingInfo for creation.',
1396
+ },
1397
+ {
1398
+ error: new Error(),
1399
+ infoLogMessage: true,
1400
+ debugLogMessage:
1401
+ 'Meetings:index#createMeeting --> Debug Error fetching /meetingInfo for creation.',
1402
+ },
1403
+ ],
1404
+ ({error, debugLogMessage, infoLogMessage}) => {
1405
+ it('creates the meeting from a rejected meeting info fetch', async () => {
1406
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1407
+ .stub()
1408
+ .returns(Promise.reject(error));
1409
+
1410
+ LoggerProxy.logger.debug = sinon.stub();
1411
+ LoggerProxy.logger.info = sinon.stub();
1412
+
1413
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1414
+
1415
+ assert.instanceOf(
1416
+ meeting,
1417
+ Meeting,
1418
+ 'createMeeting should eventually resolve to a Meeting Object'
1419
+ );
1420
+
1421
+ assert.calledWith(LoggerProxy.logger.debug, debugLogMessage);
1422
+
1423
+ if (infoLogMessage) {
1424
+ assert.calledWith(
1425
+ LoggerProxy.logger.info,
1426
+ 'Meetings:index#createMeeting --> Info Unable to fetch meeting info for test destination.'
1427
+ );
1428
+ } else {
1429
+ assert.notCalled(LoggerProxy.logger.info);
1430
+ }
1431
+ });
1432
+ }
1433
+ );
1434
+ });
1192
1435
  });
1193
1436
  });
1194
1437
  describe('Public Event Triggers', () => {
@@ -1267,6 +1510,9 @@ describe('plugin-meetings', () => {
1267
1510
  });
1268
1511
 
1269
1512
  describe('#fetchUserPreferredWebexSite', () => {
1513
+
1514
+ let loggerProxySpy;
1515
+
1270
1516
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
1271
1517
  assert.isDefined(webex.meetings.preferredWebexSite);
1272
1518
  await webex.meetings.fetchUserPreferredWebexSite();
@@ -1274,7 +1520,24 @@ describe('plugin-meetings', () => {
1274
1520
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
1275
1521
  });
1276
1522
 
1523
+ const setup = ({user} = {}) => {
1524
+ loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
1525
+
1526
+ Object.assign(webex.internal, {
1527
+ services: {
1528
+ getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1529
+ },
1530
+ user: {
1531
+ get: sinon.stub().returns(
1532
+ Promise.resolve(user)
1533
+ ),
1534
+ },
1535
+ });
1536
+ }
1537
+
1277
1538
  it('should not fail if UserPreferred info is not fetched ', async () => {
1539
+ setup();
1540
+
1278
1541
  Object.assign(webex.internal, {
1279
1542
  services: {
1280
1543
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
@@ -1284,7 +1547,62 @@ describe('plugin-meetings', () => {
1284
1547
  await webex.meetings.fetchUserPreferredWebexSite().then(() => {
1285
1548
  assert.equal(webex.meetings.preferredWebexSite, '');
1286
1549
  });
1550
+ assert.calledOnceWithExactly(
1551
+ loggerProxySpy,
1552
+ 'Failed to fetch preferred site from user - no site will be set'
1553
+ );
1287
1554
  });
1555
+
1556
+ it('should fall back to fetching the site from the user', async () => {
1557
+ setup({
1558
+ user: {
1559
+ userPreferences: {
1560
+ userPreferencesItems: {
1561
+ preferredWebExSite: 'site.webex.com',
1562
+ },
1563
+ },
1564
+ },
1565
+ });
1566
+
1567
+ await webex.meetings.fetchUserPreferredWebexSite();
1568
+
1569
+ assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
1570
+ assert.notCalled(loggerProxySpy);
1571
+ });
1572
+
1573
+ forEach([
1574
+ {user: undefined},
1575
+ {user: {userPreferences: {}}},
1576
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1577
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1578
+ ], ({user}) => {
1579
+ it(`should handle invalid user data ${user}`, async () => {
1580
+ setup({user});
1581
+
1582
+ await webex.meetings.fetchUserPreferredWebexSite();
1583
+
1584
+ assert.equal(webex.meetings.preferredWebexSite, '');
1585
+ assert.calledOnceWithExactly(
1586
+ loggerProxySpy,
1587
+ 'Failed to fetch preferred site from user - no site will be set'
1588
+ );
1589
+ });
1590
+ });
1591
+
1592
+ it('should handle a get user failure', async () => {
1593
+ setup();
1594
+
1595
+ webex.internal.user.get.rejects(new Error());
1596
+
1597
+ await webex.meetings.fetchUserPreferredWebexSite();
1598
+
1599
+ assert.equal(webex.meetings.preferredWebexSite, '');
1600
+ assert.calledOnceWithExactly(
1601
+ loggerProxySpy,
1602
+ 'Failed to fetch preferred site from user - no site will be set'
1603
+ );
1604
+ });
1605
+
1288
1606
  });
1289
1607
  });
1290
1608
 
@@ -1368,5 +1686,411 @@ describe('plugin-meetings', () => {
1368
1686
  );
1369
1687
  });
1370
1688
  });
1689
+
1690
+ describe('#isNeedHandleMainLocus', () => {
1691
+ let meeting;
1692
+ let newLocus;
1693
+ beforeEach(() => {
1694
+ meeting = {
1695
+ controls: {},
1696
+ self: {},
1697
+ };
1698
+ newLocus = {
1699
+ controls: {},
1700
+ self: {},
1701
+ }
1702
+ });
1703
+ afterEach(() => {
1704
+ sinon.restore();
1705
+ });
1706
+ it('check normal case will return true', () => {
1707
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1708
+ LoggerProxy.logger.log = sinon.stub();
1709
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1710
+ assert.equal(result, true);
1711
+ assert.calledWith(
1712
+ LoggerProxy.logger.log,
1713
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1714
+ );
1715
+ });
1716
+
1717
+ it('check self joined and joined on this device, return true', () => {
1718
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1719
+ newLocus.self.state = 'JOINED';
1720
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1721
+
1722
+ LoggerProxy.logger.log = sinon.stub();
1723
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1724
+ assert.equal(result, true);
1725
+ assert.calledWith(
1726
+ LoggerProxy.logger.log,
1727
+ 'Meetings:index#isNeedHandleMainLocus --> self this device shown as JOINED in the main session'
1728
+ );
1729
+ });
1730
+
1731
+ it('if newLocus replaceAt time is expired, then return false', () => {
1732
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({joinedWith: {replaces: [{
1733
+ replaceAt: '2023-03-27T02:17:02.506Z',
1734
+ }]}});
1735
+ newLocus.self.state = 'JOINED';
1736
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1737
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1738
+ replaces: [{
1739
+ replaceAt: '2023-03-27T02:17:01.506Z'
1740
+ }]
1741
+ })
1742
+
1743
+ LoggerProxy.logger.log = sinon.stub();
1744
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1745
+ assert.equal(result, false);
1746
+ assert.calledWith(
1747
+ LoggerProxy.logger.log,
1748
+ `Meetings:index#isNeedHandleMainLocus --> this is expired main joined status locus_dto replacedAt 2023-03-27T02:17:01.506Z bo replacedAt 2023-03-27T02:17:02.506Z`
1749
+ );
1750
+ });
1751
+
1752
+ it('check current is in breakout join with this device, return false', () => {
1753
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({
1754
+ joinedWith: {
1755
+ correlationId: '111',
1756
+ },
1757
+ });
1758
+ newLocus.controls.breakout = {url: 'url'};
1759
+ meeting.correlationId = '111';
1760
+
1761
+ LoggerProxy.logger.log = sinon.stub();
1762
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1763
+ assert.equal(result, false);
1764
+ assert.calledWith(
1765
+ LoggerProxy.logger.log,
1766
+ `Meetings:index#isNeedHandleMainLocus --> there is active breakout session and joined on this device, and don't need to handle main session: url`
1767
+ );
1768
+ });
1769
+
1770
+ it('check self is moved and removed, return false', () => {
1771
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1772
+ newLocus.self.state = 'LEFT';
1773
+ newLocus.self.reason = 'MOVED';
1774
+ newLocus.self.removed = true;
1775
+ LoggerProxy.logger.log = sinon.stub();
1776
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1777
+ assert.equal(result, false);
1778
+ assert.calledWith(
1779
+ LoggerProxy.logger.log,
1780
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1781
+ );
1782
+ });
1783
+
1784
+ it('check self is moved and device resource removed, return false', () => {
1785
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1786
+ newLocus.self.state = 'LEFT';
1787
+ newLocus.self.reason = 'MOVED';
1788
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1789
+ state: 'LEFT',
1790
+ reason: 'MOVED',
1791
+ });
1792
+ LoggerProxy.logger.log = sinon.stub();
1793
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1794
+ assert.equal(result, false);
1795
+ assert.calledWith(
1796
+ LoggerProxy.logger.log,
1797
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1798
+ );
1799
+ });
1800
+
1801
+ it('check self is joined but device resource removed, return false', () => {
1802
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1803
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(false);
1804
+ newLocus.self.state = 'JOINED';
1805
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1806
+ state: 'LEFT',
1807
+ reason: 'MOVED',
1808
+ });
1809
+ LoggerProxy.logger.log = sinon.stub();
1810
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1811
+ assert.equal(result, false);
1812
+ assert.calledWith(
1813
+ LoggerProxy.logger.log,
1814
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
1815
+ );
1816
+ });
1817
+ });
1818
+
1819
+ describe('#isNeedHandleLocusDTO', () => {
1820
+ let meeting;
1821
+ let newLocus;
1822
+ beforeEach(() => {
1823
+ meeting = {
1824
+ controls: {},
1825
+ self: {},
1826
+ };
1827
+ newLocus = {
1828
+ controls: {},
1829
+ self: {},
1830
+ }
1831
+ });
1832
+ afterEach(() => {
1833
+ sinon.restore();
1834
+ });
1835
+ it('initial DTO , joined breakout session, return true', () => {
1836
+ newLocus.controls.breakout = {
1837
+ sessionType: 'BREAKOUT',
1838
+ };
1839
+ newLocus.self.state = 'JOINED';
1840
+ newLocus.fullState = {
1841
+ active: true,
1842
+ };
1843
+ LoggerProxy.logger.log = sinon.stub();
1844
+ const result = webex.meetings.isNeedHandleLocusDTO(null, newLocus);
1845
+ assert.equal(result, true);
1846
+ assert.calledWith(
1847
+ LoggerProxy.logger.log,
1848
+ `Meetings:index#isNeedHandleLocusDTO --> the first breakout session locusDTO active status: true`
1849
+ );
1850
+ });
1851
+ it('others go to check isNeedHandleMainLocus', () => {
1852
+ newLocus.controls.breakout = {
1853
+ sessionType: 'MAIN',
1854
+ };
1855
+ newLocus.self.state = 'JOINED';
1856
+
1857
+ LoggerProxy.logger.log = sinon.stub();
1858
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1859
+ assert.equal(result, true);
1860
+ assert.calledWith(
1861
+ LoggerProxy.logger.log,
1862
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1863
+ );
1864
+ });
1865
+ it('joined breakout session, self status is moved, return false', () => {
1866
+ newLocus.controls.breakout = {
1867
+ sessionType: 'BREAKOUT',
1868
+ };
1869
+ newLocus.self.state = 'LEFT';
1870
+ newLocus.self.reason = 'MOVED';
1871
+
1872
+ LoggerProxy.logger.log = sinon.stub();
1873
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1874
+ assert.equal(result, false);
1875
+ });
1876
+ });
1877
+
1878
+ describe('#getCorrespondingMeetingByLocus', () => {
1879
+ let locus;
1880
+ let mockReturnMeeting = {meeting: 'meeting1'};
1881
+ const mockGetByKey = (keyWillReturnMeeting) => {
1882
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((key) => {
1883
+ if (key === keyWillReturnMeeting) {
1884
+ return mockReturnMeeting;
1885
+ }
1886
+ return null;
1887
+ });
1888
+ };
1889
+
1890
+ beforeEach(() => {
1891
+ locus = {
1892
+ controls: {},
1893
+ self: {
1894
+ callbackInfo: {
1895
+ callbackAddress: 'address1',
1896
+ }
1897
+ },
1898
+ info: {
1899
+ webExMeetingId: '123456',
1900
+ isUnifiedSpaceMeeting: false,
1901
+ },
1902
+ conversationUrl: 'conversationUrl1'
1903
+ };
1904
+
1905
+ sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
1906
+ });
1907
+ afterEach(() => {
1908
+ sinon.restore();
1909
+ });
1910
+ it('check the calls when no meeting found in meetingCollection', () => {
1911
+ mockGetByKey();
1912
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1913
+ assert.isNull(result);
1914
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1915
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1916
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1917
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1918
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1919
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1920
+ });
1921
+
1922
+ it('not try getByKey "conversationUrl" when isUnifiedSpaceMeeting is true', () => {
1923
+ mockGetByKey();
1924
+ locus.info.isUnifiedSpaceMeeting = true;
1925
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1926
+ assert.isNull(result);
1927
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1928
+ })
1929
+
1930
+ it('check the calls when meeting found by key: locusUrl', () => {
1931
+ mockGetByKey('locusUrl');
1932
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1933
+ assert.deepEqual(result, mockReturnMeeting);
1934
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 1);
1935
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1936
+ });
1937
+
1938
+ it('check the calls when meeting found by key: correlationId', () => {
1939
+ mockGetByKey('correlationId');
1940
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1941
+ assert.deepEqual(result, mockReturnMeeting);
1942
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1943
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1944
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1945
+ });
1946
+
1947
+ it('check the calls when meeting found by key: sipUri', () => {
1948
+ mockGetByKey('sipUri');
1949
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1950
+ assert.deepEqual(result, mockReturnMeeting);
1951
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1952
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1953
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1954
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1955
+ });
1956
+
1957
+ it('check the calls when meeting found by key: conversationUrl', () => {
1958
+ mockGetByKey('conversationUrl');
1959
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1960
+ assert.deepEqual(result, mockReturnMeeting);
1961
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1962
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1963
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1964
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1965
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1966
+ });
1967
+
1968
+ it('check the calls when meeting found by key: meetingNumber', () => {
1969
+ mockGetByKey('meetingNumber');
1970
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1971
+ assert.deepEqual(result, mockReturnMeeting);
1972
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1973
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1974
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1975
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1976
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1977
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1978
+ });
1979
+ });
1980
+
1981
+ describe('#sortLocusArrayToUpdate', () => {
1982
+ let lociArray;
1983
+ let mainLocus;
1984
+ let breakoutLocus;
1985
+ beforeEach(() => {
1986
+ mainLocus = {
1987
+ url: 'mainUrl1',
1988
+ controls: {
1989
+ breakout: {
1990
+ sessionType: 'MAIN',
1991
+ url: 'breakoutUnifiedUrl1'
1992
+ }
1993
+ }
1994
+ };
1995
+ breakoutLocus = {
1996
+ url: 'breakoutUrl1',
1997
+ controls: {
1998
+ breakout: {
1999
+ sessionType: 'BREAKOUT',
2000
+ url: 'breakoutUnifiedUrl1'
2001
+ }
2002
+ }
2003
+ };
2004
+ lociArray = [mainLocus, breakoutLocus];
2005
+
2006
+ sinon.stub(MeetingsUtil, 'isValidBreakoutLocus').callsFake((locus) => {
2007
+ return locus.url === 'breakoutUrl1';
2008
+ });
2009
+ });
2010
+ afterEach(() => {
2011
+ sinon.restore();
2012
+ });
2013
+
2014
+ it('if both main and breakout locus is in array for non-exist meeting, return main locus to create first', () => {
2015
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
2016
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2017
+ assert.deepEqual(result, [mainLocus]);
2018
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, [breakoutLocus]);
2019
+ });
2020
+
2021
+ it('if both main and breakout locus is in array for an exist meeting, return all locus', () => {
2022
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2023
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2024
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2025
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, []);
2026
+ });
2027
+
2028
+ it('if the breakout locus has no associated main locus, return all', () => {
2029
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2030
+ breakoutLocus.controls.breakout.url = 'testUrl';
2031
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2032
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2033
+ });
2034
+ });
2035
+
2036
+ describe('#checkHandleBreakoutLocus', () => {
2037
+ let breakoutLocus;
2038
+ beforeEach(() => {
2039
+ breakoutLocus = {
2040
+ url: 'breakoutUrl1',
2041
+ controls: {
2042
+ breakout: {
2043
+ sessionType: 'BREAKOUT',
2044
+ url: 'breakoutUnifiedUrl1',
2045
+ }
2046
+ }
2047
+ };
2048
+
2049
+ webex.meetings.handleLocusEvent = sinon.stub();
2050
+ });
2051
+ afterEach(() => {
2052
+ sinon.restore();
2053
+ });
2054
+ it('do nothing if new created locus is null/no cached breakouts for updating', () => {
2055
+ webex.meetings.checkHandleBreakoutLocus(null);
2056
+ webex.meetings.breakoutLocusForHandleLater = null;
2057
+ webex.meetings.checkHandleBreakoutLocus({});
2058
+ webex.meetings.breakoutLocusForHandleLater = [];
2059
+ webex.meetings.checkHandleBreakoutLocus({});
2060
+ assert.notCalled(webex.meetings.handleLocusEvent);
2061
+ });
2062
+
2063
+ it('do nothing if new created locus is breakout locus', () => {
2064
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2065
+ webex.meetings.checkHandleBreakoutLocus(breakoutLocus);
2066
+ assert.notCalled(webex.meetings.handleLocusEvent);
2067
+ });
2068
+
2069
+ it('do nothing if no cached locus is associated with the new created locus', () => {
2070
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2071
+ webex.meetings.checkHandleBreakoutLocus({
2072
+ controls: {
2073
+ breakout: {
2074
+ sessionType: 'MAIN',
2075
+ url: 'breakoutUnifiedUrl2',
2076
+ }
2077
+ }
2078
+ });
2079
+ assert.notCalled(webex.meetings.handleLocusEvent);
2080
+ });
2081
+
2082
+ it('update the cached breakout locus which associate the new created locus', () => {
2083
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2084
+ webex.meetings.checkHandleBreakoutLocus({
2085
+ controls: {
2086
+ breakout: {
2087
+ sessionType: 'MAIN',
2088
+ url: 'breakoutUnifiedUrl1',
2089
+ }
2090
+ }
2091
+ });
2092
+ assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2093
+ });
2094
+ });
1371
2095
  });
1372
2096
  });