diff --git a/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/ChromeUser.java b/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/ChromeUser.java index f42b3e6e6..726fdb808 100644 --- a/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/ChromeUser.java +++ b/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/ChromeUser.java @@ -17,22 +17,41 @@ package io.openvidu.test.browsers; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.openqa.selenium.Capabilities; +import org.openqa.selenium.NoSuchSessionException; import org.openqa.selenium.UnexpectedAlertBehaviour; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebDriverException; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; +import org.openqa.selenium.chromium.HasCdp; +import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.RemoteWebDriver; public class ChromeUser extends BrowserUser { + private Long chromeDriverPid; + public ChromeUser(String userName, int timeOfWaitInSeconds, boolean headless) { this(userName, timeOfWaitInSeconds, generateDefaultScreenChromeOptions(), headless); } @@ -92,7 +111,9 @@ public class ChromeUser extends BrowserUser { } } else { log.info("Using local web driver"); - this.driver = new ChromeDriver(options); + ChromeDriver chromeDriver = new ChromeDriver(options); + this.driver = chromeDriver; + this.chromeDriverPid = getChromeDriverPid(chromeDriver); } this.driver.manage().timeouts().scriptTimeout(Duration.ofSeconds(timeOfWaitInSeconds)); @@ -135,4 +156,184 @@ public class ChromeUser extends BrowserUser { return options; } + /** + * Simulates an abrupt Chrome crash by forcefully killing the browser process. + * Works for both local and remote WebDriver instances. + * + * @throws IOException if process killing fails + */ + public void simulateCrash() throws IOException { + String REMOTE_URL = System.getProperty("REMOTE_URL_CHROME"); + if (REMOTE_URL != null) { + // Remote WebDriver: Use Chrome DevTools Protocol to crash the browser + simulateRemoteCrash(); + } else { + // Local WebDriver: Kill the Chrome process directly + simulateLocalCrash(); + } + log.info("Simulated Chrome crash for user {}", this.clientData); + } + + /** + * Simulates crash for local Chrome instance by killing the process + */ + private void simulateLocalCrash() throws IOException { + ProcessHandle.of(chromeDriverPid).ifPresent(ph -> { + // Kill all descendant processes (the actual Chrome browser processes) + ph.descendants().forEach(child -> child.destroyForcibly()); + }); + } + + /** + * Simulates crash for remote Chrome instance using CDP + */ + private void simulateRemoteCrash() { + ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + CompletableFuture cf = CompletableFuture.runAsync(() -> { + try { + Map params = Collections.emptyMap(); + HasCdp cdp = (driver instanceof HasCdp) + ? (HasCdp) driver + : (HasCdp) new Augmenter().augment(driver); + cdp.executeCdpCommand("Browser.crash", params); + } catch (Exception ignored) { + // Expected if browser crashes while executing the command + } + }, executor); + + try { + cf.get(2, TimeUnit.SECONDS); + log.info("Browser crash command executed (response received)"); + } catch (TimeoutException te) { + log.info("Browser crash command sent (no response as expected)"); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + log.warn("Interrupted while sending crash command", ie); + } catch (ExecutionException ee) { + log.info("Browser crashed (execution failure)", ee.getCause()); + } + } catch (Exception e) { + log.warn( + "CDP crash command failed, attempting alternative method by directly killing \"selenium/standalone-chrome\" docker container", + e); + try { + Runtime.getRuntime().exec(new String[] { "sh", "-c", + "docker ps | grep selenium/standalone-chrome | awk '{print $1}' | xargs -I {} docker kill {}" }); + } catch (IOException ex) { + log.error("Failed to kill remote Chrome process", ex); + } + } finally { + executor.shutdownNow(); + } + } + + /** + * Extracts Chrome driver process PID from ChromeDriver + */ + private Long getChromeDriverPid(ChromeDriver driver) { + try { + Capabilities caps = driver.getCapabilities(); + Object debuggerAddress = caps.getCapability("goog:chromeOptions"); + + if (debuggerAddress instanceof Map) { + @SuppressWarnings("unchecked") + Map options = (Map) debuggerAddress; + Object addr = options.get("debuggerAddress"); + if (addr != null) { + // Parse port from debugger address (e.g., "localhost:12345") + String[] parts = addr.toString().split(":"); + if (parts.length == 2) { + int port = Integer.parseInt(parts[1]); + return findPidByPort(port); + } + } + } + + // Fallback: Find Chrome process by command line + return findChromePidByCommandLine(); + } catch (Exception e) { + log.warn("Failed to get Chrome PID from driver", e); + return null; + } + } + + /** + * Finds Chrome PID by the port it's listening on + */ + private Long findPidByPort(int port) { + try { + String os = System.getProperty("os.name").toLowerCase(); + Process process; + + if (os.contains("win")) { + process = Runtime.getRuntime().exec(new String[] { "netstat", "-ano" }); + } else { + process = Runtime.getRuntime().exec(new String[] { "sh", "-c", "lsof -ti:" + port + " | head -n 1" }); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + + if (os.contains("win")) { + while ((line = reader.readLine()) != null) { + if (line.contains(":" + port + " ")) { + String[] parts = line.trim().split("\\s+"); + return Long.parseLong(parts[parts.length - 1]); + } + } + } else { + line = reader.readLine(); + if (line != null && !line.isEmpty()) { + return Long.parseLong(line.trim()); + } + } + } catch (Exception e) { + log.warn("Failed to find PID by port", e); + } + return null; + } + + /** + * Finds Chrome PID by searching for chrome process + */ + private Long findChromePidByCommandLine() { + try { + String os = System.getProperty("os.name").toLowerCase(); + Process process; + + if (os.contains("win")) { + process = Runtime.getRuntime() + .exec(new String[] { "sh", "-c", + "wmic process where \"name='chrome.exe'\" get ProcessId,CommandLine" }); + } else if (os.contains("mac")) { + process = Runtime.getRuntime().exec(new String[] { "sh", "-c", + "ps aux | grep -i chrome | grep -v grep | awk '{print $2}' | head -n 1" }); + } else { + process = Runtime.getRuntime().exec(new String[] { "sh", "-c", + "pgrep -f chrome | head -n 1" }); + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + + if (os.contains("win")) { + reader.readLine(); // Skip header + line = reader.readLine(); + if (line != null) { + String[] parts = line.trim().split("\\s+"); + return Long.parseLong(parts[parts.length - 1]); + } + } else { + line = reader.readLine(); + if (line != null && !line.isEmpty()) { + return Long.parseLong(line.trim()); + } + } + } catch (Exception e) { + log.warn("Failed to find Chrome PID by command line", e); + } + return null; + } + } \ No newline at end of file diff --git a/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/utils/RecordingUtils.java b/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/utils/RecordingUtils.java index 8e312e59c..265406077 100644 --- a/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/utils/RecordingUtils.java +++ b/openvidu-test-browsers/src/main/java/io/openvidu/test/browsers/utils/RecordingUtils.java @@ -47,7 +47,7 @@ public class RecordingUtils { private boolean recordedFileFine(File file, Recording recording, Function, Boolean> colorCheckFunction) throws IOException { this.checkMultimediaFile(file, recording.hasAudio(), recording.hasVideo(), recording.getDuration(), - recording.getResolution(), recording.getFrameRate(), "aac", "h264", true); + recording.getResolution(), recording.getFrameRate(), "aac", "h264", true, 2); boolean isFine = false; Picture frame; @@ -115,7 +115,8 @@ public class RecordingUtils { } public void checkIndividualRecording(String recPath, Recording recording, int numberOfVideoFiles, - String audioDecoder, String videoDecoder, boolean checkAudio) throws IOException { + String audioDecoder, String videoDecoder, boolean checkAudio, long durationToleranceInSeconds) + throws IOException { // Should be only 2 files: zip and metadata File folder = new File(recPath); @@ -179,7 +180,8 @@ public class RecordingUtils { log.info("Duration of {} according to sync metadata json file: {} s", webmFile.getName(), durationInSeconds); this.checkMultimediaFile(webmFile, recording.hasAudio(), recording.hasVideo(), durationInSeconds, - recording.getResolution(), recording.getFrameRate(), audioDecoder, videoDecoder, checkAudio); + recording.getResolution(), recording.getFrameRate(), audioDecoder, videoDecoder, checkAudio, + durationToleranceInSeconds); webmFile.delete(); } @@ -190,7 +192,9 @@ public class RecordingUtils { } public void checkMultimediaFile(File file, boolean hasAudio, boolean hasVideo, double duration, String resolution, - Integer frameRate, String audioDecoder, String videoDecoder, boolean checkAudio) throws IOException { + Integer frameRate, String audioDecoder, String videoDecoder, boolean checkAudio, + long durationToleranceInSeconds) + throws IOException { // Check tracks, duration, resolution, framerate and decoders MultimediaFileMetadata metadata = new MultimediaFileMetadata(file.getAbsolutePath()); @@ -225,11 +229,11 @@ public class RecordingUtils { df.setRoundingMode(RoundingMode.UP); log.info("Duration of {} according to ffmpeg: {} s", file.getName(), metadata.getDuration()); log.info("Duration of {} according to 'duration' property: {} s", file.getName(), duration); - log.info("Difference in s duration: {}", Math.abs(metadata.getDuration() - duration)); - final double difference = 10; - Assertions.assertTrue(Math.abs((metadata.getDuration() - duration)) < difference, + log.info("Difference in s duration: {}", Math.abs(duration - metadata.getDuration())); + Assertions.assertTrue(Math.abs((duration - metadata.getDuration())) < durationToleranceInSeconds, "Difference between recording entity duration (" + duration + ") and real video duration (" - + metadata.getDuration() + ") is greater than " + difference + " in file " + file.getName()); + + metadata.getDuration() + ") is greater than " + durationToleranceInSeconds + " in file " + + file.getName()); } public boolean thumbnailIsFine(File file, Function, Boolean> colorCheckFunction) { diff --git a/openvidu-test-e2e/src/main/java/io/openvidu/test/e2e/MediaNodeDockerUtils.java b/openvidu-test-e2e/src/main/java/io/openvidu/test/e2e/MediaNodeDockerUtils.java index 7e88690af..79118d91c 100644 --- a/openvidu-test-e2e/src/main/java/io/openvidu/test/e2e/MediaNodeDockerUtils.java +++ b/openvidu-test-e2e/src/main/java/io/openvidu/test/e2e/MediaNodeDockerUtils.java @@ -45,7 +45,7 @@ public class MediaNodeDockerUtils { DockerClient dockerClient = getDockerClient(); ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId).withAttachStdout(true) .withAttachStderr(true) - .withCmd("bash", "-c", "docker stop kms && sleep " + (millisStop / 1000) + " && docker start kms") + .withCmd("bash", "-c", "docker kill kms && sleep " + (millisStop / 1000) + " && docker start kms") .exec(); dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ResultCallback.Adapter<>() { }); diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java index 01c558b97..59fb877dd 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java @@ -58,12 +58,14 @@ import io.openvidu.java.client.OpenViduRole; import io.openvidu.java.client.Recording; import io.openvidu.java.client.RecordingProperties; import io.openvidu.java.client.Session; +import io.openvidu.test.browsers.ChromeUser; import io.openvidu.test.browsers.utils.CustomHttpClient; import io.openvidu.test.browsers.utils.RecordingUtils; import io.openvidu.test.browsers.utils.Unzipper; import io.openvidu.test.browsers.utils.layout.CustomLayoutHandler; import io.openvidu.test.browsers.utils.webhook.CustomWebhook; import io.openvidu.test.e2e.utils.TestUtils; +import io.openvidu.test.e2e.annotations.OnlyKurento; public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { @@ -649,10 +651,13 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { } } + long accumulatedTimesWhenSartingRecordings = 0; + // Start the recording of the sessions restClient.rest(HttpMethod.POST, "/openvidu/api/recordings/start", "{'session':'" + sessionName + "','outputMode':'INDIVIDUAL'}", HttpURLConnection.HTTP_OK); user.getEventManager().waitUntilEventReaches("recordingStarted", 3); + Thread.sleep(1000); // Get connectionId and streamId for one of the users configured to NOT be @@ -671,20 +676,39 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { } } + long timeBeforeOp = System.currentTimeMillis(); + // Generate 3 total recordings of 1 second length for the stream of the user // configured to NOT be recorded restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/" + sessionName + "/connection/" + connectionId2, "{'record':true}", HttpURLConnection.HTTP_OK); + user.getEventManager().waitUntilEventReaches("connectionPropertyChanged", 1); + + accumulatedTimesWhenSartingRecordings += System.currentTimeMillis() - timeBeforeOp; + Thread.sleep(1000); + + timeBeforeOp = System.currentTimeMillis(); + restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/" + sessionName + "/connection/" + connectionId2, "{'record':false}", HttpURLConnection.HTTP_OK); restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/" + sessionName + "/connection/" + connectionId2, "{'record':true}", HttpURLConnection.HTTP_OK); + user.getEventManager().waitUntilEventReaches("connectionPropertyChanged", 3); + + accumulatedTimesWhenSartingRecordings += System.currentTimeMillis() - timeBeforeOp; + Thread.sleep(1000); + + timeBeforeOp = System.currentTimeMillis(); restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/" + sessionName + "/connection/" + connectionId2, "{'record':false}", HttpURLConnection.HTTP_OK); restClient.rest(HttpMethod.PATCH, "/openvidu/api/sessions/" + sessionName + "/connection/" + connectionId2, "{'record':true}", HttpURLConnection.HTTP_OK); + user.getEventManager().waitUntilEventReaches("connectionPropertyChanged", 5); + + accumulatedTimesWhenSartingRecordings += System.currentTimeMillis() - timeBeforeOp; + Thread.sleep(1000); restClient.rest(HttpMethod.POST, "/openvidu/api/recordings/stop/" + sessionName, HttpURLConnection.HTTP_OK); @@ -695,7 +719,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { String recPath = "/opt/openvidu/recordings/" + sessionName + "/"; Recording recording = new OpenVidu(OpenViduTestAppE2eTest.OPENVIDU_URL, OpenViduTestAppE2eTest.OPENVIDU_SECRET) .getRecording(sessionName); - this.recordingUtils.checkIndividualRecording(recPath, recording, 4, "opus", "vp8", true); + this.recordingUtils.checkIndividualRecording(recPath, recording, 4, "opus", "vp8", true, 5); // Analyze INDIVIDUAL recording metadata new Unzipper().unzipFile(recPath, recording.getName() + ".zip"); @@ -718,8 +742,9 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { Assertions.assertEquals(connectionId1, file.get("connectionId").getAsString(), "Wrong connectionId file metadata property"); long msDuration = file.get("endTimeOffset").getAsLong() - file.get("startTimeOffset").getAsLong(); - Assertions.assertTrue((msDuration - 4000) < 1000, - "Wrong recording duration of individual file. Difference: " + (msDuration - 4000)); + long differenceInDuration = msDuration - 4000 - accumulatedTimesWhenSartingRecordings; + Assertions.assertTrue(differenceInDuration < 750, + "Wrong recording duration of individual file. Difference: " + differenceInDuration); count1++; } else if (fileStreamId.equals(streamId2)) { // Dynamically recorded user @@ -753,6 +778,137 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { Assertions.assertTrue(regexNames.isEmpty(), "Some expected file name didn't existed: " + regexNames.toString()); } + @Test + @DisplayName("Individual record with abrupt user disconnection") + void individualRecordWithAbruptUserDisconnectionTest() throws Exception { + isRecordingTest = true; + + log.info("Individual record with abrupt user disconnection"); + + CustomHttpClient restClient = new CustomHttpClient(OpenViduTestAppE2eTest.OPENVIDU_URL, "OPENVIDUAPP", + OpenViduTestAppE2eTest.OPENVIDU_SECRET); + JsonObject config = restClient.rest(HttpMethod.GET, "/openvidu/api/config", HttpURLConnection.HTTP_OK); + + String defaultOpenViduWebhookEndpoint = null; + Integer defaultOpenViduRecordingAutostopTimeout = null; + if (config.has("OPENVIDU_WEBHOOK_ENDPOINT")) { + defaultOpenViduWebhookEndpoint = config.get("OPENVIDU_WEBHOOK_ENDPOINT").getAsString(); + } + if (config.has("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT")) { + defaultOpenViduRecordingAutostopTimeout = config.get("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT").getAsInt(); + } + + CountDownLatch initLatch = new CountDownLatch(1); + io.openvidu.test.browsers.utils.webhook.CustomWebhook.main(new String[0], initLatch); + + try { + + if (!initLatch.await(30, TimeUnit.SECONDS)) { + Assertions.fail("Timeout waiting for webhook springboot app to start"); + CustomWebhook.shutDown(); + return; + } + + Map newConfig = Map.of("OPENVIDU_PRO_NETWORK_QUALITY", false, + "OPENVIDU_PRO_SPEECH_TO_TEXT", "disabled", "OPENVIDU_WEBHOOK", true, + "OPENVIDU_WEBHOOK_ENDPOINT", "http://127.0.0.1:7777/webhook", + "OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", 0); + restartOpenViduServer(newConfig); + + OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome"); + + final String sessionName = "AbruptStopOfIndividualRecording"; + final String recordingName = "ABRUPT_STOP_OF_INDIVIDUAL_RECORDING"; + + user.getDriver().findElement(By.id("add-user-btn")).click(); + user.getDriver().findElement(By.id("session-name-input-0")).clear(); + user.getDriver().findElement(By.id("session-name-input-0")).sendKeys(sessionName); + user.getDriver().findElement(By.className("join-btn")).click(); + + user.getEventManager().waitUntilEventReaches("connectionCreated", 1); + user.getEventManager().waitUntilEventReaches("accessAllowed", 1); + user.getEventManager().waitUntilEventReaches("streamCreated", 1); + user.getEventManager().waitUntilEventReaches("streamPlaying", 1); + + int numberOfVideos = user.getDriver().findElements(By.tagName("video")).size(); + Assertions.assertEquals(1, numberOfVideos, "Expected 1 video but found " + numberOfVideos); + Assertions.assertTrue( + user.getBrowserUser().assertMediaTracks(user.getDriver().findElements(By.tagName("video")), true, + true), + "Video was expected to have audio and video tracks"); + + user.getDriver().findElement(By.id("session-api-btn-0")).click(); + Thread.sleep(1000); + user.getDriver().findElement(By.id("rec-properties-btn")).click(); + Thread.sleep(500); + + // Set recording name + user.getDriver().findElement(By.id("recording-name-field")).sendKeys(recordingName); + // Set OutputMode to INDIVIDUAL + user.getDriver().findElement(By.id("rec-outputmode-select")).click(); + Thread.sleep(500); + user.getDriver().findElement(By.id("option-INDIVIDUAL")).click(); + Thread.sleep(500); + + user.getDriver().findElement(By.id("start-recording-btn")).click(); + + user.getWaiter().until(ExpectedConditions.attributeToBe(By.id("api-response-text-area"), "value", + "Recording started [" + sessionName + "]")); + + user.getEventManager().waitUntilEventReaches("recordingStarted", 1); + + Thread.sleep(3000); + + CustomWebhook.clean(); + + ((ChromeUser) user.getBrowserUser()).simulateCrash(); + + JsonObject event = CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 20); + Assertions.assertEquals("networkDisconnect", event.get("reason").getAsString(), + "Wrong reason for webrtcConnectionDestroyed event"); + + event = CustomWebhook.waitForEvent("participantLeft", 1); + Assertions.assertEquals("networkDisconnect", event.get("reason").getAsString(), + "Wrong reason for participantLeft event"); + + event = CustomWebhook.waitForEvent("recordingStatusChanged", 1); + Assertions.assertEquals("lastParticipantLeft", event.get("reason").getAsString(), + "Wrong reason for recordingStatusChanged event"); + Assertions.assertEquals("stopped", event.get("status").getAsString(), + "Wrong status in recordingStatusChanged event"); + + event = CustomWebhook.waitForEvent("sessionDestroyed", 1); + Assertions.assertEquals("lastParticipantLeft", event.get("reason").getAsString(), + "Wrong reason for sessionDestroyed event"); + + event = CustomWebhook.waitForEvent("recordingStatusChanged", 1); + Assertions.assertEquals("lastParticipantLeft", event.get("reason").getAsString(), + "Wrong reason for recordingStatusChanged event"); + Assertions.assertEquals("ready", event.get("status").getAsString(), + "Wrong status in recordingStatusChanged event"); + + // Check that the INDIVIDUAL recording has been properly saved and is healthy + // even after Chrome crash + String recPath = "/opt/openvidu/recordings/" + sessionName + "/"; + Recording recording = new OpenVidu(OpenViduTestAppE2eTest.OPENVIDU_URL, + OpenViduTestAppE2eTest.OPENVIDU_SECRET) + .getRecording(sessionName); + this.recordingUtils.checkIndividualRecording(recPath, recording, 1, "opus", "vp8", true, 15); + + } finally { + Map oldConfig = new HashMap<>(); + oldConfig.put("OPENVIDU_WEBHOOK", false); + if (defaultOpenViduWebhookEndpoint != null) { + oldConfig.put("OPENVIDU_WEBHOOK_ENDPOINT", defaultOpenViduWebhookEndpoint); + } + if (defaultOpenViduRecordingAutostopTimeout != null) { + oldConfig.put("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", defaultOpenViduRecordingAutostopTimeout); + } + restartOpenViduServer(oldConfig); + CustomWebhook.shutDown(); + } + } + @Test @DisplayName("REST API PRO test") void restApiProTest() throws Exception { @@ -1143,6 +1299,7 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { } @Test + @OnlyKurento @DisplayName("Network quality test") void networkQualityTest() throws Exception { @@ -1290,7 +1447,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { filterOptionsInput = user.getDriver().findElement(By.id("filter-options-field")); filterOptionsInput.clear(); - filterOptionsInput.sendKeys("{\"url\": \"https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Solid_red.svg/1024px-Solid_red.svg.png\"}"); + filterOptionsInput.sendKeys( + "{\"url\": \"https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Solid_red.svg/1024px-Solid_red.svg.png\"}"); user.getDriver().findElement(By.id("apply-filter-btn")).click(); user.getWaiter().until( ExpectedConditions.attributeContains(By.id("operation-response-text-area"), "value", "Filter applied")); @@ -1326,7 +1484,8 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest { // Blue filterParamsInput.clear(); - filterParamsInput.sendKeys("{\"url\": \"https://png.pngtree.com/thumb_back/fw800/background/20210207/pngtree-blue-pure-color-simple-background-image_557085.jpg\"}"); + filterParamsInput.sendKeys( + "{\"url\": \"https://png.pngtree.com/thumb_back/fw800/background/20210207/pngtree-blue-pure-color-simple-background-image_557085.jpg\"}"); user.getDriver().findElement(By.id("exec-filter-btn")).click(); user.getWaiter().until(ExpectedConditions.attributeContains(By.id("operation-response-text-area"), "value", "Filter method executed")); 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 9754dd6e3..089252307 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 @@ -1646,7 +1646,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { String recPath = recordingsPath + sessionName + "/"; Recording recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(sessionName); - this.recordingUtils.checkIndividualRecording(recPath, recording, 2, "opus", "vp8", true); + this.recordingUtils.checkIndividualRecording(recPath, recording, 2, "opus", "vp8", true, 2); // Try to get the stopped recording user.getDriver().findElement(By.id("get-recording-btn")).click(); @@ -1853,17 +1853,17 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { String recPath = recordingsPath + SESSION_NAME + "/"; Recording recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(SESSION_NAME); this.recordingUtils.checkMultimediaFile(new File(recPath + recording.getName() + ".mp4"), false, true, - recording.getDuration(), recording.getResolution(), recording.getFrameRate(), null, "h264", true); + recording.getDuration(), recording.getResolution(), recording.getFrameRate(), null, "h264", true, 2); // Check video-only INDIVIDUAL recording recPath = recordingsPath + SESSION_NAME + "~1/"; recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(SESSION_NAME + "~1"); - this.recordingUtils.checkIndividualRecording(recPath, recording, 3, "opus", "vp8", true); + this.recordingUtils.checkIndividualRecording(recPath, recording, 3, "opus", "vp8", true, 2); // Check audio-only INDIVIDUAL recording recPath = recordingsPath + SESSION_NAME + "~2/"; recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(SESSION_NAME + "~2"); - this.recordingUtils.checkIndividualRecording(recPath, recording, 2, "opus", "vp8", true); + this.recordingUtils.checkIndividualRecording(recPath, recording, 2, "opus", "vp8", true, 2); user.getDriver().findElement(By.id("close-dialog-btn")).click(); Thread.sleep(500); @@ -1945,7 +1945,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { // Check audio-only COMPOSED recording Recording recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(SESSION_NAME); this.recordingUtils.checkMultimediaFile(new File(recordingFilePath), true, false, recording.getDuration(), null, - null, "opus", null, true); + null, "opus", null, true, 2); user.getDriver().findElement(By.id("close-dialog-btn")).click(); Thread.sleep(500); @@ -2970,7 +2970,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { Assertions.assertFalse(OV.fetch(), "OpenVidu.fetch() should return false"); this.recordingUtils.checkIndividualRecording("/opt/openvidu/recordings/" + customSessionId + "/", recording, 2, - "opus", "vp8", false); + "opus", "vp8", false, 2); // Not recorded session try { @@ -3991,7 +3991,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { Assertions.assertTrue(rec.getSize() > 0, "Recording size is 0"); this.recordingUtils.checkIndividualRecording("/opt/openvidu/recordings/TestSession/", rec, 1, "opus", "vp8", - true); + true, 10); user.getDriver().findElement(By.id("remove-all-users-btn")).click(); user.getEventManager().clearAllCurrentEvents(); @@ -4075,7 +4075,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { Assertions.assertTrue(rec.getSize() > 0, "Recording size is 0"); this.recordingUtils.checkIndividualRecording("/opt/openvidu/recordings/TestSession/", rec, 1, "opus", "vp8", - true); + true, 10); OV.fetch(); sessions = OV.getActiveSessions(); @@ -4569,7 +4569,7 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest { CustomWebhook.waitForEvent("recordingStatusChanged", 10); // Ready Recording recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(recId); - this.recordingUtils.checkIndividualRecording(recPath + recId + "/", recording, 1, "opus", "vp8", true); + this.recordingUtils.checkIndividualRecording(recPath + recId + "/", recording, 1, "opus", "vp8", true, 2); // Test IPCAM individual recording (IPCAM video only, recording audio and video)