mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: React Native and native Android tests
parent
83057362bd
commit
2b2c2c8d01
|
@ -193,7 +193,7 @@ public class OpenViduTestE2e {
|
||||||
private static GenericContainer<?> androidContainer(String image, long shmSize) {
|
private static GenericContainer<?> androidContainer(String image, long shmSize) {
|
||||||
GenericContainer<?> android = new GenericContainer<>(DockerImageName.parse(image)).withPrivilegedMode(true)
|
GenericContainer<?> android = new GenericContainer<>(DockerImageName.parse(image)).withPrivilegedMode(true)
|
||||||
.withEnv(Map.of("DEVICE", "Samsung Galaxy S10", "APPIUM", "true", "APPIUM_HOST", "172.17.0.1",
|
.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)
|
.withSharedMemorySize(shmSize).withExposedPorts(6080, 5554, 5555, 4723).waitingFor(waitAndroid)
|
||||||
.withFileSystemBind("/opt/openvidu/android", "/opt/openvidu/android").withReuse(true);
|
.withFileSystemBind("/opt/openvidu/android", "/opt/openvidu/android").withReuse(true);
|
||||||
android.setPortBindings(Arrays.asList("6080:6080", "5554:5554", "5555:5555", "4723:4723"));
|
android.setPortBindings(Arrays.asList("6080:6080", "5554:5554", "5555:5555", "4723:4723"));
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
package io.openvidu.test.e2e;
|
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.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
@ -11,15 +20,17 @@ import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openqa.selenium.By;
|
import org.openqa.selenium.By;
|
||||||
import org.openqa.selenium.Keys;
|
import org.openqa.selenium.Keys;
|
||||||
|
import org.openqa.selenium.OutputType;
|
||||||
|
import org.openqa.selenium.WebDriver;
|
||||||
import org.openqa.selenium.WebElement;
|
import org.openqa.selenium.WebElement;
|
||||||
import org.openqa.selenium.support.ui.ExpectedConditions;
|
import org.openqa.selenium.support.ui.ExpectedConditions;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
|
||||||
|
import io.appium.java_client.AppiumBy;
|
||||||
import io.appium.java_client.AppiumDriver;
|
import io.appium.java_client.AppiumDriver;
|
||||||
import io.appium.java_client.remote.SupportsContextSwitching;
|
import io.appium.java_client.remote.SupportsContextSwitching;
|
||||||
import io.openvidu.test.browsers.BrowserUser;
|
import io.openvidu.test.browsers.BrowserUser;
|
||||||
import io.openvidu.test.browsers.utils.CustomHttpClient;
|
import io.openvidu.test.browsers.utils.CustomHttpClient;
|
||||||
import io.openvidu.test.browsers.utils.RecordingUtils;
|
|
||||||
|
|
||||||
public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
|
public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
|
||||||
|
|
||||||
|
@ -160,7 +171,226 @@ public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
|
||||||
// Check Ionic is properly receiving remote video from Chrome
|
// Check Ionic is properly receiving remote video from Chrome
|
||||||
WebElement subscriberVideo = ionicUser.getDriver().findElements(By.cssSelector("video")).get(1);
|
WebElement subscriberVideo = ionicUser.getDriver().findElements(By.cssSelector("video")).get(1);
|
||||||
Map<String, Long> rgb = ionicUser.getAverageRgbFromVideo(subscriberVideo);
|
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);
|
gracefullyLeaveParticipants(chromeUser, 1);
|
||||||
|
|
||||||
|
@ -179,20 +409,37 @@ public class OpenViduMobileE2eTest extends AbstractOpenViduTestappE2eTest {
|
||||||
HttpStatus.SC_OK);
|
HttpStatus.SC_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
private Map<String, Long> getAverageColorOfElement(WebDriver driver, By locator) throws IOException {
|
||||||
// @DisplayName("React Native Android")
|
// TODO: change getScreenshotAs(OutputType.BASE64) to
|
||||||
// void reactNativeAndroid() throws Exception {
|
// getScreenshotAs(OutputType.BYTES) when
|
||||||
// long initTime = System.currentTimeMillis();
|
// https://github.com/appium/java-client/issues/1783 is fixed
|
||||||
// BrowserUser reactNativeUser = setupBrowser("reactNativeApp");
|
String base64 = driver.findElement(locator).getScreenshotAs(OutputType.BASE64);
|
||||||
//
|
System.out.println(base64);
|
||||||
// }
|
base64 = base64.replaceAll("[\n\r]", "");
|
||||||
//
|
byte[] bytes = Base64.getDecoder().decode(base64);
|
||||||
// @Test
|
InputStream is = new ByteArrayInputStream(bytes);
|
||||||
// @DisplayName("Native Android")
|
BufferedImage bi = ImageIO.read(is);
|
||||||
// void nativeAndroid() throws Exception {
|
return averageColor(bi);
|
||||||
// long initTime = System.currentTimeMillis();
|
}
|
||||||
// BrowserUser reactNativeUser = setupBrowser("androidApp");
|
|
||||||
//
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue