@webex/plugin-meetings 3.0.0-beta.21 → 3.0.0-beta.211

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 (422) hide show
  1. package/README.md +45 -7
  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 +179 -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 +359 -64
  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 +48 -135
  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 +2770 -2547
  69. package/dist/meeting/index.js.map +1 -1
  70. package/dist/meeting/locusMediaRequest.js +291 -0
  71. package/dist/meeting/locusMediaRequest.js.map +1 -0
  72. package/dist/meeting/muteState.js +229 -124
  73. package/dist/meeting/muteState.js.map +1 -1
  74. package/dist/meeting/request.js +199 -193
  75. package/dist/meeting/request.js.map +1 -1
  76. package/dist/meeting/util.js +532 -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 +357 -66
  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 +72 -27
  129. package/dist/reachability/index.js.map +1 -1
  130. package/dist/reachability/request.js +12 -5
  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 +21 -29
  139. package/dist/roap/index.js.map +1 -1
  140. package/dist/roap/request.js +110 -89
  141. package/dist/roap/request.js.map +1 -1
  142. package/dist/roap/turnDiscovery.js +93 -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 +1020 -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 +1482 -0
  213. package/dist/types/meeting/locusMediaRequest.d.ts +72 -0
  214. package/dist/types/meeting/muteState.d.ts +184 -0
  215. package/dist/types/meeting/request.d.ts +257 -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 +79 -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 +367 -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 +152 -0
  251. package/dist/types/reachability/request.d.ts +37 -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 +36 -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 +46 -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 +165 -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 +383 -61
  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 +87 -140
  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 +2099 -2083
  305. package/src/meeting/locusMediaRequest.ts +311 -0
  306. package/src/meeting/muteState.ts +228 -132
  307. package/src/meeting/request.ts +105 -115
  308. package/src/meeting/util.ts +511 -397
  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 +392 -84
  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 +62 -15
  335. package/src/reachability/request.ts +10 -5
  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 +21 -30
  340. package/src/roap/request.ts +101 -95
  341. package/src/roap/turnDiscovery.ts +47 -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 +3573 -1663
  374. package/test/unit/spec/meeting/locusMediaRequest.ts +438 -0
  375. package/test/unit/spec/meeting/muteState.js +370 -208
  376. package/test/unit/spec/meeting/request.js +339 -44
  377. package/test/unit/spec/meeting/utils.js +456 -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 +867 -125
  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 +125 -8
  398. package/test/unit/spec/reachability/request.js +66 -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 +26 -51
  403. package/test/unit/spec/roap/request.ts +196 -85
  404. package/test/unit/spec/roap/turnDiscovery.ts +30 -7
  405. package/test/unit/spec/rtcMetrics/index.ts +60 -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/dist/multistream/multistreamMedia.js +0 -110
  417. package/dist/multistream/multistreamMedia.js.map +0 -1
  418. package/src/index.js +0 -16
  419. package/src/meeting/effectsState.ts +0 -211
  420. package/src/metrics/config.ts +0 -495
  421. package/src/multistream/multistreamMedia.ts +0 -97
  422. 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,6 +353,100 @@ 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', () => {
@@ -443,21 +552,17 @@ describe('plugin-meetings', () => {
443
552
  );
444
553
  });
445
554
  describe('when meeting is returned', () => {
446
- let parse;
447
555
 
448
556
  beforeEach(() => {
449
- parse = sinon.stub().returns(true);
450
557
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
451
- locusInfo: {
452
- parse,
453
- },
558
+ locusInfo,
454
559
  });
455
560
  });
456
561
  it('tests the sync meeting calls for existing meeting', async () => {
457
562
  await webex.meetings.syncMeetings();
458
563
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
459
564
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
460
- assert.calledOnce(parse);
565
+ assert.calledOnce(locusInfo.parse);
461
566
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
462
567
  });
463
568
  });
