mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: KMS reconnection test
parent
3bc39ed448
commit
e0b1f118eb
|
@ -62,6 +62,18 @@
|
||||||
<org-seleniumhq-selenium.version>3.141.59</org-seleniumhq-selenium.version>
|
<org-seleniumhq-selenium.version>3.141.59</org-seleniumhq-selenium.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>3.0.0-M3</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
|
|
@ -95,12 +95,27 @@ public class OpenViduEventManager {
|
||||||
|
|
||||||
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
|
Thread.UncaughtExceptionHandler h = new Thread.UncaughtExceptionHandler() {
|
||||||
public void uncaughtException(Thread th, Throwable ex) {
|
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")) {
|
if (ex.getClass().getSimpleName().equals("NoSuchSessionException")) {
|
||||||
System.err.println("Disposing driver when running 'executeScript'");
|
System.err.println("Disposing driver when running 'executeScript'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.pollingThread != null) {
|
||||||
|
this.pollingThread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
this.pollingThread = new Thread(() -> {
|
this.pollingThread = new Thread(() -> {
|
||||||
while (!this.isInterrupted.get()) {
|
while (!this.isInterrupted.get()) {
|
||||||
this.getEventsFromBrowser();
|
this.getEventsFromBrowser();
|
||||||
|
@ -116,12 +131,15 @@ public class OpenViduEventManager {
|
||||||
this.pollingThread.start();
|
this.pollingThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopPolling() {
|
public void stopPolling(boolean stopThread) {
|
||||||
this.eventCallbacks.clear();
|
this.eventCallbacks.clear();
|
||||||
this.eventCountdowns.clear();
|
this.eventCountdowns.clear();
|
||||||
this.eventNumbers.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<JsonObject> callback) {
|
public void on(String eventName, Consumer<JsonObject> callback) {
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.junit.jupiter.api.Tag;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.platform.runner.JUnitPlatform;
|
import org.junit.platform.runner.JUnitPlatform;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.openqa.selenium.Alert;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.Dimension;
|
import org.openqa.selenium.Dimension;
|
||||||
import org.openqa.selenium.Keys;
|
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.ChromeUser;
|
||||||
import io.openvidu.test.e2e.browser.FirefoxUser;
|
import io.openvidu.test.e2e.browser.FirefoxUser;
|
||||||
import io.openvidu.test.e2e.browser.OperaUser;
|
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.CustomHttpClient;
|
||||||
import io.openvidu.test.e2e.utils.MultimediaFileMetadata;
|
import io.openvidu.test.e2e.utils.MultimediaFileMetadata;
|
||||||
import io.openvidu.test.e2e.utils.Unzipper;
|
import io.openvidu.test.e2e.utils.Unzipper;
|
||||||
|
@ -126,12 +127,13 @@ public class OpenViduTestAppE2eTest {
|
||||||
BrowserUser user;
|
BrowserUser user;
|
||||||
Collection<BrowserUser> otherUsers = new ArrayList<>();
|
Collection<BrowserUser> otherUsers = new ArrayList<>();
|
||||||
volatile static boolean isRecordingTest;
|
volatile static boolean isRecordingTest;
|
||||||
|
volatile static boolean isKurentoRestartTest;
|
||||||
private static OpenVidu OV;
|
private static OpenVidu OV;
|
||||||
|
|
||||||
@BeforeAll()
|
@BeforeAll()
|
||||||
static void setupAll() {
|
static void setupAll() {
|
||||||
|
|
||||||
String ffmpegOutput = new CommandLineExecuter().executeCommand("which ffmpeg");
|
String ffmpegOutput = new CommandLineExecutor().executeCommand("which ffmpeg");
|
||||||
if (ffmpegOutput == null || ffmpegOutput.isEmpty()) {
|
if (ffmpegOutput == null || ffmpegOutput.isEmpty()) {
|
||||||
log.error("ffmpeg package is not installed in the host machine");
|
log.error("ffmpeg package is not installed in the host machine");
|
||||||
Assert.fail();
|
Assert.fail();
|
||||||
|
@ -186,7 +188,10 @@ public class OpenViduTestAppE2eTest {
|
||||||
this.user = new ChromeAndroidUser("TestUser", 50);
|
this.user = new ChromeAndroidUser("TestUser", 50);
|
||||||
break;
|
break;
|
||||||
case "chromeAlternateScreenShare":
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
this.user = new ChromeUser("TestUser", 50);
|
this.user = new ChromeUser("TestUser", 50);
|
||||||
|
@ -250,6 +255,9 @@ public class OpenViduTestAppE2eTest {
|
||||||
}
|
}
|
||||||
isRecordingTest = false;
|
isRecordingTest = false;
|
||||||
}
|
}
|
||||||
|
if (isKurentoRestartTest) {
|
||||||
|
new CommandLineExecutor().executeCommand("sudo service kurento-media-server restart");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -2558,6 +2566,150 @@ public class OpenViduTestAppE2eTest {
|
||||||
+ "'openviduRecordingVersion':'STR','openviduRecordingPath':'STR','openviduRecordingPublicAccess':false,'openviduRecordingNotification':'STR','openviduRecordingCustomLayout':'STR','openviduRecordingAutostopTimeout':0}");
|
+ "'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<Session> 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() {
|
private void listEmptyRecordings() {
|
||||||
// List existing recordings (empty)
|
// List existing recordings (empty)
|
||||||
user.getDriver().findElement(By.id("list-recording-btn")).click();
|
user.getDriver().findElement(By.id("list-recording-btn")).click();
|
||||||
|
|
|
@ -73,7 +73,7 @@ public class BrowserUser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
this.eventManager.stopPolling();
|
this.eventManager.stopPolling(true);
|
||||||
this.driver.quit();
|
this.driver.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,11 @@ import org.springframework.core.io.ClassPathResource;
|
||||||
public class ChromeUser extends BrowserUser {
|
public class ChromeUser extends BrowserUser {
|
||||||
|
|
||||||
public ChromeUser(String userName, int timeOfWaitInSeconds) {
|
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) {
|
public ChromeUser(String userName, int timeOfWaitInSeconds, String screenToCapture, boolean runningAsRoot) {
|
||||||
this(userName, timeOfWaitInSeconds, generateScreenChromeOptions(screenToCapture));
|
this(userName, timeOfWaitInSeconds, generateScreenChromeOptions(screenToCapture, runningAsRoot));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChromeUser(String userName, int timeOfWaitInSeconds, Path fakeVideoLocation) {
|
public ChromeUser(String userName, int timeOfWaitInSeconds, Path fakeVideoLocation) {
|
||||||
|
@ -66,7 +66,7 @@ public class ChromeUser extends BrowserUser {
|
||||||
this.configureDriver();
|
this.configureDriver();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChromeOptions generateScreenChromeOptions(String screenToCapture) {
|
private static ChromeOptions generateScreenChromeOptions(String screenToCapture, boolean runningAsRoot) {
|
||||||
ChromeOptions options = new ChromeOptions();
|
ChromeOptions options = new ChromeOptions();
|
||||||
// This flag avoids to grant the user media
|
// This flag avoids to grant the user media
|
||||||
options.addArguments("--use-fake-ui-for-media-stream");
|
options.addArguments("--use-fake-ui-for-media-stream");
|
||||||
|
@ -80,6 +80,11 @@ public class ChromeUser extends BrowserUser {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runningAsRoot) {
|
||||||
|
options.addArguments("--no-sandbox");
|
||||||
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ package io.openvidu.test.e2e.utils;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
public class CommandLineExecuter {
|
public class CommandLineExecutor {
|
||||||
|
|
||||||
public String executeCommand(String command) {
|
public String executeCommand(String command) {
|
||||||
String output = "";
|
String output = "";
|
|
@ -28,7 +28,7 @@ public class MultimediaFileMetadata {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MultimediaFileMetadata.class);
|
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 JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
private JsonObject json;
|
private JsonObject json;
|
||||||
|
|
Loading…
Reference in New Issue