Skip to content

Commit

Permalink
test: Add sender limit tests. (#885)
Browse files Browse the repository at this point in the history
Co-authored-by: James A <[email protected]>
  • Loading branch information
jqdrqgnq and jqdrqgnq authored Mar 1, 2022
1 parent f14ca1c commit aace8cf
Show file tree
Hide file tree
Showing 5 changed files with 252 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,7 @@ protected IQ processJingleIQ(JingleIQ iq)
}
}

/**
* {@inheritDoc}
*/
@Override
public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
private JingleIQ createAddSourceIq(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
{
JingleIQ addSourceIq = new JingleIQ(JingleAction.SOURCEADD, session.getSessionID());
addSourceIq.setFrom(getOurJID());
Expand All @@ -403,11 +399,45 @@ public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session,

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

/**
* {@inheritDoc}
*/
@Override
public void sendAddSourceIQ(ConferenceSourceMap sources, JingleSession session, boolean encodeSourcesAsJson)
{
JingleIQ addSourceIq = createAddSourceIq(sources, session, encodeSourcesAsJson);
UtilKt.tryToSendStanza(getConnection(), addSourceIq);
stats.stanzaSent(JingleAction.SOURCEADD);
}

/**
* Sends 'source-add' proprietary notification. Wait for response and return status.
*
* @param sources the sources to be included in the source-add message.
* @param session the <tt>JingleSession</tt> used to send the notification.
* @param encodeSourcesAsJson whether to encode {@code sources} as JSON or standard Jingle.
* @return {@code true} if the source-add completed successfully.
*/
public boolean sendAddSourceIQAndGetResult(ConferenceSourceMap sources, JingleSession session,
boolean encodeSourcesAsJson)
throws SmackException.NotConnectedException
{
JingleIQ addSourceIq = createAddSourceIq(sources, session, encodeSourcesAsJson);
IQ reply = UtilKt.sendIqAndGetResponse(getConnection(), addSourceIq);
stats.stanzaSent(JingleAction.SOURCEADD);

if (reply == null)
return false;
if (IQ.Type.result.equals(reply.getType()))
return true;

logger.error("Failed to do 'source-add' to " + session.getAddress() + ": " + reply.toXML());
return false;
}

/**
* {@inheritDoc}
*/
Expand Down
22 changes: 18 additions & 4 deletions src/test/java/mock/MockParticipant.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.jitsi.xmpp.extensions.jingle.*;

import org.jitsi.protocol.xmpp.*;
import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.packet.id.*;
import org.jxmpp.jid.*;
Expand Down Expand Up @@ -397,22 +398,35 @@ public void audioSourceRemove()
jingle.sendRemoveSourceIQ(toRemove, jingleSession, false);
}

public void videoSourceAdd(long[] newSSRCs)
private boolean sourceAdd(String media, long[] newSSRCs)
{
ConferenceSourceMap toAdd = new ConferenceSourceMap();

// Create new SSRCs
for (int i=0; i<newSSRCs.length; i++)
{
Source ssrcPe = addLocalSSRC("video", newSSRCs[i]);
Source ssrcPe = addLocalSSRC(media, newSSRCs[i]);

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

// Send source-add
jingle.sendAddSourceIQ(toAdd, jingleSession, false);
try {
return jingle.sendAddSourceIQAndGetResult(toAdd, jingleSession, false);
}
catch (SmackException.NotConnectedException e) {
return false;
}
}

public boolean videoSourceAdd(long[] newSSRCs) { return sourceAdd("video", newSSRCs); }

public boolean audioSourceAdd(long[] newSSRCs) { return sourceAdd("audio", newSSRCs); }

public void audioMute(boolean enable) { user.audioMute(enable); }

public void videoMute(boolean enable) { user.videoMute(enable); }

public ConferenceSourceMap getRemoteSources()
{
return remoteSSRCs;
Expand Down Expand Up @@ -462,7 +476,7 @@ public Jid getMyJid()
return myJid;
}

public Source addLocalSSRC(String media, long ssrc)
private Source addLocalSSRC(String media, long ssrc)
{
Source source = new Source(ssrc, MediaType.parseString(media), null, null, false);

Expand Down
58 changes: 53 additions & 5 deletions src/test/java/mock/muc/MockChatRoom.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ public class MockChatRoom

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

/**
* The number of members that currently have their audio sources unmuted.
*/
private int numAudioSenders;

/**
* The number of members that currently have their video sources unmuted.
*/
private int numVideoSenders;

public MockChatRoom(EntityBareJid roomName, XmppProvider xmppProvider)
{
this.roomName = roomName;
Expand Down Expand Up @@ -261,15 +271,53 @@ public int getMembersCount()
}

@Override
public int getAudioSendersCount()
public int getAudioSendersCount() { return numAudioSenders; }

@Override
public int getVideoSendersCount() { return numVideoSenders; }

public void addAudioSender()
{
++numAudioSenders;
logger.debug(() -> "The number of audio senders has increased to " + numAudioSenders + ".");

eventEmitter.fireEvent(handler -> {
handler.numAudioSendersChanged(numAudioSenders);
return Unit.INSTANCE;
});
}

public void removeAudioSender()
{
return 0; /* implement */
--numAudioSenders;
logger.debug(() -> "The number of audio senders has decreased to " + numAudioSenders + ".");

eventEmitter.fireEvent(handler -> {
handler.numAudioSendersChanged(numAudioSenders);
return Unit.INSTANCE;
});
}

@Override
public int getVideoSendersCount()
public void addVideoSender()
{
return 0; /* implement */
++numVideoSenders;
logger.debug(() -> "The number of video senders has increased to " + numVideoSenders + ".");

eventEmitter.fireEvent(handler -> {
handler.numVideoSendersChanged(numVideoSenders);
return Unit.INSTANCE;
});
}

public void removeVideoSender()
{
--numVideoSenders;
logger.debug(() -> "The number of video senders has decreased to " + numVideoSenders + ".");

eventEmitter.fireEvent(handler -> {
handler.numVideoSendersChanged(numVideoSenders);
return Unit.INSTANCE;
});
}

private void grantRole(EntityFullJid address, MemberRole newRole)
Expand Down
38 changes: 36 additions & 2 deletions src/test/java/mock/muc/MockRoomMember.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ public class MockRoomMember

private MemberRole role = MemberRole.GUEST;

/**
* Indicates whether the member's audio sources are currently muted.
*/
private boolean isAudioMuted = true;

/**
* Indicates whether the member's video sources are currently muted.
*/
private boolean isVideoMuted = true;

public MockRoomMember(EntityFullJid address, MockChatRoom chatRoom)
{
this.address = address;
Expand Down Expand Up @@ -111,10 +121,34 @@ public boolean isJibri()
}

@Override
public boolean isAudioMuted() { return false; }
public boolean isAudioMuted() { return isAudioMuted; }

@Override
public boolean isVideoMuted() { return false; }
public boolean isVideoMuted() { return isVideoMuted; }

public void audioMute(boolean enable)
{
if (isAudioMuted != enable)
{
isAudioMuted = enable;
if (enable)
room.removeAudioSender();
else
room.addAudioSender();
}
}

public void videoMute(boolean enable)
{
if (isVideoMuted != enable)
{
isVideoMuted = enable;
if (enable)
room.removeVideoSender();
else
room.addVideoSender();
}
}

@Override
public Presence getPresence()
Expand Down
110 changes: 110 additions & 0 deletions src/test/kotlin/org/jitsi/jicofo/SenderLimitTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright @ 2021 - present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.jicofo

import io.kotest.core.spec.IsolationMode
import io.kotest.matchers.booleans.shouldBeFalse
import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.matchers.shouldBe
import mock.MockParticipant
import mock.util.TestConference
import org.jitsi.config.withNewConfig
import org.jxmpp.jid.impl.JidCreate

/**
* Test audio and video sender limits.
*/
class SenderLimitTest : JicofoHarnessTest() {
override fun isolationMode(): IsolationMode? = IsolationMode.SingleInstance

init {

val names = arrayOf(
"Tipsy_0", "Queasy_1", "Surly_2", "Sleazy_3", "Edgy_4", "Dizzy_5", "Remorseful_6"
)

context("sender limit test") {
withNewConfig(
"jicofo.conference.max-video-senders=5, jicofo.conference.max-audio-senders=5," +
" jicofo.colibri.enable-colibri2=true"
) {

ConferenceConfig.config.maxVideoSenders shouldBe 5
ConferenceConfig.config.maxAudioSenders shouldBe 5

val roomName = JidCreate.entityBareFrom("[email protected]")
val testConference = TestConference(harness, roomName)

testConference.conference.start()

val ps = Array(names.size) { i -> MockParticipant(names[i]).also { it.join(testConference.chatRoom) } }

context("set it up") {
ps.forEach { it.acceptInvite(4000) }
ps.forEach { it.waitForAddSource(4000) }
}

context("video sender limit test") {
addVideoSource(ps[0]).shouldBeTrue()
addVideoSource(ps[1]).shouldBeTrue()
addVideoSource(ps[2]).shouldBeTrue()
addVideoSource(ps[3]).shouldBeTrue()
addVideoSource(ps[4]).shouldBeTrue()
addVideoSource(ps[5]).shouldBeFalse()
addVideoSource(ps[6]).shouldBeFalse()

ps[0].videoMute(true)
addVideoSource(ps[5]).shouldBeTrue()
addVideoSource(ps[6]).shouldBeFalse()

ps[1].videoMute(true)
addVideoSource(ps[6]).shouldBeTrue()
}

context("audio sender limit test") {
addAudioSource(ps[0]).shouldBeTrue()
addAudioSource(ps[1]).shouldBeTrue()
addAudioSource(ps[2]).shouldBeTrue()
addAudioSource(ps[3]).shouldBeTrue()
addAudioSource(ps[4]).shouldBeTrue()
addAudioSource(ps[5]).shouldBeFalse()
addAudioSource(ps[6]).shouldBeFalse()

ps[0].audioMute(true)
addAudioSource(ps[5]).shouldBeTrue()
addAudioSource(ps[6]).shouldBeFalse()

ps[1].audioMute(true)
addAudioSource(ps[6]).shouldBeTrue()
}
}
}
}
}

fun addVideoSource(p: MockParticipant): Boolean {
val result = p.videoSourceAdd(longArrayOf(MockParticipant.nextSSRC()))
if (result)
p.videoMute(false)
return result
}

fun addAudioSource(p: MockParticipant): Boolean {
val result = p.audioSourceAdd(longArrayOf(MockParticipant.nextSSRC()))
if (result)
p.audioMute(false)
return result
}

0 comments on commit aace8cf

Please sign in to comment.