@@ -470,6 +575,7 @@ describe('plugin-meetings', () => {
470
575
  webex.meetings.create = sinon.stub().returns(
471
576
  Promise.resolve({
472
577
  locusInfo: {
578
+ ...locusInfo,
473
579
  initialSetup,
474
580
  },
475
581
  })
@@ -478,7 +584,7 @@ describe('plugin-meetings', () => {
478
584
  it('tests the sync meeting calls for not existing meeting', async () => {
479
585
  await webex.meetings.syncMeetings();
480
586
  assert.calledOnce(webex.meetings.request.getActiveMeetings);
481
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
587
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
482
588
  assert.calledOnce(initialSetup);
483
589
  assert.calledOnce(webex.meetings.create);
484
590
  assert.calledWith(webex.meetings.request.getActiveMeetings);
@@ -502,12 +608,9 @@ describe('plugin-meetings', () => {
502
608
 
503
609
  beforeEach(() => {
504
610
  destroySpy = sinon.spy(webex.meetings, 'destroy');
505
- parse = sinon.stub().returns(true);
506
611
  initialSetup = sinon.stub().returns(true);
507
612
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
508
- locusInfo: {
509
- parse,
510
- },
613
+ locusInfo,
511
614
  sendCallAnalyzerMetrics: sinon.stub(),
512
615
  });
513
616
  webex.meetings.meetingCollection.getAll = sinon.stub().returns({
@@ -576,12 +679,26 @@ describe('plugin-meetings', () => {
576
679
 
577
680
  it('calls createMeeting and returns its promise', async () => {
578
681
  const FAKE_USE_RANDOM_DELAY = true;
579
- const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY);
682
+ const correlationId = 'my-correlationId';
683
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
580
684
 
581
685
  assert.exists(create.then);
582
686
  await create;
583
687
  assert.calledOnce(webex.meetings.createMeeting);
584
- assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY);
688
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, {}, correlationId);
689
+ });
690
+
691
+ it('calls createMeeting with extra info params and returns its promise', async () => {
692
+ const FAKE_USE_RANDOM_DELAY = false;
693
+ const correlationId = 'my-correlationId';
694
+
695
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
696
+ const create = webex.meetings.create(test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
697
+
698
+ assert.exists(create.then);
699
+ await create;
700
+ assert.calledOnce(webex.meetings.createMeeting);
701
+ assert.calledWith(webex.meetings.createMeeting, test1, test2, FAKE_USE_RANDOM_DELAY, FAKE_INFO_EXTRA_PARAMS, correlationId);
585
702
  });
586
703
 
587
704
  it('creates a new meeting when a scheduled meeting exists in the conversation', async () => {
@@ -677,45 +794,52 @@ describe('plugin-meetings', () => {
677
794
  });
678
795
  describe('#handleLocusEvent', () => {
679
796
  describe('there was a meeting', () => {
680
- let parse;
681
797
 
682
798
  beforeEach(() => {
683
- parse = sinon.stub().returns(true);
684
799
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns({
685
- locusInfo: {
686
- parse,
687
- },
800
+ locusInfo,
688
801
  });
689
802
  });
690
- it('should parse the meeting info', () => {
803
+ it('should parse the meeting info and update main session locus cache', () => {
804
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(false);
691
805
  webex.meetings.handleLocusEvent({
692
806
  locusUrl: url1,
693
807
  });
694
808
  assert.calledOnce(webex.meetings.meetingCollection.getByKey);
695
809
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
696
- assert.calledOnce(parse);
810
+ assert.calledOnce(locusInfo.parse);
811
+ assert.calledOnce(locusInfo.updateMainSessionLocusCache);
697
812
  assert.calledWith(
698
- parse,
813
+ locusInfo.parse,
699
814
  {
700
- locusInfo: {
701
- parse,
702
- },
815
+ locusInfo,
703
816
  },
704
817
  {
705
818
  locusUrl: url1,
706
819
  }
707
820
  );
708
821
  });
822
+
823
+ it('should not update main session locus cache', () => {
824
+ sinon.stub(MeetingsUtil, 'isBreakoutLocusDTO').returns(true);
825
+ webex.meetings.handleLocusEvent({
826
+ locusUrl: url1,
827
+ });
828
+ assert.notCalled(locusInfo.updateMainSessionLocusCache);
829
+ });
709
830
  });
710
831
  describe('there was not a meeting', () => {
711
832
  let initialSetup;
833
+ const webExMeetingId = '123456';
712
834
 
713
835
  beforeEach(() => {
714
836
  initialSetup = sinon.stub().returns(true);
715
837
  webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
716
838
  webex.meetings.create = sinon.stub().returns(
717
839
  Promise.resolve({
840
+ id: 'meeting-id',
718
841
  locusInfo: {
842
+ ...locusInfo,
719
843
  initialSetup,
720
844
  },
721
845
  })
@@ -735,12 +859,16 @@ describe('plugin-meetings', () => {
735
859
  callbackAddress: uri1,
736
860
  },
737
861
  },
862
+ info: {
863
+ webExMeetingId
864
+ },
738
865
  },
739
866
  eventType: 'locus.difference',
740
867
  locusUrl: url1,
741
868
  });
742
- assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
869
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 6);
743
870
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
871
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
744
872
  assert.calledOnce(initialSetup);
745
873
  assert.calledWith(initialSetup, {
746
874
  id: uuid1,
@@ -754,6 +882,9 @@ describe('plugin-meetings', () => {
754
882
  callbackAddress: uri1,
755
883
  },
756
884
  },
885
+ info: {
886
+ webExMeetingId
887
+ },
757
888
  });
758
889
  });
759
890
  it('should setup the meeting by difference event without replaces', async () => {
@@ -765,12 +896,16 @@ describe('plugin-meetings', () => {
765
896
  callbackAddress: uri1,
766
897
  },
767
898
  },
899
+ info: {
900
+ webExMeetingId
901
+ },
768
902
  },
769
903
  eventType: 'locus.difference',
770
904
  locusUrl: url1,
771
905
  });
772
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
906
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
773
907
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
908
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
774
909
  assert.calledOnce(initialSetup);
775
910
  assert.calledWith(initialSetup, {
776
911
  id: uuid1,
@@ -779,8 +914,44 @@ describe('plugin-meetings', () => {
779
914
  callbackAddress: uri1,
780
915
  },
781
916
  },
917
+ info: {
918
+ webExMeetingId
919
+ },
782
920
  });
783
921
  });
922
+
923
+ it('sends client event correctly on finally', async () => {
924
+ webex.meetings.getMeetingByType = sinon.stub().returns(true);
925
+
926
+ await webex.meetings.handleLocusEvent({
927
+ locus: {
928
+ id: uuid1,
929
+ self: {
930
+ callBackInfo: {
931
+ callbackAddress: uri1,
932
+ },
933
+ },
934
+ info: {
935
+ webExMeetingId,
936
+ },
937
+ },
938
+ eventType: 'locus.difference',
939
+ locusUrl: url1,
940
+ });
941
+
942
+ await testUtils.flushPromises();
943
+
944
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
945
+ name: 'client.call.remote-started',
946
+ payload: {
947
+ trigger: 'mercury-event',
948
+ },
949
+ options: {
950
+ meetingId: 'meeting-id',
951
+ },
952
+ });
953
+ });
954
+
784
955
  it('should setup the meeting by a not difference event', async () => {
785
956
  await webex.meetings.handleLocusEvent({
786
957
  locus: {
@@ -790,12 +961,16 @@ describe('plugin-meetings', () => {
790
961
  callbackAddress: uri1,
791
962
  },
792
963
  },
964
+ info: {
965
+ webExMeetingId
966
+ },
793
967
  },
794
968
  eventType: test1,
795
969
  locusUrl: url1,
796
970
  });
797
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
971
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
798
972
  assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
973
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', webExMeetingId);
799
974
  assert.calledOnce(initialSetup);
800
975
  assert.calledWith(initialSetup, {
801
976
  id: uuid1,
@@ -804,6 +979,9 @@ describe('plugin-meetings', () => {
804
979
  callbackAddress: uri1,
805
980
  },
806
981
  },
982
+ info: {
983
+ webExMeetingId
984
+ },
807
985
  });
808
986
  });
809
987
 
@@ -826,7 +1004,7 @@ describe('plugin-meetings', () => {
826
1004
 
827
1005
  it('should not try to match USM meetings by conversation url', async () => {
828
1006
  await webex.meetings.handleLocusEvent(generateFakeLocusData(true));
829
- assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1007
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
830
1008
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
831
1009
  'locusUrl',
832
1010
  url1,
@@ -843,7 +1021,7 @@ describe('plugin-meetings', () => {
843
1021
  });
844
1022
  it('should try to match non-USM meetings by conversation url', async () => {
845
1023
  await webex.meetings.handleLocusEvent(generateFakeLocusData(false));
846
- assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1024
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
847
1025
  assert.deepEqual(webex.meetings.meetingCollection.getByKey.getCall(0).args, [
848
1026
  'locusUrl',
849
1027
  url1,
@@ -874,6 +1052,7 @@ describe('plugin-meetings', () => {
874
1052
  });
875
1053
  describe('successful MeetingInfo.#fetchMeetingInfo', () => {
876
1054
  let clock, setTimeoutSpy, fakeMeetingStartTimeString, FAKE_TIME_TO_START;
1055
+ const FAKE_INFO_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
877
1056
 
878
1057
  beforeEach(() => {
879
1058
  clock = sinon.useFakeTimers();
@@ -903,13 +1082,14 @@ describe('plugin-meetings', () => {
903
1082
  meeting,
904
1083
  destination,
905
1084
  type,
1085
+ extraParams = {},
906
1086
  expectedMeetingData = {}
907
1087
  ) => {
908
1088
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
909
1089
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
910
1090
  assert.notCalled(setTimeoutSpy);
911
- assert.calledThrice(TriggerProxy.trigger);
912
- assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type);
1091
+ assert.callCount(TriggerProxy.trigger, 5);
1092
+ assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
913
1093
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
914
1094
 
915
1095
  if (expectedMeetingData.permissionToken) {
@@ -918,6 +1098,9 @@ describe('plugin-meetings', () => {
918
1098
  if (expectedMeetingData.meetingJoinUrl) {
919
1099
  assert.equal(meeting.meetingJoinUrl, expectedMeetingData.meetingJoinUrl);
920
1100
  }
1101
+ if(expectedMeetingData.correlationId) {
1102
+ assert.equal(meeting.correlationId, expectedMeetingData.correlationId);
1103
+ }
921
1104
  assert.equal(meeting.destination, destination);
922
1105
  assert.equal(meeting.destinationType, type);
923
1106
  assert.calledWith(
@@ -947,108 +1130,119 @@ describe('plugin-meetings', () => {
947
1130
  const expectedMeetingData = {
948
1131
  permissionToken: 'PT',
949
1132
  meetingJoinUrl: 'meetingJoinUrl',
1133
+ correlationId: meeting.id,
950
1134
  };
951
1135
 
952
- checkCreateWithoutDelay(meeting, 'test destination', 'test type', expectedMeetingData);
1136
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
953
1137
  });
954
1138
 
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
- };
1139
+ [undefined, FAKE_INFO_EXTRA_PARAMS].forEach((infoExtraParams) => {
1140
+ const infoExtraParamsProvided = infoExtraParams !== undefined;
961
1141
 
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
- });
1142
+ it(`creates the meeting from a successful meeting info fetch meeting resolve testing${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1143
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, infoExtraParams);
1144
+ const expectedMeetingData = {
1145
+ permissionToken: 'PT',
1146
+ meetingJoinUrl: 'meetingJoinUrl',
1147
+ };
969
1148
 
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
- };
1149
+ assert.instanceOf(
1150
+ meeting,
1151
+ Meeting,
1152
+ 'createMeeting should eventually resolve to a Meeting Object'
1153
+ );
1154
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', infoExtraParamsProvided ? infoExtraParams : {}, expectedMeetingData);
1155
+ });
986
1156
 
987
- const meeting = await webex.meetings.createMeeting(
988
- FAKE_LOCUS_MEETING,
989
- 'test type',
990
- true
991
- );
1157
+ it(`creates the meeting from a successful meeting info fetch with random delay${infoExtraParamsProvided ? ' with infoExtraParams' : ''}`, async () => {
1158
+ const FAKE_LOCUS_MEETING = {
1159
+ conversationUrl: 'locusConvURL',
1160
+ url: 'locusUrl',
1161
+ info: {
1162
+ webExMeetingId: 'locusMeetingId',
1163
+ sipUri: 'locusSipUri',
1164
+ owner: 'locusOwner',
1165
+ },
1166
+ meeting: {
1167
+ startTime: fakeMeetingStartTimeString,
1168
+ },
1169
+ fullState: {
1170
+ active: false,
1171
+ },
1172
+ };
992
1173
 
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
- );
1174
+ const meeting = await webex.meetings.createMeeting(
1175
+ FAKE_LOCUS_MEETING,
1176
+ 'test type',
1177
+ true,
1178
+ infoExtraParams
1179
+ );
1026
1180
 
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
- );
1181
+ assert.instanceOf(
1182
+ meeting,
1183
+ Meeting,
1184
+ 'createMeeting should eventually resolve to a Meeting Object'
1185
+ );
1186
+ assert.notCalled(webex.meetings.meetingInfo.fetchMeetingInfo);
1187
+ assert.calledOnce(setTimeoutSpy);
1188
+
1189
+ // Parse meeting info with locus object
1190
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1191
+ assert.equal(meeting.locusUrl, 'locusUrl');
1192
+ assert.equal(meeting.sipUri, 'locusSipUri');
1193
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1194
+ assert.isUndefined(meeting.meetingJoinUrl);
1195
+ assert.equal(meeting.owner, 'locusOwner');
1196
+ assert.isUndefined(meeting.permissionToken);
1197
+
1198
+ // Add meeting and send trigger
1199
+ assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1200
+ assert.calledTwice(TriggerProxy.trigger);
1201
+ assert.calledWith(
1202
+ TriggerProxy.trigger,
1203
+ sinon.match.instanceOf(Meetings),
1204
+ {
1205
+ file: 'meetings',
1206
+ function: 'createMeeting',
1207
+ },
1208
+ 'meeting:added',
1209
+ {
1210
+ meeting: sinon.match.instanceOf(Meeting),
1211
+ type: 'test meeting added type',
1212
+ }
1213
+ );
1034
1214
 
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');
1215
+ // When timer expires
1216
+ clock.tick(FAKE_TIME_TO_START);
1217
+ assert.calledWith(
1218
+ webex.meetings.meetingInfo.fetchMeetingInfo,
1219
+ FAKE_LOCUS_MEETING,
1220
+ 'test type',
1221
+ null,
1222
+ null,
1223
+ undefined,
1224
+ undefined,
1225
+ infoExtraParamsProvided ? infoExtraParams : {}
1226
+ );
1044
1227
 
1045
- assert.calledWith(
1046
- TriggerProxy.trigger,
1047
- meeting,
1048
- {file: 'meetings', function: 'fetchMeetingInfo'},
1049
- 'meeting:meetingInfoAvailable'
1050
- );
1051
- });
1228
+ // Parse meeting info is called again with new meeting info
1229
+ await testUtils.flushPromises();
1230
+ assert.equal(meeting.conversationUrl, 'locusConvURL');
1231
+ assert.equal(meeting.locusUrl, 'locusUrl');
1232
+ assert.equal(meeting.sipUri, 'locusSipUri');
1233
+ assert.equal(meeting.meetingNumber, 'locusMeetingId');
1234
+ assert.equal(meeting.meetingJoinUrl, 'meetingJoinUrl');
1235
+ assert.equal(meeting.owner, 'locusOwner');
1236
+ assert.equal(meeting.permissionToken, 'PT');
1237
+
1238
+ assert.calledWith(
1239
+ TriggerProxy.trigger,
1240
+ meeting,
1241
+ {file: 'meetings', function: 'fetchMeetingInfo'},
1242
+ 'meeting:meetingInfoAvailable'
1243
+ );
1244
+ });
1245
+ })
1052
1246
 
1053
1247
  it('creates the meeting from a successful meeting info fetch that has no random delay because it is active', async () => {
1054
1248
  const FAKE_LOCUS_MEETING = {
@@ -1147,6 +1341,16 @@ describe('plugin-meetings', () => {
1147
1341
  );
1148
1342
  checkCreateWithoutDelay(meeting, FAKE_LOCUS_MEETING, 'test type');
1149
1343
  });
1344
+
1345
+ it('creates meeting with the correlationId provided', async () => {
1346
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type', false, {}, 'my-correlationId');
1347
+
1348
+ const expectedMeetingData = {
1349
+ correlationId: 'my-correlationId',
1350
+ };
1351
+
1352
+ checkCreateWithoutDelay(meeting, 'test destination', 'test type', {}, expectedMeetingData);
1353
+ })
1150
1354
  });
1151
1355
 
1152
1356
  describe('rejected MeetingInfo.#fetchMeetingInfo', () => {
@@ -1167,7 +1371,7 @@ describe('plugin-meetings', () => {
1167
1371
  );
1168
1372
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1169
1373
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1170
- assert.calledTwice(TriggerProxy.trigger);
1374
+ assert.calledThrice(TriggerProxy.trigger);
1171
1375
  assert.calledWith(
1172
1376
  webex.meetings.meetingInfo.fetchMeetingInfo,
1173
1377
  'test destination',
@@ -1189,6 +1393,63 @@ describe('plugin-meetings', () => {
1189
1393
  );
1190
1394
  });
1191
1395
  });
1396
+
1397
+ describe('rejected MeetingInfo.#fetchMeetingInfo - does not log for known Error types', () => {
1398
+ forEach(
1399
+ [
1400
+ {
1401
+ error: new CaptchaError(),
1402
+ debugLogMessage:
1403
+ 'Meetings:index#createMeeting --> Debug CaptchaError: Captcha is required. fetching /meetingInfo for creation.',
1404
+ },
1405
+ {
1406
+ error: new PasswordError(),
1407
+ debugLogMessage:
1408
+ 'Meetings:index#createMeeting --> Debug PasswordError: Password is required, please use verifyPassword() fetching /meetingInfo for creation.',
1409
+ },
1410
+ {
1411
+ error: new PermissionError(),
1412
+ debugLogMessage:
1413
+ '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.',
1414
+ },
1415
+ {
1416
+ error: new Error(),
1417
+ infoLogMessage: true,
1418
+ debugLogMessage:
1419
+ 'Meetings:index#createMeeting --> Debug Error fetching /meetingInfo for creation.',
1420
+ },
1421
+ ],
1422
+ ({error, debugLogMessage, infoLogMessage}) => {
1423
+ it('creates the meeting from a rejected meeting info fetch', async () => {
1424
+ webex.meetings.meetingInfo.fetchMeetingInfo = sinon
1425
+ .stub()
1426
+ .returns(Promise.reject(error));
1427
+
1428
+ LoggerProxy.logger.debug = sinon.stub();
1429
+ LoggerProxy.logger.info = sinon.stub();
1430
+
1431
+ const meeting = await webex.meetings.createMeeting('test destination', 'test type');
1432
+
1433
+ assert.instanceOf(
1434
+ meeting,
1435
+ Meeting,
1436
+ 'createMeeting should eventually resolve to a Meeting Object'
1437
+ );
1438
+
1439
+ assert.calledWith(LoggerProxy.logger.debug, debugLogMessage);
1440
+
1441
+ if (infoLogMessage) {
1442
+ assert.calledWith(
1443
+ LoggerProxy.logger.info,
1444
+ 'Meetings:index#createMeeting --> Info Unable to fetch meeting info for test destination.'
1445
+ );
1446
+ } else {
1447
+ assert.notCalled(LoggerProxy.logger.info);
1448
+ }
1449
+ });
1450
+ }
1451
+ );
1452
+ });
1192
1453
  });
1193
1454
  });
1194
1455
  describe('Public Event Triggers', () => {
@@ -1267,6 +1528,9 @@ describe('plugin-meetings', () => {
1267
1528
  });
1268
1529
 
1269
1530
  describe('#fetchUserPreferredWebexSite', () => {
1531
+
1532
+ let loggerProxySpy;
1533
+
1270
1534
  it('should call request.getMeetingPreferences to get the preferred webex site ', async () => {
1271
1535
  assert.isDefined(webex.meetings.preferredWebexSite);
1272
1536
  await webex.meetings.fetchUserPreferredWebexSite();
@@ -1274,7 +1538,24 @@ describe('plugin-meetings', () => {
1274
1538
  assert.equal(webex.meetings.preferredWebexSite, 'go.webex.com');
1275
1539
  });
1276
1540
 
1541
+ const setup = ({user} = {}) => {
1542
+ loggerProxySpy = sinon.spy(LoggerProxy.logger, 'error');
1543
+
1544
+ Object.assign(webex.internal, {
1545
+ services: {
1546
+ getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
1547
+ },
1548
+ user: {
1549
+ get: sinon.stub().returns(
1550
+ Promise.resolve(user)
1551
+ ),
1552
+ },
1553
+ });
1554
+ }
1555
+
1277
1556
  it('should not fail if UserPreferred info is not fetched ', async () => {
1557
+ setup();
1558
+
1278
1559
  Object.assign(webex.internal, {
1279
1560
  services: {
1280
1561
  getMeetingPreferences: sinon.stub().returns(Promise.resolve({})),
@@ -1284,7 +1565,62 @@ describe('plugin-meetings', () => {
1284
1565
  await webex.meetings.fetchUserPreferredWebexSite().then(() => {
1285
1566
  assert.equal(webex.meetings.preferredWebexSite, '');
1286
1567
  });
1568
+ assert.calledOnceWithExactly(
1569
+ loggerProxySpy,
1570
+ 'Failed to fetch preferred site from user - no site will be set'
1571
+ );
1287
1572
  });
1573
+
1574
+ it('should fall back to fetching the site from the user', async () => {
1575
+ setup({
1576
+ user: {
1577
+ userPreferences: {
1578
+ userPreferencesItems: {
1579
+ preferredWebExSite: 'site.webex.com',
1580
+ },
1581
+ },
1582
+ },
1583
+ });
1584
+
1585
+ await webex.meetings.fetchUserPreferredWebexSite();
1586
+
1587
+ assert.equal(webex.meetings.preferredWebexSite, 'site.webex.com');
1588
+ assert.notCalled(loggerProxySpy);
1589
+ });
1590
+
1591
+ forEach([
1592
+ {user: undefined},
1593
+ {user: {userPreferences: {}}},
1594
+ {user: {userPreferences: {userPreferencesItems: {}}}},
1595
+ {user: {userPreferences: {userPreferencesItems: {preferredWebExSite: undefined}}}},
1596
+ ], ({user}) => {
1597
+ it(`should handle invalid user data ${user}`, async () => {
1598
+ setup({user});
1599
+
1600
+ await webex.meetings.fetchUserPreferredWebexSite();
1601
+
1602
+ assert.equal(webex.meetings.preferredWebexSite, '');
1603
+ assert.calledOnceWithExactly(
1604
+ loggerProxySpy,
1605
+ 'Failed to fetch preferred site from user - no site will be set'
1606
+ );
1607
+ });
1608
+ });
1609
+
1610
+ it('should handle a get user failure', async () => {
1611
+ setup();
1612
+
1613
+ webex.internal.user.get.rejects(new Error());
1614
+
1615
+ await webex.meetings.fetchUserPreferredWebexSite();
1616
+
1617
+ assert.equal(webex.meetings.preferredWebexSite, '');
1618
+ assert.calledOnceWithExactly(
1619
+ loggerProxySpy,
1620
+ 'Failed to fetch preferred site from user - no site will be set'
1621
+ );
1622
+ });
1623
+
1288
1624
  });
1289
1625
  });
1290
1626
 
@@ -1368,5 +1704,411 @@ describe('plugin-meetings', () => {
1368
1704
  );
1369
1705
  });
1370
1706
  });
1707
+
1708
+ describe('#isNeedHandleMainLocus', () => {
1709
+ let meeting;
1710
+ let newLocus;
1711
+ beforeEach(() => {
1712
+ meeting = {
1713
+ controls: {},
1714
+ self: {},
1715
+ };
1716
+ newLocus = {
1717
+ controls: {},
1718
+ self: {},
1719
+ }
1720
+ });
1721
+ afterEach(() => {
1722
+ sinon.restore();
1723
+ });
1724
+ it('check normal case will return true', () => {
1725
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1726
+ LoggerProxy.logger.log = sinon.stub();
1727
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1728
+ assert.equal(result, true);
1729
+ assert.calledWith(
1730
+ LoggerProxy.logger.log,
1731
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1732
+ );
1733
+ });
1734
+
1735
+ it('check self joined and joined on this device, return true', () => {
1736
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns(null);
1737
+ newLocus.self.state = 'JOINED';
1738
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1739
+
1740
+ LoggerProxy.logger.log = sinon.stub();
1741
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1742
+ assert.equal(result, true);
1743
+ assert.calledWith(
1744
+ LoggerProxy.logger.log,
1745
+ 'Meetings:index#isNeedHandleMainLocus --> self this device shown as JOINED in the main session'
1746
+ );
1747
+ });
1748
+
1749
+ it('if newLocus replaceAt time is expired, then return false', () => {
1750
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({joinedWith: {replaces: [{
1751
+ replaceAt: '2023-03-27T02:17:02.506Z',
1752
+ }]}});
1753
+ newLocus.self.state = 'JOINED';
1754
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(true);
1755
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1756
+ replaces: [{
1757
+ replaceAt: '2023-03-27T02:17:01.506Z'
1758
+ }]
1759
+ })
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 --> this is expired main joined status locus_dto replacedAt 2023-03-27T02:17:01.506Z bo replacedAt 2023-03-27T02:17:02.506Z`
1767
+ );
1768
+ });
1769
+
1770
+ it('check current is in breakout join with this device, return false', () => {
1771
+ sinon.stub(webex.meetings.meetingCollection, 'getActiveBreakoutLocus').returns({
1772
+ joinedWith: {
1773
+ correlationId: '111',
1774
+ },
1775
+ });
1776
+ newLocus.controls.breakout = {url: 'url'};
1777
+ meeting.correlationId = '111';
1778
+
1779
+ LoggerProxy.logger.log = sinon.stub();
1780
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1781
+ assert.equal(result, false);
1782
+ assert.calledWith(
1783
+ LoggerProxy.logger.log,
1784
+ `Meetings:index#isNeedHandleMainLocus --> there is active breakout session and joined on this device, and don't need to handle main session: url`
1785
+ );
1786
+ });
1787
+
1788
+ it('check self is moved and removed, return false', () => {
1789
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1790
+ newLocus.self.state = 'LEFT';
1791
+ newLocus.self.reason = 'MOVED';
1792
+ newLocus.self.removed = true;
1793
+ LoggerProxy.logger.log = sinon.stub();
1794
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1795
+ assert.equal(result, false);
1796
+ assert.calledWith(
1797
+ LoggerProxy.logger.log,
1798
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1799
+ );
1800
+ });
1801
+
1802
+ it('check self is moved and device resource removed, return false', () => {
1803
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1804
+ newLocus.self.state = 'LEFT';
1805
+ newLocus.self.reason = 'MOVED';
1806
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1807
+ state: 'LEFT',
1808
+ reason: 'MOVED',
1809
+ });
1810
+ LoggerProxy.logger.log = sinon.stub();
1811
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1812
+ assert.equal(result, false);
1813
+ assert.calledWith(
1814
+ LoggerProxy.logger.log,
1815
+ 'Meetings:index#isNeedHandleMainLocus --> self moved main locus with self removed status or with device resource moved, not need to handle'
1816
+ );
1817
+ });
1818
+
1819
+ it('check self is joined but device resource removed, return false', () => {
1820
+ webex.meetings.meetingCollection.getActiveBreakoutLocus = sinon.stub().returns(null);
1821
+ sinon.stub(MeetingsUtil, 'joinedOnThisDevice').returns(false);
1822
+ newLocus.self.state = 'JOINED';
1823
+ sinon.stub(MeetingsUtil, 'getThisDevice').returns({
1824
+ state: 'LEFT',
1825
+ reason: 'MOVED',
1826
+ });
1827
+ LoggerProxy.logger.log = sinon.stub();
1828
+ const result = webex.meetings.isNeedHandleMainLocus(meeting, newLocus);
1829
+ assert.equal(result, false);
1830
+ assert.calledWith(
1831
+ LoggerProxy.logger.log,
1832
+ 'Meetings:index#isNeedHandleMainLocus --> self device left&moved in main locus with self joined status, not need to handle'
1833
+ );
1834
+ });
1835
+ });
1836
+
1837
+ describe('#isNeedHandleLocusDTO', () => {
1838
+ let meeting;
1839
+ let newLocus;
1840
+ beforeEach(() => {
1841
+ meeting = {
1842
+ controls: {},
1843
+ self: {},
1844
+ };
1845
+ newLocus = {
1846
+ controls: {},
1847
+ self: {},
1848
+ }
1849
+ });
1850
+ afterEach(() => {
1851
+ sinon.restore();
1852
+ });
1853
+ it('initial DTO , joined breakout session, return true', () => {
1854
+ newLocus.controls.breakout = {
1855
+ sessionType: 'BREAKOUT',
1856
+ };
1857
+ newLocus.self.state = 'JOINED';
1858
+ newLocus.fullState = {
1859
+ active: true,
1860
+ };
1861
+ LoggerProxy.logger.log = sinon.stub();
1862
+ const result = webex.meetings.isNeedHandleLocusDTO(null, newLocus);
1863
+ assert.equal(result, true);
1864
+ assert.calledWith(
1865
+ LoggerProxy.logger.log,
1866
+ `Meetings:index#isNeedHandleLocusDTO --> the first breakout session locusDTO active status: true`
1867
+ );
1868
+ });
1869
+ it('others go to check isNeedHandleMainLocus', () => {
1870
+ newLocus.controls.breakout = {
1871
+ sessionType: 'MAIN',
1872
+ };
1873
+ newLocus.self.state = 'JOINED';
1874
+
1875
+ LoggerProxy.logger.log = sinon.stub();
1876
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1877
+ assert.equal(result, true);
1878
+ assert.calledWith(
1879
+ LoggerProxy.logger.log,
1880
+ 'Meetings:index#isNeedHandleMainLocus --> this is a normal main session locusDTO update case'
1881
+ );
1882
+ });
1883
+ it('joined breakout session, self status is moved, return false', () => {
1884
+ newLocus.controls.breakout = {
1885
+ sessionType: 'BREAKOUT',
1886
+ };
1887
+ newLocus.self.state = 'LEFT';
1888
+ newLocus.self.reason = 'MOVED';
1889
+
1890
+ LoggerProxy.logger.log = sinon.stub();
1891
+ const result = webex.meetings.isNeedHandleLocusDTO(meeting, newLocus);
1892
+ assert.equal(result, false);
1893
+ });
1894
+ });
1895
+
1896
+ describe('#getCorrespondingMeetingByLocus', () => {
1897
+ let locus;
1898
+ let mockReturnMeeting = {meeting: 'meeting1'};
1899
+ const mockGetByKey = (keyWillReturnMeeting) => {
1900
+ webex.meetings.meetingCollection.getByKey = sinon.stub().callsFake((key) => {
1901
+ if (key === keyWillReturnMeeting) {
1902
+ return mockReturnMeeting;
1903
+ }
1904
+ return null;
1905
+ });
1906
+ };
1907
+
1908
+ beforeEach(() => {
1909
+ locus = {
1910
+ controls: {},
1911
+ self: {
1912
+ callbackInfo: {
1913
+ callbackAddress: 'address1',
1914
+ }
1915
+ },
1916
+ info: {
1917
+ webExMeetingId: '123456',
1918
+ isUnifiedSpaceMeeting: false,
1919
+ },
1920
+ conversationUrl: 'conversationUrl1'
1921
+ };
1922
+
1923
+ sinon.stub(MeetingsUtil, 'checkForCorrelationId').returns('correlationId1');
1924
+ });
1925
+ afterEach(() => {
1926
+ sinon.restore();
1927
+ });
1928
+ it('check the calls when no meeting found in meetingCollection', () => {
1929
+ mockGetByKey();
1930
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1931
+ assert.isNull(result);
1932
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1933
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1934
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1935
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1936
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1937
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1938
+ });
1939
+
1940
+ it('not try getByKey "conversationUrl" when isUnifiedSpaceMeeting is true', () => {
1941
+ mockGetByKey();
1942
+ locus.info.isUnifiedSpaceMeeting = true;
1943
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1944
+ assert.isNull(result);
1945
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1946
+ })
1947
+
1948
+ it('check the calls when meeting found by key: locusUrl', () => {
1949
+ mockGetByKey('locusUrl');
1950
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1951
+ assert.deepEqual(result, mockReturnMeeting);
1952
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 1);
1953
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1954
+ });
1955
+
1956
+ it('check the calls when meeting found by key: correlationId', () => {
1957
+ mockGetByKey('correlationId');
1958
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1959
+ assert.deepEqual(result, mockReturnMeeting);
1960
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 2);
1961
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1962
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1963
+ });
1964
+
1965
+ it('check the calls when meeting found by key: sipUri', () => {
1966
+ mockGetByKey('sipUri');
1967
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1968
+ assert.deepEqual(result, mockReturnMeeting);
1969
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 3);
1970
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1971
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1972
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1973
+ });
1974
+
1975
+ it('check the calls when meeting found by key: conversationUrl', () => {
1976
+ mockGetByKey('conversationUrl');
1977
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1978
+ assert.deepEqual(result, mockReturnMeeting);
1979
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 4);
1980
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1981
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1982
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1983
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1984
+ });
1985
+
1986
+ it('check the calls when meeting found by key: meetingNumber', () => {
1987
+ mockGetByKey('meetingNumber');
1988
+ const result = webex.meetings.getCorrespondingMeetingByLocus({locus, locusUrl: url1});
1989
+ assert.deepEqual(result, mockReturnMeeting);
1990
+ assert.callCount(webex.meetings.meetingCollection.getByKey, 5);
1991
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'locusUrl', url1);
1992
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'correlationId', 'correlationId1');
1993
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'sipUri', 'address1');
1994
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'conversationUrl', 'conversationUrl1');
1995
+ assert.calledWith(webex.meetings.meetingCollection.getByKey, 'meetingNumber', '123456');
1996
+ });
1997
+ });
1998
+
1999
+ describe('#sortLocusArrayToUpdate', () => {
2000
+ let lociArray;
2001
+ let mainLocus;
2002
+ let breakoutLocus;
2003
+ beforeEach(() => {
2004
+ mainLocus = {
2005
+ url: 'mainUrl1',
2006
+ controls: {
2007
+ breakout: {
2008
+ sessionType: 'MAIN',
2009
+ url: 'breakoutUnifiedUrl1'
2010
+ }
2011
+ }
2012
+ };
2013
+ breakoutLocus = {
2014
+ url: 'breakoutUrl1',
2015
+ controls: {
2016
+ breakout: {
2017
+ sessionType: 'BREAKOUT',
2018
+ url: 'breakoutUnifiedUrl1'
2019
+ }
2020
+ }
2021
+ };
2022
+ lociArray = [mainLocus, breakoutLocus];
2023
+
2024
+ sinon.stub(MeetingsUtil, 'isValidBreakoutLocus').callsFake((locus) => {
2025
+ return locus.url === 'breakoutUrl1';
2026
+ });
2027
+ });
2028
+ afterEach(() => {
2029
+ sinon.restore();
2030
+ });
2031
+
2032
+ it('if both main and breakout locus is in array for non-exist meeting, return main locus to create first', () => {
2033
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns(undefined);
2034
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2035
+ assert.deepEqual(result, [mainLocus]);
2036
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, [breakoutLocus]);
2037
+ });
2038
+
2039
+ it('if both main and breakout locus is in array for an exist meeting, return all locus', () => {
2040
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2041
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2042
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2043
+ assert.deepEqual(webex.meetings.breakoutLocusForHandleLater, []);
2044
+ });
2045
+
2046
+ it('if the breakout locus has no associated main locus, return all', () => {
2047
+ webex.meetings.meetingCollection.getByKey = sinon.stub().returns({});
2048
+ breakoutLocus.controls.breakout.url = 'testUrl';
2049
+ const result = webex.meetings.sortLocusArrayToUpdate(lociArray);
2050
+ assert.deepEqual(result, [mainLocus, breakoutLocus]);
2051
+ });
2052
+ });
2053
+
2054
+ describe('#checkHandleBreakoutLocus', () => {
2055
+ let breakoutLocus;
2056
+ beforeEach(() => {
2057
+ breakoutLocus = {
2058
+ url: 'breakoutUrl1',
2059
+ controls: {
2060
+ breakout: {
2061
+ sessionType: 'BREAKOUT',
2062
+ url: 'breakoutUnifiedUrl1',
2063
+ }
2064
+ }
2065
+ };
2066
+
2067
+ webex.meetings.handleLocusEvent = sinon.stub();
2068
+ });
2069
+ afterEach(() => {
2070
+ sinon.restore();
2071
+ });
2072
+ it('do nothing if new created locus is null/no cached breakouts for updating', () => {
2073
+ webex.meetings.checkHandleBreakoutLocus(null);
2074
+ webex.meetings.breakoutLocusForHandleLater = null;
2075
+ webex.meetings.checkHandleBreakoutLocus({});
2076
+ webex.meetings.breakoutLocusForHandleLater = [];
2077
+ webex.meetings.checkHandleBreakoutLocus({});
2078
+ assert.notCalled(webex.meetings.handleLocusEvent);
2079
+ });
2080
+
2081
+ it('do nothing if new created locus is breakout locus', () => {
2082
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2083
+ webex.meetings.checkHandleBreakoutLocus(breakoutLocus);
2084
+ assert.notCalled(webex.meetings.handleLocusEvent);
2085
+ });
2086
+
2087
+ it('do nothing if no cached locus is associated with the new created locus', () => {
2088
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2089
+ webex.meetings.checkHandleBreakoutLocus({
2090
+ controls: {
2091
+ breakout: {
2092
+ sessionType: 'MAIN',
2093
+ url: 'breakoutUnifiedUrl2',
2094
+ }
2095
+ }
2096
+ });
2097
+ assert.notCalled(webex.meetings.handleLocusEvent);
2098
+ });
2099
+
2100
+ it('update the cached breakout locus which associate the new created locus', () => {
2101
+ webex.meetings.breakoutLocusForHandleLater = [breakoutLocus];
2102
+ webex.meetings.checkHandleBreakoutLocus({
2103
+ controls: {
2104
+ breakout: {
2105
+ sessionType: 'MAIN',
2106
+ url: 'breakoutUnifiedUrl1',
2107
+ }
2108
+ }
2109
+ });
2110
+ assert.calledWith(webex.meetings.handleLocusEvent, {locus: breakoutLocus, locusUrl: breakoutLocus.url});
2111
+ });
2112
+ });
1371
2113
  });
1372
2114
  });