openvidu-test-e2e: add RTSP and SRT tests

master
pabloFuente 2025-02-03 15:36:37 +01:00
parent 6ea42e82c0
commit 5fb3be503c
2 changed files with 141 additions and 33 deletions

View File

@ -12,6 +12,7 @@ import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -50,7 +51,8 @@ public class OpenViduTestE2e {
private final static WaitStrategy waitBrowser = Wait.forLogMessage("^.*Started Selenium Standalone.*$", 1);
protected static String MEDIA_SERVER_IMAGE = "livekit-server:latest";
protected static String RTSP_SERVER_IMAGE = "lroktu/vlc-server:latest";
protected static String SRT_SERVER_IMAGE = "linuxserver/ffmpeg:latest";
protected static String LIVEKIT_API_KEY = "devkey";
protected static String LIVEKIT_API_SECRET = "secret";
@ -80,8 +82,6 @@ public class OpenViduTestE2e {
protected static RoomServiceClient LK;
protected static IngressServiceClient LK_INGRESS;
private static boolean isMediaServerRestartTest = false;
protected static void checkFfmpegInstallation() {
String ffmpegOutput = commandLine.executeCommand("which ffmpeg", 60);
if (ffmpegOutput == null || ffmpegOutput.isEmpty()) {
@ -141,6 +141,37 @@ public class OpenViduTestE2e {
return edge;
}
public void startRtspServer(boolean withAudio, boolean withVideo) throws Exception {
GenericContainer<?> rtspServerContainer = new GenericContainer<>(DockerImageName.parse(RTSP_SERVER_IMAGE))
.withCommand(getFileUrl(withAudio, withVideo)
+ " --loop :sout=#gather:rtp{sdp=rtsp://:8554/} :network-caching=1500 :sout-all :sout-keep");
rtspServerContainer.setPortBindings(Arrays.asList("8554:8554"));
rtspServerContainer.start();
containers.add(rtspServerContainer);
}
public void startSrtServer(boolean withAudio, boolean withVideo) throws Exception {
GenericContainer<?> srtServerContainer = new GenericContainer<>(DockerImageName.parse(SRT_SERVER_IMAGE))
.withNetworkMode("host").withCommand(
"-i " + getFileUrl(withAudio, withVideo) + " -c:v libx264 -f mpegts srt://:8554?mode=listener");
srtServerContainer.start();
containers.add(srtServerContainer);
}
private String getFileUrl(boolean withAudio, boolean withVideo) throws Exception {
String fileUrl;
if (withAudio && withVideo) {
fileUrl = "https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal.mp4";
} else if (!withAudio && withVideo) {
fileUrl = "https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal_noaudio.mp4";
} else if (withAudio) {
fileUrl = "https://s3.eu-west-1.amazonaws.com/public.openvidu.io/bbb_sunflower_1080p_60fps_normal_onlyaudio.mp3";
} else {
throw new Exception("Must have audio or video");
}
return fileUrl;
}
protected static void setUpLiveKitClient() throws NoSuchAlgorithmException {
URI uri = null;
try {
@ -209,12 +240,6 @@ public class OpenViduTestE2e {
}
log.info("Using api secret {} to connect to livekit-server", LIVEKIT_API_SECRET);
String mediaServerImage = System.getProperty("MEDIA_SERVER_IMAGE");
if (mediaServerImage != null) {
MEDIA_SERVER_IMAGE = mediaServerImage;
}
log.info("Using media server {} for e2e tests", MEDIA_SERVER_IMAGE);
String chromeVersion = System.getProperty("CHROME_VERSION");
if (chromeVersion != null && !chromeVersion.isBlank()) {
CHROME_VERSION = chromeVersion;
@ -366,13 +391,6 @@ public class OpenViduTestE2e {
// Close all remaining Rooms
this.closeAllRooms(LK);
// Reset Media Server
if (isMediaServerRestartTest) {
this.stopMediaServer();
this.startMediaServer();
isMediaServerRestartTest = false;
}
// Dispose all browsers users
Iterator<BrowserUser> it1 = browserUsers.iterator();
while (it1.hasNext()) {
@ -458,17 +476,4 @@ public class OpenViduTestE2e {
throw new Exception("File " + path.toAbsolutePath().toString() + " exists but is not readable");
}
}
protected void startMediaServer() {
String command = "docker run --rm -p 1880:7880 -e LIVEKIT_KEYS=\"" + LIVEKIT_API_KEY + " : "
+ LIVEKIT_API_SECRET + "\" " + MEDIA_SERVER_IMAGE;
commandLine.executeCommand(command, 60);
}
protected void stopMediaServer() {
isMediaServerRestartTest = true;
final String dockerRemoveCmd = "docker ps -a | awk '{ print $1,$2 }' | grep livekit-server | awk '{ print $1 }' | xargs -I {} docker rm -f {}";
commandLine.executeCommand(dockerRemoveCmd, 60);
}
}

View File

@ -54,6 +54,8 @@ import com.google.gson.JsonParser;
import io.openvidu.test.e2e.annotations.OnlyMediasoup;
import io.openvidu.test.e2e.annotations.OnlyPion;
import livekit.LivekitIngress.IngressInfo;
import livekit.LivekitIngress.IngressState;
/**
* E2E tests for openvidu-testapp.
@ -1659,7 +1661,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 1);
// Try publishing H264 with 2 layer simulcast
createIngress(user, "H264_540P_25FPS_2_LAYERS", null, true);
createIngress(user, "H264_540P_25FPS_2_LAYERS", null, true, "HTTP");
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 1);
user.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("video"), 1));
@ -1688,7 +1690,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("participantDisconnected", "RoomEvent", 1);
// Try publishing H264 with 3 layer simulcast
createIngress(user, "H264_1080P_30FPS_3_LAYERS_HIGH_MOTION", null, true);
createIngress(user, "H264_1080P_30FPS_3_LAYERS_HIGH_MOTION", null, true, "HTTP");
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 1);
user.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("video"), 1));
numberOfVideos = user.getDriver().findElements(By.tagName("video")).size();
@ -1712,6 +1714,102 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
this.waitUntilSubscriberFrameHeightIs(user, subscriberVideo, 1080);
}
@Test
@DisplayName("RTSP ingress")
void rtspIngressTest() throws Exception {
startRtspServer(true, true);
urPullCommon("RTSP", true, true);
}
@Test
@DisplayName("RTSP ingress only video")
void rtspIngressTestOnlyVideo() throws Exception {
startRtspServer(false, true);
urPullCommon("RTSP", false, true);
}
@Test
@DisplayName("RTSP ingress only audio")
void rtspIngressTestOnlyAudio() throws Exception {
startRtspServer(true, false);
urPullCommon("RTSP", true, false);
}
@Test
@DisplayName("SRT ingress")
void srtIngressTest() throws Exception {
startSrtServer(true, true);
urPullCommon("SRT", true, true);
}
@Test
@DisplayName("SRT ingress only video")
void srtIngressTestOnlyVideo() throws Exception {
startSrtServer(false, true);
urPullCommon("SRT", false, true);
}
@Test
@DisplayName("SRT ingress only audio")
void srtIngressTestOnlyAudio() throws Exception {
startSrtServer(true, false);
urPullCommon("SRT", true, false);
}
private void urPullCommon(String urlType, boolean withAudio, boolean withVideo) throws Exception {
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
this.addSubscriber(user, false);
user.getDriver().findElements(By.className("connect-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 1);
createIngress(user, null, "VP8", false, urlType);
if (withAudio && withVideo) {
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 2);
} else {
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 1);
}
if (withAudio) {
user.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("audio"), 1));
final int numberOfAudios = user.getDriver().findElements(By.tagName("audio")).size();
Assertions.assertEquals(1, numberOfAudios, "Wrong number of videos");
Assertions.assertTrue(user.getBrowserUser().assertAllElementsHaveTracks("audio", true, false),
"HTMLAudioElements were expected to have only one audio track");
if (!withVideo) {
final int numberOfVideos = user.getDriver().findElements(By.tagName("video")).size();
Assertions.assertEquals(0, numberOfVideos, "Wrong number of videos");
}
}
if (withVideo) {
user.getWaiter().until(ExpectedConditions.numberOfElementsToBe(By.tagName("video"), 1));
final int numberOfVideos = user.getDriver().findElements(By.tagName("video")).size();
Assertions.assertEquals(1, numberOfVideos, "Wrong number of videos");
Assertions.assertTrue(user.getBrowserUser().assertAllElementsHaveTracks("video", false, true),
"HTMLVideoElements were expected to have only one video track");
if (!withAudio) {
final int numberOfAudios = user.getDriver().findElements(By.tagName("audio")).size();
Assertions.assertEquals(0, numberOfAudios, "Wrong number of videos");
}
WebElement subscriberVideo = user.getDriver()
.findElement(By.cssSelector("#openvidu-instance-0 video.remote"));
waitUntilVideoLayersNotEmpty(user, subscriberVideo);
long bytesReceived = this.getSubscriberVideoBytesReceived(user, subscriberVideo);
this.waitUntilSubscriberBytesReceivedIncrease(user, subscriberVideo, bytesReceived);
this.waitUntilSubscriberFramesPerSecondNotZero(user, subscriberVideo);
JsonArray json = this.getLayersAsJsonArray(user, subscriberVideo);
String subscriberCodec = json.get(0).getAsJsonObject().get("codec").getAsString();
String expectedCodec = "video/VP8";
Assertions.assertEquals(expectedCodec, subscriberCodec);
}
List<IngressInfo> ingresses = LK_INGRESS.listIngress().execute().body();
Assertions.assertEquals(1, ingresses.size());
Assertions.assertTrue(ingresses.get(0).getUrl().startsWith(urlType.toLowerCase() + "://"));
Assertions.assertEquals(IngressState.Status.ENDPOINT_PUBLISHING, ingresses.get(0).getState().getStatus());
}
private void ingressSimulcastTest(OpenViduTestappUser user, boolean simulcast, String codec, String preset)
throws Exception {
@ -1721,7 +1819,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
user.getEventManager().waitUntilEventReaches("connected", "RoomEvent", 1);
createIngress(user, preset, codec, simulcast);
createIngress(user, preset, codec, simulcast, "HTTP");
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 1);
@ -2074,7 +2172,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
}
}
private void createIngress(OpenViduTestappUser user, String preset, String codec, boolean simulcast)
private void createIngress(OpenViduTestappUser user, String preset, String codec, boolean simulcast, String urlType)
throws InterruptedException {
if (!user.getDriver().findElements(By.id("close-dialog-btn")).isEmpty()) {
user.getDriver().findElement(By.id("close-dialog-btn")).click();
@ -2094,6 +2192,11 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("#mat-option-" + codec.toUpperCase())).click();
}
if (urlType != null) {
user.getDriver().findElement(By.cssSelector("#ingress-url-type-select")).click();
Thread.sleep(300);
user.getDriver().findElement(By.cssSelector("#mat-option-" + urlType.toUpperCase())).click();
}
user.getDriver().findElement(By.cssSelector("#create-ingress-api-btn")).click();
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
Thread.sleep(300);