@webex/plugin-meetings 2.60.1-next.7 → 2.60.1-next.8
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.
- package/README.md +12 -0
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.d.ts +12 -2
- package/dist/constants.js +15 -5
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.d.ts +1 -1
- package/dist/locus-info/index.js +8 -8
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.d.ts +62 -18
- package/dist/meeting/index.js +679 -568
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +25 -18
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.d.ts +16 -0
- package/dist/meeting/util.js +71 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.d.ts +25 -3
- package/dist/meetings/index.js +83 -32
- package/dist/meetings/index.js.map +1 -1
- package/dist/reachability/index.js +11 -6
- package/dist/reachability/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +3 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +50 -54
- package/dist/roap/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +1 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js +13 -10
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/constants.ts +13 -2
- package/src/locus-info/index.ts +13 -12
- package/src/meeting/index.ts +215 -116
- package/src/meeting/request.ts +7 -0
- package/src/meeting/util.ts +97 -0
- package/src/meetings/index.ts +59 -18
- package/src/reachability/index.ts +7 -4
- package/src/reconnection-manager/index.ts +1 -1
- package/src/roap/index.ts +49 -51
- package/src/statsAnalyzer/index.ts +2 -2
- package/src/statsAnalyzer/mqaUtil.ts +15 -14
- package/test/unit/spec/locus-info/index.js +53 -5
- package/test/unit/spec/meeting/index.js +1792 -1139
- package/test/unit/spec/meeting/request.js +22 -12
- package/test/unit/spec/meeting/utils.js +93 -0
- package/test/unit/spec/meetings/index.js +180 -21
- package/test/unit/spec/reachability/index.ts +2 -1
- package/test/unit/spec/reconnection-manager/index.js +1 -0
- package/test/unit/spec/roap/index.ts +28 -42
- package/test/unit/spec/stats-analyzer/index.js +415 -30
|
@@ -13,7 +13,7 @@ import {Credentials, Token, WebexPlugin} from '@webex/webex-core';
|
|
|
13
13
|
import Support from '@webex/internal-plugin-support';
|
|
14
14
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
15
15
|
import StaticConfig from '@webex/plugin-meetings/src/common/config';
|
|
16
|
-
import {
|
|
16
|
+
import {Defer} from '@webex/common';
|
|
17
17
|
import {
|
|
18
18
|
FLOOR_ACTION,
|
|
19
19
|
SHARE_STATUS,
|
|
@@ -44,9 +44,7 @@ import {
|
|
|
44
44
|
RemoteTrackType,
|
|
45
45
|
MediaType,
|
|
46
46
|
} from '@webex/internal-media-core';
|
|
47
|
-
import {
|
|
48
|
-
StreamEventNames,
|
|
49
|
-
} from '@webex/media-helpers';
|
|
47
|
+
import {StreamEventNames} from '@webex/media-helpers';
|
|
50
48
|
import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
|
|
51
49
|
import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
|
|
52
50
|
import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
|
|
@@ -73,7 +71,7 @@ import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
|
73
71
|
import {MediaRequestManager} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
|
|
74
72
|
import * as ReceiveSlotManagerModule from '@webex/plugin-meetings/src/multistream/receiveSlotManager';
|
|
75
73
|
import * as SendSlotManagerModule from '@webex/plugin-meetings/src/multistream/sendSlotManager';
|
|
76
|
-
import {
|
|
74
|
+
import {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';
|
|
77
75
|
|
|
78
76
|
import CallDiagnosticLatencies from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics-latencies';
|
|
79
77
|
import LLM from '@webex/internal-plugin-llm';
|
|
@@ -110,10 +108,9 @@ import {
|
|
|
110
108
|
MISSING_ROAP_ANSWER_CLIENT_CODE,
|
|
111
109
|
} from '@webex/internal-plugin-metrics/src/call-diagnostic/config';
|
|
112
110
|
import CallDiagnosticMetrics from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics';
|
|
113
|
-
import {
|
|
111
|
+
import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagnostic/config';
|
|
114
112
|
import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
|
|
115
113
|
|
|
116
|
-
|
|
117
114
|
describe('plugin-meetings', () => {
|
|
118
115
|
const logger = {
|
|
119
116
|
info: () => {},
|
|
@@ -392,7 +389,7 @@ describe('plugin-meetings', () => {
|
|
|
392
389
|
correlationId: uuid4,
|
|
393
390
|
joinTrigger: 'fake-join-trigger',
|
|
394
391
|
loginType: 'fake-login-type',
|
|
395
|
-
}
|
|
392
|
+
},
|
|
396
393
|
},
|
|
397
394
|
{
|
|
398
395
|
parent: webex,
|
|
@@ -495,8 +492,7 @@ describe('plugin-meetings', () => {
|
|
|
495
492
|
let mockSendSlotManagerCtor;
|
|
496
493
|
|
|
497
494
|
beforeEach(() => {
|
|
498
|
-
mockSendSlotManagerCtor = sinon
|
|
499
|
-
.stub(SendSlotManagerModule,'default');
|
|
495
|
+
mockSendSlotManagerCtor = sinon.stub(SendSlotManagerModule, 'default');
|
|
500
496
|
|
|
501
497
|
meeting = new Meeting(
|
|
502
498
|
{
|
|
@@ -868,7 +864,11 @@ describe('plugin-meetings', () => {
|
|
|
868
864
|
|
|
869
865
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
870
866
|
name: 'client.call.initiated',
|
|
871
|
-
payload: {
|
|
867
|
+
payload: {
|
|
868
|
+
trigger: 'user-interaction',
|
|
869
|
+
isRoapCallEnabled: true,
|
|
870
|
+
pstnAudioType: 'dial-in',
|
|
871
|
+
},
|
|
872
872
|
options: {meetingId: meeting.id},
|
|
873
873
|
});
|
|
874
874
|
|
|
@@ -1041,22 +1041,23 @@ describe('plugin-meetings', () => {
|
|
|
1041
1041
|
|
|
1042
1042
|
assert.equal(result, joinMeetingResult);
|
|
1043
1043
|
|
|
1044
|
-
defer.reject(new Error(
|
|
1044
|
+
defer.reject(new Error('bad day', {cause: 'bad weather'}));
|
|
1045
1045
|
|
|
1046
1046
|
try {
|
|
1047
1047
|
await defer.promise;
|
|
1048
1048
|
} catch (err) {
|
|
1049
|
-
|
|
1050
1049
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
|
|
1051
|
-
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1052
|
-
|
|
1050
|
+
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1051
|
+
{correlation_id: meeting.correlationId},
|
|
1052
|
+
]);
|
|
1053
1053
|
|
|
1054
1054
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
|
|
1055
|
-
BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE,
|
|
1055
|
+
BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE,
|
|
1056
|
+
{
|
|
1056
1057
|
correlation_id: meeting.correlationId,
|
|
1057
1058
|
reason: err.message,
|
|
1058
1059
|
stack: err.stack,
|
|
1059
|
-
}
|
|
1060
|
+
},
|
|
1060
1061
|
]);
|
|
1061
1062
|
}
|
|
1062
1063
|
});
|
|
@@ -1094,25 +1095,27 @@ describe('plugin-meetings', () => {
|
|
|
1094
1095
|
|
|
1095
1096
|
assert.equal(result, joinMeetingResult);
|
|
1096
1097
|
|
|
1097
|
-
defer.reject(new Error(
|
|
1098
|
+
defer.reject(new Error('bad day', {cause: 'bad weather'}));
|
|
1098
1099
|
|
|
1099
1100
|
try {
|
|
1100
1101
|
await defer.promise;
|
|
1101
1102
|
} catch (err) {
|
|
1102
1103
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
|
|
1103
|
-
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1104
|
-
|
|
1104
|
+
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1105
|
+
{correlation_id: meeting.correlationId},
|
|
1106
|
+
]);
|
|
1105
1107
|
|
|
1106
1108
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
|
|
1107
|
-
BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE,
|
|
1109
|
+
BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE,
|
|
1110
|
+
{
|
|
1108
1111
|
correlation_id: meeting.correlationId,
|
|
1109
1112
|
reason: err.message,
|
|
1110
1113
|
stack: err.stack,
|
|
1111
|
-
}
|
|
1114
|
+
},
|
|
1112
1115
|
]);
|
|
1113
1116
|
}
|
|
1114
|
-
})
|
|
1115
|
-
})
|
|
1117
|
+
});
|
|
1118
|
+
});
|
|
1116
1119
|
|
|
1117
1120
|
describe('refreshPermissionToken', () => {
|
|
1118
1121
|
it('should continue if permissionTokenRefresh fails with a generic error', async () => {
|
|
@@ -1123,14 +1126,20 @@ describe('plugin-meetings', () => {
|
|
|
1123
1126
|
const result = await meeting.join();
|
|
1124
1127
|
assert.notCalled(stateMachineFailSpy);
|
|
1125
1128
|
assert.equal(result, joinMeetingResult);
|
|
1126
|
-
assert.calledOnceWithExactly(
|
|
1129
|
+
assert.calledOnceWithExactly(
|
|
1130
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1131
|
+
30,
|
|
1132
|
+
'ttl-join'
|
|
1133
|
+
);
|
|
1127
1134
|
} catch (error) {
|
|
1128
1135
|
assert.fail('join should not throw an Error');
|
|
1129
1136
|
}
|
|
1130
|
-
})
|
|
1137
|
+
});
|
|
1131
1138
|
|
|
1132
1139
|
it('should throw if permissionTokenRefresh fails with a captcha error', async () => {
|
|
1133
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1140
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1141
|
+
.stub()
|
|
1142
|
+
.rejects(new CaptchaError('bad captcha'));
|
|
1134
1143
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1135
1144
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
1136
1145
|
|
|
@@ -1139,16 +1148,22 @@ describe('plugin-meetings', () => {
|
|
|
1139
1148
|
assert.fail('join should have thrown a Captcha Error.');
|
|
1140
1149
|
} catch (error) {
|
|
1141
1150
|
assert.calledOnce(stateMachineFailSpy);
|
|
1142
|
-
assert.calledOnceWithExactly(
|
|
1151
|
+
assert.calledOnceWithExactly(
|
|
1152
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1153
|
+
30,
|
|
1154
|
+
'ttl-join'
|
|
1155
|
+
);
|
|
1143
1156
|
assert.instanceOf(error, CaptchaError);
|
|
1144
1157
|
assert.equal(error.message, 'bad captcha');
|
|
1145
1158
|
// should not get to the end promise chain, which does do the join
|
|
1146
1159
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1147
1160
|
}
|
|
1148
|
-
})
|
|
1161
|
+
});
|
|
1149
1162
|
|
|
1150
1163
|
it('should throw if permissionTokenRefresh fails with a password error', async () => {
|
|
1151
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1164
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1165
|
+
.stub()
|
|
1166
|
+
.rejects(new PasswordError('bad password'));
|
|
1152
1167
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1153
1168
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
1154
1169
|
|
|
@@ -1157,16 +1172,22 @@ describe('plugin-meetings', () => {
|
|
|
1157
1172
|
assert.fail('join should have thrown a Password Error.');
|
|
1158
1173
|
} catch (error) {
|
|
1159
1174
|
assert.calledOnce(stateMachineFailSpy);
|
|
1160
|
-
assert.calledOnceWithExactly(
|
|
1175
|
+
assert.calledOnceWithExactly(
|
|
1176
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1177
|
+
30,
|
|
1178
|
+
'ttl-join'
|
|
1179
|
+
);
|
|
1161
1180
|
assert.instanceOf(error, PasswordError);
|
|
1162
1181
|
assert.equal(error.message, 'bad password');
|
|
1163
1182
|
// should not get to the end promise chain, which does do the join
|
|
1164
1183
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1165
1184
|
}
|
|
1166
|
-
})
|
|
1185
|
+
});
|
|
1167
1186
|
|
|
1168
1187
|
it('should throw if permissionTokenRefresh fails with a permission error', async () => {
|
|
1169
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1188
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1189
|
+
.stub()
|
|
1190
|
+
.rejects(new PermissionError('bad permission'));
|
|
1170
1191
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1171
1192
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
1172
1193
|
|
|
@@ -1175,15 +1196,19 @@ describe('plugin-meetings', () => {
|
|
|
1175
1196
|
assert.fail('join should have thrown a Permission Error.');
|
|
1176
1197
|
} catch (error) {
|
|
1177
1198
|
assert.calledOnce(stateMachineFailSpy);
|
|
1178
|
-
assert.calledOnceWithExactly(
|
|
1199
|
+
assert.calledOnceWithExactly(
|
|
1200
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1201
|
+
30,
|
|
1202
|
+
'ttl-join'
|
|
1203
|
+
);
|
|
1179
1204
|
assert.instanceOf(error, PermissionError);
|
|
1180
1205
|
assert.equal(error.message, 'bad permission');
|
|
1181
1206
|
// should not get to the end promise chain, which does do the join
|
|
1182
1207
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1183
1208
|
}
|
|
1184
|
-
})
|
|
1185
|
-
})
|
|
1186
|
-
})
|
|
1209
|
+
});
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1187
1212
|
});
|
|
1188
1213
|
|
|
1189
1214
|
describe('#addMedia', () => {
|
|
@@ -1253,7 +1278,7 @@ describe('plugin-meetings', () => {
|
|
|
1253
1278
|
meeting.webex.meetings.reachability = {
|
|
1254
1279
|
getReachabilityMetrics: sinon.stub().resolves({
|
|
1255
1280
|
someReachabilityMetric1: 'some value1',
|
|
1256
|
-
someReachabilityMetric2: 'some value2'
|
|
1281
|
+
someReachabilityMetric2: 'some value2',
|
|
1257
1282
|
}),
|
|
1258
1283
|
};
|
|
1259
1284
|
|
|
@@ -1713,9 +1738,9 @@ describe('plugin-meetings', () => {
|
|
|
1713
1738
|
|
|
1714
1739
|
it('should reject if waitForMediaConnectionConnected() rejects after turn server retry', async () => {
|
|
1715
1740
|
const FAKE_ERROR = {fatal: true};
|
|
1716
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
1717
|
-
.
|
|
1718
|
-
|
|
1741
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
1742
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
1743
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
1719
1744
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
|
1720
1745
|
const generateClientErrorCodeForIceFailureStub = sinon
|
|
1721
1746
|
.stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
|
|
@@ -1726,17 +1751,22 @@ describe('plugin-meetings', () => {
|
|
|
1726
1751
|
let errorThrown = undefined;
|
|
1727
1752
|
|
|
1728
1753
|
// Stub doTurnDiscovery so that on the first call we skip turn discovery
|
|
1729
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1754
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
1755
|
+
.stub()
|
|
1756
|
+
.onFirstCall()
|
|
1757
|
+
.returns({
|
|
1758
|
+
turnServerInfo: undefined,
|
|
1759
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
1760
|
+
})
|
|
1761
|
+
.onSecondCall()
|
|
1762
|
+
.returns({
|
|
1763
|
+
turnServerInfo: {
|
|
1764
|
+
url: FAKE_TURN_URL,
|
|
1765
|
+
username: FAKE_TURN_USER,
|
|
1766
|
+
password: FAKE_TURN_PASSWORD,
|
|
1767
|
+
},
|
|
1768
|
+
turnDiscoverySkippedReason: undefined,
|
|
1769
|
+
});
|
|
1740
1770
|
meeting.meetingState = 'ACTIVE';
|
|
1741
1771
|
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(new Error('fake error'));
|
|
1742
1772
|
|
|
@@ -1764,18 +1794,20 @@ describe('plugin-meetings', () => {
|
|
|
1764
1794
|
signalingState: 'unknown',
|
|
1765
1795
|
iceConnectionState: 'unknown',
|
|
1766
1796
|
turnServerUsed: false,
|
|
1767
|
-
})
|
|
1797
|
+
});
|
|
1768
1798
|
assert.calledWith(generateClientErrorCodeForIceFailureStub, {
|
|
1769
1799
|
signalingState: 'unknown',
|
|
1770
1800
|
iceConnectionState: 'unknown',
|
|
1771
1801
|
turnServerUsed: true,
|
|
1772
|
-
})
|
|
1802
|
+
});
|
|
1773
1803
|
|
|
1774
1804
|
assert.calledTwice(getErrorPayloadForClientErrorCodeStub);
|
|
1775
|
-
assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
|
1805
|
+
assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
|
1806
|
+
clientErrorCode: MOCK_CLIENT_ERROR_CODE,
|
|
1807
|
+
});
|
|
1776
1808
|
|
|
1777
1809
|
assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
|
|
1778
|
-
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall,
|
|
1810
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
|
|
1779
1811
|
name: 'client.media.capabilities',
|
|
1780
1812
|
payload: {
|
|
1781
1813
|
mediaCapabilities: {
|
|
@@ -1825,18 +1857,26 @@ describe('plugin-meetings', () => {
|
|
|
1825
1857
|
// Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
|
|
1826
1858
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
1827
1859
|
assert.equal(submitInternalEventCalls.length, 4);
|
|
1828
|
-
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1860
|
+
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
1861
|
+
{
|
|
1862
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
1863
|
+
},
|
|
1864
|
+
]);
|
|
1865
|
+
assert.deepEqual(submitInternalEventCalls[1].args, [
|
|
1866
|
+
{
|
|
1867
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
1868
|
+
},
|
|
1869
|
+
]);
|
|
1870
|
+
assert.deepEqual(submitInternalEventCalls[2].args, [
|
|
1871
|
+
{
|
|
1872
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
1873
|
+
},
|
|
1874
|
+
]);
|
|
1875
|
+
assert.deepEqual(submitInternalEventCalls[3].args, [
|
|
1876
|
+
{
|
|
1877
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
1878
|
+
},
|
|
1879
|
+
]);
|
|
1840
1880
|
|
|
1841
1881
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
1842
1882
|
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
@@ -1879,16 +1919,8 @@ describe('plugin-meetings', () => {
|
|
|
1879
1919
|
// Check that doTurnDiscovery is called with th4 correct value of isForced
|
|
1880
1920
|
const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
|
|
1881
1921
|
assert.equal(doTurnDiscoveryCalls.length, 2);
|
|
1882
|
-
assert.deepEqual(doTurnDiscoveryCalls[0].args, [
|
|
1883
|
-
|
|
1884
|
-
false,
|
|
1885
|
-
false
|
|
1886
|
-
]);
|
|
1887
|
-
assert.deepEqual(doTurnDiscoveryCalls[1].args, [
|
|
1888
|
-
meeting,
|
|
1889
|
-
true,
|
|
1890
|
-
true
|
|
1891
|
-
]);
|
|
1922
|
+
assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
|
|
1923
|
+
assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
|
|
1892
1924
|
|
|
1893
1925
|
// Some clean up steps happens twice
|
|
1894
1926
|
assert.calledTwice(forceRtcMetricsSend);
|
|
@@ -1900,9 +1932,9 @@ describe('plugin-meetings', () => {
|
|
|
1900
1932
|
|
|
1901
1933
|
it('should resolve if waitForMediaConnectionConnected() rejects the first time but resolves the second time', async () => {
|
|
1902
1934
|
const FAKE_ERROR = {fatal: true};
|
|
1903
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
1904
|
-
.
|
|
1905
|
-
|
|
1935
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
1936
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
1937
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
1906
1938
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
|
1907
1939
|
const generateClientErrorCodeForIceFailureStub = sinon
|
|
1908
1940
|
.stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
|
|
@@ -1913,18 +1945,28 @@ describe('plugin-meetings', () => {
|
|
|
1913
1945
|
let errorThrown = undefined;
|
|
1914
1946
|
|
|
1915
1947
|
meeting.meetingState = 'ACTIVE';
|
|
1916
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1948
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
1949
|
+
.stub()
|
|
1950
|
+
.onFirstCall()
|
|
1951
|
+
.returns({
|
|
1952
|
+
turnServerInfo: undefined,
|
|
1953
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
1954
|
+
})
|
|
1955
|
+
.onSecondCall()
|
|
1956
|
+
.returns({
|
|
1957
|
+
turnServerInfo: {
|
|
1958
|
+
url: FAKE_TURN_URL,
|
|
1959
|
+
username: FAKE_TURN_USER,
|
|
1960
|
+
password: FAKE_TURN_PASSWORD,
|
|
1961
|
+
},
|
|
1962
|
+
turnDiscoverySkippedReason: undefined,
|
|
1963
|
+
});
|
|
1964
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
|
1965
|
+
.stub()
|
|
1966
|
+
.onFirstCall()
|
|
1967
|
+
.rejects()
|
|
1968
|
+
.onSecondCall()
|
|
1969
|
+
.resolves();
|
|
1928
1970
|
|
|
1929
1971
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
|
1930
1972
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -1949,10 +1991,12 @@ describe('plugin-meetings', () => {
|
|
|
1949
1991
|
signalingState: 'unknown',
|
|
1950
1992
|
iceConnectionState: 'unknown',
|
|
1951
1993
|
turnServerUsed: false,
|
|
1952
|
-
})
|
|
1994
|
+
});
|
|
1953
1995
|
|
|
1954
1996
|
assert.calledOnce(getErrorPayloadForClientErrorCodeStub);
|
|
1955
|
-
assert.calledWith(getErrorPayloadForClientErrorCodeStub, {
|
|
1997
|
+
assert.calledWith(getErrorPayloadForClientErrorCodeStub, {
|
|
1998
|
+
clientErrorCode: MOCK_CLIENT_ERROR_CODE,
|
|
1999
|
+
});
|
|
1956
2000
|
|
|
1957
2001
|
assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
|
|
1958
2002
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
|
|
@@ -2000,18 +2044,26 @@ describe('plugin-meetings', () => {
|
|
|
2000
2044
|
// Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
|
|
2001
2045
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
2002
2046
|
assert.equal(submitInternalEventCalls.length, 4);
|
|
2003
|
-
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2047
|
+
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
2048
|
+
{
|
|
2049
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
2050
|
+
},
|
|
2051
|
+
]);
|
|
2052
|
+
assert.deepEqual(submitInternalEventCalls[1].args, [
|
|
2053
|
+
{
|
|
2054
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
2055
|
+
},
|
|
2056
|
+
]);
|
|
2057
|
+
assert.deepEqual(submitInternalEventCalls[2].args, [
|
|
2058
|
+
{
|
|
2059
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
2060
|
+
},
|
|
2061
|
+
]);
|
|
2062
|
+
assert.deepEqual(submitInternalEventCalls[3].args, [
|
|
2063
|
+
{
|
|
2064
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
2065
|
+
},
|
|
2066
|
+
]);
|
|
2015
2067
|
|
|
2016
2068
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
2017
2069
|
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
@@ -2043,21 +2095,13 @@ describe('plugin-meetings', () => {
|
|
|
2043
2095
|
retriedWithTurnServer: true,
|
|
2044
2096
|
},
|
|
2045
2097
|
]);
|
|
2046
|
-
meeting.roap.doTurnDiscovery
|
|
2098
|
+
meeting.roap.doTurnDiscovery;
|
|
2047
2099
|
|
|
2048
2100
|
// Check that doTurnDiscovery is called with th4 correct value of isForced
|
|
2049
2101
|
const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
|
|
2050
2102
|
assert.equal(doTurnDiscoveryCalls.length, 2);
|
|
2051
|
-
assert.deepEqual(doTurnDiscoveryCalls[0].args, [
|
|
2052
|
-
|
|
2053
|
-
false,
|
|
2054
|
-
false
|
|
2055
|
-
]);
|
|
2056
|
-
assert.deepEqual(doTurnDiscoveryCalls[1].args, [
|
|
2057
|
-
meeting,
|
|
2058
|
-
true,
|
|
2059
|
-
true
|
|
2060
|
-
]);
|
|
2103
|
+
assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
|
|
2104
|
+
assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
|
|
2061
2105
|
|
|
2062
2106
|
assert.calledOnce(forceRtcMetricsSend);
|
|
2063
2107
|
assert.calledOnce(closeMediaConnectionStub);
|
|
@@ -2073,18 +2117,28 @@ describe('plugin-meetings', () => {
|
|
|
2073
2117
|
|
|
2074
2118
|
meeting.meetingState = 'ACTIVE';
|
|
2075
2119
|
meeting.state = 'LEFT';
|
|
2076
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2120
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2121
|
+
.stub()
|
|
2122
|
+
.onFirstCall()
|
|
2123
|
+
.returns({
|
|
2124
|
+
turnServerInfo: undefined,
|
|
2125
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2126
|
+
})
|
|
2127
|
+
.onSecondCall()
|
|
2128
|
+
.returns({
|
|
2129
|
+
turnServerInfo: {
|
|
2130
|
+
url: FAKE_TURN_URL,
|
|
2131
|
+
username: FAKE_TURN_USER,
|
|
2132
|
+
password: FAKE_TURN_PASSWORD,
|
|
2133
|
+
},
|
|
2134
|
+
turnDiscoverySkippedReason: undefined,
|
|
2135
|
+
});
|
|
2136
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
|
2137
|
+
.stub()
|
|
2138
|
+
.onFirstCall()
|
|
2139
|
+
.rejects()
|
|
2140
|
+
.onSecondCall()
|
|
2141
|
+
.resolves();
|
|
2088
2142
|
meeting.join = sinon.stub().resolves();
|
|
2089
2143
|
|
|
2090
2144
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -2115,18 +2169,28 @@ describe('plugin-meetings', () => {
|
|
|
2115
2169
|
|
|
2116
2170
|
meeting.meetingState = 'ACTIVE';
|
|
2117
2171
|
meeting.state = 'LEFT';
|
|
2118
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2172
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2173
|
+
.stub()
|
|
2174
|
+
.onFirstCall()
|
|
2175
|
+
.returns({
|
|
2176
|
+
turnServerInfo: undefined,
|
|
2177
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2178
|
+
})
|
|
2179
|
+
.onSecondCall()
|
|
2180
|
+
.returns({
|
|
2181
|
+
turnServerInfo: {
|
|
2182
|
+
url: FAKE_TURN_URL,
|
|
2183
|
+
username: FAKE_TURN_USER,
|
|
2184
|
+
password: FAKE_TURN_PASSWORD,
|
|
2185
|
+
},
|
|
2186
|
+
turnDiscoverySkippedReason: undefined,
|
|
2187
|
+
});
|
|
2188
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
|
2189
|
+
.stub()
|
|
2190
|
+
.onFirstCall()
|
|
2191
|
+
.rejects()
|
|
2192
|
+
.onSecondCall()
|
|
2193
|
+
.resolves();
|
|
2130
2194
|
meeting.join = sinon.stub().rejects();
|
|
2131
2195
|
|
|
2132
2196
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -2154,7 +2218,7 @@ describe('plugin-meetings', () => {
|
|
|
2154
2218
|
meeting.webex.meetings.reachability = {
|
|
2155
2219
|
getReachabilityMetrics: sinon.stub().resolves({
|
|
2156
2220
|
someReachabilityMetric1: 'some value1',
|
|
2157
|
-
someReachabilityMetric2: 'some value2'
|
|
2221
|
+
someReachabilityMetric2: 'some value2',
|
|
2158
2222
|
}),
|
|
2159
2223
|
};
|
|
2160
2224
|
await meeting.addMedia({
|
|
@@ -2216,7 +2280,8 @@ describe('plugin-meetings', () => {
|
|
|
2216
2280
|
});
|
|
2217
2281
|
|
|
2218
2282
|
// Check that the only metric sent is ADD_MEDIA_FAILURE
|
|
2219
|
-
assert.calledOnceWithExactly(
|
|
2283
|
+
assert.calledOnceWithExactly(
|
|
2284
|
+
Metrics.sendBehavioralMetric,
|
|
2220
2285
|
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
|
2221
2286
|
{
|
|
2222
2287
|
correlation_id: meeting.correlationId,
|
|
@@ -2556,550 +2621,609 @@ describe('plugin-meetings', () => {
|
|
|
2556
2621
|
to @webex/internal-media-core when addMedia, updateMedia, publishTracks, unpublishTracks are called
|
|
2557
2622
|
in various combinations.
|
|
2558
2623
|
*/
|
|
2559
|
-
[true,false].forEach((isMultistream) =>
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2624
|
+
[true, false].forEach((isMultistream) =>
|
|
2625
|
+
describe(`addMedia/updateMedia semi-integration tests (${
|
|
2626
|
+
isMultistream ? 'multistream' : 'transcoded'
|
|
2627
|
+
})`, () => {
|
|
2628
|
+
let fakeMicrophoneStream;
|
|
2629
|
+
let fakeRoapMediaConnection;
|
|
2630
|
+
let fakeMultistreamRoapMediaConnection;
|
|
2631
|
+
let roapMediaConnectionConstructorStub;
|
|
2632
|
+
let multistreamRoapMediaConnectionConstructorStub;
|
|
2633
|
+
let locusMediaRequestStub; // stub for /media requests to Locus
|
|
2567
2634
|
|
|
2568
|
-
|
|
2569
|
-
|
|
2635
|
+
const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
|
|
2636
|
+
const roapOKMessage = {messageType: 'OK', seq: '1'};
|
|
2570
2637
|
|
|
2571
|
-
|
|
2572
|
-
|
|
2638
|
+
let expectedMediaConnectionConfig;
|
|
2639
|
+
let expectedDebugId;
|
|
2573
2640
|
|
|
2574
|
-
|
|
2641
|
+
let clock;
|
|
2575
2642
|
|
|
2576
|
-
|
|
2577
|
-
|
|
2643
|
+
beforeEach(() => {
|
|
2644
|
+
clock = sinon.useFakeTimers();
|
|
2578
2645
|
|
|
2579
|
-
|
|
2646
|
+
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
|
|
2580
2647
|
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2648
|
+
meeting.deviceUrl = 'deviceUrl';
|
|
2649
|
+
meeting.config.deviceType = 'web';
|
|
2650
|
+
meeting.isMultistream = isMultistream;
|
|
2651
|
+
meeting.meetingState = 'ACTIVE';
|
|
2652
|
+
meeting.mediaId = 'fake media id';
|
|
2653
|
+
meeting.selfUrl = 'selfUrl';
|
|
2654
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
2655
|
+
meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
|
|
2656
|
+
meeting.setMercuryListener = sinon.stub();
|
|
2657
|
+
meeting.locusInfo.onFullLocus = sinon.stub();
|
|
2658
|
+
meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
|
|
2659
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2660
|
+
.stub()
|
|
2661
|
+
.resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
|
|
2662
|
+
meeting.deferSDPAnswer = new Defer();
|
|
2663
|
+
meeting.deferSDPAnswer.resolve();
|
|
2664
|
+
meeting.webex.meetings.meetingCollection = new MeetingCollection();
|
|
2665
|
+
meeting.webex.meetings.meetingCollection.set(meeting);
|
|
2666
|
+
|
|
2667
|
+
StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
|
|
2668
|
+
|
|
2669
|
+
// setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
|
|
2670
|
+
expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
|
|
2671
|
+
expectedMediaConnectionConfig = {
|
|
2672
|
+
iceServers: [{urls: undefined, username: '', credential: ''}],
|
|
2673
|
+
skipInactiveTransceivers: false,
|
|
2674
|
+
requireH264: true,
|
|
2675
|
+
sdpMunging: {
|
|
2676
|
+
convertPort9to0: false,
|
|
2677
|
+
addContentSlides: true,
|
|
2678
|
+
bandwidthLimits: {
|
|
2679
|
+
audio: StaticConfig.meetings.bandwidth.audio,
|
|
2680
|
+
video: StaticConfig.meetings.bandwidth.video,
|
|
2681
|
+
},
|
|
2682
|
+
startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
|
|
2683
|
+
periodicKeyframes: 20,
|
|
2684
|
+
disableExtmap: !meeting.config.enableExtmap,
|
|
2685
|
+
disableRtx: !meeting.config.enableRtx,
|
|
2686
|
+
},
|
|
2687
|
+
};
|
|
2621
2688
|
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2689
|
+
// setup stubs
|
|
2690
|
+
fakeMicrophoneStream = {
|
|
2691
|
+
on: sinon.stub(),
|
|
2692
|
+
off: sinon.stub(),
|
|
2693
|
+
getSettings: sinon.stub().returns({
|
|
2694
|
+
deviceId: 'some device id',
|
|
2695
|
+
}),
|
|
2696
|
+
muted: false,
|
|
2697
|
+
setUnmuteAllowed: sinon.stub(),
|
|
2698
|
+
setMuted: sinon.stub(),
|
|
2699
|
+
setServerMuted: sinon.stub(),
|
|
2700
|
+
outputStream: {
|
|
2701
|
+
getTracks: () => {
|
|
2702
|
+
return [
|
|
2703
|
+
{
|
|
2704
|
+
id: 'fake mic',
|
|
2705
|
+
},
|
|
2706
|
+
];
|
|
2707
|
+
},
|
|
2708
|
+
},
|
|
2709
|
+
};
|
|
2641
2710
|
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2711
|
+
fakeRoapMediaConnection = {
|
|
2712
|
+
id: 'roap media connection',
|
|
2713
|
+
close: sinon.stub(),
|
|
2714
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2715
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2716
|
+
update: sinon.stub().resolves({}),
|
|
2717
|
+
on: sinon.stub(),
|
|
2718
|
+
};
|
|
2650
2719
|
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2720
|
+
fakeMultistreamRoapMediaConnection = {
|
|
2721
|
+
id: 'multistream roap media connection',
|
|
2722
|
+
close: sinon.stub(),
|
|
2723
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2724
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2725
|
+
on: sinon.stub(),
|
|
2726
|
+
requestMedia: sinon.stub(),
|
|
2727
|
+
createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
|
|
2728
|
+
createSendSlot: sinon.stub().returns({
|
|
2729
|
+
publishStream: sinon.stub(),
|
|
2730
|
+
unpublishStream: sinon.stub(),
|
|
2731
|
+
}),
|
|
2732
|
+
enableMultistreamAudio: sinon.stub(),
|
|
2733
|
+
};
|
|
2665
2734
|
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2735
|
+
roapMediaConnectionConstructorStub = sinon
|
|
2736
|
+
.stub(internalMediaModule, 'RoapMediaConnection')
|
|
2737
|
+
.returns(fakeRoapMediaConnection);
|
|
2669
2738
|
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2739
|
+
multistreamRoapMediaConnectionConstructorStub = sinon
|
|
2740
|
+
.stub(internalMediaModule, 'MultistreamRoapMediaConnection')
|
|
2741
|
+
.returns(fakeMultistreamRoapMediaConnection);
|
|
2673
2742
|
|
|
2674
|
-
|
|
2675
|
-
|
|
2743
|
+
locusMediaRequestStub = sinon
|
|
2744
|
+
.stub(WebexPlugin.prototype, 'request')
|
|
2745
|
+
.resolves({body: {locus: {fullState: {}}}});
|
|
2746
|
+
});
|
|
2676
2747
|
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2748
|
+
afterEach(() => {
|
|
2749
|
+
clock.restore();
|
|
2750
|
+
sinon.restore();
|
|
2751
|
+
});
|
|
2681
2752
|
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2753
|
+
// helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
|
|
2754
|
+
const stableState = async () => {
|
|
2755
|
+
await testUtils.flushPromises();
|
|
2756
|
+
clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
|
|
2757
|
+
};
|
|
2687
2758
|
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
};
|
|
2759
|
+
const resetHistory = () => {
|
|
2760
|
+
locusMediaRequestStub.resetHistory();
|
|
2761
|
+
fakeRoapMediaConnection.update.resetHistory();
|
|
2762
|
+
try {
|
|
2763
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream.resetHistory();
|
|
2764
|
+
} catch (e) {}
|
|
2765
|
+
};
|
|
2696
2766
|
|
|
2697
|
-
|
|
2698
|
-
|
|
2767
|
+
const getRoapListener = () => {
|
|
2768
|
+
const roapMediaConnectionToCheck = isMultistream
|
|
2769
|
+
? fakeMultistreamRoapMediaConnection
|
|
2770
|
+
: fakeRoapMediaConnection;
|
|
2699
2771
|
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2772
|
+
for (let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx += 1) {
|
|
2773
|
+
if (
|
|
2774
|
+
roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND
|
|
2775
|
+
) {
|
|
2776
|
+
return roapMediaConnectionToCheck.on.getCall(idx).args[1];
|
|
2777
|
+
}
|
|
2703
2778
|
}
|
|
2779
|
+
assert.fail(
|
|
2780
|
+
'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
|
|
2781
|
+
);
|
|
2704
2782
|
};
|
|
2705
|
-
assert.fail(
|
|
2706
|
-
'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
|
|
2707
|
-
);
|
|
2708
|
-
};
|
|
2709
2783
|
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
await roapListener({roapMessage: roapOfferMessage});
|
|
2716
|
-
await stableState();
|
|
2717
|
-
};
|
|
2784
|
+
// simulates a Roap offer being generated by the RoapMediaConnection
|
|
2785
|
+
const simulateRoapOffer = async () => {
|
|
2786
|
+
meeting.deferSDPAnswer = {resolve: sinon.stub()};
|
|
2787
|
+
const roapListener = getRoapListener();
|
|
2718
2788
|
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2789
|
+
await roapListener({roapMessage: roapOfferMessage});
|
|
2790
|
+
await stableState();
|
|
2791
|
+
};
|
|
2722
2792
|
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2793
|
+
// simulates a Roap OK being sent
|
|
2794
|
+
const simulateRoapOk = async () => {
|
|
2795
|
+
const roapListener = getRoapListener();
|
|
2726
2796
|
|
|
2727
|
-
|
|
2728
|
-
|
|
2797
|
+
await roapListener({roapMessage: roapOKMessage});
|
|
2798
|
+
await stableState();
|
|
2799
|
+
};
|
|
2729
2800
|
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2801
|
+
const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
|
|
2802
|
+
const {sdp, seq, tieBreaker} = roapOfferMessage;
|
|
2803
|
+
|
|
2804
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2805
|
+
method: 'PUT',
|
|
2806
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2807
|
+
body: {
|
|
2808
|
+
device: {
|
|
2809
|
+
url: meeting.deviceUrl,
|
|
2810
|
+
deviceType: meeting.config.deviceType,
|
|
2811
|
+
regionCode: 'EU',
|
|
2812
|
+
countryCode: 'UK',
|
|
2813
|
+
},
|
|
2814
|
+
correlationId: meeting.correlationId,
|
|
2815
|
+
localMedias: [
|
|
2816
|
+
{
|
|
2817
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OFFER","sdps":["${sdp}"],"version":"2","seq":"${seq}","tieBreaker":"${tieBreaker}","headers":["includeAnswerInHttpResponse","noOkInTransaction"]}}`,
|
|
2818
|
+
mediaId: 'fake media id',
|
|
2819
|
+
},
|
|
2820
|
+
],
|
|
2821
|
+
clientMediaPreferences: {
|
|
2822
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2823
|
+
joinCookie: undefined,
|
|
2824
|
+
ipver: 0,
|
|
2745
2825
|
},
|
|
2746
|
-
],
|
|
2747
|
-
clientMediaPreferences: {
|
|
2748
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2749
|
-
joinCookie: undefined,
|
|
2750
|
-
ipver: 0,
|
|
2751
2826
|
},
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
};
|
|
2755
|
-
|
|
2756
|
-
const checkOkSent = ({audioMuted, videoMuted}) => {
|
|
2757
|
-
const {seq} = roapOKMessage;
|
|
2827
|
+
});
|
|
2828
|
+
};
|
|
2758
2829
|
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2772
|
-
ipver: undefined,
|
|
2773
|
-
joinCookie: undefined
|
|
2774
|
-
},
|
|
2775
|
-
localMedias: [
|
|
2776
|
-
{
|
|
2777
|
-
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
|
|
2778
|
-
mediaId: 'fake media id'
|
|
2830
|
+
const checkOkSent = ({audioMuted, videoMuted}) => {
|
|
2831
|
+
const {seq} = roapOKMessage;
|
|
2832
|
+
|
|
2833
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2834
|
+
method: 'PUT',
|
|
2835
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2836
|
+
body: {
|
|
2837
|
+
device: {
|
|
2838
|
+
url: meeting.deviceUrl,
|
|
2839
|
+
deviceType: meeting.config.deviceType,
|
|
2840
|
+
countryCode: 'UK',
|
|
2841
|
+
regionCode: 'EU',
|
|
2779
2842
|
},
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2843
|
+
correlationId: meeting.correlationId,
|
|
2844
|
+
clientMediaPreferences: {
|
|
2845
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2846
|
+
ipver: undefined,
|
|
2847
|
+
joinCookie: undefined,
|
|
2848
|
+
},
|
|
2849
|
+
localMedias: [
|
|
2850
|
+
{
|
|
2851
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
|
|
2852
|
+
mediaId: 'fake media id',
|
|
2853
|
+
},
|
|
2854
|
+
],
|
|
2855
|
+
},
|
|
2856
|
+
});
|
|
2857
|
+
};
|
|
2784
2858
|
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2859
|
+
const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
|
|
2860
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2861
|
+
method: 'PUT',
|
|
2862
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2863
|
+
body: {
|
|
2864
|
+
device: {
|
|
2865
|
+
url: meeting.deviceUrl,
|
|
2866
|
+
deviceType: meeting.config.deviceType,
|
|
2867
|
+
regionCode: 'EU',
|
|
2868
|
+
countryCode: 'UK',
|
|
2869
|
+
},
|
|
2870
|
+
correlationId: meeting.correlationId,
|
|
2871
|
+
localMedias: [
|
|
2872
|
+
{
|
|
2873
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted}}`,
|
|
2874
|
+
mediaId: 'fake media id',
|
|
2875
|
+
},
|
|
2876
|
+
],
|
|
2877
|
+
clientMediaPreferences: {
|
|
2878
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2879
|
+
ipver: undefined,
|
|
2880
|
+
},
|
|
2881
|
+
respOnlySdp: true,
|
|
2882
|
+
usingResource: null,
|
|
2795
2883
|
},
|
|
2796
|
-
|
|
2797
|
-
|
|
2884
|
+
});
|
|
2885
|
+
};
|
|
2886
|
+
|
|
2887
|
+
const checkMediaConnectionCreated = ({
|
|
2888
|
+
mediaConnectionConfig,
|
|
2889
|
+
localStreams,
|
|
2890
|
+
direction,
|
|
2891
|
+
remoteQualityLevel,
|
|
2892
|
+
expectedDebugId,
|
|
2893
|
+
meetingId,
|
|
2894
|
+
}) => {
|
|
2895
|
+
if (isMultistream) {
|
|
2896
|
+
const {iceServers} = mediaConnectionConfig;
|
|
2897
|
+
|
|
2898
|
+
assert.calledOnceWithMatch(
|
|
2899
|
+
multistreamRoapMediaConnectionConstructorStub,
|
|
2798
2900
|
{
|
|
2799
|
-
|
|
2800
|
-
mediaId: 'fake media id',
|
|
2901
|
+
iceServers,
|
|
2801
2902
|
},
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2805
|
-
ipver: undefined
|
|
2806
|
-
},
|
|
2807
|
-
respOnlySdp: true,
|
|
2808
|
-
usingResource: null,
|
|
2809
|
-
},
|
|
2810
|
-
});
|
|
2811
|
-
};
|
|
2903
|
+
meetingId
|
|
2904
|
+
);
|
|
2812
2905
|
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2906
|
+
assert.calledWith(
|
|
2907
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2908
|
+
MediaType.AudioMain,
|
|
2909
|
+
direction.audio !== 'inactive'
|
|
2910
|
+
);
|
|
2911
|
+
assert.calledWith(
|
|
2912
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2913
|
+
MediaType.VideoMain,
|
|
2914
|
+
direction.video !== 'inactive'
|
|
2915
|
+
);
|
|
2916
|
+
assert.calledWith(
|
|
2917
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2918
|
+
MediaType.AudioSlides,
|
|
2919
|
+
direction.screenShare !== 'inactive'
|
|
2920
|
+
);
|
|
2921
|
+
assert.calledWith(
|
|
2922
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2923
|
+
MediaType.VideoSlides,
|
|
2924
|
+
direction.screenShare !== 'inactive'
|
|
2925
|
+
);
|
|
2926
|
+
|
|
2927
|
+
for (let type in localStreams) {
|
|
2928
|
+
const stream = localStreams[type];
|
|
2929
|
+
if (stream !== undefined) {
|
|
2930
|
+
switch (type) {
|
|
2931
|
+
case 'audio':
|
|
2932
|
+
assert.calledOnceWithExactly(
|
|
2933
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
2934
|
+
stream
|
|
2935
|
+
);
|
|
2936
|
+
break;
|
|
2937
|
+
case 'video':
|
|
2938
|
+
assert.calledOnceWithExactly(
|
|
2939
|
+
meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream,
|
|
2940
|
+
stream
|
|
2941
|
+
);
|
|
2942
|
+
break;
|
|
2943
|
+
case 'screenShareAudio':
|
|
2944
|
+
assert.calledOnceWithExactly(
|
|
2945
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
|
|
2946
|
+
stream
|
|
2947
|
+
);
|
|
2948
|
+
break;
|
|
2949
|
+
case 'screenShareVideo':
|
|
2950
|
+
assert.calledOnceWithExactly(
|
|
2951
|
+
meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
|
|
2952
|
+
stream
|
|
2953
|
+
);
|
|
2954
|
+
break;
|
|
2955
|
+
}
|
|
2842
2956
|
}
|
|
2843
2957
|
}
|
|
2844
|
-
}
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2958
|
+
} else {
|
|
2959
|
+
assert.calledOnceWithExactly(
|
|
2960
|
+
roapMediaConnectionConstructorStub,
|
|
2961
|
+
mediaConnectionConfig,
|
|
2962
|
+
{
|
|
2963
|
+
localTracks: {
|
|
2964
|
+
audio: localStreams.audio?.outputStream?.getTracks()[0],
|
|
2965
|
+
video: localStreams.video?.outputStream?.getTracks()[0],
|
|
2966
|
+
screenShareVideo: localStreams.screenShareVideo?.outputStream?.getTracks()[0],
|
|
2967
|
+
screenShareAudio: localStreams.screenShareAudio?.outputStream?.getTracks()[0],
|
|
2968
|
+
},
|
|
2969
|
+
direction: {
|
|
2970
|
+
audio: direction.audio,
|
|
2971
|
+
video: direction.video,
|
|
2972
|
+
screenShareVideo: direction.screenShare,
|
|
2973
|
+
},
|
|
2974
|
+
remoteQualityLevel,
|
|
2853
2975
|
},
|
|
2854
|
-
|
|
2855
|
-
|
|
2976
|
+
expectedDebugId
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2979
|
+
};
|
|
2980
|
+
|
|
2981
|
+
it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
|
|
2982
|
+
await meeting.addMedia();
|
|
2983
|
+
await simulateRoapOffer();
|
|
2984
|
+
await simulateRoapOk();
|
|
2985
|
+
|
|
2986
|
+
// check RoapMediaConnection was created correctly
|
|
2987
|
+
checkMediaConnectionCreated({
|
|
2988
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2989
|
+
localStreams: {
|
|
2990
|
+
audio: undefined,
|
|
2991
|
+
video: undefined,
|
|
2992
|
+
screenShareVideo: undefined,
|
|
2993
|
+
screenShareAudio: undefined,
|
|
2856
2994
|
},
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2995
|
+
direction: {
|
|
2996
|
+
audio: 'sendrecv',
|
|
2997
|
+
video: 'sendrecv',
|
|
2998
|
+
screenShare: 'recvonly',
|
|
2999
|
+
},
|
|
3000
|
+
remoteQualityLevel: 'HIGH',
|
|
3001
|
+
expectedDebugId,
|
|
3002
|
+
meetingId: meeting.id,
|
|
3003
|
+
});
|
|
2861
3004
|
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2870
|
-
localStreams: {
|
|
2871
|
-
audio: undefined,
|
|
2872
|
-
video: undefined,
|
|
2873
|
-
screenShareVideo: undefined,
|
|
2874
|
-
screenShareAudio: undefined,
|
|
2875
|
-
},
|
|
2876
|
-
direction: {
|
|
2877
|
-
audio: 'sendrecv',
|
|
2878
|
-
video: 'sendrecv',
|
|
2879
|
-
screenShare: 'recvonly',
|
|
2880
|
-
},
|
|
2881
|
-
remoteQualityLevel: 'HIGH',
|
|
2882
|
-
expectedDebugId,
|
|
2883
|
-
meetingId: meeting.id
|
|
3005
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3006
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3007
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3008
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3009
|
+
|
|
3010
|
+
// and that these were the only /media requests that were sent
|
|
3011
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2884
3012
|
});
|
|
2885
3013
|
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
3014
|
+
it('addMedia() works correctly when media is enabled with streams to publish', async () => {
|
|
3015
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3016
|
+
await simulateRoapOffer();
|
|
3017
|
+
await simulateRoapOk();
|
|
2890
3018
|
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
3019
|
+
// check RoapMediaConnection was created correctly
|
|
3020
|
+
checkMediaConnectionCreated({
|
|
3021
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3022
|
+
localStreams: {
|
|
3023
|
+
audio: fakeMicrophoneStream,
|
|
3024
|
+
video: undefined,
|
|
3025
|
+
screenShareVideo: undefined,
|
|
3026
|
+
screenShareAudio: undefined,
|
|
3027
|
+
},
|
|
3028
|
+
direction: {
|
|
3029
|
+
audio: 'sendrecv',
|
|
3030
|
+
video: 'sendrecv',
|
|
3031
|
+
screenShare: 'recvonly',
|
|
3032
|
+
},
|
|
3033
|
+
remoteQualityLevel: 'HIGH',
|
|
3034
|
+
expectedDebugId,
|
|
3035
|
+
meetingId: meeting.id,
|
|
3036
|
+
});
|
|
2894
3037
|
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
3038
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3039
|
+
checkSdpOfferSent({audioMuted: false, videoMuted: true});
|
|
3040
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3041
|
+
checkOkSent({audioMuted: false, videoMuted: true});
|
|
2899
3042
|
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2903
|
-
localStreams: {
|
|
2904
|
-
audio: fakeMicrophoneStream,
|
|
2905
|
-
video: undefined,
|
|
2906
|
-
screenShareVideo: undefined,
|
|
2907
|
-
screenShareAudio: undefined,
|
|
2908
|
-
},
|
|
2909
|
-
direction: {
|
|
2910
|
-
audio: 'sendrecv',
|
|
2911
|
-
video: 'sendrecv',
|
|
2912
|
-
screenShare: 'recvonly',
|
|
2913
|
-
},
|
|
2914
|
-
remoteQualityLevel: 'HIGH',
|
|
2915
|
-
expectedDebugId,
|
|
2916
|
-
meetingId: meeting.id
|
|
3043
|
+
// and that these were the only /media requests that were sent
|
|
3044
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2917
3045
|
});
|
|
2918
3046
|
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
// check OK was sent with the right audioMuted/videoMuted values
|
|
2922
|
-
checkOkSent({audioMuted: false, videoMuted: true});
|
|
2923
|
-
|
|
2924
|
-
// and that these were the only /media requests that were sent
|
|
2925
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
2926
|
-
});
|
|
3047
|
+
it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
|
|
3048
|
+
fakeMicrophoneStream.muted = true;
|
|
2927
3049
|
|
|
2928
|
-
|
|
2929
|
-
|
|
3050
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3051
|
+
await simulateRoapOffer();
|
|
3052
|
+
await simulateRoapOk();
|
|
2930
3053
|
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
3054
|
+
// check RoapMediaConnection was created correctly
|
|
3055
|
+
checkMediaConnectionCreated({
|
|
3056
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3057
|
+
localStreams: {
|
|
3058
|
+
audio: fakeMicrophoneStream,
|
|
3059
|
+
video: undefined,
|
|
3060
|
+
screenShareVideo: undefined,
|
|
3061
|
+
screenShareAudio: undefined,
|
|
3062
|
+
},
|
|
3063
|
+
direction: {
|
|
3064
|
+
audio: 'sendrecv',
|
|
3065
|
+
video: 'sendrecv',
|
|
3066
|
+
screenShare: 'recvonly',
|
|
3067
|
+
},
|
|
3068
|
+
remoteQualityLevel: 'HIGH',
|
|
3069
|
+
expectedDebugId,
|
|
3070
|
+
meetingId: meeting.id,
|
|
3071
|
+
});
|
|
3072
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3073
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3074
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3075
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2934
3076
|
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2938
|
-
localStreams: {
|
|
2939
|
-
audio: fakeMicrophoneStream,
|
|
2940
|
-
video: undefined,
|
|
2941
|
-
screenShareVideo: undefined,
|
|
2942
|
-
screenShareAudio: undefined,
|
|
2943
|
-
},
|
|
2944
|
-
direction: {
|
|
2945
|
-
audio: 'sendrecv',
|
|
2946
|
-
video: 'sendrecv',
|
|
2947
|
-
screenShare: 'recvonly',
|
|
2948
|
-
},
|
|
2949
|
-
remoteQualityLevel: 'HIGH',
|
|
2950
|
-
expectedDebugId,
|
|
2951
|
-
meetingId: meeting.id
|
|
3077
|
+
// and that these were the only /media requests that were sent
|
|
3078
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2952
3079
|
});
|
|
2953
|
-
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
2954
|
-
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
2955
|
-
// check OK was sent with the right audioMuted/videoMuted values
|
|
2956
|
-
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2957
3080
|
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
3081
|
+
it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
|
|
3082
|
+
await meeting.addMedia({
|
|
3083
|
+
localStreams: {microphone: fakeMicrophoneStream},
|
|
3084
|
+
audioEnabled: false,
|
|
3085
|
+
});
|
|
3086
|
+
await simulateRoapOffer();
|
|
3087
|
+
await simulateRoapOk();
|
|
2961
3088
|
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3089
|
+
// check RoapMediaConnection was created correctly
|
|
3090
|
+
checkMediaConnectionCreated({
|
|
3091
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3092
|
+
localStreams: {
|
|
3093
|
+
audio: fakeMicrophoneStream,
|
|
3094
|
+
video: undefined,
|
|
3095
|
+
screenShareVideo: undefined,
|
|
3096
|
+
screenShareAudio: undefined,
|
|
3097
|
+
},
|
|
3098
|
+
direction: {
|
|
3099
|
+
audio: 'inactive',
|
|
3100
|
+
video: 'sendrecv',
|
|
3101
|
+
screenShare: 'recvonly',
|
|
3102
|
+
},
|
|
3103
|
+
remoteQualityLevel: 'HIGH',
|
|
3104
|
+
expectedDebugId,
|
|
3105
|
+
meetingId: meeting.id,
|
|
3106
|
+
});
|
|
2966
3107
|
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
screenShareAudio: undefined,
|
|
2975
|
-
},
|
|
2976
|
-
direction: {
|
|
2977
|
-
audio: 'inactive',
|
|
2978
|
-
video: 'sendrecv',
|
|
2979
|
-
screenShare: 'recvonly',
|
|
2980
|
-
},
|
|
2981
|
-
remoteQualityLevel: 'HIGH',
|
|
2982
|
-
expectedDebugId,
|
|
2983
|
-
meetingId: meeting.id
|
|
3108
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3109
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3110
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3111
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3112
|
+
|
|
3113
|
+
// and that these were the only /media requests that were sent
|
|
3114
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2984
3115
|
});
|
|
2985
3116
|
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
3117
|
+
it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
|
|
3118
|
+
await meeting.addMedia({audioEnabled: false});
|
|
3119
|
+
await simulateRoapOffer();
|
|
3120
|
+
await simulateRoapOk();
|
|
2990
3121
|
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
3122
|
+
// check RoapMediaConnection was created correctly
|
|
3123
|
+
checkMediaConnectionCreated({
|
|
3124
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3125
|
+
localStreams: {
|
|
3126
|
+
audio: undefined,
|
|
3127
|
+
video: undefined,
|
|
3128
|
+
screenShareVideo: undefined,
|
|
3129
|
+
screenShareAudio: undefined,
|
|
3130
|
+
},
|
|
3131
|
+
direction: {
|
|
3132
|
+
audio: 'inactive',
|
|
3133
|
+
video: 'sendrecv',
|
|
3134
|
+
screenShare: 'recvonly',
|
|
3135
|
+
},
|
|
3136
|
+
remoteQualityLevel: 'HIGH',
|
|
3137
|
+
expectedDebugId,
|
|
3138
|
+
meetingId: meeting.id,
|
|
3139
|
+
});
|
|
2994
3140
|
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
3141
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3142
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3143
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3144
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2999
3145
|
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3003
|
-
localStreams: {
|
|
3004
|
-
audio: undefined,
|
|
3005
|
-
video: undefined,
|
|
3006
|
-
screenShareVideo: undefined,
|
|
3007
|
-
screenShareAudio: undefined,
|
|
3008
|
-
},
|
|
3009
|
-
direction: {
|
|
3010
|
-
audio: 'inactive',
|
|
3011
|
-
video: 'sendrecv',
|
|
3012
|
-
screenShare: 'recvonly',
|
|
3013
|
-
},
|
|
3014
|
-
remoteQualityLevel: 'HIGH',
|
|
3015
|
-
expectedDebugId,
|
|
3016
|
-
meetingId: meeting.id
|
|
3146
|
+
// and that these were the only /media requests that were sent
|
|
3147
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3017
3148
|
});
|
|
3018
3149
|
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
// and that these were the only /media requests that were sent
|
|
3025
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
3026
|
-
});
|
|
3150
|
+
it('addMedia() works correctly when video is disabled with no tracks to publish', async () => {
|
|
3151
|
+
await meeting.addMedia({videoEnabled: false});
|
|
3152
|
+
await simulateRoapOffer();
|
|
3153
|
+
await simulateRoapOk();
|
|
3027
3154
|
|
|
3155
|
+
// check RoapMediaConnection was created correctly
|
|
3156
|
+
checkMediaConnectionCreated({
|
|
3157
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3158
|
+
localStreams: {
|
|
3159
|
+
audio: undefined,
|
|
3160
|
+
video: undefined,
|
|
3161
|
+
screenShareVideo: undefined,
|
|
3162
|
+
screenShareAudio: undefined,
|
|
3163
|
+
},
|
|
3164
|
+
direction: {
|
|
3165
|
+
audio: 'sendrecv',
|
|
3166
|
+
video: 'inactive',
|
|
3167
|
+
screenShare: 'recvonly',
|
|
3168
|
+
},
|
|
3169
|
+
remoteQualityLevel: 'HIGH',
|
|
3170
|
+
expectedDebugId,
|
|
3171
|
+
meetingId: meeting.id,
|
|
3172
|
+
});
|
|
3028
3173
|
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3174
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3175
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3176
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3177
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3033
3178
|
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3037
|
-
localStreams: {
|
|
3038
|
-
audio: undefined,
|
|
3039
|
-
video: undefined,
|
|
3040
|
-
screenShareVideo: undefined,
|
|
3041
|
-
screenShareAudio: undefined,
|
|
3042
|
-
},
|
|
3043
|
-
direction: {
|
|
3044
|
-
audio: 'sendrecv',
|
|
3045
|
-
video: 'inactive',
|
|
3046
|
-
screenShare: 'recvonly',
|
|
3047
|
-
},
|
|
3048
|
-
remoteQualityLevel: 'HIGH',
|
|
3049
|
-
expectedDebugId,
|
|
3050
|
-
meetingId: meeting.id
|
|
3179
|
+
// and that these were the only /media requests that were sent
|
|
3180
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3051
3181
|
});
|
|
3052
3182
|
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
// and that these were the only /media requests that were sent
|
|
3059
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
3060
|
-
});
|
|
3183
|
+
it('addMedia() works correctly when screen share is disabled with no tracks to publish', async () => {
|
|
3184
|
+
await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
|
|
3185
|
+
await simulateRoapOffer();
|
|
3186
|
+
await simulateRoapOk();
|
|
3061
3187
|
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3188
|
+
// check RoapMediaConnection was created correctly
|
|
3189
|
+
checkMediaConnectionCreated({
|
|
3190
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3191
|
+
localStreams: {
|
|
3192
|
+
audio: undefined,
|
|
3193
|
+
video: undefined,
|
|
3194
|
+
screenShareVideo: undefined,
|
|
3195
|
+
screenShareAudio: undefined,
|
|
3196
|
+
},
|
|
3197
|
+
direction: {
|
|
3198
|
+
audio: 'sendrecv',
|
|
3199
|
+
video: 'sendrecv',
|
|
3200
|
+
screenShare: 'inactive',
|
|
3201
|
+
},
|
|
3202
|
+
remoteQualityLevel: 'HIGH',
|
|
3203
|
+
expectedDebugId,
|
|
3204
|
+
meetingId: meeting.id,
|
|
3205
|
+
});
|
|
3066
3206
|
|
|
3207
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3208
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3209
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3210
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3067
3211
|
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3071
|
-
localStreams: {
|
|
3072
|
-
audio: undefined,
|
|
3073
|
-
video: undefined,
|
|
3074
|
-
screenShareVideo: undefined,
|
|
3075
|
-
screenShareAudio: undefined,
|
|
3076
|
-
},
|
|
3077
|
-
direction: {
|
|
3078
|
-
audio: 'sendrecv',
|
|
3079
|
-
video: 'sendrecv',
|
|
3080
|
-
screenShare: 'inactive',
|
|
3081
|
-
},
|
|
3082
|
-
remoteQualityLevel: 'HIGH',
|
|
3083
|
-
expectedDebugId,
|
|
3084
|
-
meetingId: meeting.id
|
|
3212
|
+
// and that these were the only /media requests that were sent
|
|
3213
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3085
3214
|
});
|
|
3086
3215
|
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
{mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
|
|
3099
|
-
{mediaEnabled: false, expected: {direction: 'inactive', localMuteSentValue: undefined}}
|
|
3100
|
-
]
|
|
3101
|
-
.forEach(({mediaEnabled, expected}) => {
|
|
3102
|
-
it(`first publishStreams() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
|
|
3216
|
+
describe('publishStreams()/unpublishStreams() calls', () => {
|
|
3217
|
+
[
|
|
3218
|
+
{mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
|
|
3219
|
+
{
|
|
3220
|
+
mediaEnabled: false,
|
|
3221
|
+
expected: {direction: 'inactive', localMuteSentValue: undefined},
|
|
3222
|
+
},
|
|
3223
|
+
].forEach(({mediaEnabled, expected}) => {
|
|
3224
|
+
it(`first publishStreams() call while media is ${
|
|
3225
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3226
|
+
}`, async () => {
|
|
3103
3227
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3104
3228
|
await simulateRoapOffer();
|
|
3105
3229
|
await simulateRoapOk();
|
|
@@ -3121,10 +3245,18 @@ describe('plugin-meetings', () => {
|
|
|
3121
3245
|
}
|
|
3122
3246
|
|
|
3123
3247
|
if (isMultistream) {
|
|
3124
|
-
assert.calledOnceWithExactly(
|
|
3248
|
+
assert.calledOnceWithExactly(
|
|
3249
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
3250
|
+
fakeMicrophoneStream
|
|
3251
|
+
);
|
|
3125
3252
|
} else {
|
|
3126
3253
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3127
|
-
localTracks: {
|
|
3254
|
+
localTracks: {
|
|
3255
|
+
audio: fakeMicrophoneStream.outputStream.getTracks()[0],
|
|
3256
|
+
video: null,
|
|
3257
|
+
screenShareVideo: null,
|
|
3258
|
+
screenShareAudio: null,
|
|
3259
|
+
},
|
|
3128
3260
|
direction: {
|
|
3129
3261
|
audio: expected.direction,
|
|
3130
3262
|
video: 'sendrecv',
|
|
@@ -3135,7 +3267,9 @@ describe('plugin-meetings', () => {
|
|
|
3135
3267
|
}
|
|
3136
3268
|
});
|
|
3137
3269
|
|
|
3138
|
-
it(`second publishStreams() call while media is ${
|
|
3270
|
+
it(`second publishStreams() call while media is ${
|
|
3271
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3272
|
+
}`, async () => {
|
|
3139
3273
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3140
3274
|
await simulateRoapOffer();
|
|
3141
3275
|
await simulateRoapOk();
|
|
@@ -3152,22 +3286,32 @@ describe('plugin-meetings', () => {
|
|
|
3152
3286
|
setMuted: sinon.stub(),
|
|
3153
3287
|
outputStream: {
|
|
3154
3288
|
getTracks: () => {
|
|
3155
|
-
return [
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3289
|
+
return [
|
|
3290
|
+
{
|
|
3291
|
+
id: 'fake mic 2',
|
|
3292
|
+
},
|
|
3293
|
+
];
|
|
3294
|
+
},
|
|
3295
|
+
},
|
|
3296
|
+
};
|
|
3161
3297
|
|
|
3162
3298
|
await meeting.publishStreams({microphone: fakeMicrophoneStream2});
|
|
3163
3299
|
await stableState();
|
|
3164
3300
|
|
|
3165
3301
|
// only the roap media connection should be updated
|
|
3166
3302
|
if (isMultistream) {
|
|
3167
|
-
assert.calledOnceWithExactly(
|
|
3303
|
+
assert.calledOnceWithExactly(
|
|
3304
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
3305
|
+
fakeMicrophoneStream2
|
|
3306
|
+
);
|
|
3168
3307
|
} else {
|
|
3169
3308
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3170
|
-
localTracks: {
|
|
3309
|
+
localTracks: {
|
|
3310
|
+
audio: fakeMicrophoneStream2.outputStream.getTracks()[0],
|
|
3311
|
+
video: null,
|
|
3312
|
+
screenShareVideo: null,
|
|
3313
|
+
screenShareAudio: null,
|
|
3314
|
+
},
|
|
3171
3315
|
direction: {
|
|
3172
3316
|
audio: expected.direction,
|
|
3173
3317
|
video: 'sendrecv',
|
|
@@ -3181,7 +3325,9 @@ describe('plugin-meetings', () => {
|
|
|
3181
3325
|
assert.notCalled(locusMediaRequestStub);
|
|
3182
3326
|
});
|
|
3183
3327
|
|
|
3184
|
-
it(`unpublishStreams() call while media is ${
|
|
3328
|
+
it(`unpublishStreams() call while media is ${
|
|
3329
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3330
|
+
}`, async () => {
|
|
3185
3331
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3186
3332
|
await simulateRoapOffer();
|
|
3187
3333
|
await simulateRoapOk();
|
|
@@ -3195,10 +3341,17 @@ describe('plugin-meetings', () => {
|
|
|
3195
3341
|
|
|
3196
3342
|
// the roap media connection should be updated
|
|
3197
3343
|
if (isMultistream) {
|
|
3198
|
-
assert.calledOnce(
|
|
3344
|
+
assert.calledOnce(
|
|
3345
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
|
|
3346
|
+
);
|
|
3199
3347
|
} else {
|
|
3200
3348
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3201
|
-
localTracks: {
|
|
3349
|
+
localTracks: {
|
|
3350
|
+
audio: null,
|
|
3351
|
+
video: null,
|
|
3352
|
+
screenShareVideo: null,
|
|
3353
|
+
screenShareAudio: null,
|
|
3354
|
+
},
|
|
3202
3355
|
direction: {
|
|
3203
3356
|
audio: expected.direction,
|
|
3204
3357
|
video: 'sendrecv',
|
|
@@ -3221,180 +3374,194 @@ describe('plugin-meetings', () => {
|
|
|
3221
3374
|
}
|
|
3222
3375
|
});
|
|
3223
3376
|
});
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
describe('updateMedia()', () => {
|
|
3377
|
+
});
|
|
3227
3378
|
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3379
|
+
describe('updateMedia()', () => {
|
|
3380
|
+
const addMedia = async (enableMedia, stream) => {
|
|
3381
|
+
await meeting.addMedia({
|
|
3382
|
+
audioEnabled: enableMedia,
|
|
3383
|
+
localStreams: {microphone: stream},
|
|
3384
|
+
});
|
|
3385
|
+
await simulateRoapOffer();
|
|
3386
|
+
await simulateRoapOk();
|
|
3232
3387
|
|
|
3233
|
-
|
|
3234
|
-
|
|
3388
|
+
resetHistory();
|
|
3389
|
+
};
|
|
3235
3390
|
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3391
|
+
const checkAudioEnabled = (expectedStream, expectedDirection) => {
|
|
3392
|
+
if (isMultistream) {
|
|
3393
|
+
assert.equal(
|
|
3394
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).active,
|
|
3395
|
+
expectedDirection !== 'inactive'
|
|
3396
|
+
);
|
|
3397
|
+
} else {
|
|
3398
|
+
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3399
|
+
localTracks: {
|
|
3400
|
+
audio: expectedStream?.outputStream.getTracks()[0] ?? null,
|
|
3401
|
+
video: null,
|
|
3402
|
+
screenShareVideo: null,
|
|
3403
|
+
screenShareAudio: null,
|
|
3404
|
+
},
|
|
3405
|
+
direction: {
|
|
3406
|
+
audio: expectedDirection,
|
|
3407
|
+
video: 'sendrecv',
|
|
3408
|
+
screenShareVideo: 'recvonly',
|
|
3409
|
+
},
|
|
3410
|
+
remoteQualityLevel: 'HIGH',
|
|
3411
|
+
});
|
|
3412
|
+
}
|
|
3413
|
+
};
|
|
3251
3414
|
|
|
3252
|
-
|
|
3253
|
-
|
|
3415
|
+
it('updateMedia() disables media when nothing is published', async () => {
|
|
3416
|
+
await addMedia(true);
|
|
3254
3417
|
|
|
3255
|
-
|
|
3418
|
+
await meeting.updateMedia({audioEnabled: false});
|
|
3256
3419
|
|
|
3257
|
-
|
|
3258
|
-
|
|
3420
|
+
// the roap media connection should be updated
|
|
3421
|
+
checkAudioEnabled(null, 'inactive');
|
|
3259
3422
|
|
|
3260
|
-
|
|
3261
|
-
|
|
3423
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3424
|
+
await simulateRoapOffer();
|
|
3262
3425
|
|
|
3263
|
-
|
|
3264
|
-
|
|
3426
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3427
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3265
3428
|
|
|
3266
|
-
|
|
3267
|
-
|
|
3429
|
+
// simulate OK being sent in response to remote answer being received
|
|
3430
|
+
await simulateRoapOk();
|
|
3268
3431
|
|
|
3269
|
-
|
|
3270
|
-
|
|
3432
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3433
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3271
3434
|
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3435
|
+
// and no other local mute requests were sent to Locus
|
|
3436
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3437
|
+
});
|
|
3275
3438
|
|
|
3276
|
-
|
|
3277
|
-
|
|
3439
|
+
it('updateMedia() enables media when nothing is published', async () => {
|
|
3440
|
+
await addMedia(false);
|
|
3278
3441
|
|
|
3279
|
-
|
|
3442
|
+
await meeting.updateMedia({audioEnabled: true});
|
|
3280
3443
|
|
|
3281
|
-
|
|
3282
|
-
|
|
3444
|
+
// the roap media connection should be updated
|
|
3445
|
+
checkAudioEnabled(null, 'sendrecv');
|
|
3283
3446
|
|
|
3284
|
-
|
|
3285
|
-
|
|
3447
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3448
|
+
await simulateRoapOffer();
|
|
3286
3449
|
|
|
3287
|
-
|
|
3288
|
-
|
|
3450
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3451
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3289
3452
|
|
|
3290
|
-
|
|
3291
|
-
|
|
3453
|
+
// simulate OK being sent in response to remote answer being received
|
|
3454
|
+
await simulateRoapOk();
|
|
3292
3455
|
|
|
3293
|
-
|
|
3294
|
-
|
|
3456
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3457
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3295
3458
|
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3459
|
+
// and no other local mute requests were sent to Locus
|
|
3460
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3461
|
+
});
|
|
3299
3462
|
|
|
3300
|
-
|
|
3301
|
-
|
|
3463
|
+
it('updateMedia() disables media when stream is published', async () => {
|
|
3464
|
+
await addMedia(true, fakeMicrophoneStream);
|
|
3302
3465
|
|
|
3303
|
-
|
|
3304
|
-
|
|
3466
|
+
await meeting.updateMedia({audioEnabled: false});
|
|
3467
|
+
await stableState();
|
|
3305
3468
|
|
|
3306
|
-
|
|
3307
|
-
|
|
3469
|
+
// the roap media connection should be updated
|
|
3470
|
+
checkAudioEnabled(fakeMicrophoneStream, 'inactive');
|
|
3308
3471
|
|
|
3309
|
-
|
|
3472
|
+
checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
|
|
3310
3473
|
|
|
3311
|
-
|
|
3474
|
+
locusMediaRequestStub.resetHistory();
|
|
3312
3475
|
|
|
3313
|
-
|
|
3314
|
-
|
|
3476
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3477
|
+
await simulateRoapOffer();
|
|
3315
3478
|
|
|
3316
|
-
|
|
3317
|
-
|
|
3479
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3480
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3318
3481
|
|
|
3319
|
-
|
|
3320
|
-
|
|
3482
|
+
// simulate OK being sent in response to remote answer being received
|
|
3483
|
+
await simulateRoapOk();
|
|
3321
3484
|
|
|
3322
|
-
|
|
3323
|
-
|
|
3485
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3486
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3324
3487
|
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3488
|
+
// and no other local mute requests were sent to Locus
|
|
3489
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3490
|
+
});
|
|
3328
3491
|
|
|
3329
|
-
|
|
3330
|
-
|
|
3492
|
+
it('updateMedia() enables media when stream is published', async () => {
|
|
3493
|
+
await addMedia(false, fakeMicrophoneStream);
|
|
3331
3494
|
|
|
3332
|
-
|
|
3333
|
-
|
|
3495
|
+
await meeting.updateMedia({audioEnabled: true});
|
|
3496
|
+
await stableState();
|
|
3334
3497
|
|
|
3335
|
-
|
|
3336
|
-
|
|
3498
|
+
// the roap media connection should be updated
|
|
3499
|
+
checkAudioEnabled(fakeMicrophoneStream, 'sendrecv');
|
|
3337
3500
|
|
|
3338
|
-
|
|
3501
|
+
checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
|
|
3339
3502
|
|
|
3340
|
-
|
|
3503
|
+
locusMediaRequestStub.resetHistory();
|
|
3341
3504
|
|
|
3342
|
-
|
|
3343
|
-
|
|
3505
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3506
|
+
await simulateRoapOffer();
|
|
3344
3507
|
|
|
3345
|
-
|
|
3346
|
-
|
|
3508
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3509
|
+
checkSdpOfferSent({audioMuted: false, videoMuted: true});
|
|
3347
3510
|
|
|
3348
|
-
|
|
3349
|
-
|
|
3511
|
+
// simulate OK being sent in response to remote answer being received
|
|
3512
|
+
await simulateRoapOk();
|
|
3350
3513
|
|
|
3351
|
-
|
|
3352
|
-
|
|
3514
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3515
|
+
checkOkSent({audioMuted: false, videoMuted: true});
|
|
3353
3516
|
|
|
3354
|
-
|
|
3355
|
-
|
|
3517
|
+
// and no other local mute requests were sent to Locus
|
|
3518
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3519
|
+
});
|
|
3356
3520
|
});
|
|
3357
|
-
});
|
|
3358
3521
|
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3522
|
+
[
|
|
3523
|
+
{mute: true, title: 'muting a track before confluence is created'},
|
|
3524
|
+
{mute: false, title: 'unmuting a track before confluence is created'},
|
|
3525
|
+
].forEach(({mute, title}) =>
|
|
3526
|
+
it(title, async () => {
|
|
3527
|
+
// initialize the microphone mute state to opposite of what we do in the test
|
|
3528
|
+
fakeMicrophoneStream.muted = !mute;
|
|
3366
3529
|
|
|
3367
|
-
|
|
3368
|
-
|
|
3530
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3531
|
+
await stableState();
|
|
3369
3532
|
|
|
3370
|
-
|
|
3533
|
+
resetHistory();
|
|
3371
3534
|
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3535
|
+
assert.equal(
|
|
3536
|
+
fakeMicrophoneStream.on.getCall(0).args[0],
|
|
3537
|
+
StreamEventNames.MuteStateChange
|
|
3538
|
+
);
|
|
3539
|
+
const mutedListener = fakeMicrophoneStream.on.getCall(0).args[1];
|
|
3540
|
+
// simulate track being muted
|
|
3541
|
+
mutedListener(mute);
|
|
3376
3542
|
|
|
3377
|
-
|
|
3543
|
+
await stableState();
|
|
3378
3544
|
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3545
|
+
// nothing should happen
|
|
3546
|
+
assert.notCalled(locusMediaRequestStub);
|
|
3547
|
+
assert.notCalled(fakeRoapMediaConnection.update);
|
|
3382
3548
|
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3549
|
+
// now simulate roap offer and ok
|
|
3550
|
+
await simulateRoapOffer();
|
|
3551
|
+
await simulateRoapOk();
|
|
3386
3552
|
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3553
|
+
// it should be sent with the right mute status
|
|
3554
|
+
checkSdpOfferSent({audioMuted: mute, videoMuted: true});
|
|
3555
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3556
|
+
checkOkSent({audioMuted: mute, videoMuted: true});
|
|
3391
3557
|
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3558
|
+
// nothing else should happen
|
|
3559
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3560
|
+
assert.notCalled(fakeRoapMediaConnection.update);
|
|
3561
|
+
})
|
|
3562
|
+
);
|
|
3563
|
+
})
|
|
3564
|
+
);
|
|
3398
3565
|
|
|
3399
3566
|
describe('#acknowledge', () => {
|
|
3400
3567
|
it('should have #acknowledge', () => {
|
|
@@ -3625,6 +3792,7 @@ describe('plugin-meetings', () => {
|
|
|
3625
3792
|
it('should have #requestScreenShareFloor', () => {
|
|
3626
3793
|
assert.exists(meeting.requestScreenShareFloor);
|
|
3627
3794
|
});
|
|
3795
|
+
|
|
3628
3796
|
beforeEach(() => {
|
|
3629
3797
|
meeting.locusInfo.mediaShares = [{name: 'content', url: url1}];
|
|
3630
3798
|
meeting.locusInfo.self = {url: url1};
|
|
@@ -3632,13 +3800,47 @@ describe('plugin-meetings', () => {
|
|
|
3632
3800
|
meeting.mediaProperties.shareVideoStream = {};
|
|
3633
3801
|
meeting.mediaProperties.mediaDirection.sendShare = true;
|
|
3634
3802
|
meeting.state = 'JOINED';
|
|
3803
|
+
meeting.localShareInstanceId = '1234-5678';
|
|
3635
3804
|
});
|
|
3805
|
+
|
|
3806
|
+
afterEach(() => {
|
|
3807
|
+
sinon.restore();
|
|
3808
|
+
});
|
|
3809
|
+
|
|
3636
3810
|
it('should send the share', async () => {
|
|
3637
3811
|
const share = meeting.requestScreenShareFloor();
|
|
3638
3812
|
|
|
3639
3813
|
assert.exists(share.then);
|
|
3640
3814
|
await share;
|
|
3641
3815
|
assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
|
|
3816
|
+
|
|
3817
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
3818
|
+
name: 'client.share.floor-grant.request',
|
|
3819
|
+
payload: {mediaType: 'share', shareInstanceId: '1234-5678'},
|
|
3820
|
+
options: {meetingId: meeting.id},
|
|
3821
|
+
});
|
|
3822
|
+
});
|
|
3823
|
+
|
|
3824
|
+
it('should submit expected metric on failure', async () => {
|
|
3825
|
+
const error = new Error('forced');
|
|
3826
|
+
|
|
3827
|
+
meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.reject(error));
|
|
3828
|
+
const getChangeMeetingFloorErrorPayloadSpy = sinon
|
|
3829
|
+
.stub(MeetingUtil, 'getChangeMeetingFloorErrorPayload')
|
|
3830
|
+
.returns('foo');
|
|
3831
|
+
|
|
3832
|
+
await meeting.requestScreenShareFloor().catch((err) => {
|
|
3833
|
+
assert.equal(err, error);
|
|
3834
|
+
});
|
|
3835
|
+
|
|
3836
|
+
assert.calledWith(getChangeMeetingFloorErrorPayloadSpy, 'forced');
|
|
3837
|
+
|
|
3838
|
+
// ensure the expected CA share metric is submitted
|
|
3839
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
3840
|
+
name: 'client.share.floor-granted.local',
|
|
3841
|
+
payload: {mediaType: 'share', errors: 'foo', shareInstanceId: '1234-5678'},
|
|
3842
|
+
options: {meetingId: meeting.id},
|
|
3843
|
+
});
|
|
3642
3844
|
});
|
|
3643
3845
|
});
|
|
3644
3846
|
|
|
@@ -3691,13 +3893,13 @@ describe('plugin-meetings', () => {
|
|
|
3691
3893
|
outputStream: {
|
|
3692
3894
|
getTracks: () => {
|
|
3693
3895
|
return [{id: 'fake underlying track'}];
|
|
3694
|
-
}
|
|
3695
|
-
}
|
|
3896
|
+
},
|
|
3897
|
+
},
|
|
3696
3898
|
});
|
|
3697
3899
|
beforeEach(() => {
|
|
3698
3900
|
sandbox = sinon.createSandbox();
|
|
3699
|
-
meeting.audio = {
|
|
3700
|
-
meeting.video = {
|
|
3901
|
+
meeting.audio = {enable: sinon.stub()};
|
|
3902
|
+
meeting.video = {enable: sinon.stub()};
|
|
3701
3903
|
meeting.mediaProperties.audioStream = createFakeLocalStream();
|
|
3702
3904
|
meeting.mediaProperties.videoStream = createFakeLocalStream();
|
|
3703
3905
|
meeting.mediaProperties.shareVideoStream = createFakeLocalStream();
|
|
@@ -3709,12 +3911,15 @@ describe('plugin-meetings', () => {
|
|
|
3709
3911
|
receiveAudio: true,
|
|
3710
3912
|
receiveVideo: true,
|
|
3711
3913
|
receiveShare: true,
|
|
3712
|
-
}
|
|
3914
|
+
};
|
|
3713
3915
|
const fakeMultistreamRoapMediaConnection = {
|
|
3714
|
-
createSendSlot: () => {}
|
|
3916
|
+
createSendSlot: () => {},
|
|
3715
3917
|
};
|
|
3716
|
-
sinon.stub(fakeMultistreamRoapMediaConnection,'createSendSlot').returns({active: true});
|
|
3717
|
-
meeting.sendSlotManager.createSlot(
|
|
3918
|
+
sinon.stub(fakeMultistreamRoapMediaConnection, 'createSendSlot').returns({active: true});
|
|
3919
|
+
meeting.sendSlotManager.createSlot(
|
|
3920
|
+
fakeMultistreamRoapMediaConnection,
|
|
3921
|
+
MediaType.AudioMain
|
|
3922
|
+
);
|
|
3718
3923
|
});
|
|
3719
3924
|
|
|
3720
3925
|
afterEach(() => {
|
|
@@ -3771,23 +3976,22 @@ describe('plugin-meetings', () => {
|
|
|
3771
3976
|
// and check that update is called with the original args
|
|
3772
3977
|
assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.update);
|
|
3773
3978
|
|
|
3774
|
-
assert.calledWith(
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
);
|
|
3979
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.update, {
|
|
3980
|
+
localTracks: {
|
|
3981
|
+
audio: meeting.mediaProperties.audioStream.outputStream.getTracks()[0],
|
|
3982
|
+
video: meeting.mediaProperties.videoStream.outputStream.getTracks()[0],
|
|
3983
|
+
screenShareVideo:
|
|
3984
|
+
meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
|
|
3985
|
+
screenShareAudio:
|
|
3986
|
+
meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
|
|
3987
|
+
},
|
|
3988
|
+
direction: {
|
|
3989
|
+
audio: 'inactive',
|
|
3990
|
+
video: 'inactive',
|
|
3991
|
+
screenShareVideo: 'sendrecv',
|
|
3992
|
+
},
|
|
3993
|
+
remoteQualityLevel: 'HIGH',
|
|
3994
|
+
});
|
|
3791
3995
|
assert.isTrue(myPromiseResolved);
|
|
3792
3996
|
});
|
|
3793
3997
|
});
|
|
@@ -3805,15 +4009,13 @@ describe('plugin-meetings', () => {
|
|
|
3805
4009
|
receiveVideo: true,
|
|
3806
4010
|
};
|
|
3807
4011
|
meeting.mediaProperties.mediaDirection = mediaDirection;
|
|
3808
|
-
meeting.mediaProperties.remoteVideoStream = sinon
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
}
|
|
3816
|
-
});
|
|
4012
|
+
meeting.mediaProperties.remoteVideoStream = sinon.stub().returns({
|
|
4013
|
+
outputStream: {
|
|
4014
|
+
getTracks: () => {
|
|
4015
|
+
id: 'some mock id';
|
|
4016
|
+
},
|
|
4017
|
+
},
|
|
4018
|
+
});
|
|
3817
4019
|
|
|
3818
4020
|
meeting.meetingRequest.changeVideoLayoutDebounced = sinon
|
|
3819
4021
|
.stub()
|
|
@@ -3890,7 +4092,9 @@ describe('plugin-meetings', () => {
|
|
|
3890
4092
|
});
|
|
3891
4093
|
|
|
3892
4094
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
3893
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4095
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4096
|
+
.stub()
|
|
4097
|
+
.returns({mockTrack: 'mockTrack'});
|
|
3894
4098
|
|
|
3895
4099
|
// now call it again with just content
|
|
3896
4100
|
await meeting.changeVideoLayout(layoutTypeSingle, {content: {width: 500, height: 600}});
|
|
@@ -3959,7 +4163,9 @@ describe('plugin-meetings', () => {
|
|
|
3959
4163
|
|
|
3960
4164
|
it('does not call changeVideoLayoutDebounced if renderInfo content changes only very slightly', async () => {
|
|
3961
4165
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
3962
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4166
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4167
|
+
.stub()
|
|
4168
|
+
.returns({mockTrack: 'mockTrack'});
|
|
3963
4169
|
|
|
3964
4170
|
await meeting.changeVideoLayout(layoutTypeSingle, {
|
|
3965
4171
|
main: {width: 500, height: 510},
|
|
@@ -3999,7 +4205,9 @@ describe('plugin-meetings', () => {
|
|
|
3999
4205
|
|
|
4000
4206
|
it('rounds the width and height values to nearest integers', async () => {
|
|
4001
4207
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
4002
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4208
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4209
|
+
.stub()
|
|
4210
|
+
.returns({mockTrack: 'mockTrack'});
|
|
4003
4211
|
|
|
4004
4212
|
await meeting.changeVideoLayout(layoutTypeSingle, {
|
|
4005
4213
|
main: {width: 500.5, height: 510.09},
|
|
@@ -4265,11 +4473,7 @@ describe('plugin-meetings', () => {
|
|
|
4265
4473
|
FAKE_OPTIONS
|
|
4266
4474
|
);
|
|
4267
4475
|
|
|
4268
|
-
assert.calledWith(
|
|
4269
|
-
meeting.parseMeetingInfo,
|
|
4270
|
-
{body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
|
|
4271
|
-
FAKE_DESTINATION
|
|
4272
|
-
);
|
|
4476
|
+
assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
|
|
4273
4477
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4274
4478
|
...FAKE_MEETING_INFO,
|
|
4275
4479
|
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
@@ -4323,11 +4527,7 @@ describe('plugin-meetings', () => {
|
|
|
4323
4527
|
);
|
|
4324
4528
|
|
|
4325
4529
|
// parseMeeting info
|
|
4326
|
-
assert.calledWith(
|
|
4327
|
-
meeting.parseMeetingInfo,
|
|
4328
|
-
{body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
|
|
4329
|
-
FAKE_DESTINATION
|
|
4330
|
-
);
|
|
4530
|
+
assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
|
|
4331
4531
|
|
|
4332
4532
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4333
4533
|
...FAKE_MEETING_INFO,
|
|
@@ -4463,7 +4663,7 @@ describe('plugin-meetings', () => {
|
|
|
4463
4663
|
await assert.isRejected(
|
|
4464
4664
|
meeting.fetchMeetingInfo({
|
|
4465
4665
|
password: 'aaa',
|
|
4466
|
-
sendCAevents: true
|
|
4666
|
+
sendCAevents: true,
|
|
4467
4667
|
}),
|
|
4468
4668
|
CaptchaError
|
|
4469
4669
|
);
|
|
@@ -4569,62 +4769,222 @@ describe('plugin-meetings', () => {
|
|
|
4569
4769
|
assert.equal(meeting.requiredCaptcha, null);
|
|
4570
4770
|
});
|
|
4571
4771
|
|
|
4572
|
-
it('refreshes captcha when captcha was required and we received 403 error code', async () => {
|
|
4573
|
-
meeting.destination = FAKE_DESTINATION;
|
|
4574
|
-
meeting.destinationType = FAKE_TYPE;
|
|
4575
|
-
const refreshedCaptcha = {
|
|
4576
|
-
captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
|
|
4577
|
-
verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
|
|
4578
|
-
verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
|
|
4579
|
-
};
|
|
4580
|
-
|
|
4772
|
+
it('refreshes captcha when captcha was required and we received 403 error code', async () => {
|
|
4773
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4774
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4775
|
+
const refreshedCaptcha = {
|
|
4776
|
+
captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
|
|
4777
|
+
verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
|
|
4778
|
+
verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
|
|
4779
|
+
};
|
|
4780
|
+
|
|
4781
|
+
meeting.attrs.meetingInfoProvider = {
|
|
4782
|
+
fetchMeetingInfo: sinon
|
|
4783
|
+
.stub()
|
|
4784
|
+
.throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
|
|
4785
|
+
};
|
|
4786
|
+
meeting.meetingRequest.refreshCaptcha = sinon.stub().returns(
|
|
4787
|
+
Promise.resolve({
|
|
4788
|
+
body: refreshedCaptcha,
|
|
4789
|
+
})
|
|
4790
|
+
);
|
|
4791
|
+
meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
|
4792
|
+
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4793
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4794
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4795
|
+
|
|
4796
|
+
await assert.isRejected(
|
|
4797
|
+
meeting.fetchMeetingInfo({
|
|
4798
|
+
password: 'aaa',
|
|
4799
|
+
captchaCode: 'bbb',
|
|
4800
|
+
sendCAevents: true,
|
|
4801
|
+
})
|
|
4802
|
+
);
|
|
4803
|
+
|
|
4804
|
+
assert.calledWith(
|
|
4805
|
+
meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
|
|
4806
|
+
FAKE_DESTINATION,
|
|
4807
|
+
FAKE_TYPE,
|
|
4808
|
+
'aaa',
|
|
4809
|
+
{code: 'bbb', id: FAKE_CAPTCHA_ID},
|
|
4810
|
+
undefined,
|
|
4811
|
+
'locus-id',
|
|
4812
|
+
{},
|
|
4813
|
+
{meetingId: meeting.id, sendCAevents: true}
|
|
4814
|
+
);
|
|
4815
|
+
|
|
4816
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
4817
|
+
assert.equal(
|
|
4818
|
+
meeting.meetingInfoFailureReason,
|
|
4819
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
4820
|
+
);
|
|
4821
|
+
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4822
|
+
assert.deepEqual(meeting.requiredCaptcha, {
|
|
4823
|
+
captchaId: refreshedCaptcha.captchaID,
|
|
4824
|
+
verificationImageURL: refreshedCaptcha.verificationImageURL,
|
|
4825
|
+
verificationAudioURL: refreshedCaptcha.verificationAudioURL,
|
|
4826
|
+
refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
|
|
4827
|
+
});
|
|
4828
|
+
});
|
|
4829
|
+
});
|
|
4830
|
+
|
|
4831
|
+
describe('#injectMeetingInfo', () => {
|
|
4832
|
+
const FAKE_PASSWORD = '123456';
|
|
4833
|
+
const FAKE_CAPTCHA_CODE = '654321';
|
|
4834
|
+
const FAKE_DESTINATION = 'something@somecompany.com';
|
|
4835
|
+
const FAKE_TYPE = _SIP_URI_;
|
|
4836
|
+
const FAKE_INSTALLED_ORG_ID = '123456';
|
|
4837
|
+
const FAKE_MEETING_INFO_LOOKUP_URL = 'meetingLookupUrl';
|
|
4838
|
+
|
|
4839
|
+
const FAKE_SDK_CAPTCHA_INFO = {};
|
|
4840
|
+
const FAKE_MEETING_INFO = {
|
|
4841
|
+
conversationUrl: 'some_convo_url',
|
|
4842
|
+
locusUrl: 'some_locus_url',
|
|
4843
|
+
sipUrl: 'some_sip_url', // or sipMeetingUri
|
|
4844
|
+
meetingNumber: '123456', // this.config.experimental.enableUnifiedMeetings
|
|
4845
|
+
hostId: 'some_host_id', // this.owner;
|
|
4846
|
+
};
|
|
4847
|
+
|
|
4848
|
+
[
|
|
4849
|
+
{
|
|
4850
|
+
input: {
|
|
4851
|
+
meetingInfo: FAKE_MEETING_INFO,
|
|
4852
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4853
|
+
},
|
|
4854
|
+
expected: {
|
|
4855
|
+
meetingInfo: {
|
|
4856
|
+
...FAKE_MEETING_INFO,
|
|
4857
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4858
|
+
},
|
|
4859
|
+
},
|
|
4860
|
+
},
|
|
4861
|
+
{
|
|
4862
|
+
input: {
|
|
4863
|
+
meetingInfo: undefined,
|
|
4864
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4865
|
+
},
|
|
4866
|
+
expected: {meetingInfo: null},
|
|
4867
|
+
},
|
|
4868
|
+
,
|
|
4869
|
+
{
|
|
4870
|
+
input: {
|
|
4871
|
+
meetingInfo: FAKE_MEETING_INFO,
|
|
4872
|
+
meetingLookupUrl: undefined,
|
|
4873
|
+
},
|
|
4874
|
+
expected: {
|
|
4875
|
+
meetingInfo: {
|
|
4876
|
+
...FAKE_MEETING_INFO,
|
|
4877
|
+
meetingLookupUrl: undefined,
|
|
4878
|
+
},
|
|
4879
|
+
},
|
|
4880
|
+
},
|
|
4881
|
+
,
|
|
4882
|
+
{
|
|
4883
|
+
input: {
|
|
4884
|
+
meetingInfo: undefined,
|
|
4885
|
+
meetingLookupUrl: undefined,
|
|
4886
|
+
},
|
|
4887
|
+
expected: {meetingInfo: null},
|
|
4888
|
+
},
|
|
4889
|
+
].forEach(({input, expected}) => {
|
|
4890
|
+
it(`calls meetingInfoProvider with all the right parameters and parses the result when ${JSON.stringify(
|
|
4891
|
+
input
|
|
4892
|
+
)}`, async () => {
|
|
4893
|
+
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4894
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4895
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4896
|
+
meeting.config.installedOrgID = FAKE_INSTALLED_ORG_ID;
|
|
4897
|
+
meeting.parseMeetingInfo = sinon.stub().returns(undefined);
|
|
4898
|
+
meeting.updateMeetingActions = sinon.stub().returns(undefined);
|
|
4899
|
+
|
|
4900
|
+
await meeting.injectMeetingInfo(
|
|
4901
|
+
input.meetingInfo,
|
|
4902
|
+
{sendCAevents: true},
|
|
4903
|
+
input.meetingLookupUrl
|
|
4904
|
+
);
|
|
4905
|
+
|
|
4906
|
+
assert.calledWith(meeting.parseMeetingInfo, input.meetingInfo, FAKE_DESTINATION);
|
|
4907
|
+
assert.deepEqual(meeting.meetingInfo, expected.meetingInfo);
|
|
4908
|
+
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
|
|
4909
|
+
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4910
|
+
assert.equal(meeting.requiredCaptcha, null);
|
|
4911
|
+
assert.calledThrice(TriggerProxy.trigger);
|
|
4912
|
+
assert.calledWith(
|
|
4913
|
+
TriggerProxy.trigger,
|
|
4914
|
+
meeting,
|
|
4915
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4916
|
+
'meeting:meetingInfoAvailable'
|
|
4917
|
+
);
|
|
4918
|
+
assert.calledWith(meeting.updateMeetingActions);
|
|
4919
|
+
});
|
|
4920
|
+
});
|
|
4921
|
+
|
|
4922
|
+
it('fails if captchaCode is provided when captcha not needed', async () => {
|
|
4923
|
+
meeting.attrs.meetingInfoProvider = {
|
|
4924
|
+
fetchMeetingInfo: sinon.stub().resolves(),
|
|
4925
|
+
};
|
|
4926
|
+
meeting.requiredCaptcha = null;
|
|
4927
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4928
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4929
|
+
|
|
4930
|
+
await assert.isRejected(
|
|
4931
|
+
meeting.injectMeetingInfo(
|
|
4932
|
+
{},
|
|
4933
|
+
{
|
|
4934
|
+
captchaCode: FAKE_CAPTCHA_CODE,
|
|
4935
|
+
}
|
|
4936
|
+
),
|
|
4937
|
+
Error,
|
|
4938
|
+
'injectMeetingInfo() called with captchaCode when captcha was not required'
|
|
4939
|
+
);
|
|
4940
|
+
|
|
4941
|
+
assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4942
|
+
assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
|
|
4943
|
+
assert.neverCalledWith(
|
|
4944
|
+
TriggerProxy.trigger,
|
|
4945
|
+
meeting,
|
|
4946
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4947
|
+
'meeting:meetingInfoAvailable'
|
|
4948
|
+
);
|
|
4949
|
+
});
|
|
4950
|
+
|
|
4951
|
+
it('fails if password is provided when not required', async () => {
|
|
4581
4952
|
meeting.attrs.meetingInfoProvider = {
|
|
4582
|
-
fetchMeetingInfo: sinon
|
|
4583
|
-
.stub()
|
|
4584
|
-
.throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
|
|
4953
|
+
fetchMeetingInfo: sinon.stub().resolves(),
|
|
4585
4954
|
};
|
|
4586
|
-
meeting.
|
|
4587
|
-
Promise.resolve({
|
|
4588
|
-
body: refreshedCaptcha,
|
|
4589
|
-
})
|
|
4590
|
-
);
|
|
4591
|
-
meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
|
4592
|
-
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4955
|
+
meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
4593
4956
|
meeting.destination = FAKE_DESTINATION;
|
|
4594
4957
|
meeting.destinationType = FAKE_TYPE;
|
|
4595
4958
|
|
|
4596
4959
|
await assert.isRejected(
|
|
4597
|
-
meeting.
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4960
|
+
meeting.injectMeetingInfo(
|
|
4961
|
+
{},
|
|
4962
|
+
{
|
|
4963
|
+
password: FAKE_PASSWORD,
|
|
4964
|
+
}
|
|
4965
|
+
),
|
|
4966
|
+
Error,
|
|
4967
|
+
'injectMeetingInfo() called with password when password was not required'
|
|
4602
4968
|
);
|
|
4603
4969
|
|
|
4604
|
-
assert.
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
{
|
|
4610
|
-
|
|
4611
|
-
'locus-id',
|
|
4612
|
-
{},
|
|
4613
|
-
{meetingId: meeting.id, sendCAevents: true}
|
|
4970
|
+
assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4971
|
+
assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
|
|
4972
|
+
assert.neverCalledWith(
|
|
4973
|
+
TriggerProxy.trigger,
|
|
4974
|
+
meeting,
|
|
4975
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4976
|
+
'meeting:meetingInfoAvailable'
|
|
4614
4977
|
);
|
|
4978
|
+
});
|
|
4615
4979
|
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4622
|
-
assert.deepEqual(meeting.requiredCaptcha, {
|
|
4623
|
-
captchaId: refreshedCaptcha.captchaID,
|
|
4624
|
-
verificationImageURL: refreshedCaptcha.verificationImageURL,
|
|
4625
|
-
verificationAudioURL: refreshedCaptcha.verificationAudioURL,
|
|
4626
|
-
refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
|
|
4980
|
+
it('should clean the fetch meeting info timeout', async () => {
|
|
4981
|
+
meeting.fetchMeetingInfoTimeoutId = 42; // pending delayed request
|
|
4982
|
+
|
|
4983
|
+
await meeting.injectMeetingInfo(FAKE_MEETING_INFO, {
|
|
4984
|
+
sendCAevents: true,
|
|
4627
4985
|
});
|
|
4986
|
+
|
|
4987
|
+
assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
|
|
4628
4988
|
});
|
|
4629
4989
|
});
|
|
4630
4990
|
|
|
@@ -4648,9 +5008,9 @@ describe('plugin-meetings', () => {
|
|
|
4648
5008
|
meeting.destination = 'meeting-destination';
|
|
4649
5009
|
meeting.destinationType = 'meeting-destination-type';
|
|
4650
5010
|
meeting.updateMeetingActions = sinon.stub().returns(undefined);
|
|
4651
|
-
|
|
5011
|
+
|
|
4652
5012
|
meeting.meetingInfoExtraParams = {
|
|
4653
|
-
extraParam1: 'value1'
|
|
5013
|
+
extraParam1: 'value1',
|
|
4654
5014
|
};
|
|
4655
5015
|
meeting.attrs.meetingInfoProvider = {
|
|
4656
5016
|
fetchMeetingInfo: sinon
|
|
@@ -4685,7 +5045,7 @@ describe('plugin-meetings', () => {
|
|
|
4685
5045
|
);
|
|
4686
5046
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4687
5047
|
...FAKE_MEETING_INFO,
|
|
4688
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5048
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4689
5049
|
});
|
|
4690
5050
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4691
5051
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4700,7 +5060,9 @@ describe('plugin-meetings', () => {
|
|
|
4700
5060
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4701
5061
|
|
|
4702
5062
|
assert.calledWith(
|
|
4703
|
-
Metrics.sendBehavioralMetric,
|
|
5063
|
+
Metrics.sendBehavioralMetric,
|
|
5064
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5065
|
+
{
|
|
4704
5066
|
correlationId: meeting.correlationId,
|
|
4705
5067
|
timeLeft: FAKE_TIMESTAMPS.timeLeft,
|
|
4706
5068
|
expiryTime: FAKE_TIMESTAMPS.expiryTime,
|
|
@@ -4728,7 +5090,7 @@ describe('plugin-meetings', () => {
|
|
|
4728
5090
|
);
|
|
4729
5091
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4730
5092
|
...FAKE_MEETING_INFO,
|
|
4731
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5093
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4732
5094
|
});
|
|
4733
5095
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4734
5096
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4743,7 +5105,9 @@ describe('plugin-meetings', () => {
|
|
|
4743
5105
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4744
5106
|
|
|
4745
5107
|
assert.calledWith(
|
|
4746
|
-
Metrics.sendBehavioralMetric,
|
|
5108
|
+
Metrics.sendBehavioralMetric,
|
|
5109
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5110
|
+
{
|
|
4747
5111
|
correlationId: meeting.correlationId,
|
|
4748
5112
|
timeLeft: undefined,
|
|
4749
5113
|
expiryTime: undefined,
|
|
@@ -4774,13 +5138,13 @@ describe('plugin-meetings', () => {
|
|
|
4774
5138
|
'locus-id',
|
|
4775
5139
|
{
|
|
4776
5140
|
extraParam1: 'value1',
|
|
4777
|
-
permissionToken: FAKE_PERMISSION_TOKEN
|
|
5141
|
+
permissionToken: FAKE_PERMISSION_TOKEN,
|
|
4778
5142
|
},
|
|
4779
5143
|
{meetingId: meeting.id, sendCAevents: true}
|
|
4780
5144
|
);
|
|
4781
5145
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4782
5146
|
...FAKE_MEETING_INFO,
|
|
4783
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5147
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4784
5148
|
});
|
|
4785
5149
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4786
5150
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4795,7 +5159,9 @@ describe('plugin-meetings', () => {
|
|
|
4795
5159
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4796
5160
|
|
|
4797
5161
|
assert.calledWith(
|
|
4798
|
-
Metrics.sendBehavioralMetric,
|
|
5162
|
+
Metrics.sendBehavioralMetric,
|
|
5163
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5164
|
+
{
|
|
4799
5165
|
correlationId: meeting.correlationId,
|
|
4800
5166
|
timeLeft: FAKE_TIMESTAMPS.timeLeft,
|
|
4801
5167
|
expiryTime: FAKE_TIMESTAMPS.expiryTime,
|
|
@@ -4824,9 +5190,12 @@ describe('plugin-meetings', () => {
|
|
|
4824
5190
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4825
5191
|
|
|
4826
5192
|
assert.calledWith(
|
|
4827
|
-
Metrics.sendBehavioralMetric,
|
|
5193
|
+
Metrics.sendBehavioralMetric,
|
|
5194
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5195
|
+
{
|
|
4828
5196
|
correlationId: meeting.correlationId,
|
|
4829
|
-
reason:
|
|
5197
|
+
reason:
|
|
5198
|
+
'Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action.',
|
|
4830
5199
|
stack: sinon.match.any,
|
|
4831
5200
|
}
|
|
4832
5201
|
);
|
|
@@ -4845,13 +5214,18 @@ describe('plugin-meetings', () => {
|
|
|
4845
5214
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4846
5215
|
...FAKE_MEETING_INFO,
|
|
4847
5216
|
});
|
|
4848
|
-
assert.equal(
|
|
5217
|
+
assert.equal(
|
|
5218
|
+
meeting.meetingInfoFailureReason,
|
|
5219
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
5220
|
+
);
|
|
4849
5221
|
assert.equal(meeting.requiredCaptcha, null);
|
|
4850
5222
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4851
5223
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4852
5224
|
|
|
4853
5225
|
assert.calledWith(
|
|
4854
|
-
Metrics.sendBehavioralMetric,
|
|
5226
|
+
Metrics.sendBehavioralMetric,
|
|
5227
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5228
|
+
{
|
|
4855
5229
|
correlationId: meeting.correlationId,
|
|
4856
5230
|
reason: 'Password is required, please use verifyPassword()',
|
|
4857
5231
|
stack: sinon.match.any,
|
|
@@ -4875,13 +5249,18 @@ describe('plugin-meetings', () => {
|
|
|
4875
5249
|
await assert.isRejected(meeting.refreshPermissionToken());
|
|
4876
5250
|
|
|
4877
5251
|
assert.calledOnce(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4878
|
-
assert.equal(
|
|
5252
|
+
assert.equal(
|
|
5253
|
+
meeting.meetingInfoFailureReason,
|
|
5254
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
5255
|
+
);
|
|
4879
5256
|
assert.equal(meeting.requiredCaptcha, FAKE_SDK_CAPTCHA_INFO);
|
|
4880
5257
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4881
5258
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4882
5259
|
|
|
4883
5260
|
assert.calledWith(
|
|
4884
|
-
Metrics.sendBehavioralMetric,
|
|
5261
|
+
Metrics.sendBehavioralMetric,
|
|
5262
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5263
|
+
{
|
|
4885
5264
|
correlationId: meeting.correlationId,
|
|
4886
5265
|
reason: 'Captcha is required.',
|
|
4887
5266
|
stack: sinon.match.any,
|
|
@@ -5306,14 +5685,26 @@ describe('plugin-meetings', () => {
|
|
|
5306
5685
|
describe('#updateCallStateForMetrics', () => {
|
|
5307
5686
|
it('should update the callState, overriding existing values', () => {
|
|
5308
5687
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId});
|
|
5309
|
-
meeting.updateCallStateForMetrics({
|
|
5310
|
-
|
|
5688
|
+
meeting.updateCallStateForMetrics({
|
|
5689
|
+
correlationId: uuid1,
|
|
5690
|
+
joinTrigger: 'jt',
|
|
5691
|
+
loginType: 'lt',
|
|
5692
|
+
});
|
|
5693
|
+
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5694
|
+
correlationId: uuid1,
|
|
5695
|
+
joinTrigger: 'jt',
|
|
5696
|
+
loginType: 'lt',
|
|
5697
|
+
});
|
|
5311
5698
|
});
|
|
5312
5699
|
|
|
5313
5700
|
it('should update the callState, keeping non-supplied values', () => {
|
|
5314
5701
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId});
|
|
5315
5702
|
meeting.updateCallStateForMetrics({joinTrigger: 'jt', loginType: 'lt'});
|
|
5316
|
-
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5703
|
+
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5704
|
+
correlationId,
|
|
5705
|
+
joinTrigger: 'jt',
|
|
5706
|
+
loginType: 'lt',
|
|
5707
|
+
});
|
|
5317
5708
|
});
|
|
5318
5709
|
});
|
|
5319
5710
|
|
|
@@ -5327,35 +5718,35 @@ describe('plugin-meetings', () => {
|
|
|
5327
5718
|
beforeEach(() => {
|
|
5328
5719
|
audioStream = {
|
|
5329
5720
|
getSettings: sinon.stub().returns({
|
|
5330
|
-
deviceId: 'some device id'
|
|
5721
|
+
deviceId: 'some device id',
|
|
5331
5722
|
}),
|
|
5332
5723
|
on: sinon.stub(),
|
|
5333
5724
|
off: sinon.stub(),
|
|
5334
|
-
}
|
|
5725
|
+
};
|
|
5335
5726
|
|
|
5336
5727
|
videoStream = {
|
|
5337
5728
|
getSettings: sinon.stub().returns({
|
|
5338
|
-
deviceId: 'some device id'
|
|
5729
|
+
deviceId: 'some device id',
|
|
5339
5730
|
}),
|
|
5340
5731
|
on: sinon.stub(),
|
|
5341
5732
|
off: sinon.stub(),
|
|
5342
|
-
}
|
|
5733
|
+
};
|
|
5343
5734
|
|
|
5344
5735
|
audioShareStream = {
|
|
5345
5736
|
on: sinon.stub(),
|
|
5346
5737
|
off: sinon.stub(),
|
|
5347
5738
|
getSettings: sinon.stub().returns({
|
|
5348
|
-
deviceId: 'some device id'
|
|
5739
|
+
deviceId: 'some device id',
|
|
5349
5740
|
}),
|
|
5350
|
-
}
|
|
5741
|
+
};
|
|
5351
5742
|
|
|
5352
5743
|
videoShareStream = {
|
|
5353
5744
|
on: sinon.stub(),
|
|
5354
5745
|
off: sinon.stub(),
|
|
5355
5746
|
getSettings: sinon.stub().returns({
|
|
5356
|
-
deviceId: 'some device id'
|
|
5747
|
+
deviceId: 'some device id',
|
|
5357
5748
|
}),
|
|
5358
|
-
}
|
|
5749
|
+
};
|
|
5359
5750
|
|
|
5360
5751
|
meeting.requestScreenShareFloor = sinon.stub().resolves({});
|
|
5361
5752
|
meeting.releaseScreenShareFloor = sinon.stub().resolves({});
|
|
@@ -5366,20 +5757,32 @@ describe('plugin-meetings', () => {
|
|
|
5366
5757
|
};
|
|
5367
5758
|
meeting.isMultistream = true;
|
|
5368
5759
|
meeting.mediaProperties.webrtcMediaConnection = {};
|
|
5369
|
-
meeting.audio = {
|
|
5370
|
-
meeting.video = {
|
|
5760
|
+
meeting.audio = {handleLocalStreamChange: sinon.stub()};
|
|
5761
|
+
meeting.video = {handleLocalStreamChange: sinon.stub()};
|
|
5371
5762
|
fakeMultistreamRoapMediaConnection = {
|
|
5372
5763
|
createSendSlot: () => {
|
|
5373
5764
|
return {
|
|
5374
5765
|
publishStream: sinon.stub(),
|
|
5375
5766
|
unpublishStream: sinon.stub(),
|
|
5376
|
-
}
|
|
5377
|
-
}
|
|
5378
|
-
}
|
|
5379
|
-
meeting.sendSlotManager.createSlot(
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5767
|
+
};
|
|
5768
|
+
},
|
|
5769
|
+
};
|
|
5770
|
+
meeting.sendSlotManager.createSlot(
|
|
5771
|
+
fakeMultistreamRoapMediaConnection,
|
|
5772
|
+
MediaType.VideoSlides
|
|
5773
|
+
);
|
|
5774
|
+
meeting.sendSlotManager.createSlot(
|
|
5775
|
+
fakeMultistreamRoapMediaConnection,
|
|
5776
|
+
MediaType.AudioSlides
|
|
5777
|
+
);
|
|
5778
|
+
meeting.sendSlotManager.createSlot(
|
|
5779
|
+
fakeMultistreamRoapMediaConnection,
|
|
5780
|
+
MediaType.AudioMain
|
|
5781
|
+
);
|
|
5782
|
+
meeting.sendSlotManager.createSlot(
|
|
5783
|
+
fakeMultistreamRoapMediaConnection,
|
|
5784
|
+
MediaType.VideoMain
|
|
5785
|
+
);
|
|
5383
5786
|
});
|
|
5384
5787
|
afterEach(() => {
|
|
5385
5788
|
sinon.restore();
|
|
@@ -5415,16 +5818,22 @@ describe('plugin-meetings', () => {
|
|
|
5415
5818
|
const checkScreenShareVideoPublished = (stream) => {
|
|
5416
5819
|
assert.calledOnce(meeting.requestScreenShareFloor);
|
|
5417
5820
|
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5821
|
+
// ensure the CA share metrics are submitted
|
|
5822
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
5823
|
+
name: 'client.share.initiated',
|
|
5824
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.localShareInstanceId},
|
|
5825
|
+
options: {meetingId: meeting.id},
|
|
5826
|
+
});
|
|
5423
5827
|
assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
|
|
5424
5828
|
};
|
|
5425
5829
|
|
|
5426
5830
|
const checkScreenShareAudioPublished = (stream) => {
|
|
5427
|
-
|
|
5831
|
+
// ensure the CA share metrics are submitted
|
|
5832
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
5833
|
+
name: 'client.share.initiated',
|
|
5834
|
+
payload: {mediaType: 'share', shareInstanceId: meeting.localShareInstanceId},
|
|
5835
|
+
options: {meetingId: meeting.id},
|
|
5836
|
+
});
|
|
5428
5837
|
|
|
5429
5838
|
assert.calledWith(
|
|
5430
5839
|
meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
|
|
@@ -5503,18 +5912,14 @@ describe('plugin-meetings', () => {
|
|
|
5503
5912
|
});
|
|
5504
5913
|
|
|
5505
5914
|
const checkAudioUnpublished = () => {
|
|
5506
|
-
assert.calledOnce(
|
|
5507
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
|
|
5508
|
-
);
|
|
5915
|
+
assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream);
|
|
5509
5916
|
|
|
5510
5917
|
assert.equal(meeting.mediaProperties.audioStream, null);
|
|
5511
5918
|
assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, 'fake value');
|
|
5512
5919
|
};
|
|
5513
5920
|
|
|
5514
5921
|
const checkVideoUnpublished = () => {
|
|
5515
|
-
assert.calledOnce(
|
|
5516
|
-
meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream
|
|
5517
|
-
);
|
|
5922
|
+
assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream);
|
|
5518
5923
|
|
|
5519
5924
|
assert.equal(meeting.mediaProperties.videoStream, null);
|
|
5520
5925
|
assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, 'fake value');
|
|
@@ -5547,12 +5952,22 @@ describe('plugin-meetings', () => {
|
|
|
5547
5952
|
it('fails if there is no media connection', async () => {
|
|
5548
5953
|
meeting.mediaProperties.webrtcMediaConnection = undefined;
|
|
5549
5954
|
await assert.isRejected(
|
|
5550
|
-
meeting.unpublishStreams([
|
|
5955
|
+
meeting.unpublishStreams([
|
|
5956
|
+
audioStream,
|
|
5957
|
+
videoStream,
|
|
5958
|
+
videoShareStream,
|
|
5959
|
+
audioShareStream,
|
|
5960
|
+
])
|
|
5551
5961
|
);
|
|
5552
5962
|
});
|
|
5553
5963
|
|
|
5554
5964
|
it('un-publishes the streams correctly (all 4 together)', async () => {
|
|
5555
|
-
await meeting.unpublishStreams([
|
|
5965
|
+
await meeting.unpublishStreams([
|
|
5966
|
+
audioStream,
|
|
5967
|
+
videoStream,
|
|
5968
|
+
videoShareStream,
|
|
5969
|
+
audioShareStream,
|
|
5970
|
+
]);
|
|
5556
5971
|
|
|
5557
5972
|
checkAudioUnpublished();
|
|
5558
5973
|
checkVideoUnpublished();
|
|
@@ -5612,40 +6027,48 @@ describe('plugin-meetings', () => {
|
|
|
5612
6027
|
return {
|
|
5613
6028
|
setCodecParameters: sinon.stub().resolves(),
|
|
5614
6029
|
deleteCodecParameters: sinon.stub().resolves(),
|
|
5615
|
-
}
|
|
5616
|
-
}
|
|
6030
|
+
};
|
|
6031
|
+
},
|
|
5617
6032
|
};
|
|
5618
|
-
meeting.sendSlotManager.createSlot(
|
|
6033
|
+
meeting.sendSlotManager.createSlot(
|
|
6034
|
+
fakeMultistreamRoapMediaConnection,
|
|
6035
|
+
MediaType.AudioMain,
|
|
6036
|
+
false
|
|
6037
|
+
);
|
|
5619
6038
|
meeting.mediaProperties.webrtcMediaConnection = {};
|
|
5620
6039
|
});
|
|
5621
6040
|
afterEach(() => {
|
|
5622
6041
|
sinon.restore();
|
|
5623
6042
|
});
|
|
5624
|
-
[
|
|
5625
|
-
{shouldEnableMusicMode
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
});
|
|
6043
|
+
[{shouldEnableMusicMode: true}, {shouldEnableMusicMode: false}].forEach(
|
|
6044
|
+
({shouldEnableMusicMode}) => {
|
|
6045
|
+
it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
|
|
6046
|
+
meeting.mediaProperties.webrtcMediaConnection = undefined;
|
|
6047
|
+
await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
|
|
6048
|
+
});
|
|
6049
|
+
}
|
|
6050
|
+
);
|
|
5633
6051
|
|
|
5634
6052
|
it('should set the codec parameters when shouldEnableMusicMode is true', async () => {
|
|
5635
6053
|
await meeting.enableMusicMode(true);
|
|
5636
|
-
assert.calledOnceWithExactly(
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
6054
|
+
assert.calledOnceWithExactly(
|
|
6055
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters,
|
|
6056
|
+
{
|
|
6057
|
+
maxaveragebitrate: '64000',
|
|
6058
|
+
maxplaybackrate: '48000',
|
|
6059
|
+
}
|
|
6060
|
+
);
|
|
6061
|
+
assert.notCalled(
|
|
6062
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters
|
|
6063
|
+
);
|
|
5641
6064
|
});
|
|
5642
6065
|
|
|
5643
6066
|
it('should set the codec parameters when shouldEnableMusicMode is false', async () => {
|
|
5644
6067
|
await meeting.enableMusicMode(false);
|
|
5645
|
-
assert.calledOnceWithExactly(
|
|
5646
|
-
|
|
5647
|
-
'maxplaybackrate'
|
|
5648
|
-
|
|
6068
|
+
assert.calledOnceWithExactly(
|
|
6069
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters,
|
|
6070
|
+
['maxaveragebitrate', 'maxplaybackrate']
|
|
6071
|
+
);
|
|
5649
6072
|
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters);
|
|
5650
6073
|
});
|
|
5651
6074
|
});
|
|
@@ -5656,8 +6079,8 @@ describe('plugin-meetings', () => {
|
|
|
5656
6079
|
beforeEach(() => {
|
|
5657
6080
|
const fakeMediaStream = () => {
|
|
5658
6081
|
return {
|
|
5659
|
-
id: 'fake stream'
|
|
5660
|
-
}
|
|
6082
|
+
id: 'fake stream',
|
|
6083
|
+
};
|
|
5661
6084
|
};
|
|
5662
6085
|
|
|
5663
6086
|
sandbox = sinon.createSandbox();
|
|
@@ -5724,7 +6147,7 @@ describe('plugin-meetings', () => {
|
|
|
5724
6147
|
} catch (err) {
|
|
5725
6148
|
assert.fail('reconnect should not error after clean up');
|
|
5726
6149
|
}
|
|
5727
|
-
})
|
|
6150
|
+
});
|
|
5728
6151
|
|
|
5729
6152
|
it('should trigger reconnection success and send CA metric', async () => {
|
|
5730
6153
|
await meeting.reconnect();
|
|
@@ -5744,7 +6167,10 @@ describe('plugin-meetings', () => {
|
|
|
5744
6167
|
meetingId: meeting.id,
|
|
5745
6168
|
},
|
|
5746
6169
|
});
|
|
5747
|
-
assert.calledOnceWithExactly(
|
|
6170
|
+
assert.calledOnceWithExactly(
|
|
6171
|
+
meeting.reconnectionManager.setStatus,
|
|
6172
|
+
RECONNECTION.STATE.COMPLETE
|
|
6173
|
+
);
|
|
5748
6174
|
});
|
|
5749
6175
|
|
|
5750
6176
|
it('should reset after reconnection success', async () => {
|
|
@@ -5839,7 +6265,7 @@ describe('plugin-meetings', () => {
|
|
|
5839
6265
|
let eventListeners;
|
|
5840
6266
|
const fakeStream = {
|
|
5841
6267
|
id: 'stream',
|
|
5842
|
-
getTracks: () => [{
|
|
6268
|
+
getTracks: () => [{id: 'track', addEventListener: sinon.stub()}],
|
|
5843
6269
|
};
|
|
5844
6270
|
|
|
5845
6271
|
beforeEach(() => {
|
|
@@ -5906,7 +6332,7 @@ describe('plugin-meetings', () => {
|
|
|
5906
6332
|
});
|
|
5907
6333
|
|
|
5908
6334
|
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5909
|
-
})
|
|
6335
|
+
});
|
|
5910
6336
|
|
|
5911
6337
|
it('sends client.ice.start correctly when hasMediaConnectionConnectedAtLeastOnce = false', () => {
|
|
5912
6338
|
meeting.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
@@ -5922,7 +6348,7 @@ describe('plugin-meetings', () => {
|
|
|
5922
6348
|
meetingId: meeting.id,
|
|
5923
6349
|
},
|
|
5924
6350
|
});
|
|
5925
|
-
})
|
|
6351
|
+
});
|
|
5926
6352
|
});
|
|
5927
6353
|
|
|
5928
6354
|
describe('submitClientEvent on connectionSuccess', () => {
|
|
@@ -6050,22 +6476,17 @@ describe('plugin-meetings', () => {
|
|
|
6050
6476
|
|
|
6051
6477
|
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
6052
6478
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
6053
|
-
assert.calledWith(
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
networkStatus: meeting.networkStatus,
|
|
6060
|
-
hasMediaConnectionConnectedAtLeastOnce,
|
|
6061
|
-
},
|
|
6062
|
-
);
|
|
6479
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
|
|
6480
|
+
correlation_id: meeting.correlationId,
|
|
6481
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
6482
|
+
networkStatus: meeting.networkStatus,
|
|
6483
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
6484
|
+
});
|
|
6063
6485
|
};
|
|
6064
6486
|
|
|
6065
6487
|
it('handles "Disconnected" state correctly when waitForIceReconnect resolves', async () => {
|
|
6066
6488
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().resolves();
|
|
6067
6489
|
|
|
6068
|
-
|
|
6069
6490
|
mockDisconnectedEvent();
|
|
6070
6491
|
|
|
6071
6492
|
await testUtils.flushPromises();
|
|
@@ -6079,14 +6500,13 @@ describe('plugin-meetings', () => {
|
|
|
6079
6500
|
|
|
6080
6501
|
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = true', async () => {
|
|
6081
6502
|
const FAKE_ERROR = {fatal: true};
|
|
6082
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
6083
|
-
.
|
|
6084
|
-
|
|
6503
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
6504
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
6505
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
6085
6506
|
meeting.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
6086
6507
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
6087
6508
|
meeting.hasMediaConnectionConnectedAtLeastOnce = true;
|
|
6088
6509
|
|
|
6089
|
-
|
|
6090
6510
|
mockDisconnectedEvent();
|
|
6091
6511
|
|
|
6092
6512
|
await testUtils.flushPromises();
|
|
@@ -6101,7 +6521,6 @@ describe('plugin-meetings', () => {
|
|
|
6101
6521
|
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
6102
6522
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
6103
6523
|
|
|
6104
|
-
|
|
6105
6524
|
mockDisconnectedEvent();
|
|
6106
6525
|
|
|
6107
6526
|
await testUtils.flushPromises();
|
|
@@ -6115,7 +6534,6 @@ describe('plugin-meetings', () => {
|
|
|
6115
6534
|
});
|
|
6116
6535
|
|
|
6117
6536
|
describe('CONNECTION_STATE_CHANGED event when state = "Failed"', () => {
|
|
6118
|
-
|
|
6119
6537
|
const mockFailedEvent = () => {
|
|
6120
6538
|
meeting.setupMediaConnectionListeners();
|
|
6121
6539
|
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
@@ -6125,16 +6543,12 @@ describe('plugin-meetings', () => {
|
|
|
6125
6543
|
|
|
6126
6544
|
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
6127
6545
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
6128
|
-
assert.calledWith(
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
networkStatus: meeting.networkStatus,
|
|
6135
|
-
hasMediaConnectionConnectedAtLeastOnce,
|
|
6136
|
-
},
|
|
6137
|
-
);
|
|
6546
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
|
|
6547
|
+
correlation_id: meeting.correlationId,
|
|
6548
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
6549
|
+
networkStatus: meeting.networkStatus,
|
|
6550
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
6551
|
+
});
|
|
6138
6552
|
};
|
|
6139
6553
|
|
|
6140
6554
|
it('handles "Failed" state correctly when hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
@@ -6399,7 +6813,6 @@ describe('plugin-meetings', () => {
|
|
|
6399
6813
|
sdp: 'fake sdp',
|
|
6400
6814
|
tieBreaker: 12345,
|
|
6401
6815
|
meeting,
|
|
6402
|
-
reconnect: false,
|
|
6403
6816
|
});
|
|
6404
6817
|
assert.notCalled(meeting.roapMessageReceived);
|
|
6405
6818
|
});
|
|
@@ -6426,14 +6839,13 @@ describe('plugin-meetings', () => {
|
|
|
6426
6839
|
sdp: 'fake sdp',
|
|
6427
6840
|
tieBreaker: 12345,
|
|
6428
6841
|
meeting,
|
|
6429
|
-
reconnect: false,
|
|
6430
6842
|
});
|
|
6431
6843
|
assert.calledWith(meeting.roapMessageReceived, fakeAnswer);
|
|
6432
6844
|
});
|
|
6433
6845
|
|
|
6434
6846
|
it('handles OFFER message correctly when request fails', async () => {
|
|
6435
6847
|
const clock = sinon.useFakeTimers();
|
|
6436
|
-
sinon.spy(clock,
|
|
6848
|
+
sinon.spy(clock, 'clearTimeout');
|
|
6437
6849
|
meeting.deferSDPAnswer = {reject: sinon.stub()};
|
|
6438
6850
|
meeting.sdpResponseTimer = '1234';
|
|
6439
6851
|
sendRoapMediaRequestStub.rejects();
|
|
@@ -6456,7 +6868,6 @@ describe('plugin-meetings', () => {
|
|
|
6456
6868
|
sdp: 'fake sdp',
|
|
6457
6869
|
tieBreaker: 12345,
|
|
6458
6870
|
meeting,
|
|
6459
|
-
reconnect: false,
|
|
6460
6871
|
});
|
|
6461
6872
|
assert.notCalled(meeting.roapMessageReceived);
|
|
6462
6873
|
assert.calledOnce(meeting.deferSDPAnswer.reject);
|
|
@@ -7041,41 +7452,6 @@ describe('plugin-meetings', () => {
|
|
|
7041
7452
|
);
|
|
7042
7453
|
});
|
|
7043
7454
|
|
|
7044
|
-
it('listens to the timing that user joined into breakout', async () => {
|
|
7045
|
-
const mainLocusUrl = 'mainLocusUrl123';
|
|
7046
|
-
|
|
7047
|
-
meeting.meetingRequest.getLocusStatusByUrl = sinon.stub().returns(Promise.resolve());
|
|
7048
|
-
|
|
7049
|
-
await meeting.locusInfo.emit(
|
|
7050
|
-
{function: 'test', file: 'test'},
|
|
7051
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7052
|
-
{mainLocusUrl}
|
|
7053
|
-
);
|
|
7054
|
-
|
|
7055
|
-
assert.calledOnceWithExactly(meeting.meetingRequest.getLocusStatusByUrl, mainLocusUrl);
|
|
7056
|
-
const error = {statusCode: 403};
|
|
7057
|
-
meeting.meetingRequest.getLocusStatusByUrl.rejects(error);
|
|
7058
|
-
meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
7059
|
-
await meeting.locusInfo.emit(
|
|
7060
|
-
{function: 'test', file: 'test'},
|
|
7061
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7062
|
-
{mainLocusUrl}
|
|
7063
|
-
);
|
|
7064
|
-
|
|
7065
|
-
assert.calledOnce(meeting.locusInfo.clearMainSessionLocusCache);
|
|
7066
|
-
|
|
7067
|
-
const otherError = new Error('something wrong');
|
|
7068
|
-
meeting.meetingRequest.getLocusStatusByUrl.rejects(otherError);
|
|
7069
|
-
meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
7070
|
-
await meeting.locusInfo.emit(
|
|
7071
|
-
{function: 'test', file: 'test'},
|
|
7072
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7073
|
-
{mainLocusUrl}
|
|
7074
|
-
);
|
|
7075
|
-
|
|
7076
|
-
assert.notCalled(meeting.locusInfo.clearMainSessionLocusCache);
|
|
7077
|
-
});
|
|
7078
|
-
|
|
7079
7455
|
it('listens to the locus interpretation update event', () => {
|
|
7080
7456
|
const interpretation = {
|
|
7081
7457
|
siLanguages: [{languageCode: 20, languageName: 'en'}],
|
|
@@ -7203,8 +7579,8 @@ describe('plugin-meetings', () => {
|
|
|
7203
7579
|
newLocusServices.services.webcast.url
|
|
7204
7580
|
);
|
|
7205
7581
|
assert.calledWith(
|
|
7206
|
-
|
|
7207
|
-
|
|
7582
|
+
meeting.webinar.webinarAttendeesSearchingUrlUpdate,
|
|
7583
|
+
newLocusServices.services.webinarAttendeesSearching.url
|
|
7208
7584
|
);
|
|
7209
7585
|
assert.calledOnce(meeting.recordingController.setSessionId);
|
|
7210
7586
|
done();
|
|
@@ -7380,20 +7756,19 @@ describe('plugin-meetings', () => {
|
|
|
7380
7756
|
});
|
|
7381
7757
|
|
|
7382
7758
|
describe('#setPermissionTokenPayload', () => {
|
|
7383
|
-
|
|
7384
7759
|
let now;
|
|
7385
7760
|
let clock;
|
|
7386
|
-
|
|
7761
|
+
|
|
7387
7762
|
beforeEach(() => {
|
|
7388
7763
|
now = Date.now();
|
|
7389
|
-
|
|
7764
|
+
|
|
7390
7765
|
// mock `new Date()` with constant `now`
|
|
7391
7766
|
clock = sinon.useFakeTimers(now);
|
|
7392
7767
|
});
|
|
7393
|
-
|
|
7768
|
+
|
|
7394
7769
|
afterEach(() => {
|
|
7395
7770
|
clock.restore();
|
|
7396
|
-
})
|
|
7771
|
+
});
|
|
7397
7772
|
it('sets correctly', () => {
|
|
7398
7773
|
assert.notOk(meeting.permissionTokenPayload);
|
|
7399
7774
|
|
|
@@ -7415,10 +7790,12 @@ describe('plugin-meetings', () => {
|
|
|
7415
7790
|
|
|
7416
7791
|
const testUrl = 'https://example.com';
|
|
7417
7792
|
|
|
7418
|
-
const policyData = {
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7793
|
+
const policyData = {
|
|
7794
|
+
permission: {
|
|
7795
|
+
userPolicies: {a: true},
|
|
7796
|
+
enforceVBGImagesURL: testUrl,
|
|
7797
|
+
},
|
|
7798
|
+
};
|
|
7422
7799
|
meeting.permissionTokenPayload = policyData;
|
|
7423
7800
|
|
|
7424
7801
|
meeting.setSelfUserPolicies();
|
|
@@ -7519,8 +7896,11 @@ describe('plugin-meetings', () => {
|
|
|
7519
7896
|
assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
|
|
7520
7897
|
assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
|
|
7521
7898
|
|
|
7522
|
-
if(expectedInfoToParse.permissionTokenPayload) {
|
|
7523
|
-
assert.deepEqual(
|
|
7899
|
+
if (expectedInfoToParse.permissionTokenPayload) {
|
|
7900
|
+
assert.deepEqual(
|
|
7901
|
+
meeting.permissionTokenPayload,
|
|
7902
|
+
expectedInfoToParse.permissionTokenPayload
|
|
7903
|
+
);
|
|
7524
7904
|
}
|
|
7525
7905
|
};
|
|
7526
7906
|
|
|
@@ -7529,12 +7909,12 @@ describe('plugin-meetings', () => {
|
|
|
7529
7909
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7530
7910
|
|
|
7531
7911
|
const expectedPermissionTokenPayload = {
|
|
7532
|
-
exp:
|
|
7912
|
+
exp: '123456',
|
|
7533
7913
|
permission: {
|
|
7534
7914
|
userPolicies: {
|
|
7535
|
-
a: true
|
|
7536
|
-
}
|
|
7537
|
-
}
|
|
7915
|
+
a: true,
|
|
7916
|
+
},
|
|
7917
|
+
},
|
|
7538
7918
|
};
|
|
7539
7919
|
|
|
7540
7920
|
// generated permissionToken with secret `secret` and
|
|
@@ -7543,16 +7923,14 @@ describe('plugin-meetings', () => {
|
|
|
7543
7923
|
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0';
|
|
7544
7924
|
|
|
7545
7925
|
const FAKE_MEETING_INFO = {
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
owner: test2,
|
|
7555
|
-
},
|
|
7926
|
+
conversationUrl: uuid1,
|
|
7927
|
+
locusUrl: url1,
|
|
7928
|
+
meetingJoinUrl: url2,
|
|
7929
|
+
meetingNumber: '12345',
|
|
7930
|
+
permissionToken,
|
|
7931
|
+
sipMeetingUri: test1,
|
|
7932
|
+
sipUrl: test1,
|
|
7933
|
+
owner: test2,
|
|
7556
7934
|
};
|
|
7557
7935
|
|
|
7558
7936
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7566,7 +7944,7 @@ describe('plugin-meetings', () => {
|
|
|
7566
7944
|
owner: test2,
|
|
7567
7945
|
selfUserPolicies: {a: true},
|
|
7568
7946
|
permissionToken,
|
|
7569
|
-
permissionTokenPayload: expectedPermissionTokenPayload
|
|
7947
|
+
permissionTokenPayload: expectedPermissionTokenPayload,
|
|
7570
7948
|
};
|
|
7571
7949
|
|
|
7572
7950
|
checkParseMeetingInfo(expectedInfoToParse);
|
|
@@ -7584,16 +7962,14 @@ describe('plugin-meetings', () => {
|
|
|
7584
7962
|
},
|
|
7585
7963
|
};
|
|
7586
7964
|
const FAKE_MEETING_INFO = {
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
owner: test2,
|
|
7596
|
-
},
|
|
7965
|
+
conversationUrl: uuid1,
|
|
7966
|
+
locusUrl: url1,
|
|
7967
|
+
meetingJoinUrl: url2,
|
|
7968
|
+
meetingNumber: '12345',
|
|
7969
|
+
permissionToken: 'abc',
|
|
7970
|
+
sipMeetingUri: test1,
|
|
7971
|
+
sipUrl: test1,
|
|
7972
|
+
owner: test2,
|
|
7597
7973
|
};
|
|
7598
7974
|
|
|
7599
7975
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_LOCUS_MEETING);
|
|
@@ -7613,16 +7989,14 @@ describe('plugin-meetings', () => {
|
|
|
7613
7989
|
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
7614
7990
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7615
7991
|
const FAKE_MEETING_INFO = {
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
owner: test2,
|
|
7625
|
-
},
|
|
7992
|
+
conversationUrl: uuid1,
|
|
7993
|
+
locusUrl: url1,
|
|
7994
|
+
meetingJoinUrl: url2,
|
|
7995
|
+
meetingNumber: '12345',
|
|
7996
|
+
permissionToken: 'abc',
|
|
7997
|
+
sipMeetingUri: test1,
|
|
7998
|
+
sipUrl: test1,
|
|
7999
|
+
owner: test2,
|
|
7626
8000
|
};
|
|
7627
8001
|
|
|
7628
8002
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7643,16 +8017,14 @@ describe('plugin-meetings', () => {
|
|
|
7643
8017
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7644
8018
|
const FAKE_STRING_DESTINATION = 'sipUrl';
|
|
7645
8019
|
const FAKE_MEETING_INFO = {
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
owner: test2,
|
|
7655
|
-
},
|
|
8020
|
+
conversationUrl: uuid1,
|
|
8021
|
+
locusUrl: url1,
|
|
8022
|
+
meetingJoinUrl: url2,
|
|
8023
|
+
meetingNumber: '12345',
|
|
8024
|
+
permissionToken: 'abc',
|
|
8025
|
+
sipMeetingUri: test1,
|
|
8026
|
+
sipUrl: test1,
|
|
8027
|
+
owner: test2,
|
|
7656
8028
|
};
|
|
7657
8029
|
|
|
7658
8030
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
|
|
@@ -7671,24 +8043,42 @@ describe('plugin-meetings', () => {
|
|
|
7671
8043
|
it('should parse interpretation info correctly', () => {
|
|
7672
8044
|
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
7673
8045
|
const mockToggleOnData = {
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
],
|
|
7687
|
-
},
|
|
8046
|
+
meetingSiteSetting: {
|
|
8047
|
+
enableHostInterpreterControlSI: true,
|
|
8048
|
+
},
|
|
8049
|
+
turnOnSimultaneousInterpretation: true,
|
|
8050
|
+
simultaneousInterpretation: {
|
|
8051
|
+
currentSIInterpreter: false,
|
|
8052
|
+
siLanguages: [
|
|
8053
|
+
{
|
|
8054
|
+
languageCode: 'ar',
|
|
8055
|
+
languageGroupId: 4,
|
|
8056
|
+
},
|
|
8057
|
+
],
|
|
7688
8058
|
},
|
|
7689
8059
|
};
|
|
7690
8060
|
meeting.parseMeetingInfo(mockToggleOnData);
|
|
7691
|
-
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData
|
|
8061
|
+
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData);
|
|
8062
|
+
});
|
|
8063
|
+
|
|
8064
|
+
it('should handle error', () => {
|
|
8065
|
+
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
8066
|
+
const FAKE_MEETING_INFO = {
|
|
8067
|
+
conversationUrl: uuid1,
|
|
8068
|
+
locusUrl: url1,
|
|
8069
|
+
meetingJoinUrl: url2,
|
|
8070
|
+
meetingNumber: '12345',
|
|
8071
|
+
permissionToken: 'abc',
|
|
8072
|
+
sipMeetingUri: test1,
|
|
8073
|
+
sipUrl: test1,
|
|
8074
|
+
owner: test2,
|
|
8075
|
+
};
|
|
8076
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO, undefined, 'Error');
|
|
8077
|
+
|
|
8078
|
+
checkParseMeetingInfo({
|
|
8079
|
+
locusUrl: meeting.locusUrl,
|
|
8080
|
+
});
|
|
8081
|
+
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, FAKE_MEETING_INFO);
|
|
7692
8082
|
});
|
|
7693
8083
|
});
|
|
7694
8084
|
|
|
@@ -9326,6 +9716,13 @@ describe('plugin-meetings', () => {
|
|
|
9326
9716
|
assert.exists(whiteboardShare.then);
|
|
9327
9717
|
await whiteboardShare;
|
|
9328
9718
|
assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
|
|
9719
|
+
|
|
9720
|
+
// ensure the CA share metric is submitted
|
|
9721
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
|
|
9722
|
+
name: 'client.share.initiated',
|
|
9723
|
+
payload: {mediaType: 'whiteboard'},
|
|
9724
|
+
options: {meetingId: meeting.id},
|
|
9725
|
+
});
|
|
9329
9726
|
});
|
|
9330
9727
|
});
|
|
9331
9728
|
describe('#stopWhiteboardShare', () => {
|
|
@@ -9425,7 +9822,6 @@ describe('plugin-meetings', () => {
|
|
|
9425
9822
|
REMOTE_B: 'remote-user-B-url',
|
|
9426
9823
|
};
|
|
9427
9824
|
|
|
9428
|
-
|
|
9429
9825
|
const generateContent = (
|
|
9430
9826
|
beneficiaryId = null,
|
|
9431
9827
|
disposition = null,
|
|
@@ -9434,7 +9830,7 @@ describe('plugin-meetings', () => {
|
|
|
9434
9830
|
) => ({
|
|
9435
9831
|
beneficiaryId,
|
|
9436
9832
|
disposition,
|
|
9437
|
-
deviceUrlSharing
|
|
9833
|
+
deviceUrlSharing,
|
|
9438
9834
|
});
|
|
9439
9835
|
const generateWhiteboard = (
|
|
9440
9836
|
beneficiaryId = null,
|
|
@@ -9453,7 +9849,7 @@ describe('plugin-meetings', () => {
|
|
|
9453
9849
|
annotation,
|
|
9454
9850
|
url,
|
|
9455
9851
|
shareInstanceId,
|
|
9456
|
-
deviceUrlSharing
|
|
9852
|
+
deviceUrlSharing
|
|
9457
9853
|
) => {
|
|
9458
9854
|
const newPayload = cloneDeep(payload);
|
|
9459
9855
|
|
|
@@ -9898,7 +10294,7 @@ describe('plugin-meetings', () => {
|
|
|
9898
10294
|
true,
|
|
9899
10295
|
false,
|
|
9900
10296
|
USER_IDS.ME,
|
|
9901
|
-
RESOURCE_URLS.WHITEBOARD_A
|
|
10297
|
+
RESOURCE_URLS.WHITEBOARD_A
|
|
9902
10298
|
);
|
|
9903
10299
|
const data2 = generateData(
|
|
9904
10300
|
data1.payload,
|
|
@@ -9907,7 +10303,7 @@ describe('plugin-meetings', () => {
|
|
|
9907
10303
|
USER_IDS.ME,
|
|
9908
10304
|
RESOURCE_URLS.WHITEBOARD_A,
|
|
9909
10305
|
true,
|
|
9910
|
-
USER_IDS.ME
|
|
10306
|
+
USER_IDS.ME
|
|
9911
10307
|
);
|
|
9912
10308
|
const data3 = generateData(
|
|
9913
10309
|
data2.payload,
|
|
@@ -9920,9 +10316,21 @@ describe('plugin-meetings', () => {
|
|
|
9920
10316
|
undefined,
|
|
9921
10317
|
undefined,
|
|
9922
10318
|
undefined,
|
|
9923
|
-
DEVICE_URL.LOCAL_WEB
|
|
10319
|
+
DEVICE_URL.LOCAL_WEB
|
|
10320
|
+
);
|
|
10321
|
+
const data4 = generateData(
|
|
10322
|
+
data3.payload,
|
|
10323
|
+
false,
|
|
10324
|
+
true,
|
|
10325
|
+
USER_IDS.ME,
|
|
10326
|
+
undefined,
|
|
10327
|
+
undefined,
|
|
10328
|
+
undefined,
|
|
10329
|
+
undefined,
|
|
10330
|
+
undefined,
|
|
10331
|
+
undefined,
|
|
10332
|
+
DEVICE_URL.LOCAL_WEB
|
|
9924
10333
|
);
|
|
9925
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9926
10334
|
|
|
9927
10335
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9928
10336
|
});
|
|
@@ -9955,7 +10363,7 @@ describe('plugin-meetings', () => {
|
|
|
9955
10363
|
undefined,
|
|
9956
10364
|
undefined,
|
|
9957
10365
|
undefined,
|
|
9958
|
-
DEVICE_URL.REMOTE_A
|
|
10366
|
+
DEVICE_URL.REMOTE_A
|
|
9959
10367
|
);
|
|
9960
10368
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
9961
10369
|
|
|
@@ -9990,9 +10398,21 @@ describe('plugin-meetings', () => {
|
|
|
9990
10398
|
undefined,
|
|
9991
10399
|
undefined,
|
|
9992
10400
|
undefined,
|
|
9993
|
-
DEVICE_URL.LOCAL_WEB
|
|
10401
|
+
DEVICE_URL.LOCAL_WEB
|
|
10402
|
+
);
|
|
10403
|
+
const data4 = generateData(
|
|
10404
|
+
data3.payload,
|
|
10405
|
+
false,
|
|
10406
|
+
true,
|
|
10407
|
+
USER_IDS.ME,
|
|
10408
|
+
undefined,
|
|
10409
|
+
undefined,
|
|
10410
|
+
undefined,
|
|
10411
|
+
undefined,
|
|
10412
|
+
undefined,
|
|
10413
|
+
undefined,
|
|
10414
|
+
DEVICE_URL.LOCAL_WEB
|
|
9994
10415
|
);
|
|
9995
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9996
10416
|
|
|
9997
10417
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9998
10418
|
});
|
|
@@ -10025,7 +10445,7 @@ describe('plugin-meetings', () => {
|
|
|
10025
10445
|
undefined,
|
|
10026
10446
|
undefined,
|
|
10027
10447
|
undefined,
|
|
10028
|
-
DEVICE_URL.REMOTE_A
|
|
10448
|
+
DEVICE_URL.REMOTE_A
|
|
10029
10449
|
);
|
|
10030
10450
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
10031
10451
|
|
|
@@ -10060,7 +10480,7 @@ describe('plugin-meetings', () => {
|
|
|
10060
10480
|
undefined,
|
|
10061
10481
|
undefined,
|
|
10062
10482
|
undefined,
|
|
10063
|
-
DEVICE_URL.REMOTE_B
|
|
10483
|
+
DEVICE_URL.REMOTE_B
|
|
10064
10484
|
);
|
|
10065
10485
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
|
|
10066
10486
|
|
|
@@ -10070,7 +10490,19 @@ describe('plugin-meetings', () => {
|
|
|
10070
10490
|
|
|
10071
10491
|
describe('Desktop --> Whiteboard A', () => {
|
|
10072
10492
|
it('Scenario #1: you share desktop and then share whiteboard', () => {
|
|
10073
|
-
const data1 = generateData(
|
|
10493
|
+
const data1 = generateData(
|
|
10494
|
+
blankPayload,
|
|
10495
|
+
true,
|
|
10496
|
+
true,
|
|
10497
|
+
USER_IDS.ME,
|
|
10498
|
+
undefined,
|
|
10499
|
+
false,
|
|
10500
|
+
undefined,
|
|
10501
|
+
undefined,
|
|
10502
|
+
undefined,
|
|
10503
|
+
undefined,
|
|
10504
|
+
DEVICE_URL.LOCAL_WEB
|
|
10505
|
+
);
|
|
10074
10506
|
const data2 = generateData(
|
|
10075
10507
|
data1.payload,
|
|
10076
10508
|
true,
|
|
@@ -10084,7 +10516,19 @@ describe('plugin-meetings', () => {
|
|
|
10084
10516
|
});
|
|
10085
10517
|
|
|
10086
10518
|
it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
|
|
10087
|
-
const data1 = generateData(
|
|
10519
|
+
const data1 = generateData(
|
|
10520
|
+
blankPayload,
|
|
10521
|
+
true,
|
|
10522
|
+
true,
|
|
10523
|
+
USER_IDS.ME,
|
|
10524
|
+
undefined,
|
|
10525
|
+
false,
|
|
10526
|
+
undefined,
|
|
10527
|
+
undefined,
|
|
10528
|
+
undefined,
|
|
10529
|
+
undefined,
|
|
10530
|
+
DEVICE_URL.LOCAL_WEB
|
|
10531
|
+
);
|
|
10088
10532
|
const data2 = generateData(
|
|
10089
10533
|
data1.payload,
|
|
10090
10534
|
true,
|
|
@@ -10098,7 +10542,19 @@ describe('plugin-meetings', () => {
|
|
|
10098
10542
|
});
|
|
10099
10543
|
|
|
10100
10544
|
it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
|
|
10101
|
-
const data1 = generateData(
|
|
10545
|
+
const data1 = generateData(
|
|
10546
|
+
blankPayload,
|
|
10547
|
+
true,
|
|
10548
|
+
true,
|
|
10549
|
+
USER_IDS.REMOTE_A,
|
|
10550
|
+
undefined,
|
|
10551
|
+
false,
|
|
10552
|
+
undefined,
|
|
10553
|
+
undefined,
|
|
10554
|
+
undefined,
|
|
10555
|
+
undefined,
|
|
10556
|
+
DEVICE_URL.REMOTE_A
|
|
10557
|
+
);
|
|
10102
10558
|
const data2 = generateData(
|
|
10103
10559
|
data1.payload,
|
|
10104
10560
|
true,
|
|
@@ -10112,7 +10568,19 @@ describe('plugin-meetings', () => {
|
|
|
10112
10568
|
});
|
|
10113
10569
|
|
|
10114
10570
|
it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
|
|
10115
|
-
const data1 = generateData(
|
|
10571
|
+
const data1 = generateData(
|
|
10572
|
+
blankPayload,
|
|
10573
|
+
true,
|
|
10574
|
+
true,
|
|
10575
|
+
USER_IDS.REMOTE_A,
|
|
10576
|
+
undefined,
|
|
10577
|
+
false,
|
|
10578
|
+
undefined,
|
|
10579
|
+
undefined,
|
|
10580
|
+
undefined,
|
|
10581
|
+
undefined,
|
|
10582
|
+
DEVICE_URL.REMOTE_A
|
|
10583
|
+
);
|
|
10116
10584
|
const data2 = generateData(
|
|
10117
10585
|
data1.payload,
|
|
10118
10586
|
true,
|
|
@@ -10126,7 +10594,19 @@ describe('plugin-meetings', () => {
|
|
|
10126
10594
|
});
|
|
10127
10595
|
|
|
10128
10596
|
it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
|
|
10129
|
-
const data1 = generateData(
|
|
10597
|
+
const data1 = generateData(
|
|
10598
|
+
blankPayload,
|
|
10599
|
+
true,
|
|
10600
|
+
true,
|
|
10601
|
+
USER_IDS.REMOTE_A,
|
|
10602
|
+
undefined,
|
|
10603
|
+
false,
|
|
10604
|
+
undefined,
|
|
10605
|
+
undefined,
|
|
10606
|
+
undefined,
|
|
10607
|
+
undefined,
|
|
10608
|
+
DEVICE_URL.REMOTE_A
|
|
10609
|
+
);
|
|
10130
10610
|
const data2 = generateData(
|
|
10131
10611
|
data1.payload,
|
|
10132
10612
|
true,
|
|
@@ -10141,26 +10621,146 @@ describe('plugin-meetings', () => {
|
|
|
10141
10621
|
});
|
|
10142
10622
|
describe('Desktop A --> Desktop B', () => {
|
|
10143
10623
|
it('Scenario #1: you share desktop using web client and then share using native client', () => {
|
|
10144
|
-
const data1 = generateData(
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10624
|
+
const data1 = generateData(
|
|
10625
|
+
blankPayload,
|
|
10626
|
+
true,
|
|
10627
|
+
true,
|
|
10628
|
+
USER_IDS.ME,
|
|
10629
|
+
undefined,
|
|
10630
|
+
false,
|
|
10631
|
+
undefined,
|
|
10632
|
+
undefined,
|
|
10633
|
+
undefined,
|
|
10634
|
+
undefined,
|
|
10635
|
+
DEVICE_URL.LOCAL_WEB
|
|
10636
|
+
);
|
|
10637
|
+
const data2 = generateData(
|
|
10638
|
+
data1.payload,
|
|
10639
|
+
false,
|
|
10640
|
+
true,
|
|
10641
|
+
USER_IDS.ME,
|
|
10642
|
+
undefined,
|
|
10643
|
+
false,
|
|
10644
|
+
undefined,
|
|
10645
|
+
undefined,
|
|
10646
|
+
undefined,
|
|
10647
|
+
undefined,
|
|
10648
|
+
DEVICE_URL.LOCAL_WEB
|
|
10649
|
+
);
|
|
10650
|
+
const data3 = generateData(
|
|
10651
|
+
data2.payload,
|
|
10652
|
+
true,
|
|
10653
|
+
true,
|
|
10654
|
+
USER_IDS.ME,
|
|
10655
|
+
undefined,
|
|
10656
|
+
false,
|
|
10657
|
+
undefined,
|
|
10658
|
+
undefined,
|
|
10659
|
+
undefined,
|
|
10660
|
+
undefined,
|
|
10661
|
+
DEVICE_URL.LOCAL_MAC
|
|
10662
|
+
);
|
|
10663
|
+
const data4 = generateData(
|
|
10664
|
+
data3.payload,
|
|
10665
|
+
false,
|
|
10666
|
+
true,
|
|
10667
|
+
USER_IDS.ME,
|
|
10668
|
+
undefined,
|
|
10669
|
+
false,
|
|
10670
|
+
undefined,
|
|
10671
|
+
undefined,
|
|
10672
|
+
undefined,
|
|
10673
|
+
undefined,
|
|
10674
|
+
DEVICE_URL.LOCAL_MAC
|
|
10675
|
+
);
|
|
10148
10676
|
|
|
10149
10677
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
10150
10678
|
});
|
|
10151
10679
|
|
|
10152
10680
|
it('Scenario #2: you share desktop using web client and remote person A shares desktop', () => {
|
|
10153
|
-
const data1 = generateData(
|
|
10154
|
-
|
|
10155
|
-
|
|
10681
|
+
const data1 = generateData(
|
|
10682
|
+
blankPayload,
|
|
10683
|
+
true,
|
|
10684
|
+
true,
|
|
10685
|
+
USER_IDS.ME,
|
|
10686
|
+
undefined,
|
|
10687
|
+
false,
|
|
10688
|
+
undefined,
|
|
10689
|
+
undefined,
|
|
10690
|
+
undefined,
|
|
10691
|
+
undefined,
|
|
10692
|
+
DEVICE_URL.LOCAL_WEB
|
|
10693
|
+
);
|
|
10694
|
+
const data2 = generateData(
|
|
10695
|
+
data1.payload,
|
|
10696
|
+
true,
|
|
10697
|
+
true,
|
|
10698
|
+
USER_IDS.REMOTE_A,
|
|
10699
|
+
undefined,
|
|
10700
|
+
false,
|
|
10701
|
+
undefined,
|
|
10702
|
+
undefined,
|
|
10703
|
+
undefined,
|
|
10704
|
+
undefined,
|
|
10705
|
+
DEVICE_URL.REMOTE_A
|
|
10706
|
+
);
|
|
10707
|
+
const data3 = generateData(
|
|
10708
|
+
data2.payload,
|
|
10709
|
+
false,
|
|
10710
|
+
true,
|
|
10711
|
+
USER_IDS.REMOTE_A,
|
|
10712
|
+
undefined,
|
|
10713
|
+
false,
|
|
10714
|
+
undefined,
|
|
10715
|
+
undefined,
|
|
10716
|
+
undefined,
|
|
10717
|
+
undefined,
|
|
10718
|
+
DEVICE_URL.REMOTE_A
|
|
10719
|
+
);
|
|
10156
10720
|
|
|
10157
10721
|
payloadTestHelper([data1, data2, data3]);
|
|
10158
10722
|
});
|
|
10159
10723
|
|
|
10160
10724
|
it('Scenario #3: remote person A shares desktop and then you share desktop using web client', () => {
|
|
10161
|
-
const data1 = generateData(
|
|
10162
|
-
|
|
10163
|
-
|
|
10725
|
+
const data1 = generateData(
|
|
10726
|
+
blankPayload,
|
|
10727
|
+
true,
|
|
10728
|
+
true,
|
|
10729
|
+
USER_IDS.REMOTE_A,
|
|
10730
|
+
undefined,
|
|
10731
|
+
false,
|
|
10732
|
+
undefined,
|
|
10733
|
+
undefined,
|
|
10734
|
+
undefined,
|
|
10735
|
+
undefined,
|
|
10736
|
+
DEVICE_URL.REMOTE_A
|
|
10737
|
+
);
|
|
10738
|
+
const data2 = generateData(
|
|
10739
|
+
data1.payload,
|
|
10740
|
+
true,
|
|
10741
|
+
true,
|
|
10742
|
+
USER_IDS.ME,
|
|
10743
|
+
undefined,
|
|
10744
|
+
false,
|
|
10745
|
+
undefined,
|
|
10746
|
+
undefined,
|
|
10747
|
+
undefined,
|
|
10748
|
+
undefined,
|
|
10749
|
+
DEVICE_URL.LOCAL_WEB
|
|
10750
|
+
);
|
|
10751
|
+
const data3 = generateData(
|
|
10752
|
+
data2.payload,
|
|
10753
|
+
false,
|
|
10754
|
+
true,
|
|
10755
|
+
USER_IDS.ME,
|
|
10756
|
+
undefined,
|
|
10757
|
+
false,
|
|
10758
|
+
undefined,
|
|
10759
|
+
undefined,
|
|
10760
|
+
undefined,
|
|
10761
|
+
undefined,
|
|
10762
|
+
DEVICE_URL.LOCAL_WEB
|
|
10763
|
+
);
|
|
10164
10764
|
|
|
10165
10765
|
payloadTestHelper([data1, data2, data3]);
|
|
10166
10766
|
});
|
|
@@ -10174,8 +10774,32 @@ describe('plugin-meetings', () => {
|
|
|
10174
10774
|
});
|
|
10175
10775
|
|
|
10176
10776
|
it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
|
|
10177
|
-
const data1 = generateData(
|
|
10178
|
-
|
|
10777
|
+
const data1 = generateData(
|
|
10778
|
+
blankPayload,
|
|
10779
|
+
true,
|
|
10780
|
+
true,
|
|
10781
|
+
USER_IDS.REMOTE_A,
|
|
10782
|
+
undefined,
|
|
10783
|
+
false,
|
|
10784
|
+
undefined,
|
|
10785
|
+
undefined,
|
|
10786
|
+
undefined,
|
|
10787
|
+
undefined,
|
|
10788
|
+
DEVICE_URL.REMOTE_A
|
|
10789
|
+
);
|
|
10790
|
+
const data2 = generateData(
|
|
10791
|
+
data1.payload,
|
|
10792
|
+
true,
|
|
10793
|
+
true,
|
|
10794
|
+
USER_IDS.REMOTE_B,
|
|
10795
|
+
undefined,
|
|
10796
|
+
false,
|
|
10797
|
+
undefined,
|
|
10798
|
+
undefined,
|
|
10799
|
+
undefined,
|
|
10800
|
+
undefined,
|
|
10801
|
+
DEVICE_URL.REMOTE_B
|
|
10802
|
+
);
|
|
10179
10803
|
const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
|
|
10180
10804
|
|
|
10181
10805
|
payloadTestHelper([data1, data2, data3]);
|
|
@@ -10594,26 +11218,34 @@ describe('plugin-meetings', () => {
|
|
|
10594
11218
|
|
|
10595
11219
|
afterEach(() => {
|
|
10596
11220
|
clock.restore();
|
|
10597
|
-
})
|
|
11221
|
+
});
|
|
10598
11222
|
|
|
10599
11223
|
it('should return undefined if exp is undefined', () => {
|
|
10600
|
-
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined)
|
|
11224
|
+
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined);
|
|
10601
11225
|
});
|
|
10602
11226
|
|
|
10603
11227
|
it('should return the expected positive exp', () => {
|
|
10604
11228
|
// set permission token as now + 1 sec
|
|
10605
11229
|
const expiryTime = now + 1000;
|
|
10606
|
-
meeting.permissionTokenPayload = {exp:
|
|
11230
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
10607
11231
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10608
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11232
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11233
|
+
timeLeft: 1,
|
|
11234
|
+
expiryTime: Number(expiryTime),
|
|
11235
|
+
currentTime: now,
|
|
11236
|
+
});
|
|
10609
11237
|
});
|
|
10610
11238
|
|
|
10611
11239
|
it('should return the expected negative exp', () => {
|
|
10612
11240
|
// set permission token as now - 1 sec
|
|
10613
11241
|
const expiryTime = now - 1000;
|
|
10614
|
-
meeting.permissionTokenPayload = {exp:
|
|
11242
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
10615
11243
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10616
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11244
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11245
|
+
timeLeft: -1,
|
|
11246
|
+
expiryTime: Number(expiryTime),
|
|
11247
|
+
currentTime: now,
|
|
11248
|
+
});
|
|
10617
11249
|
});
|
|
10618
11250
|
|
|
10619
11251
|
describe('#getPermissionTokenExpiryInfo with wrong current time which is in future', () => {
|
|
@@ -10622,34 +11254,41 @@ describe('plugin-meetings', () => {
|
|
|
10622
11254
|
beforeEach(() => {
|
|
10623
11255
|
// current time is 3 hours off
|
|
10624
11256
|
now = Date.now() + 10800000;
|
|
10625
|
-
|
|
11257
|
+
|
|
10626
11258
|
// mock `new Date()` with constant `now`
|
|
10627
11259
|
clock = sinon.useFakeTimers(now);
|
|
10628
11260
|
});
|
|
10629
|
-
|
|
11261
|
+
|
|
10630
11262
|
afterEach(() => {
|
|
10631
11263
|
clock.restore();
|
|
10632
|
-
})
|
|
10633
|
-
|
|
11264
|
+
});
|
|
11265
|
+
|
|
10634
11266
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
10635
11267
|
const serverTime = Date.now();
|
|
10636
|
-
|
|
10637
|
-
|
|
11268
|
+
|
|
11269
|
+
// set permission token as now + 1 sec
|
|
10638
11270
|
const expiryTime = serverTime + 1000;
|
|
10639
|
-
meeting.permissionTokenPayload = {exp:
|
|
11271
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10640
11272
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10641
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11273
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11274
|
+
timeLeft: 1,
|
|
11275
|
+
expiryTime: Number(expiryTime),
|
|
11276
|
+
currentTime: now,
|
|
11277
|
+
});
|
|
10642
11278
|
});
|
|
10643
|
-
|
|
11279
|
+
|
|
10644
11280
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
10645
11281
|
const serverTime = Date.now();
|
|
10646
11282
|
// set permission token as now - 1 sec
|
|
10647
11283
|
const expiryTime = serverTime - 1000;
|
|
10648
|
-
meeting.permissionTokenPayload = {exp:
|
|
11284
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10649
11285
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10650
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11286
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11287
|
+
timeLeft: -1,
|
|
11288
|
+
expiryTime: Number(expiryTime),
|
|
11289
|
+
currentTime: now,
|
|
11290
|
+
});
|
|
10651
11291
|
});
|
|
10652
|
-
|
|
10653
11292
|
});
|
|
10654
11293
|
|
|
10655
11294
|
describe('#getPermissionTokenExpiryInfo with wrong current Time which is in the past', () => {
|
|
@@ -10658,42 +11297,47 @@ describe('plugin-meetings', () => {
|
|
|
10658
11297
|
beforeEach(() => {
|
|
10659
11298
|
// current time is 3 hours off
|
|
10660
11299
|
now = Date.now() - 10800000;
|
|
10661
|
-
|
|
11300
|
+
|
|
10662
11301
|
// mock `new Date()` with constant `now`
|
|
10663
11302
|
clock = sinon.useFakeTimers(now);
|
|
10664
11303
|
});
|
|
10665
|
-
|
|
11304
|
+
|
|
10666
11305
|
afterEach(() => {
|
|
10667
11306
|
clock.restore();
|
|
10668
|
-
})
|
|
10669
|
-
|
|
11307
|
+
});
|
|
11308
|
+
|
|
10670
11309
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
10671
11310
|
const serverTime = Date.now();
|
|
10672
|
-
|
|
10673
|
-
|
|
11311
|
+
|
|
11312
|
+
// set permission token as now + 1 sec
|
|
10674
11313
|
const expiryTime = serverTime + 1000;
|
|
10675
|
-
meeting.permissionTokenPayload = {exp:
|
|
11314
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10676
11315
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10677
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11316
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11317
|
+
timeLeft: 1,
|
|
11318
|
+
expiryTime: Number(expiryTime),
|
|
11319
|
+
currentTime: now,
|
|
11320
|
+
});
|
|
10678
11321
|
});
|
|
10679
|
-
|
|
11322
|
+
|
|
10680
11323
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
10681
11324
|
const serverTime = Date.now();
|
|
10682
11325
|
// set permission token as now - 1 sec
|
|
10683
11326
|
const expiryTime = serverTime - 1000;
|
|
10684
|
-
meeting.permissionTokenPayload = {exp:
|
|
11327
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10685
11328
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10686
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11329
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
11330
|
+
timeLeft: -1,
|
|
11331
|
+
expiryTime: Number(expiryTime),
|
|
11332
|
+
currentTime: now,
|
|
11333
|
+
});
|
|
10687
11334
|
});
|
|
10688
|
-
|
|
10689
11335
|
});
|
|
10690
11336
|
});
|
|
10691
11337
|
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
11338
|
describe('#checkAndRefreshPermissionToken', () => {
|
|
10695
|
-
it('should not fire refreshPermissionToken if permissionToken is not defined', async() => {
|
|
10696
|
-
meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined)
|
|
11339
|
+
it('should not fire refreshPermissionToken if permissionToken is not defined', async () => {
|
|
11340
|
+
meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined);
|
|
10697
11341
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10698
11342
|
|
|
10699
11343
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10703,8 +11347,10 @@ describe('plugin-meetings', () => {
|
|
|
10703
11347
|
assert.equal(returnValue, undefined);
|
|
10704
11348
|
});
|
|
10705
11349
|
|
|
10706
|
-
it('should fire refreshPermissionToken if time left is below 10sec', async() => {
|
|
10707
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11350
|
+
it('should fire refreshPermissionToken if time left is below 10sec', async () => {
|
|
11351
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11352
|
+
.stub()
|
|
11353
|
+
.returns({timeLeft: 9, expiryTime: 122132, currentTime: Date.now()});
|
|
10708
11354
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10709
11355
|
|
|
10710
11356
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10715,7 +11361,9 @@ describe('plugin-meetings', () => {
|
|
|
10715
11361
|
});
|
|
10716
11362
|
|
|
10717
11363
|
it('should fire refreshPermissionToken if time left is equal 10sec', async () => {
|
|
10718
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11364
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11365
|
+
.stub()
|
|
11366
|
+
.returns({timeLeft: 10, expiryTime: 122132, currentTime: Date.now()});
|
|
10719
11367
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10720
11368
|
|
|
10721
11369
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10726,7 +11374,9 @@ describe('plugin-meetings', () => {
|
|
|
10726
11374
|
});
|
|
10727
11375
|
|
|
10728
11376
|
it('should not fire refreshPermissionToken if time left is higher than 10sec', async () => {
|
|
10729
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11377
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
11378
|
+
.stub()
|
|
11379
|
+
.returns({timeLeft: 11, expiryTime: 122132, currentTime: Date.now()});
|
|
10730
11380
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10731
11381
|
|
|
10732
11382
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10739,19 +11389,22 @@ describe('plugin-meetings', () => {
|
|
|
10739
11389
|
|
|
10740
11390
|
describe('#roapMessageReceived', () => {
|
|
10741
11391
|
it('calls roapMessageReceived on the webrtc media connection', () => {
|
|
10742
|
-
const fakeMessage = {
|
|
11392
|
+
const fakeMessage = {messageType: 'fake', sdp: 'fake sdp'};
|
|
10743
11393
|
|
|
10744
11394
|
const getMediaServer = sinon.stub(MeetingsUtil, 'getMediaServer').returns('homer');
|
|
10745
11395
|
|
|
10746
11396
|
meeting.mediaProperties.webrtcMediaConnection = {
|
|
10747
|
-
roapMessageReceived: sinon.stub()
|
|
11397
|
+
roapMessageReceived: sinon.stub(),
|
|
10748
11398
|
};
|
|
10749
11399
|
|
|
10750
11400
|
meeting.roapMessageReceived(fakeMessage);
|
|
10751
11401
|
|
|
10752
|
-
assert.calledOnceWithExactly(
|
|
11402
|
+
assert.calledOnceWithExactly(
|
|
11403
|
+
meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived,
|
|
11404
|
+
fakeMessage
|
|
11405
|
+
);
|
|
10753
11406
|
assert.calledOnceWithExactly(getMediaServer, 'fake sdp');
|
|
10754
11407
|
assert.equal(meeting.mediaProperties.webrtcMediaConnection.mediaServer, 'homer');
|
|
10755
|
-
})
|
|
10756
|
-
})
|
|
11408
|
+
});
|
|
11409
|
+
});
|
|
10757
11410
|
});
|