Skip to content

Commit aace8cf

Browse files
authored
test: Add sender limit tests. (#885)
Co-authored-by: James A <[email protected]>
1 parent f14ca1c commit aace8cf

File tree

5 files changed

+252
-16
lines changed

5 files changed

+252
-16
lines changed

src/main/java/org/jitsi/protocol/xmpp/AbstractOperationSetJingle.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,7 @@ protected IQ processJingleIQ(JingleIQ iq)
382382
}
383383
}
384384

385-
/**
386-
* {@inheritDoc}
387-
*/
388-
@Override
389-
public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
385+
private JingleIQ createAddSourceIq(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
390386
{
391387
JingleIQ addSourceIq = new JingleIQ(JingleAction.SOURCEADD, session.getSessionID());
392388
addSourceIq.setFrom(getOurJID());
@@ -403,11 +399,45 @@ public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session,
403399

404400
logger.debug("Sending source-add to " + session.getAddress()
405401
+ ", SID=" + session.getSessionID() + ", sources=" + sources);
402+
return addSourceIq;
403+
}
406404

405+
/**
406+
* {@inheritDoc}
407+
*/
408+
@Override
409+
public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
410+
{
411+
JingleIQ addSourceIq = createAddSourceIq(sources, session, encodeSourcesAsJson);
407412
UtilKt.tryToSendStanza(getConnection(), addSourceIq);
408413
stats.stanzaSent(JingleAction.SOURCEADD);
409414
}
410415

416+
/**
417+
* Sends 'source-add' proprietary notification. Wait for response and return status.
418+
*
419+
* @param sources the sources to be included in the source-add message.
420+
* @param session the <tt>JingleSession</tt> used to send the notification.
421+
* @param encodeSourcesAsJson whether to encode {@code sources} as JSON or standard Jingle.
422+
* @return {@code true} if the source-add completed successfully.
423+
*/
424+
public boolean sendAddSourceIQAndGetResult(ConferenceSourceMap sources, JingleSession session,
425+
boolean encodeSourcesAsJson)
426+
throws SmackException.NotConnectedException
427+
{
428+
JingleIQ addSourceIq = createAddSourceIq(sources, session, encodeSourcesAsJson);
429+
IQ reply = UtilKt.sendIqAndGetResponse(getConnection(), addSourceIq);
430+
stats.stanzaSent(JingleAction.SOURCEADD);
431+
432+
if (reply == null)
433+
return false;
434+
if (IQ.Type.result.equals(reply.getType()))
435+
return true;
436+
437+
logger.error("Failed to do 'source-add' to " + session.getAddress() + ": " + reply.toXML());
438+
return false;
439+
}
440+
411441
/**
412442
* {@inheritDoc}
413443
*/

src/test/java/mock/MockParticipant.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.jitsi.xmpp.extensions.jingle.*;
3333

3434
import org.jitsi.protocol.xmpp.*;
35+
import org.jivesoftware.smack.*;
3536
import org.jivesoftware.smack.packet.*;
3637
import org.jivesoftware.smack.packet.id.*;
3738
import org.jxmpp.jid.*;
@@ -397,22 +398,35 @@ public void audioSourceRemove()
397398
jingle.sendRemoveSourceIQ(toRemove, jingleSession, false);
398399
}
399400

400-
public void videoSourceAdd(long[] newSSRCs)
401+
private boolean sourceAdd(String media, long[] newSSRCs)
401402
{
402403
ConferenceSourceMap toAdd = new ConferenceSourceMap();
403404

404405
// Create new SSRCs
405406
for (int i=0; i<newSSRCs.length; i++)
406407
{
407-
Source ssrcPe = addLocalSSRC("video", newSSRCs[i]);
408+
Source ssrcPe = addLocalSSRC(media, newSSRCs[i]);
408409

409410
toAdd.add(getMyJid(), new EndpointSourceSet(ssrcPe));
410411
}
411412

412413
// Send source-add
413-
jingle.sendAddSourceIQ(toAdd, jingleSession, false);
414+
try {
415+
return jingle.sendAddSourceIQAndGetResult(toAdd, jingleSession, false);
416+
}
417+
catch (SmackException.NotConnectedException e) {
418+
return false;
419+
}
414420
}
415421

