mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: improve test execution time
parent
d61aca3135
commit
73c3d581bd
|
|
@ -93,6 +93,8 @@ import static org.openqa.selenium.OutputType.BASE64;
|
|||
@ExtendWith(SpringExtension.class)
|
||||
public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
||||
|
||||
private static final long WAIT_UNTIL_MAX_MILLIS = 20000;
|
||||
|
||||
@BeforeAll()
|
||||
protected static void setupAll() throws Exception {
|
||||
checkFfmpegInstallation();
|
||||
|
|
@ -3379,33 +3381,42 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
@Test
|
||||
@DisplayName("SVC VP9 (L3T3_KEY)")
|
||||
void svcVP9L3T3_KEYTest() throws Exception {
|
||||
svcTest("VP9", "L3T3_KEY");
|
||||
svcTest("VP9", "L3T3_KEY", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("SVC AV1 (L3T3_KEY)")
|
||||
void svcAV1L3T3_KEYTest() throws Exception {
|
||||
svcTest("AV1", "L3T3_KEY");
|
||||
svcTest("AV1", "L3T3_KEY", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("SVC VP9 (L2T2)")
|
||||
void svcVP9L2T2Test() throws Exception {
|
||||
svcTest("VP9", "L2T2");
|
||||
svcTest("VP9", "L2T2", false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("SVC AV1 (L2T2)")
|
||||
void svcAV1L2T2Test() throws Exception {
|
||||
svcTest("AV1", "L2T2");
|
||||
svcTest("AV1", "L2T2", false);
|
||||
}
|
||||
|
||||
private void svcTest(String codec, String scalabilityMode) throws Exception {
|
||||
@Test
|
||||
@DisplayName("SVC AV1 (L2T2) with adaptiveStream")
|
||||
void svcAV1L2T2WithAdaptiveStreamTest() throws Exception {
|
||||
svcTest("AV1", "L2T2", true);
|
||||
}
|
||||
|
||||
private void svcTest(String codec, String scalabilityMode, boolean adaptiveStream) throws Exception {
|
||||
final String codecUpperCase = codec.toUpperCase();
|
||||
final long testStart = System.currentTimeMillis();
|
||||
log.info("[SVC] START test: codec={}, scalabilityMode={}, adaptiveStream={}", codec, scalabilityMode,
|
||||
adaptiveStream);
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
this.addOnlyPublisherVideo(user, false, false, true, scalabilityMode);
|
||||
this.forceCodec(user, 0, codec);
|
||||
this.addSubscriber(user, false);
|
||||
this.addSubscriber(user, adaptiveStream);
|
||||
user.getDriver().findElements(By.className("connect-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
|
||||
user.getEventManager().waitUntilEventReaches("localTrackSubscribed", "ParticipantEvent", 1);
|
||||
user.getEventManager().waitUntilEventReaches("trackSubscribed", "ParticipantEvent", 1);
|
||||
|
|
@ -3428,24 +3439,54 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
|
||||
// Validate SVC by dynamically switching subscriber quality and checking
|
||||
// subscriber frameWidth transitions.
|
||||
// With adaptiveStream disabled, quality is switched manually through the
|
||||
// "max-video-quality" selector, which lets HIGH/MEDIUM/LOW be requested
|
||||
// explicitly. With adaptiveStream enabled, that manual selector has no
|
||||
// effect: the spatial layer is instead derived from the rendered size of
|
||||
// the subscriber's video element
|
||||
int spatialLayers = Integer.parseInt(scalabilityMode.substring(1, 2));
|
||||
int highWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
if (spatialLayers >= 3) {
|
||||
if (adaptiveStream) {
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "HIGH");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, highWidth, true);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int bigWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "LOW");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, bigWidth, false);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int smallWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertTrue(bigWidth > smallWidth,
|
||||
"Expected the zoomed-in width to exceed the zoomed-out width, but got big=" + bigWidth
|
||||
+ ", small=" + smallWidth);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "HIGH");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, smallWidth, true);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int finalBigWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertEquals(bigWidth, finalBigWidth,
|
||||
"Expected the zoomed-in width to be restored, but got first=" + bigWidth + ", second="
|
||||
+ finalBigWidth);
|
||||
} else if (spatialLayers >= 3) {
|
||||
// 3 spatial layers (e.g. L3T3_KEY): layers are LOW, MEDIUM, HIGH.
|
||||
// HIGH → MEDIUM → LOW, each a distinct lower resolution.
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "MEDIUM");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, highWidth, false);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int mediumWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "LOW");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, mediumWidth, false);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int lowWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertTrue(highWidth > mediumWidth && mediumWidth > lowWidth,
|
||||
"Expected HIGH > MEDIUM > LOW frame widths, but got HIGH=" + highWidth
|
||||
|
|
@ -3453,17 +3494,16 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "HIGH");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, lowWidth, true);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
} else {
|
||||
// 2 spatial layers (e.g. L2T2): layers are LOW and MEDIUM only.
|
||||
// HIGH and MEDIUM both map to the highest spatial layer (same width).
|
||||
// Only LOW gives a distinct lower resolution.
|
||||
|
||||
// 1. Switch to MEDIUM: should stay at the same width as HIGH
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "MEDIUM");
|
||||
Thread.sleep(4000);
|
||||
int mediumWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertEquals(highWidth, mediumWidth,
|
||||
|
|
@ -3471,11 +3511,12 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
+ highWidth + ", MEDIUM=" + mediumWidth);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
|
||||
// 2. Switch to LOW: should decrease
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-LOW");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "LOW");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, mediumWidth, false);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int lowWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertTrue(highWidth > lowWidth,
|
||||
"Expected HIGH > LOW frame widths, but got HIGH=" + highWidth + ", LOW=" + lowWidth);
|
||||
|
|
@ -3483,23 +3524,48 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
Thread.sleep(300);
|
||||
|
||||
// 3. Switch to MEDIUM: should increase back to highest spatial layer
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-MEDIUM");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "MEDIUM");
|
||||
this.waitUntilSubscriberFrameWidthChanges(user, subscriberVideo, lowWidth, true);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
int mediumWidth2 = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
user.getDriver().findElement(By.cssSelector("#close-dialog-btn")).click();
|
||||
Thread.sleep(300);
|
||||
|
||||
// 4. Switch to HIGH: should stay at the same width as MEDIUM
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-HIGH");
|
||||
this.switchSubscriberSpatialLayer(user, subscriberVideo, adaptiveStream, "HIGH");
|
||||
Thread.sleep(4000);
|
||||
int finalHighWidth = this.getSubscriberVideoFrameWidth(user, subscriberVideo);
|
||||
Assertions.assertEquals(mediumWidth2, finalHighWidth,
|
||||
"With " + spatialLayers + " spatial layers, HIGH should equal MEDIUM width, but got MEDIUM="
|
||||
+ mediumWidth2 + ", HIGH=" + finalHighWidth);
|
||||
this.waitUntilSubscriberFramesDecodedIncrease(user, subscriberVideo);
|
||||
}
|
||||
|
||||
gracefullyLeaveParticipants(user, 2);
|
||||
|
||||
log.info("[SVC] END test: codec={}, scalabilityMode={}, adaptiveStream={}, totalDuration={} ms", codec,
|
||||
scalabilityMode, adaptiveStream, System.currentTimeMillis() - testStart);
|
||||
}
|
||||
|
||||
// With adaptiveStream disabled, the subscriber's preferred quality is
|
||||
// switched manually through the "max-video-quality" selector. With
|
||||
// adaptiveStream enabled, that manual selector is ignored by the client SDK,
|
||||
// which instead derives the desired spatial layer from the rendered size of
|
||||
// the subscriber's video element, always picking the smallest layer that is
|
||||
// sufficient for that size. Only "LOW" (small element) and "HIGH" (large
|
||||
// element) are meaningful in that case.
|
||||
private void switchSubscriberSpatialLayer(OpenViduTestappUser user, WebElement subscriberVideo,
|
||||
boolean adaptiveStream, String quality) {
|
||||
if (adaptiveStream) {
|
||||
if ("LOW".equals(quality)) {
|
||||
changeElementSize(user, subscriberVideo, 80, 100);
|
||||
} else {
|
||||
changeElementSize(user, subscriberVideo, 1000, 700);
|
||||
}
|
||||
} else {
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 #max-video-quality")).click();
|
||||
this.waitForBackdropAndClick(user, "mat-option.mode-" + quality);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -4364,18 +4430,26 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
|
||||
private <T> T getSubscriberVideoLayerStat(OpenViduTestappUser user, WebElement subscriberVideo, String field,
|
||||
java.util.function.Function<JsonElement, T> extractor) {
|
||||
waitUntilVideoLayersNotEmpty(user, subscriberVideo);
|
||||
final java.util.concurrent.atomic.AtomicReference<T> value = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
this.waitUntilAux(user, subscriberVideo, () -> {
|
||||
JsonElement element = getLayersAsJsonArray(user, subscriberVideo).get(0).getAsJsonObject().get(field);
|
||||
if (element != null && !element.isJsonNull()) {
|
||||
value.set(extractor.apply(element));
|
||||
return true;
|
||||
final long deadline = System.currentTimeMillis() + WAIT_UNTIL_MAX_MILLIS;
|
||||
JsonElement element = null;
|
||||
do {
|
||||
try {
|
||||
element = getLayersAsJsonArray(user, subscriberVideo).get(0).getAsJsonObject().get(field);
|
||||
} catch (Exception e) {
|
||||
element = null;
|
||||
}
|
||||
return false;
|
||||
}, "Timeout waiting for " + field + " to exist");
|
||||
openInfoDialog(user, subscriberVideo);
|
||||
return value.get();
|
||||
if (element == null || element.isJsonNull()) {
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
} while ((element == null || element.isJsonNull()) && System.currentTimeMillis() < deadline);
|
||||
if (element == null || element.isJsonNull()) {
|
||||
Assertions.fail("Timeout waiting for " + field + " to exist");
|
||||
}
|
||||
return extractor.apply(element);
|
||||
}
|
||||
|
||||
// If rid is null, retrieve the first layer
|
||||
|
|
@ -4406,10 +4480,10 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
}
|
||||
|
||||
private void waitUntilVideoLayersNotEmpty(OpenViduTestappUser user, WebElement videoElement) {
|
||||
this.waitUntilAux(user, videoElement,
|
||||
() -> !getLayersAsString(user, videoElement).isBlank()
|
||||
&& !getLayersAsJsonArray(user, videoElement).isEmpty(),
|
||||
"Timeout waiting video layers to not be empty");
|
||||
this.waitUntilAux(user, videoElement, () -> {
|
||||
String value = getLayersAsString(user, videoElement);
|
||||
return !value.isBlank() && !JsonParser.parseString(value).getAsJsonArray().isEmpty();
|
||||
}, "Timeout waiting video layers to not be empty");
|
||||
}
|
||||
|
||||
private void waitUntilSubscriberFramesPerSecondNotZero(OpenViduTestappUser user, WebElement videoElement) {
|
||||
|
|
@ -4502,13 +4576,10 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
private void waitUntilAux(OpenViduTestappUser user, WebElement videoElement,
|
||||
Callable<Boolean> breakFromLoopFunction, String errMsg) {
|
||||
try {
|
||||
final int maxWaitMillis = 6000;
|
||||
final int intervalWait = 250;
|
||||
final int MAX_ITERATIONS = maxWaitMillis / intervalWait;
|
||||
int iteration = 0;
|
||||
final long intervalWait = 250;
|
||||
final long deadline = System.currentTimeMillis() + WAIT_UNTIL_MAX_MILLIS;
|
||||
boolean breakFromLoop = false;
|
||||
while (!breakFromLoop && iteration < MAX_ITERATIONS) {
|
||||
iteration++;
|
||||
while (!breakFromLoop && System.currentTimeMillis() < deadline) {
|
||||
try {
|
||||
breakFromLoop = breakFromLoopFunction.call();
|
||||
} catch (Exception e1) {
|
||||
|
|
@ -4543,23 +4614,30 @@ public class OpenViduTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
private void openInfoDialog(OpenViduTestappUser user, WebElement video) {
|
||||
String videoId = video.getDomProperty("id");
|
||||
// Open the track info dialog if required
|
||||
boolean dialogWasOpened;
|
||||
if (!user.getDriver().findElements(By.cssSelector("app-info-dialog")).isEmpty()) {
|
||||
// Dialog already opened
|
||||
if (!user.getDriver().findElement(By.cssSelector("#subtitle")).getText().equals(videoId)) {
|
||||
// Wrong dialog
|
||||
this.waitForBackdropAndClick(user, "#close-dialog-btn");
|
||||
this.waitForBackdropAndClick(user, "#" + videoId + " ~ .bottom-div .video-track-info");
|
||||
dialogWasOpened = true;
|
||||
} else {
|
||||
dialogWasOpened = false;
|
||||
}
|
||||
} else {
|
||||
// Dialog is not opened
|
||||
this.waitForBackdropAndClick(user, "#" + videoId + " ~ .bottom-div .video-track-info");
|
||||
dialogWasOpened = true;
|
||||
}
|
||||
if (dialogWasOpened) {
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPublisherSubscriber(OpenViduTestappUser user, boolean hasAudio, boolean hasVideo)
|
||||
throws InterruptedException {
|
||||
|
|
|
|||
Loading…
Reference in New Issue