@webex/plugin-meetings 3.0.0-beta.24 → 3.0.0-beta.241

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