422+
public boolean videoSourceAdd(long[] newSSRCs) { return sourceAdd("video", newSSRCs); }
423+
424+
public boolean audioSourceAdd(long[] newSSRCs) { return sourceAdd("audio", newSSRCs); }
425+
426+
public void audioMute(boolean enable) { user.audioMute(enable); }
427+
428+
public void videoMute(boolean enable) { user.videoMute(enable); }
429+
416430
public ConferenceSourceMap getRemoteSources()
417431
{
418432
return remoteSSRCs;
@@ -462,7 +476,7 @@ public Jid getMyJid()
462476
return myJid;
463477
}
464478

465-
public Source addLocalSSRC(String media, long ssrc)
479+
private Source addLocalSSRC(String media, long ssrc)
466480
{
467481
Source source = new Source(ssrc, MediaType.parseString(media), null, null, false);
468482

src/test/java/mock/muc/MockChatRoom.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ public class MockChatRoom
6161

6262
private final List<ChatRoomMember> members = new CopyOnWriteArrayList<>();
6363

64+
/**
65+
* The number of members that currently have their audio sources unmuted.
66+
*/
67+
private int numAudioSenders;
68+
69+
/**
70+
* The number of members that currently have their video sources unmuted.
71+
*/
72+
private int numVideoSenders;
73+
6474
public MockChatRoom(EntityBareJid roomName, XmppProvider xmppProvider)
6575
{
6676
this.roomName = roomName;
@@ -261,15 +271,53 @@ public int getMembersCount()
261271
}
262272

263273
@Override
264-
public int getAudioSendersCount()
274+
public int getAudioSendersCount() { return numAudioSenders; }
275+
276+
@Override
277+
public int getVideoSendersCount() { return numVideoSenders; }
278+
279+
public void addAudioSender()
280+
{
281+
++numAudioSenders;
282+
logger.debug(() -> "The number of audio senders has increased to " + numAudioSenders + ".");
283+
284+
eventEmitter.fireEvent(handler -> {
285+
handler.numAudioSendersChanged(numAudioSenders);
286+
return Unit.INSTANCE;
287+
});
288+
}
289+
290+
public void removeAudioSender()
265291
{
266-
return 0; /* implement */
292+
--numAudioSenders;
293+
logger.debug(() -> "The number of audio senders has decreased to " + numAudioSenders + ".");
294+
295+
eventEmitter.fireEvent(handler -> {
296+
handler.numAudioSendersChanged(numAudioSenders);
297+
return Unit.INSTANCE;
298+
});
267299
}
268300

269-
@Override
270-
public int getVideoSendersCount()
301+
public void addVideoSender()
271302
{
272-
return 0; /* implement */
303+
++numVideoSenders;
304+
logger.debug(() -> "The number of video senders has increased to " + numVideoSenders + ".");
305+
306+
eventEmitter.fireEvent(handler -> {
307+
handler.numVideoSendersChanged(numVideoSenders);
308+
return Unit.INSTANCE;
309+
});
310+
}
311+
312+
public void removeVideoSender()
313+
{
314+
--numVideoSenders;
315+
logger.debug(() -> "The number of video senders has decreased to " + numVideoSenders + ".");
316+
317+
eventEmitter.fireEvent(handler -> {
318+
handler.numVideoSendersChanged(numVideoSenders);
319+
return Unit.INSTANCE;
320+
});
273321
}
274322

275323
private void grantRole(EntityFullJid address, MemberRole newRole)

src/test/java/mock/muc/MockRoomMember.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ public class MockRoomMember
3737

3838
private MemberRole role = MemberRole.GUEST;
3939

40+
/**
41+
* Indicates whether the member's audio sources are currently muted.
42+
*/
43+
private boolean isAudioMuted = true;
44+
45+
/**
46+
* Indicates whether the member's video sources are currently muted.
47+
*/
48+
private boolean isVideoMuted = true;
49+
4050
public MockRoomMember(EntityFullJid address, MockChatRoom chatRoom)
4151
{
4252
this.address = address;
@@ -111,10 +121,34 @@ public boolean isJibri()
111121
}
112122

113123
@Override
114-
public boolean isAudioMuted() { return false; }
124+
public boolean isAudioMuted() { return isAudioMuted; }
115125

116126
@Override
117-
public boolean isVideoMuted() { return false; }
127+
public boolean isVideoMuted() { return isVideoMuted; }
128+
129+
public void audioMute(boolean enable)
130+
{
131+
if (isAudioMuted != enable)
132+
{
133+
isAudioMuted = enable;
134+
if (enable)
135+
room.removeAudioSender();
136+
else
137+
room.addAudioSender();
138+
}
139+
}
140+
141+
public void videoMute(boolean enable)
142+
{
143+
if (isVideoMuted != enable)
144+
{
145+
isVideoMuted = enable;
146+
if (enable)
147+
room.removeVideoSender();
148+
else
149+
room.addVideoSender();
150+
}
151+
}
118152

119153
@Override
120154
public Presence getPresence()
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright @ 2021 - present 8x8, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.jitsi.jicofo
17+
18+
import io.kotest.core.spec.IsolationMode
19+
import io.kotest.matchers.booleans.shouldBeFalse
20+
import io.kotest.matchers.booleans.shouldBeTrue
21+
import io.kotest.matchers.shouldBe
22+
import mock.MockParticipant
23+
import mock.util.TestConference
24+
import org.jitsi.config.withNewConfig
25+
import org.jxmpp.jid.impl.JidCreate
26+
27+
/**
28+
* Test audio and video sender limits.
29+
*/
30+
class SenderLimitTest : JicofoHarnessTest() {
31+
override fun isolationMode(): IsolationMode? = IsolationMode.SingleInstance
32+
33+
init {
34+
35+
val names = arrayOf(
36+
"Tipsy_0", "Queasy_1", "Surly_2", "Sleazy_3", "Edgy_4", "Dizzy_5", "Remorseful_6"
37+
)
38+
39+
context("sender limit test") {
40+
withNewConfig(
41+
"jicofo.conference.max-video-senders=5, jicofo.conference.max-audio-senders=5," +
42+
" jicofo.colibri.enable-colibri2=true"
43+
) {
44+
45+
ConferenceConfig.config.maxVideoSenders shouldBe 5
46+
ConferenceConfig.config.maxAudioSenders shouldBe 5
47+
48+
val roomName = JidCreate.entityBareFrom("[email protected]")
49+
val testConference = TestConference(harness, roomName)
50+
51+
testConference.conference.start()
52+
53+
val ps = Array(names.size) { i -> MockParticipant(names[i]).also { it.join(testConference.chatRoom) } }
54+
55+
context("set it up") {
56+
ps.forEach { it.acceptInvite(4000) }
57+
ps.forEach { it.waitForAddSource(4000) }
58+
}
59+
60+
context("video sender limit test") {
61+
addVideoSource(ps[0]).shouldBeTrue()
62+
addVideoSource(ps[1]).shouldBeTrue()
63+
addVideoSource(ps[2]).shouldBeTrue()
64+
addVideoSource(ps[3]).shouldBeTrue()
65+
addVideoSource(ps[4]).shouldBeTrue()
66+
addVideoSource(ps[5]).shouldBeFalse()
67+
addVideoSource(ps[6]).shouldBeFalse()
68+
69+
ps[0].videoMute(true)
70+
addVideoSource(ps[5]).shouldBeTrue()
71+
addVideoSource(ps[6]).shouldBeFalse()
72+
73+
ps[1].videoMute(true)
74+
addVideoSource(ps[6]).shouldBeTrue()
75+
}
76+
77+
context("audio sender limit test") {
78+
addAudioSource(ps[0]).shouldBeTrue()
79+
addAudioSource(ps[1]).shouldBeTrue()
80+
addAudioSource(ps[2]).shouldBeTrue()
81+
addAudioSource(ps[3]).shouldBeTrue()
82+
addAudioSource(ps[4]).shouldBeTrue()
83+
addAudioSource(ps[5]).shouldBeFalse()
84+
addAudioSource(ps[6]).shouldBeFalse()
85+
86+
ps[0].audioMute(true)
87+
addAudioSource(ps[5]).shouldBeTrue()
88+
addAudioSource(ps[6]).shouldBeFalse()
89+
90+
ps[1].audioMute(true)
91+
addAudioSource(ps[6]).shouldBeTrue()
92+
}
93+
}
94+
}
95+
}
96+
}
97+
98+
fun addVideoSource(p: MockParticipant): Boolean {
99+
val result = p.videoSourceAdd(longArrayOf(MockParticipant.nextSSRC()))
100+
if (result)
101+
p.videoMute(false)
102+
return result
103+
}
104+
105+
fun addAudioSource(p: MockParticipant): Boolean {
106+
val result = p.audioSourceAdd(longArrayOf(MockParticipant.nextSSRC()))
107+
if (result)
108+
p.audioMute(false)
109+
return result
110+
}

0 commit comments

Comments
 (0)