mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: init openViduJavaClientTest and REST API test
parent
a94d9d0497
commit
248539fa42
|
@ -163,6 +163,12 @@
|
|||
<artifactId>openvidu-java-client</artifactId>
|
||||
<version>2.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mashape.unirest</groupId>
|
||||
<artifactId>unirest-java</artifactId>
|
||||
<version>1.4.9</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -44,6 +44,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.jcodec.api.FrameGrab;
|
||||
import org.jcodec.api.JCodecException;
|
||||
import org.jcodec.common.model.Picture;
|
||||
|
@ -75,19 +76,29 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.mashape.unirest.http.HttpMethod;
|
||||
|
||||
import io.github.bonigarcia.SeleniumExtension;
|
||||
import io.github.bonigarcia.wdm.WebDriverManager;
|
||||
import io.openvidu.java.client.KurentoOptions;
|
||||
import io.openvidu.java.client.MediaMode;
|
||||
import io.openvidu.java.client.OpenVidu;
|
||||
import io.openvidu.java.client.OpenViduHttpException;
|
||||
import io.openvidu.java.client.OpenViduJavaClientException;
|
||||
import io.openvidu.java.client.OpenViduRole;
|
||||
import io.openvidu.java.client.Recording;
|
||||
import io.openvidu.java.client.Recording.OutputMode;
|
||||
import io.openvidu.java.client.RecordingMode;
|
||||
import io.openvidu.java.client.Session;
|
||||
import io.openvidu.java.client.SessionProperties;
|
||||
import io.openvidu.java.client.TokenOptions;
|
||||
import io.openvidu.test.e2e.browser.BrowserUser;
|
||||
import io.openvidu.test.e2e.browser.ChromeAndroidUser;
|
||||
import io.openvidu.test.e2e.browser.ChromeUser;
|
||||
import io.openvidu.test.e2e.browser.FirefoxUser;
|
||||
import io.openvidu.test.e2e.browser.OperaUser;
|
||||
import io.openvidu.test.e2e.utils.CommandLineExecuter;
|
||||
import io.openvidu.test.e2e.utils.CustomHttpClient;
|
||||
import io.openvidu.test.e2e.utils.MultimediaFileMetadata;
|
||||
import io.openvidu.test.e2e.utils.Unzipper;
|
||||
|
||||
|
@ -206,7 +217,9 @@ public class OpenViduTestAppE2eTest {
|
|||
|
||||
@AfterEach
|
||||
void dispose() {
|
||||
user.dispose();
|
||||
if (user != null) {
|
||||
user.dispose();
|
||||
}
|
||||
Iterator<BrowserUser> it = otherUsers.iterator();
|
||||
while (it.hasNext()) {
|
||||
BrowserUser other = it.next();
|
||||
|
@ -1898,6 +1911,153 @@ public class OpenViduTestAppE2eTest {
|
|||
gracefullyLeaveParticipants(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("openvidu-java-client test")
|
||||
void openViduJavaClientTest() throws Exception {
|
||||
|
||||
setupBrowser("chrome");
|
||||
|
||||
log.info("openvidu-java-client test");
|
||||
|
||||
user.getDriver().findElement(By.id("one2one-btn")).click();
|
||||
|
||||
final String customSessionId = "openviduJavaClientSession";
|
||||
final String serverData1 = "SERVER_DATA_1";
|
||||
final String serverData2 = "SERVER_DATA_2";
|
||||
|
||||
Assert.assertFalse("OV.fetch() should return false if OV.createSession() has not been called", OV.fetch());
|
||||
List<Session> sessions = OV.getActiveSessions();
|
||||
Assert.assertEquals("Expected no active sessions but found " + sessions.size(), sessions.size(), 0);
|
||||
|
||||
SessionProperties properties = new SessionProperties.Builder().customSessionId(customSessionId)
|
||||
.mediaMode(MediaMode.ROUTED).recordingMode(RecordingMode.ALWAYS)
|
||||
.defaultOutputMode(OutputMode.INDIVIDUAL).build();
|
||||
Session session = OV.createSession(properties);
|
||||
|
||||
Assert.assertFalse("Session.fetch() should return false after OpenVidu.createSession()", session.fetch());
|
||||
Assert.assertFalse("OpenVidu.fetch() should return false after OpenVidu.createSession()", OV.fetch());
|
||||
sessions = OV.getActiveSessions();
|
||||
Assert.assertEquals("Expected 1 active session but found " + sessions.size(), 1, sessions.size());
|
||||
|
||||
KurentoOptions kurentoOptions = new KurentoOptions.Builder().videoMaxRecvBandwidth(250)
|
||||
.allowedFilters(new String[] { "GStreamerFilter" }).build();
|
||||
TokenOptions tokenOptions1 = new TokenOptions.Builder().role(OpenViduRole.MODERATOR).data(serverData1)
|
||||
.kurentoOptions(kurentoOptions).build();
|
||||
String token1 = session.generateToken(tokenOptions1);
|
||||
|
||||
TokenOptions tokenOptions2 = new TokenOptions.Builder().role(OpenViduRole.SUBSCRIBER).data(serverData2).build();
|
||||
String token2 = session.generateToken(tokenOptions2);
|
||||
|
||||
Assert.assertFalse("Session.fetch() should return false until a user has connected", session.fetch());
|
||||
|
||||
user.getDriver().findElement(By.id("session-settings-btn-0")).click();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Set token 1
|
||||
WebElement tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input"));
|
||||
tokeInput.clear();
|
||||
tokeInput.sendKeys(token1);
|
||||
|
||||
user.getDriver().findElement(By.id("save-btn")).click();
|
||||
Thread.sleep(1000);
|
||||
|
||||
user.getDriver().findElement(By.id("session-settings-btn-1")).click();
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Set token 2
|
||||
tokeInput = user.getDriver().findElement(By.cssSelector("#custom-token-div input"));
|
||||
tokeInput.clear();
|
||||
tokeInput.sendKeys(token2);
|
||||
|
||||
user.getDriver().findElement(By.id("save-btn")).click();
|
||||
Thread.sleep(1000);
|
||||
|
||||
user.getDriver().findElements(By.className("join-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
|
||||
|
||||
user.getEventManager().waitUntilEventReaches("connectionCreated", 4);
|
||||
user.getEventManager().waitUntilEventReaches("accessAllowed", 1);
|
||||
user.getEventManager().waitUntilEventReaches("streamCreated", 2);
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 2);
|
||||
|
||||
final int numberOfVideos = user.getDriver().findElements(By.tagName("video")).size();
|
||||
Assert.assertEquals("Expected 2 videos but found " + numberOfVideos, numberOfVideos, 2);
|
||||
Assert.assertTrue("Videos were expected to have audio and video tracks", user.getEventManager()
|
||||
.assertMediaTracks(user.getDriver().findElements(By.tagName("video")), true, true));
|
||||
|
||||
Assert.assertTrue("Session.fetch() should return true after users connected", session.fetch());
|
||||
|
||||
// Verify that users have the role and data they were assigned through
|
||||
// TokenOptions
|
||||
|
||||
gracefullyLeaveParticipants(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("REST API test")
|
||||
void restApiTest() throws Exception {
|
||||
|
||||
CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, OPENVIDU_SECRET);
|
||||
|
||||
// 401
|
||||
restClient.testAuthorizationError();
|
||||
|
||||
// GET /api/sessions before any session created
|
||||
restClient.rest(HttpMethod.GET, "/api/sessions/NOT_EXISTS", HttpStatus.SC_NOT_FOUND);
|
||||
Map<String, Object> returnValues = new HashMap<>();
|
||||
returnValues.put("numberOfElements", new Integer(0));
|
||||
returnValues.put("content", "[]");
|
||||
restClient.rest(HttpMethod.GET, "/api/sessions", null, HttpStatus.SC_OK, true, returnValues);
|
||||
|
||||
/** POST /api/sessions **/
|
||||
// 400
|
||||
String body = "{'mediaMode': 'ROUTED', 'recordingMode': 'ALWAYS', 'customSessionId': 999}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'mediaMode': 'ROUTED', 'recordingMode': false}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'mediaMode': 'NOT_EXISTS'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'mediaMode': 'ROUTED', 'recordingMode': 'NOT_EXISTS'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'mediaMode': 'ROUTED', 'recordingMode': 'ALWAYS', 'defaultOutputMode': 'NOT_EXISTS'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'mediaMode': 'ROUTED', 'recordingMode': 'ALWAYS', 'defaultOutputMode': 'INDIVIDUAL', 'defaultRecordingLayout': 'NOT_EXISTS'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_BAD_REQUEST);
|
||||
|
||||
// 200
|
||||
body = "{'mediaMode': 'ROUTED', 'recordingMode': 'ALWAYS', 'customSessionId': 'CUSTOM_SESSION_ID', 'defaultOutputMode': 'INDIVIDUAL', 'defaultRecordingLayout': 'BEST_FIT'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_OK, true,
|
||||
"{'id': 'STR', 'createdAt': 0}");
|
||||
|
||||
// 409
|
||||
body = "{'customSessionId': 'CUSTOM_SESSION_ID'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/sessions", body, HttpStatus.SC_CONFLICT);
|
||||
|
||||
// GET /api/sessions after session created
|
||||
restClient.rest(HttpMethod.GET, "/api/sessions/CUSTOM_SESSION_ID", null, HttpStatus.SC_OK, true,
|
||||
"{'sessionId':'STR','createdAt':0,'mediaMode':'STR','recordingMode':'STR','defaultOutputMode':'STR','customSessionId':'STR','connections':{'numberOfElements':0,'content':[]},'recording':true}");
|
||||
returnValues = new HashMap<>();
|
||||
returnValues.put("numberOfElements", new Integer(1));
|
||||
returnValues.put("content", new org.json.JSONArray());
|
||||
restClient.rest(HttpMethod.GET, "/api/sessions", null, HttpStatus.SC_OK, true, returnValues);
|
||||
|
||||
/** POST /api/tokens **/
|
||||
// 400
|
||||
body = "{'session': true}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'NOT_EXISTS', 'data': 'DATA'}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 999}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 'SERVER_DATA', 'kurentoOptions': false}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_BAD_REQUEST);
|
||||
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 'SERVER_DATA', 'kurentoOptions': {'allowedFilters': 'NOT_EXISTS'}}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_BAD_REQUEST);
|
||||
|
||||
// 200
|
||||
body = "{'session': 'CUSTOM_SESSION_ID', 'role': 'MODERATOR', 'data': 'SERVER_DATA', 'kurentoOptions': {'allowedFilters': ['GStreamerFilter']}}";
|
||||
restClient.rest(HttpMethod.POST, "/api/tokens", body, HttpStatus.SC_OK);
|
||||
}
|
||||
|
||||
private void listEmptyRecordings() {
|
||||
// List existing recordings (empty)
|
||||
user.getDriver().findElement(By.id("list-recording-btn")).click();
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* (C) Copyright 2017-2019 OpenVidu (https://openvidu.io/)
|
||||
*
|
||||
* 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 io.openvidu.test.e2e.utils;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.junit.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.mashape.unirest.http.HttpMethod;
|
||||
import com.mashape.unirest.http.HttpResponse;
|
||||
import com.mashape.unirest.http.JsonNode;
|
||||
import com.mashape.unirest.http.Unirest;
|
||||
import com.mashape.unirest.http.exceptions.UnirestException;
|
||||
import com.mashape.unirest.request.HttpRequest;
|
||||
import com.mashape.unirest.request.HttpRequestWithBody;
|
||||
|
||||
public class CustomHttpClient {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CustomHttpClient.class);
|
||||
|
||||
private String openviduUrl;
|
||||
private String headerAuth;
|
||||
|
||||
private JSONParser parser = new JSONParser();
|
||||
|
||||
public CustomHttpClient(String openviduUrl, String openviduSecret) {
|
||||
this.openviduUrl = openviduUrl.replaceFirst("/*$", "");
|
||||
this.headerAuth = "Basic " + Base64.getEncoder().encodeToString(("OPENVIDUAPP:" + openviduSecret).getBytes());
|
||||
|
||||
SSLContext sslContext = null;
|
||||
try {
|
||||
sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy() {
|
||||
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
|
||||
return true;
|
||||
}
|
||||
}).build();
|
||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||
Assert.fail("Error building custom HttpClient: " + e.getMessage());
|
||||
}
|
||||
HttpClient unsafeHttpClient = HttpClients.custom().setSSLContext(sslContext)
|
||||
.setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
|
||||
Unirest.setHttpClient(unsafeHttpClient);
|
||||
}
|
||||
|
||||
public void testAuthorizationError() {
|
||||
try {
|
||||
String wrongCredentials = "Basic "
|
||||
+ Base64.getEncoder().encodeToString(("OPENVIDUAPP:WRONG_SECRET").getBytes());
|
||||
Assert.assertEquals("Expected 401 status (unauthorized)", HttpStatus.SC_UNAUTHORIZED, Unirest
|
||||
.get(openviduUrl + "/config").header("Authorization", wrongCredentials).asJson().getStatus());
|
||||
} catch (UnirestException e) {
|
||||
Assert.fail("Error testing UNAUTHORIZED rest method: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void rest(HttpMethod method, String path, int status) {
|
||||
this.commonRest(method, path, null, status);
|
||||
}
|
||||
|
||||
public void rest(HttpMethod method, String path, String body, int status) {
|
||||
this.commonRest(method, path, body, status);
|
||||
}
|
||||
|
||||
public void rest(HttpMethod method, String path, String body, int status, boolean exactFields,
|
||||
String jsonElmentString) {
|
||||
JSONObject json = this.commonRest(method, path, body, status);
|
||||
JSONObject jsonObjExpected = null;
|
||||
jsonElmentString.replaceAll("'", "\"");
|
||||
try {
|
||||
jsonObjExpected = new JSONObject((String) jsonElmentString);
|
||||
} catch (JSONException e1) {
|
||||
Assert.fail("Expected json element is a string without a JSON format: " + jsonElmentString);
|
||||
}
|
||||
|
||||
if (exactFields) {
|
||||
Assert.assertEquals("Error in number of keys in JSON response to POST " + path, jsonObjExpected.length(),
|
||||
json.length());
|
||||
}
|
||||
for (String key : jsonObjExpected.keySet()) {
|
||||
json.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public void rest(HttpMethod method, String path, String body, int status, boolean exactFields,
|
||||
Map<String, ?> jsonResponse) {
|
||||
org.json.JSONObject json = this.commonRest(method, path, body, status);
|
||||
|
||||
if (exactFields) {
|
||||
Assert.assertEquals("Error in number of keys in JSON response to POST " + path, jsonResponse.size(),
|
||||
json.length());
|
||||
}
|
||||
|
||||
for (Entry<String, ?> entry : jsonResponse.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
|
||||
if (value instanceof String) {
|
||||
try {
|
||||
JSONObject jsonObjExpected = new JSONObject((String) value);
|
||||
JSONObject jsonObjActual = json.getJSONObject(entry.getKey());
|
||||
// COMPARE
|
||||
|
||||
} catch (JSONException e1) {
|
||||
try {
|
||||
JSONArray jsonArrayExpected = new JSONArray((String) value);
|
||||
JSONArray jsonArrayActual = json.getJSONArray(entry.getKey());
|
||||
// COMPARE
|
||||
|
||||
} catch (JSONException e2) {
|
||||
Assert.assertEquals("JSON field " + entry.getKey() + " has not expected value", (String) value,
|
||||
json.getInt(entry.getKey()));
|
||||
}
|
||||
}
|
||||
} else if (value instanceof Integer) {
|
||||
Assert.assertEquals("JSON field " + entry.getKey() + " has not expected value", (int) value,
|
||||
json.getInt(entry.getKey()));
|
||||
} else if (value instanceof Long) {
|
||||
Assert.assertEquals("JSON field " + entry.getKey() + " has not expected value", (long) value,
|
||||
json.getLong(entry.getKey()));
|
||||
} else if (value instanceof Double) {
|
||||
Assert.assertEquals("JSON field " + entry.getKey() + " has not expected value", (double) value,
|
||||
json.getDouble(entry.getKey()), 0.001);
|
||||
} else if (value instanceof Boolean) {
|
||||
Assert.assertEquals("JSON field " + entry.getKey() + " has not expected value", (boolean) value,
|
||||
json.getBoolean(entry.getKey()));
|
||||
} else if (value instanceof JSONArray) {
|
||||
json.getJSONArray(entry.getKey());
|
||||
} else if (value instanceof JSONObject) {
|
||||
json.getJSONObject(entry.getKey());
|
||||
} else {
|
||||
Assert.fail("JSON response field cannot be parsed: " + entry.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private org.json.JSONObject commonRest(HttpMethod method, String path, String body, int status) {
|
||||
HttpResponse<JsonNode> jsonResponse = null;
|
||||
org.json.JSONObject json = null;
|
||||
path = openviduUrl + (path.startsWith("/") ? path : ("/" + path));
|
||||
|
||||
HttpRequest request = null;
|
||||
if (body != null && !body.isEmpty()) {
|
||||
switch (method) {
|
||||
case POST:
|
||||
request = Unirest.post(path);
|
||||
break;
|
||||
case PUT:
|
||||
request = Unirest.put(path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
((HttpRequestWithBody) request).header("Content-Type", "application/json").body(body.replaceAll("'", "\""));
|
||||
} else {
|
||||
switch (method) {
|
||||
case GET:
|
||||
request = Unirest.get(path);
|
||||
break;
|
||||
case POST:
|
||||
request = Unirest.post(path);
|
||||
break;
|
||||
case DELETE:
|
||||
request = Unirest.delete(path);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
request.header("Content-Type", "application/x-www-form-urlencoded");
|
||||
}
|
||||
try {
|
||||
jsonResponse = request.header("Authorization", this.headerAuth).asJson();
|
||||
if (jsonResponse.getBody() != null) {
|
||||
json = jsonResponse.getBody().getObject();
|
||||
}
|
||||
} catch (UnirestException e) {
|
||||
log.error(e.getMessage());
|
||||
Assert.fail("Error sending request to " + path + ": " + e.getMessage());
|
||||
}
|
||||
Assert.assertEquals(path + " expected to return status " + status, status, jsonResponse.getStatus());
|
||||
return json;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue