diff --git a/openvidu-test-e2e/pom.xml b/openvidu-test-e2e/pom.xml
index ab50f6a4..3b01434d 100644
--- a/openvidu-test-e2e/pom.xml
+++ b/openvidu-test-e2e/pom.xml
@@ -62,6 +62,18 @@
3.141.59
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.0.0-M3
+
+
+
+
+
org.junit.jupiter
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java
index 8f7f49c6..d45ff599 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java
@@ -95,12 +95,27 @@ public class OpenViduEventManager {
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread th, Throwable ex) {
+ if (ex.getClass().getSimpleName().equals("UnhandledAlertException")
+ && ex.getMessage().contains("unexpected alert open")) {
+ stopPolling(false);
+ System.err.println("Alert opened. Waiting 1 second and restarting polling");
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ startPolling();
+ }
if (ex.getClass().getSimpleName().equals("NoSuchSessionException")) {
System.err.println("Disposing driver when running 'executeScript'");
}
}
};
+ if (this.pollingThread != null) {
+ this.pollingThread.interrupt();
+ }
+
this.pollingThread = new Thread(() -> {
while (!this.isInterrupted.get()) {
this.getEventsFromBrowser();
@@ -116,12 +131,15 @@ public class OpenViduEventManager {
this.pollingThread.start();
}
- public void stopPolling() {
+ public void stopPolling(boolean stopThread) {
this.eventCallbacks.clear();
this.eventCountdowns.clear();
this.eventNumbers.clear();
- this.isInterrupted.set(true);
- this.pollingThread.interrupt();
+
+ if (stopThread) {
+ this.isInterrupted.set(true);
+ this.pollingThread.interrupt();
+ }
}
public void on(String eventName, Consumer callback) {
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
index 49561033..2b01d7e7 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
@@ -60,6 +60,7 @@ import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
+import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.Keys;
@@ -99,7 +100,7 @@ import io.openvidu.test.e2e.browser.ChromeAndroidUser;
import io.openvidu.test.e2e.browser.ChromeUser;
import io.openvidu.test.e2e.browser.FirefoxUser;
import io.openvidu.test.e2e.browser.OperaUser;
-import io.openvidu.test.e2e.utils.CommandLineExecuter;
+import io.openvidu.test.e2e.utils.CommandLineExecutor;
import io.openvidu.test.e2e.utils.CustomHttpClient;
import io.openvidu.test.e2e.utils.MultimediaFileMetadata;
import io.openvidu.test.e2e.utils.Unzipper;
@@ -126,12 +127,13 @@ public class OpenViduTestAppE2eTest {
BrowserUser user;
Collection otherUsers = new ArrayList<>();
volatile static boolean isRecordingTest;
+ volatile static boolean isKurentoRestartTest;
private static OpenVidu OV;
@BeforeAll()
static void setupAll() {
- String ffmpegOutput = new CommandLineExecuter().executeCommand("which ffmpeg");
+ String ffmpegOutput = new CommandLineExecutor().executeCommand("which ffmpeg");
if (ffmpegOutput == null || ffmpegOutput.isEmpty()) {
log.error("ffmpeg package is not installed in the host machine");
Assert.fail();
@@ -186,7 +188,10 @@ public class OpenViduTestAppE2eTest {
this.user = new ChromeAndroidUser("TestUser", 50);
break;
case "chromeAlternateScreenShare":
- this.user = new ChromeUser("TestUser", 50, "OpenVidu TestApp");
+ this.user = new ChromeUser("TestUser", 50, "OpenVidu TestApp", false);
+ break;
+ case "chromeAsRoot":
+ this.user = new ChromeUser("TestUser", 50, "Entire screen", true);
break;
default:
this.user = new ChromeUser("TestUser", 50);
@@ -250,6 +255,9 @@ public class OpenViduTestAppE2eTest {
}
isRecordingTest = false;
}
+ if (isKurentoRestartTest) {
+ new CommandLineExecutor().executeCommand("sudo service kurento-media-server restart");
+ }
}
@Test
@@ -2558,6 +2566,150 @@ public class OpenViduTestAppE2eTest {
+ "'openviduRecordingVersion':'STR','openviduRecordingPath':'STR','openviduRecordingPublicAccess':false,'openviduRecordingNotification':'STR','openviduRecordingCustomLayout':'STR','openviduRecordingAutostopTimeout':0}");
}
+ @Test
+ @DisplayName("Kurento reconnect test")
+ void kurentoReconnectTest() throws Exception {
+ isRecordingTest = true;
+ isKurentoRestartTest = true;
+
+ log.info("Kurento reconnect test");
+
+ List sessions = OV.getActiveSessions();
+ Assert.assertEquals("Expected no active sessions but found " + sessions.size(), 0, sessions.size());
+
+ final CommandLineExecutor exec = new CommandLineExecutor();
+
+ exec.executeCommand("sudo service kurento-media-server stop");
+
+ OV.fetch();
+
+ setupBrowser("chromeAsRoot");
+
+ // Connect one publisher with no connection to KMS
+
+ user.getDriver().findElement(By.id("add-user-btn")).click();
+ user.getDriver().findElement(By.className("subscribe-remote-check")).click();
+ user.getDriver().findElement(By.className("join-btn")).click();
+
+ user.getWaiter().until(ExpectedConditions.alertIsPresent());
+ Alert alert = user.getDriver().switchTo().alert();
+
+ final String alertMessage = "Exception connecting to WebSocket server ws://localhost:8888/kurento";
+ Assert.assertTrue("Alert message wrong. Expected to contain: \"" + alertMessage + "\". Actual message: \""
+ + alert.getText() + "\"", alert.getText().contains(alertMessage));
+ alert.accept();
+
+ user.getDriver().findElement(By.id("remove-user-btn")).sendKeys(Keys.ENTER);
+
+ exec.executeCommand("sudo service kurento-media-server start");
+ Thread.sleep(3000);
+
+ // Connect one subscriber with connection to KMS -> restart KMS -> connect a
+ // publisher -> restart KMS -> check streamDestroyed events
+
+ user.getDriver().findElement(By.id("add-user-btn")).click();
+ user.getDriver().findElements(By.className("publish-checkbox")).forEach(el -> el.click());
+ user.getDriver().findElement(By.className("join-btn")).click();
+
+ user.getEventManager().waitUntilEventReaches("connectionCreated", 1);
+
+ OV.fetch();
+ sessions = OV.getActiveSessions();
+ Assert.assertEquals("Expected 1 active sessions but found " + sessions.size(), 1, sessions.size());
+
+ exec.executeCommand("sudo service kurento-media-server restart");
+ Thread.sleep(3000);
+
+ OV.fetch();
+ sessions = OV.getActiveSessions();
+ Assert.assertEquals("Expected 1 active sessions but found " + sessions.size(), 1, sessions.size());
+
+ user.getDriver().findElement(By.id("add-user-btn")).click();
+ user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click();
+
+ user.getEventManager().waitUntilEventReaches("connectionCreated", 4);
+ user.getEventManager().waitUntilEventReaches("accessAllowed", 1);
+ user.getEventManager().waitUntilEventReaches("streamCreated", 2);
+ user.getEventManager().waitUntilEventReaches("streamPlaying", 2);
+
+ final int numberOfVideos = user.getDriver().findElements(By.tagName("video")).size();
+ Assert.assertEquals("Expected 2 videos but found " + numberOfVideos, 2, numberOfVideos);
+ Assert.assertTrue("Videos were expected to have audio and video tracks", user.getEventManager()
+ .assertMediaTracks(user.getDriver().findElements(By.tagName("video")), true, true));
+
+ OV.fetch();
+ Session session = OV.getActiveSessions().get(0);
+ Assert.assertEquals("Expected 2 active connections but found " + session.getActiveConnections(), 2,
+ session.getActiveConnections().size());
+ int pubs = session.getActiveConnections().stream().mapToInt(con -> con.getPublishers().size()).sum();
+ int subs = session.getActiveConnections().stream().mapToInt(con -> con.getSubscribers().size()).sum();
+ Assert.assertEquals("Expected 1 active publisher but found " + pubs, 1, pubs);
+ Assert.assertEquals("Expected 1 active subscriber but found " + subs, 1, subs);
+
+ OV.startRecording(session.getSessionId(),
+ new RecordingProperties.Builder().outputMode(OutputMode.INDIVIDUAL).build());
+ user.getEventManager().waitUntilEventReaches("recordingStarted", 2);
+
+ long recStartTime = System.currentTimeMillis();
+
+ final CountDownLatch latch = new CountDownLatch(4);
+
+ user.getEventManager().on("recordingStopped", (event) -> {
+ String reason = event.get("reason").getAsString();
+ Assert.assertEquals("Expected 'recordingStopped' reason 'mediaServerDisconnect'", "mediaServerDisconnect",
+ reason);
+ latch.countDown();
+ });
+ user.getEventManager().on("streamDestroyed", (event) -> {
+ String reason = event.get("reason").getAsString();
+ Assert.assertEquals("Expected 'streamDestroyed' reason 'mediaServerDisconnect'", "mediaServerDisconnect",
+ reason);
+ latch.countDown();
+ });
+ exec.executeCommand("sudo service kurento-media-server restart");
+ long recEndTime = System.currentTimeMillis();
+ user.getEventManager().waitUntilEventReaches("recordingStopped", 2);
+ user.getEventManager().waitUntilEventReaches("streamDestroyed", 2);
+ if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+ gracefullyLeaveParticipants(2);
+ fail("Waiting for 2 streamDestroyed events with reason 'mediaServerDisconnect' to happen in total");
+ return;
+ }
+ user.getEventManager().off("streamDestroyed");
+
+ session.fetch();
+ Assert.assertEquals("Expected 2 active connections but found " + session.getActiveConnections(), 2,
+ session.getActiveConnections().size());
+ pubs = session.getActiveConnections().stream().mapToInt(con -> con.getPublishers().size()).sum();
+ subs = session.getActiveConnections().stream().mapToInt(con -> con.getSubscribers().size()).sum();
+ Assert.assertEquals("Expected no active publishers but found " + pubs, 0, pubs);
+ Assert.assertEquals("Expected no active subscribers but found " + subs, 0, subs);
+
+ Recording rec = OV.getRecording("TestSession");
+ double differenceInDuration = Math.abs(rec.getDuration() - ((recEndTime - recStartTime) / 1000));
+ Assert.assertTrue("Recording duration exceeds valid value. Expected no more than 0.2 seconds, got "
+ + differenceInDuration, differenceInDuration < 0.2);
+
+ this.checkIndividualRecording("/opt/openvidu/recordings/TestSession/", rec, 1, "opus", "vp8", true);
+
+ WebElement pubBtn = user.getDriver().findElements(By.cssSelector("#openvidu-instance-1 .pub-btn")).get(0);
+ pubBtn.click();
+ user.getEventManager().waitUntilEventReaches("streamDestroyed", 3); // This is not real, only in testapp
+ pubBtn.click();
+ user.getEventManager().waitUntilEventReaches("streamCreated", 4);
+ user.getEventManager().waitUntilEventReaches("streamPlaying", 4);
+
+ session.fetch();
+ Assert.assertEquals("Expected 2 active connections but found " + session.getActiveConnections(), 2,
+ session.getActiveConnections().size());
+ pubs = session.getActiveConnections().stream().mapToInt(con -> con.getPublishers().size()).sum();
+ subs = session.getActiveConnections().stream().mapToInt(con -> con.getSubscribers().size()).sum();
+ Assert.assertEquals("Expected 1 active publisher but found " + pubs, 1, pubs);
+ Assert.assertEquals("Expected 1 active subscriber but found " + subs, 1, subs);
+
+ gracefullyLeaveParticipants(2);
+ }
+
private void listEmptyRecordings() {
// List existing recordings (empty)
user.getDriver().findElement(By.id("list-recording-btn")).click();
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/BrowserUser.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/BrowserUser.java
index 126eac1b..dabde00a 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/BrowserUser.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/BrowserUser.java
@@ -73,7 +73,7 @@ public class BrowserUser {
}
public void dispose() {
- this.eventManager.stopPolling();
+ this.eventManager.stopPolling(true);
this.driver.quit();
}
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/ChromeUser.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/ChromeUser.java
index 6f1641b9..97b32c39 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/ChromeUser.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/browser/ChromeUser.java
@@ -32,11 +32,11 @@ import org.springframework.core.io.ClassPathResource;
public class ChromeUser extends BrowserUser {
public ChromeUser(String userName, int timeOfWaitInSeconds) {
- this(userName, timeOfWaitInSeconds, "Entire screen");
+ this(userName, timeOfWaitInSeconds, "Entire screen", false);
}
- public ChromeUser(String userName, int timeOfWaitInSeconds, String screenToCapture) {
- this(userName, timeOfWaitInSeconds, generateScreenChromeOptions(screenToCapture));
+ public ChromeUser(String userName, int timeOfWaitInSeconds, String screenToCapture, boolean runningAsRoot) {
+ this(userName, timeOfWaitInSeconds, generateScreenChromeOptions(screenToCapture, runningAsRoot));
}
public ChromeUser(String userName, int timeOfWaitInSeconds, Path fakeVideoLocation) {
@@ -66,7 +66,7 @@ public class ChromeUser extends BrowserUser {
this.configureDriver();
}
- private static ChromeOptions generateScreenChromeOptions(String screenToCapture) {
+ private static ChromeOptions generateScreenChromeOptions(String screenToCapture, boolean runningAsRoot) {
ChromeOptions options = new ChromeOptions();
// This flag avoids to grant the user media
options.addArguments("--use-fake-ui-for-media-stream");
@@ -80,6 +80,11 @@ public class ChromeUser extends BrowserUser {
} catch (IOException e) {
e.printStackTrace();
}
+
+ if (runningAsRoot) {
+ options.addArguments("--no-sandbox");
+ }
+
return options;
}
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecuter.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecutor.java
similarity index 97%
rename from openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecuter.java
rename to openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecutor.java
index 3aabc271..2c100997 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecuter.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/CommandLineExecutor.java
@@ -20,7 +20,7 @@ package io.openvidu.test.e2e.utils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
-public class CommandLineExecuter {
+public class CommandLineExecutor {
public String executeCommand(String command) {
String output = "";
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/MultimediaFileMetadata.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/MultimediaFileMetadata.java
index b55f42ce..e95b2545 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/MultimediaFileMetadata.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/utils/MultimediaFileMetadata.java
@@ -28,7 +28,7 @@ public class MultimediaFileMetadata {
private static final Logger log = LoggerFactory.getLogger(MultimediaFileMetadata.class);
- private CommandLineExecuter executer = new CommandLineExecuter();
+ private CommandLineExecutor executer = new CommandLineExecutor();
private JsonParser parser = new JsonParser();
private JsonObject json;