mirror of https://github.com/OpenVidu/openvidu.git
openvidu-test-e2e: EndReason test
parent
9cdca285a2
commit
c670bee1aa
|
@ -66,10 +66,9 @@ public enum EndReason {
|
|||
|
||||
/**
|
||||
* The last participant left the session, which caused the session to be closed.
|
||||
* Applies to events webrtcConnectionDestroyed, participantLeft,
|
||||
* recordingStatusChanged and sessionDestroyed. Can be triggered from other
|
||||
* events with other end reasons (disconnect, forceDisconnectByUser,
|
||||
* forceDisconnectByServer, networkDisconnect)
|
||||
* Applies to events recordingStatusChanged, broadcastStopped and
|
||||
* sessionDestroyed. Can be triggered from other events with other end reasons
|
||||
* (disconnect, forceDisconnectByServer, networkDisconnect)
|
||||
*/
|
||||
lastParticipantLeft,
|
||||
|
||||
|
@ -79,10 +78,16 @@ public enum EndReason {
|
|||
*/
|
||||
recordingStoppedByServer,
|
||||
|
||||
/**
|
||||
* The server application called the REST operation to stop a broadcast. Applies
|
||||
* to event broadcastStopped
|
||||
*/
|
||||
broadcastStoppedByServer,
|
||||
|
||||
/**
|
||||
* The server application called the REST operation to close a session. Applies
|
||||
* to events webrtcConnectionDestroyed, participantLeft, recordingStatusChanged
|
||||
* and sessionDestroyed
|
||||
* to events webrtcConnectionDestroyed, participantLeft, recordingStatusChanged,
|
||||
* broadcastStopped and sessionDestroyed
|
||||
*/
|
||||
sessionClosedByServer,
|
||||
|
||||
|
@ -96,8 +101,8 @@ public enum EndReason {
|
|||
/**
|
||||
* A media server disconnected. This is reserved for Media Nodes being
|
||||
* gracefully removed from an OpenVidu Pro cluster. Applies to events
|
||||
* webrtcConnectionDestroyed, participantLeft, recordingStatusChanged and
|
||||
* sessionDestroyed
|
||||
* webrtcConnectionDestroyed, participantLeft, recordingStatusChanged,
|
||||
* broadcastStopped and sessionDestroyed
|
||||
*/
|
||||
mediaServerDisconnect,
|
||||
|
||||
|
@ -110,22 +115,24 @@ public enum EndReason {
|
|||
|
||||
/**
|
||||
* A node has crashed. For now this means a Media Node has crashed. Applies to
|
||||
* events webrtcConnectionDestroyed, participantLeft, recordingStatusChanged and
|
||||
* sessionDestroyed
|
||||
* events webrtcConnectionDestroyed, participantLeft, recordingStatusChanged,
|
||||
* broadcastStopped and sessionDestroyed
|
||||
*/
|
||||
nodeCrashed,
|
||||
|
||||
/**
|
||||
* OpenVidu Server has gracefully stopped. This is reserved for OpenVidu Pro
|
||||
* restart operation. Applies to events webrtcConnectionDestroyed,
|
||||
* participantLeft, recordingStatusChanged and sessionDestroyed
|
||||
* participantLeft, recordingStatusChanged, broadcastStopped and
|
||||
* sessionDestroyed
|
||||
*/
|
||||
openviduServerStopped,
|
||||
|
||||
/**
|
||||
* A recording has been stopped automatically
|
||||
* (https://docs.openvidu.io/en/stable/advanced-features/recording/#automatic-stop-of-recordings).
|
||||
* Applies to event recordingStatusChanged
|
||||
* Applies to event recordingStatusChanged and sessionDestroyed (in case the
|
||||
* session was inactive except for the recording)
|
||||
*/
|
||||
automaticStop
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ public abstract class SessionManager {
|
|||
public abstract void onUnsubscribeFromSpeechToText(Participant participant, Integer transactionId,
|
||||
String connectionId);
|
||||
|
||||
public abstract void stopBroadcastIfNecessary(Session session);
|
||||
public abstract void stopBroadcastIfNecessary(Session session, EndReason reason);
|
||||
|
||||
public void onEcho(String participantPrivateId, Integer requestId) {
|
||||
sessionEventsHandler.onEcho(participantPrivateId, requestId);
|
||||
|
|
|
@ -262,6 +262,8 @@ public class KurentoSessionManager extends SessionManager {
|
|||
// "SessionManager.closeSessionAndEmptyCollections"
|
||||
if (!EndReason.sessionClosedByServer.equals(reason)) {
|
||||
|
||||
final long autoStopTimeout = this.openviduConfig.getOpenviduRecordingAutostopTimeout();
|
||||
|
||||
if (remainingParticipants.isEmpty()) {
|
||||
if (this.recordingManager.sessionIsBeingRecorded(sessionId)) {
|
||||
// Start countdown to stop recording. Will be aborted if a Publisher starts
|
||||
|
@ -269,8 +271,9 @@ public class KurentoSessionManager extends SessionManager {
|
|||
// recordings it would still remain a recorder participant
|
||||
log.info(
|
||||
"Last participant left. Starting {} seconds countdown for stopping recording of session {}",
|
||||
this.openviduConfig.getOpenviduRecordingAutostopTimeout(), sessionId);
|
||||
recordingManager.initAutomaticRecordingStopThread(session);
|
||||
autoStopTimeout, sessionId);
|
||||
recordingManager.initAutomaticRecordingStopThread(session,
|
||||
autoStopTimeout == 0 ? EndReason.lastParticipantLeft : EndReason.automaticStop);
|
||||
} else {
|
||||
try {
|
||||
if (session.closingLock.writeLock().tryLock(15, TimeUnit.SECONDS)) {
|
||||
|
@ -310,8 +313,10 @@ public class KurentoSessionManager extends SessionManager {
|
|||
// RECORDER or STT participant is the last one standing. Start countdown
|
||||
log.info(
|
||||
"Last participant left. Starting {} seconds countdown for stopping recording of session {}",
|
||||
this.openviduConfig.getOpenviduRecordingAutostopTimeout(), sessionId);
|
||||
recordingManager.initAutomaticRecordingStopThread(session);
|
||||
autoStopTimeout, sessionId);
|
||||
recordingManager.initAutomaticRecordingStopThread(session,
|
||||
autoStopTimeout == 0 ? EndReason.lastParticipantLeft
|
||||
: EndReason.automaticStop);
|
||||
|
||||
} else if (session.getSessionProperties().defaultRecordingProperties().outputMode()
|
||||
.equals(Recording.OutputMode.COMPOSED_QUICK_START)) {
|
||||
|
@ -329,7 +334,7 @@ public class KurentoSessionManager extends SessionManager {
|
|||
&& remainingParticipants.stream().anyMatch(p -> p.isBroadcastParticipant());
|
||||
|
||||
if (broadcastParticipantLeft) {
|
||||
this.stopBroadcastIfNecessary(session);
|
||||
this.stopBroadcastIfNecessary(session, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1425,7 +1430,7 @@ public class KurentoSessionManager extends SessionManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void stopBroadcastIfNecessary(Session session) {
|
||||
public void stopBroadcastIfNecessary(Session session, EndReason reason) {
|
||||
}
|
||||
|
||||
private io.openvidu.server.recording.Recording getActiveRecordingIfAllowedByParticipantRole(
|
||||
|
|
|
@ -316,7 +316,7 @@ public class RecordingManager {
|
|||
"No publisher in session {}. Starting {} seconds countdown for stopping recording",
|
||||
session.getSessionId(),
|
||||
this.openviduConfig.getOpenviduRecordingAutostopTimeout());
|
||||
this.initAutomaticRecordingStopThread(session);
|
||||
this.initAutomaticRecordingStopThread(session, EndReason.automaticStop);
|
||||
}
|
||||
return recording;
|
||||
}
|
||||
|
@ -676,7 +676,7 @@ public class RecordingManager {
|
|||
return recordingManagerUtils.getRecordingUrl(recording);
|
||||
}
|
||||
|
||||
public void initAutomaticRecordingStopThread(final Session session) {
|
||||
public void initAutomaticRecordingStopThread(final Session session, final EndReason reason) {
|
||||
final String recordingId = this.sessionsRecordings.get(session.getSessionId()).getId();
|
||||
|
||||
this.automaticRecordingStopThreads.computeIfAbsent(session.getSessionId(), f -> {
|
||||
|
@ -695,12 +695,11 @@ public class RecordingManager {
|
|||
}
|
||||
if (session.getParticipants().size() == 0
|
||||
|| session.onlyRecorderAndOrSttAndOrBroadcastParticipant()) {
|
||||
// Close session if there are no participants connected (RECORDER/STT/BROADCAST do
|
||||
// not count) and publishing
|
||||
// Close session if there are no participants connected (RECORDER/STT/BROADCAST
|
||||
// do not count) and publishing
|
||||
log.info("Closing session {} after automatic stop of recording {}",
|
||||
session.getSessionId(), recordingId);
|
||||
sessionManager.closeSessionAndEmptyCollections(session, EndReason.automaticStop,
|
||||
true);
|
||||
sessionManager.closeSessionAndEmptyCollections(session, reason, true);
|
||||
} else {
|
||||
// There are users connected, but no one is publishing
|
||||
// We don't need the lock if session is not closing
|
||||
|
@ -709,7 +708,7 @@ public class RecordingManager {
|
|||
log.info(
|
||||
"Automatic stopping recording {}. There are users connected to session {}, but no one is publishing",
|
||||
recordingId, session.getSessionId());
|
||||
this.stopRecording(session, recordingId, EndReason.automaticStop);
|
||||
this.stopRecording(session, recordingId, reason);
|
||||
}
|
||||
} finally {
|
||||
if (!alreadyUnlocked) {
|
||||
|
@ -750,8 +749,9 @@ public class RecordingManager {
|
|||
if (session.getParticipants().size() == 0
|
||||
|| session.onlyRecorderAndOrSttAndOrBroadcastParticipant()) {
|
||||
// Close session if there are no participants connected (except for
|
||||
// RECORDER/STT/BROADCAST). This code will only be executed if recording is manually
|
||||
// stopped during the automatic stop timeout, so the session must be also closed
|
||||
// RECORDER/STT/BROADCAST). This code will only be executed if recording is
|
||||
// manually stopped during the automatic stop timeout, so the session must be
|
||||
// also closed
|
||||
log.info(
|
||||
"Ongoing recording of session {} was explicetly stopped within timeout for automatic recording stop. Closing session",
|
||||
session.getSessionId());
|
||||
|
|
|
@ -217,11 +217,9 @@ public abstract class RecordingService {
|
|||
|
||||
protected void uploadRecording(final Recording recording, EndReason reason) {
|
||||
recordingUploader.uploadRecording(recording, () -> {
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
cdr.recordRecordingStatusChanged(recording, reason, timestamp, recording.getStatus());
|
||||
cdr.recordRecordingStatusChanged(recording, reason, System.currentTimeMillis(), recording.getStatus());
|
||||
}, () -> {
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
cdr.recordRecordingStatusChanged(recording, reason, timestamp,
|
||||
cdr.recordRecordingStatusChanged(recording, reason, System.currentTimeMillis(),
|
||||
io.openvidu.java.client.Recording.Status.failed);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class CustomWebhook {
|
|||
public static CountDownLatch initLatch;
|
||||
public static int accumulatedNumberOfEvents = 0;
|
||||
public final static ConcurrentMap<String, List<JsonObject>> accumulatedEvents = new ConcurrentHashMap<>();
|
||||
static final ConcurrentMap<String, BlockingQueue<JsonObject>> events = new ConcurrentHashMap<>();
|
||||
public static final ConcurrentMap<String, BlockingQueue<JsonObject>> events = new ConcurrentHashMap<>();
|
||||
static final BlockingQueue<JsonObject> eventsInOrder = new LinkedBlockingDeque<>();
|
||||
|
||||
public static void main(String[] args, CountDownLatch initLatch) {
|
||||
|
|
|
@ -102,6 +102,11 @@
|
|||
<artifactId>openvidu-java-client</artifactId>
|
||||
<version>${version.openvidu.java.client}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
<version>${version.dockerjava}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package io.openvidu.test.e2e;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.async.ResultCallback;
|
||||
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
|
||||
import com.github.dockerjava.core.DefaultDockerClientConfig;
|
||||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.core.DockerClientConfig;
|
||||
import com.github.dockerjava.jaxrs.JerseyDockerHttpClient;
|
||||
import com.github.dockerjava.transport.DockerHttpClient;
|
||||
|
||||
public class MediaNodeDockerUtils {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MediaNodeDockerUtils.class);
|
||||
|
||||
public static void crashMediaNode(String containerId) {
|
||||
log.info("Stopping Media Node container");
|
||||
DockerClient dockerClient = getDockerClient();
|
||||
dockerClient.removeContainerCmd(containerId).withForce(true).exec();
|
||||
}
|
||||
|
||||
public static String getMediaNodeIp(String containerId) {
|
||||
DockerClient dockerClient = getDockerClient();
|
||||
return dockerClient.inspectContainerCmd(containerId).exec().getNetworkSettings().getNetworks().get("bridge")
|
||||
.getIpAddress();
|
||||
}
|
||||
|
||||
public static void crashMediaServerInsideMediaNode(String containerId) {
|
||||
log.info("Stopping KMS container inside Media Node");
|
||||
DockerClient dockerClient = getDockerClient();
|
||||
ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId).withAttachStdout(true)
|
||||
.withAttachStderr(true).withCmd("bash", "-c", "docker rm -f kms").exec();
|
||||
|
||||
dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ResultCallback.Adapter<>() {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void stopMediaServerInsideMediaNodeAndRecover(String containerId, int millisStop) {
|
||||
log.info("Stopping and starting KMS container inside Media Node " + containerId + "waiting " + millisStop
|
||||
+ " ms");
|
||||
DockerClient dockerClient = getDockerClient();
|
||||
ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId).withAttachStdout(true)
|
||||
.withAttachStderr(true)
|
||||
.withCmd("bash", "-c", "docker stop kms && sleep " + (millisStop / 1000) + " && docker start kms")
|
||||
.exec();
|
||||
dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ResultCallback.Adapter<>() {
|
||||
});
|
||||
}
|
||||
|
||||
public static DockerClient getDockerClient() {
|
||||
DockerClientConfig dockerClientConfig = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
|
||||
DockerHttpClient dockerHttpClient = new JerseyDockerHttpClient.Builder()
|
||||
.dockerHost(dockerClientConfig.getDockerHost()).sslConfig(dockerClientConfig.getSSLConfig()).build();
|
||||
return DockerClientBuilder.getInstance(dockerClientConfig).withDockerHttpClient(dockerHttpClient).build();
|
||||
}
|
||||
|
||||
}
|
|
@ -210,6 +210,357 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through every EndReason and test that all affected entities trigger the
|
||||
* required Webhook events when being destroyed for that specific reason. Check
|
||||
* that "reason" property of every event is right and that there are no extra
|
||||
* events triggered.
|
||||
*/
|
||||
@Test
|
||||
@DisplayName("End reason")
|
||||
void endReasonTest() throws Exception {
|
||||
|
||||
isRecordingTest = true;
|
||||
|
||||
log.info("End reason test");
|
||||
|
||||
CountDownLatch initLatch = new CountDownLatch(1);
|
||||
io.openvidu.test.browsers.utils.webhook.CustomWebhook.main(new String[0], initLatch);
|
||||
|
||||
try {
|
||||
|
||||
if (!initLatch.await(30, TimeUnit.SECONDS)) {
|
||||
Assertions.fail("Timeout waiting for webhook springboot app to start");
|
||||
CustomWebhook.shutDown();
|
||||
return;
|
||||
}
|
||||
|
||||
CustomHttpClient restClient = new CustomHttpClient(OpenViduTestAppE2eTest.OPENVIDU_URL, "OPENVIDUAPP",
|
||||
OpenViduTestAppE2eTest.OPENVIDU_SECRET);
|
||||
JsonObject config = restClient.rest(HttpMethod.GET, "/openvidu/api/config", HttpURLConnection.HTTP_OK);
|
||||
|
||||
String defaultOpenViduWebhookEndpoint = null;
|
||||
Integer defaultOpenViduRecordingAutostopTimeout = null;
|
||||
if (config.has("OPENVIDU_WEBHOOK_ENDPOINT")) {
|
||||
defaultOpenViduWebhookEndpoint = config.get("OPENVIDU_WEBHOOK_ENDPOINT").getAsString();
|
||||
}
|
||||
if (config.has("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT")) {
|
||||
defaultOpenViduRecordingAutostopTimeout = config.get("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT").getAsInt();
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
Map<String, Object> newConfig = Map.of("OPENVIDU_WEBHOOK", true, "OPENVIDU_WEBHOOK_ENDPOINT",
|
||||
"http://127.0.0.1:7777/webhook", "OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", 0);
|
||||
restartOpenViduServer(newConfig);
|
||||
|
||||
OpenViduTestappUser user = setupBrowserAndConnectToOpenViduTestapp("chrome");
|
||||
|
||||
// unsubscribe: webrtcConnectionDestroyed
|
||||
this.connectTwoUsers(user, restClient, false, false, false);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .sub-btn")).click();
|
||||
Assertions.assertEquals("unsubscribe",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// unpublish: webrtcConnectionDestroyed
|
||||
this.connectTwoUsers(user, restClient, false, false, false);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .pub-btn")).click();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("unpublish",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// disconnect: webrtcConnectionDestroyed, participantLeft (and subsequent
|
||||
// lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
// First user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .leave-btn")).click();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
// Second user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .leave-btn")).click();
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// forceUnpublishByUser: webrtcConnectionDestroyed
|
||||
this.connectTwoUsers(user, restClient, true, false, false);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .force-unpub-btn")).click();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("forceUnpublishByUser",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// forceUnpublishByServer: webrtcConnectionDestroyed
|
||||
this.connectTwoUsers(user, restClient, false, false, false);
|
||||
String streamId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/sessions/TestSession", HttpURLConnection.HTTP_OK)
|
||||
.get("connections").getAsJsonObject().get("content").getAsJsonArray().asList().stream()
|
||||
.filter(con -> con.getAsJsonObject().get("role").getAsString().equals("PUBLISHER")).findFirst()
|
||||
.get().getAsJsonObject().get("publishers").getAsJsonArray().get(0).getAsJsonObject()
|
||||
.get("streamId").getAsString();
|
||||
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/TestSession/stream/" + streamId,
|
||||
HttpURLConnection.HTTP_NO_CONTENT);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("forceUnpublishByServer",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// forceDisconnectByUser: webrtcConnectionDestroyed, participantLeft
|
||||
this.connectTwoUsers(user, restClient, true, true, true);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .force-disconnect-btn")).click();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assertions.assertEquals("forceDisconnectByUser",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("forceDisconnectByUser",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// forceDisconnectByServer: webrtcConnectionDestroyed, participantLeft (and
|
||||
// subsequent lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String[] connectionIds = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/sessions/TestSession", HttpURLConnection.HTTP_OK)
|
||||
.get("connections").getAsJsonObject().get("content").getAsJsonArray().asList().stream()
|
||||
.map(con -> con.getAsJsonObject().get("connectionId").getAsString()).toArray(String[]::new);
|
||||
// First user out
|
||||
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/TestSession/connection/" + connectionIds[0],
|
||||
HttpURLConnection.HTTP_NO_CONTENT);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assertions.assertEquals("forceDisconnectByServer",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("forceDisconnectByServer",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
// Second user out
|
||||
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/TestSession/connection/" + connectionIds[1],
|
||||
HttpURLConnection.HTTP_NO_CONTENT);
|
||||
Assertions.assertEquals("forceDisconnectByServer",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("forceDisconnectByServer",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// sessionClosedByServer: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
restClient.rest(HttpMethod.DELETE, "/openvidu/api/sessions/TestSession",
|
||||
HttpURLConnection.HTTP_NO_CONTENT);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("sessionClosedByServer",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// networkDisconnect: webrtcConnectionDestroyed, participantLeft (and
|
||||
// subsequent lastParticipantLeft triggered events for sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped])
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
// First user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .network-drop-btn")).click();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Assertions.assertEquals("networkDisconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 20).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("networkDisconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
// Second user out
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .network-drop-btn")).click();
|
||||
Assertions.assertEquals("networkDisconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 20).get("reason").getAsString());
|
||||
Assertions.assertEquals("networkDisconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("lastParticipantLeft",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// mediaServerDisconnect: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged, [broadcastStopped]
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String mediaNodeId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/media-nodes", HttpURLConnection.HTTP_OK).get("content")
|
||||
.getAsJsonArray().get(0).getAsJsonObject().get("id").getAsString();
|
||||
restClient.rest(HttpMethod.DELETE,
|
||||
"/openvidu/api/media-nodes/" + mediaNodeId + "?wait=false&deletion-strategy=now",
|
||||
HttpURLConnection.HTTP_OK);
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 3);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 20).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("mediaServerDisconnect",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 5);
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
restartOpenViduServer(new HashMap<>(), true, HttpURLConnection.HTTP_OK);
|
||||
|
||||
// mediaServerReconnect: webrtcConnectionDestroyed, recordingStatusChanged
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String containerId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/media-nodes", HttpURLConnection.HTTP_OK).get("content")
|
||||
.getAsJsonArray().get(0).getAsJsonObject().get("environmentId").getAsString();
|
||||
MediaNodeDockerUtils.stopMediaServerInsideMediaNodeAndRecover(containerId, 400);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("mediaServerReconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("mediaServerReconnect",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// nodeCrashed: webrtcConnectionDestroyed, participantLeft, sessionDestroyed,
|
||||
// recordingStatusChanged, [broadcastStopped]
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
containerId = restClient.rest(HttpMethod.GET, "/openvidu/api/media-nodes", HttpURLConnection.HTTP_OK)
|
||||
.get("content").getAsJsonArray().get(0).getAsJsonObject().get("environmentId").getAsString();
|
||||
MediaNodeDockerUtils.crashMediaNode(containerId);
|
||||
CustomWebhook.waitForEvent("nodeCrashed", 10);
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 2);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
}
|
||||
// Only status "stopped" for recording. Not "ready" if node crash
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 2).get("reason").getAsString());
|
||||
Assertions.assertEquals("nodeCrashed",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 2);
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
restartOpenViduServer(new HashMap<>(), true, HttpURLConnection.HTTP_OK);
|
||||
|
||||
// openviduServerStopped: webrtcConnectionDestroyed, participantLeft,
|
||||
// sessionDestroyed, recordingStatusChanged, [broadcastStopped]
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
restartOpenViduServer(new HashMap<>(), true, HttpURLConnection.HTTP_OK);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 20).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("openviduServerStopped",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
for (int i = 0; i < 2; i++) {
|
||||
CustomWebhook.waitForEvent("mediaNodeStatusChanged", 15);
|
||||
}
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// automaticStop: sessionDestroyed, recordingStatusChanged
|
||||
newConfig = Map.of("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", 1);
|
||||
restartOpenViduServer(newConfig);
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-0 .leave-btn")).click();
|
||||
user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .leave-btn")).click();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("webrtcConnectionDestroyed", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("disconnect",
|
||||
CustomWebhook.waitForEvent("participantLeft", 2).get("reason").getAsString());
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("automaticStop",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
Assertions.assertEquals("automaticStop",
|
||||
CustomWebhook.waitForEvent("sessionDestroyed", 2).get("reason").getAsString());
|
||||
CustomWebhook.events.values().forEach(collection -> Assertions.assertTrue(collection.isEmpty()));
|
||||
|
||||
// recordingStoppedByServer
|
||||
this.connectTwoUsers(user, restClient, false, true, true);
|
||||
String recordingId = restClient
|
||||
.rest(HttpMethod.GET, "/openvidu/api/recordings", HttpURLConnection.HTTP_OK).get("items")
|
||||
.getAsJsonArray().asList().stream()
|
||||
.filter(rec -> rec.getAsJsonObject().get("status").getAsString()
|
||||
.equals(Recording.Status.started.name()))
|
||||
.findFirst().get().getAsJsonObject().get("id").getAsString();
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/recordings/stop/" + recordingId,
|
||||
HttpURLConnection.HTTP_OK);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Assertions.assertEquals("recordingStoppedByServer",
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 4).get("reason").getAsString());
|
||||
}
|
||||
|
||||
// [broadcastStoppedByServer]
|
||||
|
||||
} finally {
|
||||
Map<String, Object> oldConfig = new HashMap<>();
|
||||
oldConfig.put("OPENVIDU_WEBHOOK", false);
|
||||
if (defaultOpenViduWebhookEndpoint != null) {
|
||||
oldConfig.put("OPENVIDU_WEBHOOK_ENDPOINT", defaultOpenViduWebhookEndpoint);
|
||||
}
|
||||
if (defaultOpenViduRecordingAutostopTimeout != null) {
|
||||
oldConfig.put("OPENVIDU_RECORDING_AUTOSTOP_TIMEOUT", defaultOpenViduRecordingAutostopTimeout);
|
||||
}
|
||||
restartOpenViduServer(oldConfig);
|
||||
}
|
||||
|
||||
} finally {
|
||||
CustomWebhook.shutDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Individual dynamic record")
|
||||
void individualDynamicRecordTest() throws Exception {
|
||||
|
@ -2552,4 +2903,40 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestappE2eTest {
|
|||
sttUnsubUser(user, 0, 0, false, true);
|
||||
}
|
||||
|
||||
private void connectTwoUsers(OpenViduTestappUser user, CustomHttpClient restClient, boolean firstUserIsModerator,
|
||||
boolean startRecording, boolean startBroadcast) throws Exception {
|
||||
this.closeAllSessions(OV);
|
||||
user.getDriver().findElement(By.id("remove-all-users-btn")).click();
|
||||
user.getEventManager().clearAllCurrentEvents();
|
||||
CustomWebhook.clean();
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
if (firstUserIsModerator) {
|
||||
user.getDriver().findElement(By.id("session-settings-btn-0")).click();
|
||||
Thread.sleep(500);
|
||||
user.getDriver().findElement(By.id("radio-btn-mod")).click();
|
||||
user.getDriver().findElement(By.id("save-btn")).click();
|
||||
Thread.sleep(500);
|
||||
}
|
||||
user.getDriver().findElement(By.id("add-user-btn")).click();
|
||||
user.getDriver().findElements(By.className("join-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
|
||||
user.getEventManager().waitUntilEventReaches("streamPlaying", 4);
|
||||
CustomWebhook.waitForEvent("sessionCreated", 1);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
CustomWebhook.waitForEvent("participantJoined", 1);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CustomWebhook.waitForEvent("webrtcConnectionCreated", 1);
|
||||
}
|
||||
if (startRecording) {
|
||||
restClient.rest(HttpMethod.POST, "/openvidu/api/recordings/start",
|
||||
"{'session':'TestSession','outputMode':'INDIVIDUAL'}", HttpURLConnection.HTTP_OK);
|
||||
user.getEventManager().waitUntilEventReaches("recordingStarted", 2);
|
||||
Assertions.assertEquals(Recording.Status.started.name(),
|
||||
CustomWebhook.waitForEvent("recordingStatusChanged", 3).get("status").getAsString());
|
||||
}
|
||||
if (startBroadcast) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -124,6 +124,9 @@
|
|||
<button class="message-btn" (click)="sendMessage()" title="Broadcast message">
|
||||
<mat-icon aria-label="Send message button" style="font-size: 20px">chat</mat-icon>
|
||||
</button>
|
||||
<button class="network-drop-btn" (click)="simulateNetworkDrop()" title="Simulate network drop">
|
||||
<mat-icon aria-label="Simulate network drop button" style="font-size: 20px">wifi_off</mat-icon>
|
||||
</button>
|
||||
<button class="leave-btn" (click)="leaveSession()" title="Leave session">
|
||||
<mat-icon aria-label="Leave button">clear</mat-icon>
|
||||
</button>
|
||||
|
|
|
@ -284,6 +284,11 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.subscribers = [];
|
||||
}
|
||||
|
||||
private simulateNetworkDrop(): void {
|
||||
const jsonRpClient = (this.OV as any).jsonRpcClient;
|
||||
jsonRpClient.close();
|
||||
}
|
||||
|
||||
updateEventList(eventName: string, eventContent: string, event: Event) {
|
||||
const eventInterface: OpenViduEvent = { eventName, eventContent, event };
|
||||
this.events.push(eventInterface);
|
||||
|
|
Loading…
Reference in New Issue