org.kurento.test.browser.WebPage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kurento-test Show documentation
Show all versions of kurento-test Show documentation
This project contains test cases for testing Kurento
Java Client and Kurento Media Server.
/*
* (C) Copyright 2015 Kurento (http://kurento.org/)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.kurento.test.browser;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.kurento.test.grid.GridHandler;
import org.kurento.test.latency.LatencyException;
import org.kurento.test.latency.VideoTag;
import org.kurento.test.monitor.PeerConnectionStats;
import org.kurento.test.monitor.SystemMonitorManager;
import org.kurento.test.utils.Ffmpeg;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Generic web page for tests using Kurento test infrastructure.
*
* @author Boni Garcia ([email protected])
* @since 5.1.0
*/
public class WebPage {
public static Logger log = LoggerFactory.getLogger(WebPage.class);
private Map countDownLatchEvents = new HashMap<>();
private List callbackThreads = new ArrayList<>();
public Browser browser;
public Browser getBrowser() {
return browser;
}
public void setBrowser(Browser browser) {
this.browser = browser;
}
public void takeScreeshot(String file) throws IOException {
File scrFile = ((TakesScreenshot) getBrowser().getWebDriver()).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(scrFile, new File(file));
}
/*
* setThresholdTime
*/
public void setThresholdTime(int thresholdTime) {
browser.setThresholdTime(thresholdTime);
}
/*
* setColorCoordinates
*/
public void setColorCoordinates(int x, int y) {
browser.executeScript("kurentoTest.setColorCoordinates(" + x + "," + y + ");");
}
/*
* checkColor
*/
public void checkColor(String... videoTags) {
String tags = "";
for (String s : videoTags) {
if (!tags.isEmpty()) {
tags += ",";
}
tags += "'" + s + "'";
}
browser.executeScript("kurentoTest.checkColor(" + tags + ");");
}
/*
* similarColorAt
*/
public boolean similarColorAt(String videoTag, Color expectedColor, int x, int y) {
setColorCoordinates(x, y);
return similarColor(videoTag, expectedColor);
}
/*
* similarColor
*/
public boolean similarColor(String videoTag, Color expectedColor) {
boolean out;
final long endTimeMillis = System.currentTimeMillis() + browser.getTimeout() * 1000;
boolean logWarn = true;
while (true) {
out = compareColor(videoTag, expectedColor, logWarn);
if (out || System.currentTimeMillis() > endTimeMillis) {
break;
} else {
// Polling: wait 200 ms and check again the color
// Max wait = timeout variable
try {
Thread.sleep(200);
} catch (InterruptedException e) {
log.trace("InterruptedException in guard condition ({})", e.getMessage());
}
}
logWarn = false;
}
return out;
}
/*
* compareColor
*/
public boolean compareColor(String videoTag, Color expectedColor, boolean logWarn) {
@SuppressWarnings("unchecked")
List realColor = (List) browser.executeScriptAndWaitOutput(
"return kurentoTest.colorInfo['" + videoTag + "'].currentColor;");
long red = realColor.get(0);
long green = realColor.get(1);
long blue = realColor.get(2);
double distance = Math.sqrt((red - expectedColor.getRed()) * (red - expectedColor.getRed())
+ (green - expectedColor.getGreen()) * (green - expectedColor.getGreen())
+ (blue - expectedColor.getBlue()) * (blue - expectedColor.getBlue()));
String expectedColorStr = "[R=" + expectedColor.getRed() + ", G=" + expectedColor.getGreen()
+ ", B=" + expectedColor.getBlue() + "]";
String realColorStr = "[R=" + red + ", G=" + green + ", B=" + blue + "]";
boolean out = distance <= browser.getColorDistance();
if (!out) {
if (logWarn) {
log.warn("Color NOT detected in video stream. Expected: {}, Real: {}", expectedColorStr,
realColorStr);
}
} else {
log.debug("Detected color in video stream. Expected: {}, Real: {}", expectedColorStr,
realColorStr);
}
return out;
}
/*
* activatePeerConnectionInboundStats
*/
public void activatePeerConnectionInboundStats(String peerConnectionId) {
activatePeerConnectionStats("activateInboundRtcStats", peerConnectionId);
}
/*
* activatePeerConnectionOutboundStats
*/
public void activatePeerConnectionOutboundStats(String peerConnectionId) {
activatePeerConnectionStats("activateOutboundRtcStats", peerConnectionId);
}
private void activatePeerConnectionStats(String jsFunction, String peerConnectionId) {
try {
browser.executeScript("kurentoTest." + jsFunction + "('" + peerConnectionId + "');");
} catch (WebDriverException we) {
we.printStackTrace();
// If client is not ready to gather rtc statistics, we just log it
// as warning (it is not an error itself)
log.warn("Client does not support RTC statistics (function kurentoTest.{}() not defined)",
jsFunction);
}
}
/**
*
* @param peerConnectionId
*/
public void stopPeerConnectionInboundStats(String peerConnectionId) {
stopPeerConnectionStats("stopInboundRtcStats", peerConnectionId);
}
/**
*
* @param peerConnectionId
*/
public void stopPeerConnectionOutboundStats(String peerConnectionId) {
stopPeerConnectionStats("stopOutboundRtcStats", peerConnectionId);
}
private void stopPeerConnectionStats(String jsFunction, String peerConnectionId) {
try {
log.debug("kurentoTest." + jsFunction + "('" + peerConnectionId + "');");
browser.executeScript("kurentoTest." + jsFunction + "('" + peerConnectionId + "');");
} catch (WebDriverException we) {
we.printStackTrace();
// If client is not ready to gather rtc statistics, we just log it
// as warning (it is not an error itself)
log.warn("Client does not support RTC statistics (function kurentoTest.{}() not defined)");
}
}
/*
* getLatency
*/
@SuppressWarnings("deprecation")
public long getLatency() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final long[] out = new long[1];
Thread t = new Thread() {
@Override
public void run() {
Object latency = browser.executeScript("return kurentoTest.getLatency();");
if (latency != null) {
out[0] = (Long) latency;
} else {
out[0] = Long.MIN_VALUE;
}
latch.countDown();
}
};
t.start();
if (!latch.await(browser.getTimeout(), TimeUnit.SECONDS)) {
t.interrupt();
t.stop();
throw new LatencyException("Timeout getting latency (" + browser.getTimeout() + " seconds)");
}
return out[0];
}
public void waitColor(long timeoutSeconds, final VideoTag videoTag, final Color color) {
WebDriverWait wait = new WebDriverWait(browser.getWebDriver(), timeoutSeconds);
wait.until(new ExpectedCondition() {
@Override
public Boolean apply(WebDriver d) {
return !((JavascriptExecutor) d).executeScript(videoTag.getColor()).equals(color);
}
});
}
/*
* getCurrentTime
*/
public long getCurrentTime(VideoTag videoTag) {
Object time = browser.executeScript(videoTag.getTime());
return time == null ? 0 : (Long) time;
}
/*
* getCurrentColor
*/
@SuppressWarnings("unchecked")
public Color getCurrentColor(VideoTag videoTag) {
return getColor((List) browser.executeScript(videoTag.getColor()));
}
private Color getColor(List color) {
return new Color(color.get(0).intValue(), color.get(1).intValue(), color.get(2).intValue());
}
/*
* checkLatencyUntil
*/
public void checkLatencyUntil(SystemMonitorManager monitor, long endTimeMillis)
throws InterruptedException, IOException {
while (true) {
if (System.currentTimeMillis() > endTimeMillis) {
break;
}
Thread.sleep(100);
try {
long latency = getLatency();
if (latency != Long.MIN_VALUE) {
monitor.addCurrentLatency(latency);
}
} catch (LatencyException le) {
monitor.incrementLatencyErrors();
}
}
}
/*
* getRtcStats
*/
@SuppressWarnings("unchecked")
public PeerConnectionStats getRtcStats() {
Map out = new HashMap<>();
try {
if (browser != null && browser.getWebDriver() != null) {
out = (Map) browser.executeScript("return kurentoTest.rtcStats;");
log.debug(">>>>>>>>>> kurentoTest.rtcStats {} {}", browser.getId(), out);
}
} catch (WebDriverException we) {
// If client is not ready to gather rtc statistics, we just log it
// as warning (it is not an error itself)
log.warn("Client does not support RTC statistics" + " (variable rtcStats is not defined)");
}
return new PeerConnectionStats(out);
}
/*
* activateLatencyControl
*/
public void activateLatencyControl(String localId, String remoteId) {
browser.executeScript(
"kurentoTest.activateLatencyControl('" + localId + "', '" + remoteId + "');");
}
/*
* getTimeout
*/
public int getTimeout() {
return browser.getTimeout();
}
/*
* setTimeout
*/
public void setTimeout(int timeoutSeconds) {
browser.changeTimeout(timeoutSeconds);
}
/*
* getThresholdTime
*/
public int getThresholdTime() {
return browser.getThresholdTime();
}
/*
* equalDataChannelMessage
*/
public boolean compareDataChannelMessage(String message) {
boolean out;
final long endTimeMillis = System.currentTimeMillis() + browser.getTimeout() * 1000;
while (true) {
String messageReceived = (String) browser
.executeScript("return kurentoTest.getDataChannelMessage()");
out = (message.equals(messageReceived));
if (out || System.currentTimeMillis() > endTimeMillis) {
break;
} else {
// Polling: wait 200 ms and check again the color
// Max wait = timeout variable
try {
Thread.sleep(200);
} catch (InterruptedException e) {
log.trace("InterruptedException in guard condition ({})", e.getMessage());
}
}
}
return out;
}
/*
* syncTimeForOcr
*/
public void syncTimeForOcr(String videoTagId, String peerConnectionId) {
browser.executeScript(
"kurentoTest.syncTimeForOcr('" + videoTagId + "', '" + peerConnectionId + "');");
log.debug("Sync time in {} {}", browser.getId(), videoTagId);
WebDriverWait wait = new WebDriverWait(browser.getWebDriver(), browser.getTimeout());
wait.until(new ExpectedCondition() {
@Override
public Boolean apply(WebDriver d) {
return (Boolean) ((JavascriptExecutor) d).executeScript("return kurentoTest.sync;");
}
});
log.debug("[Done] Sync time in {} {}", browser.getId(), videoTagId);
}
/*
* startOcr
*/
public void startOcr() {
browser.executeScript("kurentoTest.startOcr();");
}
/*
* endOcr
*/
public void endOcr() {
browser.executeScript("kurentoTest.endOcr();");
}
/*
* getOcrMap
*/
@SuppressWarnings("unchecked")
public Map> getOcrMap() {
Map> ocrMap = (Map>) browser
.executeScript("return kurentoTest.ocrMap;");
// Transform data structure to serializable (because
// com.google.common.collect.Maps$TransformedEntriesMap is not)
Map> serializableMap = new TreeMap>();
for (String key : ocrMap.keySet()) {
serializableMap.put(key, new HashMap(ocrMap.get(key)));
}
return serializableMap;
}
public void startRecording(String stream) {
browser.executeScript("kurentoTest.startRecording(" + stream + ");");
}
public void stopRecording() {
browser.executeScript("kurentoTest.stopRecording();");
getProperty("recordRTC");
}
public File saveRecordingToDisk(String fileName, String downloadsFolder) {
browser.executeScript("kurentoTest.saveRecordingToDisk('" + fileName + "');");
File output = new File(downloadsFolder + fileName);
do {
if (!output.exists()) {
try {
Thread.sleep(500); // polling
} catch (InterruptedException e) {
log.warn("Exception waiting for file {}", output, e);
}
} else {
break;
}
} while (true);
return output;
}
public void openRecordingInNewTab() {
browser.executeScript("kurentoTest.openRecordingInNewTab();");
}
public File getRecording() throws IOException {
File tmpFile = File.createTempFile(String.valueOf(System.nanoTime()), ".webm");
return getRecording(tmpFile.getAbsolutePath());
}
public File getRecording(String fileName) throws IOException {
browser.executeScript("kurentoTest.recordingToData();");
String recording = getProperty("recordingData").toString();
// Base64 to File
File outputFile = new File(fileName);
byte[] bytes = Base64.decodeBase64(recording.substring(recording.lastIndexOf(",") + 1));
FileUtils.writeByteArrayToFile(outputFile, bytes);
return outputFile;
}
private Object getProperty(String property) {
Object value = null;
final int pollTimeMs = 200;
for (int i = 0; i < 60; i++) {
value = browser.executeScript("return kurentoTest." + property + ";");
if (value != null) {
break;
} else {
try {
log.debug("{} not present still... waiting {} ms", property, pollTimeMs);
Thread.sleep(pollTimeMs);
} catch (InterruptedException e) {
log.warn("Exception wait polling whil getting {}", property, e);
}
}
}
String clazz = value != null ? value.getClass().getName() : "";
log.trace(">>> getProperty {} {} {}", property, value, clazz);
return value;
}
public void subscribeEvent(final String videoTag, final String eventType) {
subscribeEventsToVideoTag("document.getElementById('" + videoTag + "')", eventType);
}
/*
* subscribeEventsToVideoTag
*/
protected void subscribeEventsToVideoTag(final String videoTag, final String eventType) {
CountDownLatch latch = new CountDownLatch(1);
final String browserName = browser.getId();
log.debug("Subscribe event '{}' in browser '{}'", eventType, browserName);
countDownLatchEvents.put(browserName + eventType, latch);
addEventListener(videoTag, eventType, new BrowserEventListener() {
@Override
public void onEvent(String event) {
consoleLog(ConsoleLogLevel.INFO, "Event in " + videoTag + " tag: " + event);
countDownLatchEvents.get(browserName + eventType).countDown();
}
});
}
/*
* waitForEvent
*/
public boolean waitForEvent(final String eventType) throws InterruptedException {
String browserName = browser.getId();
log.debug("Waiting for event '{}' in browser '{}'", eventType, browserName);
if (!countDownLatchEvents.containsKey(browserName + eventType)) {
log.error("We cannot wait for an event without previous subscription");
return false;
}
boolean result = countDownLatchEvents.get(browserName + eventType).await(browser.getTimeout(),
TimeUnit.SECONDS);
// Record local audio when playing event reaches the browser
if (eventType.equalsIgnoreCase("playing") && browser.getRecordAudio() > 0) {
if (browser.isRemote()) {
Ffmpeg.recordRemote(GridHandler.getInstance().getNode(browser.getId()),
browser.getRecordAudio(), browser.getAudioSampleRate(), browser.getAudioChannel());
} else {
Ffmpeg.record(browser.getRecordAudio(), browser.getAudioSampleRate(),
browser.getAudioChannel());
}
}
countDownLatchEvents.remove(browserName + eventType);
return result;
}
/*
* addEventListener
*/
@SuppressWarnings("deprecation")
public void addEventListener(final String videoTag, final String eventType,
final BrowserEventListener eventListener) {
Thread t = new Thread() {
@Override
public void run() {
browser.executeScript(
videoTag + ".addEventListener('" + eventType + "', kurentoTest.videoEvent, false);");
try {
new WebDriverWait(browser.getWebDriver(), browser.getTimeout())
.until(new ExpectedCondition() {
@Override
public Boolean apply(WebDriver d) {
Object videoEventValue = ((JavascriptExecutor) d)
.executeScript("return kurentoTest.videoEventValue;");
return videoEventValue != null
&& videoEventValue.toString().equalsIgnoreCase(eventType);
}
});
eventListener.onEvent(eventType);
} catch (Throwable t) {
log.error("~~~ Exception in addEventListener {}", t.getMessage());
t.printStackTrace();
this.interrupt();
this.stop();
}
}
};
callbackThreads.add(t);
t.setDaemon(true);
t.start();
}
/*
* consoleLog
*/
public void consoleLog(ConsoleLogLevel level, String message) {
message = message.replaceAll("'", "\"");
browser.executeScript("console." + level.toString() + "('" + message + "');");
}
@After
@SuppressWarnings("deprecation")
public void teardownKurentoServices() throws Exception {
for (Thread t : callbackThreads) {
t.stop();
}
}
/*
* stopWebRtc
*/
public void stopWebRtc() {
browser.executeScript("stop();");
browser.executeScript("var kurentoTest = new KurentoTest();");
countDownLatchEvents.clear();
}
/*
* close
*/
public void close() {
browser.close();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy