openvidu-test-e2e: React Native and native Android tests

pull/786/head
pabloFuente 2023-01-09 16:58:37 +01:00
parent 83057362bd
commit 2b2c2c8d01
2 changed files with 265 additions and 18 deletions

View File

@ -193,7 +193,7 @@ public class OpenViduTestE2e {
private static GenericContainer<?> androidContainer(String image, long shmSize) {
GenericContainer<?> android = new GenericContainer<>(DockerImageName.parse(image)).withPrivilegedMode(true)
.withEnv(Map.of("DEVICE", "Samsung Galaxy S10", "APPIUM", "true", "APPIUM_HOST", "172.17.0.1",
"APPIUM_PORT", "4723", "MOBILE_WEB_TEST", "true", "RELAXED_SECURITY", "true"))
"APPIUM_PORT", "4723", "MOBILE_WEB_TEST", "true", "RELAXED_SECURITY", "true", "DATAPARTITION", "2500m"))
.withSharedMemorySize(shmSize).withExposedPorts(6080, 5554, 5555, 4723).waitingFor(waitAndroid)
.withFileSystemBind("/opt/openvidu/android", "/opt/openvidu/android").withReuse(true);
android.setPortBindings(Arrays.asList("6080:6080", "5554:5554", "5555:5555", "4723:4723"));

View File

@ -1,8 +1,17 @@
package io.openvidu.test.e2e;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.imageio.ImageIO;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Assertions;
@ -11,15 +20,17 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.springframework.http.HttpMethod;
import io.appium.java_client.AppiumBy;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.remote.SupportsContextSwitching;
import io.openvidu.test.browsers.BrowserUser;
import io.openvidu.test.browsers.utils.CustomHttpClient;
import io.openvidu.test.browsers.utils.RecordingUtils;
public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
@ -160,7 +171,226 @@ public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
// Check Ionic is properly receiving remote video from Chrome
WebElement subscriberVideo = ionicUser.getDriver().findElements(By.cssSelector("video")).get(1);
Map<String, Long> rgb = ionicUser.getAverageRgbFromVideo(subscriberVideo);
Assertions.assertTrue(RecordingUtils.checkVideoAverageRgbGreen(rgb), "Video is not average green");
Assertions.assertTrue(checkAverageRgbGreen(rgb), "Video is not average green");
gracefullyLeaveParticipants(chromeUser, 1);
} finally {
if (chromeUser != null) {
chromeUser.dispose();
}
}
}
/**
* By default this application is prepared to run against
* https://demos.openvidu.io
*/
@Test
@DisplayName("React Native Android")
void reactNativeAndroid() throws Exception {
isAndroidTest = true;
long initTime = System.currentTimeMillis();
BrowserUser reactNativeUser = setupBrowser("reactNativeApp");
log.info("Android emulator ready after {} seconds", (System.currentTimeMillis() - initTime) / 1000);
log.info("React Native Android");
AppiumDriver appiumDriver = (AppiumDriver) reactNativeUser.getDriver();
Set<String> contextNames = ((SupportsContextSwitching) appiumDriver).getContextHandles();
log.info("Appium contexts:");
for (String contextName : contextNames) {
log.info(contextName);
}
for (String context : contextNames) {
if (context.equals("NATIVE_APP")) {
log.info("Webview context name chosen is " + context);
((SupportsContextSwitching) appiumDriver).context("NATIVE_APP");
break;
}
}
final String SESSION_NAME = "ReactNativeTestSession";
reactNativeUser.getWaiter()
.until(ExpectedConditions.elementToBeClickable(AppiumBy.className("android.widget.EditText")));
WebElement sessionNameInput = appiumDriver.findElement(AppiumBy.className("android.widget.EditText"));
sessionNameInput.clear();
sessionNameInput.sendKeys(SESSION_NAME);
List<WebElement> buttons = appiumDriver.findElements(By.className("android.widget.Button"));
WebElement joinAsPublisherButton = buttons.get(0);
joinAsPublisherButton.click();
OpenViduTestappUser chromeUser = null;
try {
chromeUser = setupBrowserAndConnectToOpenViduTestapp("chrome");
WebElement urlInput = chromeUser.getDriver().findElement(By.id("openvidu-url"));
urlInput.clear();
urlInput.sendKeys(OPENVIDU_DEPLOYMENT);
chromeUser.getDriver().findElement(By.id("add-user-btn")).click();
chromeUser.getDriver().findElement(By.id("session-settings-btn-0")).click();
Thread.sleep(1000);
WebElement tokenInput = chromeUser.getDriver().findElement(By.cssSelector("#custom-token-div input"));
tokenInput.clear();
tokenInput.sendKeys(getToken(SESSION_NAME));
chromeUser.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(1000);
chromeUser.getDriver().findElement(By.className("join-btn")).click();
chromeUser.getEventManager().waitUntilEventReaches("connectionCreated", 2);
chromeUser.getEventManager().waitUntilEventReaches("accessAllowed", 1);
chromeUser.getEventManager().waitUntilEventReaches("streamCreated", 2);
chromeUser.getEventManager().waitUntilEventReaches("streamPlaying", 2);
final int numberOfVideos = chromeUser.getDriver().findElements(By.tagName("video")).size();
Assertions.assertEquals(2, numberOfVideos, "Wrong number of videos");
Assertions.assertTrue(
chromeUser.getBrowserUser()
.assertMediaTracks(chromeUser.getDriver().findElements(By.tagName("video")), true, true),
"Videos were expected to have audio and video tracks");
// Wait for Android app to have 2 video views
// Publisher view
By localVideoLocator = AppiumBy.xpath(
"//*/android.widget.ScrollView/android.view.ViewGroup/android.view.ViewGroup[1]/android.view.View");
reactNativeUser.getWaiter()
.until(ExpectedConditions.elementToBeClickable(appiumDriver.findElement(localVideoLocator)));
// Subscriber view
By remoteVideoLocator = AppiumBy.xpath(
"//*/android.widget.ScrollView/android.view.ViewGroup/android.view.ViewGroup[2]/android.view.View");
reactNativeUser.getWaiter()
.until(ExpectedConditions.elementToBeClickable(appiumDriver.findElement(remoteVideoLocator)));
// Check subscriber video is green
Map<String, Long> rgb = getAverageColorOfElement(appiumDriver, remoteVideoLocator);
Assertions.assertTrue(checkAverageRgbGreen(rgb), "Remote video is not average green");
buttons = appiumDriver.findElements(By.className("android.widget.Button"));
WebElement muteMicBtn = buttons.get(1);
WebElement muteCamBtn = buttons.get(3);
WebElement leaveBtn = buttons.get(4);
muteMicBtn.click();
chromeUser.getEventManager().waitUntilEventReaches("streamPropertyChanged", 1);
muteMicBtn.click();
chromeUser.getEventManager().waitUntilEventReaches("streamPropertyChanged", 2);
muteCamBtn.click();
chromeUser.getEventManager().waitUntilEventReaches("streamPropertyChanged", 3);
muteCamBtn.click();
chromeUser.getEventManager().waitUntilEventReaches("streamPropertyChanged", 4);
leaveBtn.click();
reactNativeUser.getWaiter().until(
ExpectedConditions.visibilityOfElementLocated(AppiumBy.className("android.widget.EditText")));
Assertions.assertTrue(appiumDriver.findElement(AppiumBy.className("android.widget.EditText")).isEnabled());
chromeUser.getEventManager().waitUntilEventReaches("streamDestroyed", 1);
chromeUser.getEventManager().waitUntilEventReaches("connectionDestroyed", 1);
gracefullyLeaveParticipants(chromeUser, 1);
} finally {
if (chromeUser != null) {
chromeUser.dispose();
}
}
}
@Test
@DisplayName("Native Android")
void nativeAndroid() throws Exception {
isAndroidTest = true;
long initTime = System.currentTimeMillis();
BrowserUser androidUser = setupBrowser("androidApp");
log.info("Android emulator ready after {} seconds", (System.currentTimeMillis() - initTime) / 1000);
log.info("Native Android");
AppiumDriver appiumDriver = (AppiumDriver) androidUser.getDriver();
Set<String> contextNames = ((SupportsContextSwitching) appiumDriver).getContextHandles();
log.info("Appium contexts:");
for (String contextName : contextNames) {
log.info(contextName);
}
for (String context : contextNames) {
if (context.equals("NATIVE_APP")) {
log.info("Webview context name chosen is " + context);
((SupportsContextSwitching) appiumDriver).context("NATIVE_APP");
break;
}
}
final String SESSION_NAME = "NativeAndroidTestSession";
final String USER_NAME = "NativeAndroidUser";
androidUser.getWaiter().until(ExpectedConditions.elementToBeClickable(By.id("start_finish_call")));
WebElement urlInput = appiumDriver.findElement(By.id("application_server_url"));
WebElement sessionNameInput = appiumDriver.findElement(By.id("session_name"));
WebElement userNameInput = appiumDriver.findElement(By.id("participant_name"));
urlInput.clear();
sessionNameInput.clear();
userNameInput.clear();
urlInput.sendKeys(OPENVIDU_DEPLOYMENT);
sessionNameInput.sendKeys(SESSION_NAME);
userNameInput.sendKeys(USER_NAME);
appiumDriver.findElement(By.id("start_finish_call")).click();
OpenViduTestappUser chromeUser = null;
try {
chromeUser = setupBrowserAndConnectToOpenViduTestapp("chrome");
urlInput = chromeUser.getDriver().findElement(By.id("openvidu-url"));
urlInput.clear();
urlInput.sendKeys(OPENVIDU_DEPLOYMENT);
chromeUser.getDriver().findElement(By.id("add-user-btn")).click();
chromeUser.getDriver().findElement(By.id("session-settings-btn-0")).click();
Thread.sleep(1000);
WebElement tokenInput = chromeUser.getDriver().findElement(By.cssSelector("#custom-token-div input"));
tokenInput.clear();
tokenInput.sendKeys(getToken(SESSION_NAME));
chromeUser.getDriver().findElement(By.id("save-btn")).click();
Thread.sleep(1000);
chromeUser.getDriver().findElement(By.className("join-btn")).click();
chromeUser.getEventManager().waitUntilEventReaches("connectionCreated", 2);
chromeUser.getEventManager().waitUntilEventReaches("accessAllowed", 1);
chromeUser.getEventManager().waitUntilEventReaches("streamCreated", 2);
chromeUser.getEventManager().waitUntilEventReaches("streamPlaying", 2);
final int numberOfVideos = chromeUser.getDriver().findElements(By.tagName("video")).size();
Assertions.assertEquals(2, numberOfVideos, "Wrong number of videos");
Assertions.assertTrue(
chromeUser.getBrowserUser()
.assertMediaTracks(chromeUser.getDriver().findElements(By.tagName("video")), true, true),
"Videos were expected to have audio and video tracks");
// Wait for Android app to have 2 video views
// Publisher view
By localVideoLocator = AppiumBy.xpath(
"//*/android.widget.ScrollView/android.widget.LinearLayout/android.widget.FrameLayout[1]/android.view.View");
androidUser.getWaiter()
.until(ExpectedConditions.elementToBeClickable(appiumDriver.findElement(localVideoLocator)));
// Subscriber view
By remoteVideoLocator = AppiumBy.xpath(
"//*/android.widget.ScrollView/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.view.View");
androidUser.getWaiter()
.until(ExpectedConditions.elementToBeClickable(appiumDriver.findElement(remoteVideoLocator)));
// Check subscriber video is green
Map<String, Long> rgb = getAverageColorOfElement(appiumDriver, remoteVideoLocator);
Assertions.assertTrue(checkAverageRgbGreen(rgb), "Remote video is not average green");
appiumDriver.findElement(By.id("start_finish_call")).click();
androidUser.getWaiter().until(
ExpectedConditions.elementToBeClickable(appiumDriver.findElement(By.id("application_server_url"))));
Assertions.assertTrue(appiumDriver.findElement(By.id("application_server_url")).isEnabled());
chromeUser.getEventManager().waitUntilEventReaches("streamDestroyed", 1);
chromeUser.getEventManager().waitUntilEventReaches("connectionDestroyed", 1);
gracefullyLeaveParticipants(chromeUser, 1);
@ -179,20 +409,37 @@ public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
HttpStatus.SC_OK);
}
// @Test
// @DisplayName("React Native Android")
// void reactNativeAndroid() throws Exception {
// long initTime = System.currentTimeMillis();
// BrowserUser reactNativeUser = setupBrowser("reactNativeApp");
//
// }
//
// @Test
// @DisplayName("Native Android")
// void nativeAndroid() throws Exception {
// long initTime = System.currentTimeMillis();
// BrowserUser reactNativeUser = setupBrowser("androidApp");
//
// }
private Map<String, Long> getAverageColorOfElement(WebDriver driver, By locator) throws IOException {
// TODO: change getScreenshotAs(OutputType.BASE64) to
// getScreenshotAs(OutputType.BYTES) when
// https://github.com/appium/java-client/issues/1783 is fixed
String base64 = driver.findElement(locator).getScreenshotAs(OutputType.BASE64);
System.out.println(base64);
base64 = base64.replaceAll("[\n\r]", "");
byte[] bytes = Base64.getDecoder().decode(base64);
InputStream is = new ByteArrayInputStream(bytes);
BufferedImage bi = ImageIO.read(is);
return averageColor(bi);
}
private Map<String, Long> averageColor(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
long sumr = 0, sumg = 0, sumb = 0;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Color pixel = new Color(image.getRGB(x, y));
sumr += pixel.getRed();
sumg += pixel.getGreen();
sumb += pixel.getBlue();
}
}
int numPixels = width * height;
return Map.of("r", (sumr / numPixels), "g", (sumg / numPixels), "b", (sumb / numPixels));
}
private boolean checkAverageRgbGreen(Map<String, Long> rgb) {
return (rgb.get("r") < 30) && (rgb.get("g") > 120) && (rgb.get("b") < 30);
}
}