diff --git a/openvidu-test-e2e/jenkins/Jenkinsfile b/openvidu-test-e2e/jenkins/Jenkinsfile index e8aa5064..43e499cb 100644 --- a/openvidu-test-e2e/jenkins/Jenkinsfile +++ b/openvidu-test-e2e/jenkins/Jenkinsfile @@ -140,7 +140,7 @@ node('container') { mvn --batch-mode versions:set-property -Dproperty=version.openvidu.java.client -DnewVersion=TEST mvn --batch-mode versions:set-property -Dproperty=version.openvidu.test.browsers -DnewVersion=TEST cd openvidu-test-e2e - mvn -DskipTests=true clean compile + mvn -DskipTests=true clean install sudo mvn --batch-mode -Dtest=OpenViduTestAppE2eTest -DAPP_URL=https://172.17.0.1:4200/ -DOPENVIDU_URL=https://172.17.0.1:4443/ -DREMOTE_URL_CHROME=http://172.17.0.1:6666/wd/hub/ -DREMOTE_URL_FIREFOX=http://172.17.0.1:6667/wd/hub/ -DEXTERNAL_CUSTOM_LAYOUT_URL=http://172.17.0.1:5555 -DEXTERNAL_CUSTOM_LAYOUT_PARAMS=sessionId,CUSTOM_LAYOUT_SESSION,secret,MY_SECRET test git checkout -f $OPENVIDU_COMMIT '''.stripIndent()) diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java index db1a8d22..be49e3b1 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduEventManager.java @@ -283,9 +283,8 @@ public class OpenViduEventManager { } String[] events = rawEvents.replaceFirst("^", "").split(""); - JsonParser parser = new JsonParser(); for (String e : events) { - JsonObject event = (JsonObject) parser.parse(e); + JsonObject event = JsonParser.parseString(e).getAsJsonObject(); final String eventType = event.get("type").getAsString(); this.eventQueue.add(event); diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java index 01df4abc..e9eb3f90 100644 --- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java +++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduProTestAppE2eTest.java @@ -1,13 +1,22 @@ package io.openvidu.test.e2e; +import static org.junit.Assert.fail; + import java.io.File; import java.io.FileReader; +import java.util.Iterator; import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.http.HttpStatus; import org.junit.Assert; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -36,6 +45,8 @@ import io.openvidu.test.browsers.utils.Unzipper; public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest { + protected volatile static boolean isNetworkQualityTest; + @BeforeAll() protected static void setupAll() { checkFfmpegInstallation(); @@ -44,6 +55,29 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest { cleanFoldersAndSetUpOpenViduJavaClient(); } + @Override + @AfterEach + protected void dispose() { + super.dispose(); + if (isNetworkQualityTest) { + // Disable network quality API + try { + CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET); + if (restClient.rest(HttpMethod.GET, "/openvidu/api/config", 200).get("OPENVIDU_PRO_NETWORK_QUALITY") + .getAsBoolean()) { + String body = "{'OPENVIDU_PRO_NETWORK_QUALITY':false}"; + restClient.rest(HttpMethod.POST, "/openvidu/api/restart", body, 200); + waitUntilOpenViduRestarted(30); + } + } catch (Exception e) { + log.error(e.getMessage()); + Assert.fail("Error restarting OpenVidu Server to disable Network quality API"); + } finally { + isNetworkQualityTest = false; + } + } + } + @Test @DisplayName("Individual dynamic record") void individualDynamicRecordTest() throws Exception { @@ -449,6 +483,9 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest { @Test @DisplayName("openvidu-java-client PRO test") void openViduJavaClientProTest() throws Exception { + + log.info("openvidu-java-client PRO test"); + Session session = OV.createSession(); Assert.assertFalse(session.fetch()); Connection connection = session.createConnection(); @@ -462,4 +499,101 @@ public class OpenViduProTestAppE2eTest extends AbstractOpenViduTestAppE2eTest { Assert.assertFalse(session.fetch()); } + @Test + @DisplayName("Network quality test") + void networkQualityTest() throws Exception { + + isNetworkQualityTest = true; + + log.info("Network quality test"); + + CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET); + String body = "{'OPENVIDU_PRO_NETWORK_QUALITY':true, 'OPENVIDU_PRO_NETWORK_QUALITY_INTERVAL':5}"; + restClient.rest(HttpMethod.POST, "/openvidu/api/restart", body, 200); + waitUntilOpenViduRestarted(30); + + setupBrowser("chrome"); + user.getDriver().findElement(By.id("add-user-btn")).click(); + user.getDriver().findElement(By.className("join-btn")).click(); + + user.getEventManager().waitUntilEventReaches("connectionCreated", 1); + user.getEventManager().waitUntilEventReaches("streamPlaying", 1); + JsonObject res = restClient.rest(HttpMethod.GET, "/openvidu/api/sessions/TestSession/connection", + HttpStatus.SC_OK); + final String connectionId = res.getAsJsonObject().get("content").getAsJsonArray().get(0).getAsJsonObject() + .get("id").getAsString(); + + user.getDriver().findElement(By.id("add-user-btn")).click(); + user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .publish-checkbox")).click(); + user.getDriver().findElement(By.cssSelector("#openvidu-instance-1 .join-btn")).click(); + + final CountDownLatch latch1 = new CountDownLatch(1); + Queue threadAssertions = new ConcurrentLinkedQueue(); + user.getEventManager().on("networkQualityLevelChanged", (event) -> { + try { + threadAssertions.add("networkQualityLevelChanged".equals(event.get("type").getAsString())); + threadAssertions.add(event.get("oldValue") == null); + threadAssertions.add(event.has("newValue") && event.get("newValue").getAsInt() > 0 + && event.get("newValue").getAsInt() < 6); + latch1.countDown(); + } catch (Exception e) { + log.error("Error analysing NetworkQualityLevelChangedEvent: {}. {}", e.getCause(), e.getMessage()); + fail("Error analysing NetworkQualityLevelChangedEvent: " + e.getCause() + ". " + e.getMessage()); + } + }); + + user.getEventManager().waitUntilEventReaches("connectionCreated", 4); + user.getEventManager().waitUntilEventReaches("streamPlaying", 2); + user.getEventManager().waitUntilEventReaches("networkQualityLevelChanged", 2); + + if (!latch1.await(30000, TimeUnit.MILLISECONDS)) { + gracefullyLeaveParticipants(1); + fail(); + return; + } + + user.getEventManager().off("networkQualityLevelChanged"); + log.info("Thread assertions: {}", threadAssertions.toString()); + for (Iterator iter = threadAssertions.iterator(); iter.hasNext();) { + Assert.assertTrue("Some Event property was wrong", iter.next()); + iter.remove(); + } + + // Both events should have publisher's connection ID + Assert.assertTrue("Wrong connectionId in event NetworkQualityLevelChangedEvent", user.getDriver() + .findElement(By.cssSelector("#openvidu-instance-0 .mat-expansion-panel:last-child .event-content")) + .getAttribute("textContent").contains(connectionId)); + Assert.assertTrue("Wrong connectionId in event NetworkQualityLevelChangedEvent", user.getDriver() + .findElement(By.cssSelector("#openvidu-instance-1 .mat-expansion-panel:last-child .event-content")) + .getAttribute("textContent").contains(connectionId)); + + gracefullyLeaveParticipants(1); + } + + private void waitUntilOpenViduRestarted(int maxSecondsWait) throws Exception { + boolean restarted = false; + int msInterval = 500; + int attempts = 0; + final int maxAttempts = maxSecondsWait * 1000 / msInterval; + Thread.sleep(500); + while (!restarted && attempts < maxAttempts) { + try { + CustomHttpClient restClient = new CustomHttpClient(OPENVIDU_URL, "OPENVIDUAPP", OPENVIDU_SECRET); + restClient.rest(HttpMethod.GET, "/openvidu/api/health", 200); + restarted = true; + } catch (Exception e) { + try { + log.warn("Waiting for OpenVidu Server..."); + Thread.sleep(msInterval); + } catch (InterruptedException e1) { + log.error("Sleep interrupted"); + } + attempts++; + } + } + if (!restarted && attempts == maxAttempts) { + throw new TimeoutException(); + } + } + } diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html index 4e1e16ef..471988a5 100644 --- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html +++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.html @@ -18,16 +18,16 @@ - + settings cloud_circle - + notifications @@ -36,8 +36,8 @@ JOIN - Subscribe + Subscribe Publish @@ -48,26 +48,32 @@ Send - Audio - Video + Audio + + Video + Enter active - Audio - Video + Audio + Video - + Video @@ -75,15 +81,16 @@ Screen - Subscribe + Subscribe to remote - + settings {{sessionName}} - + linked_camera @@ -136,8 +144,8 @@ - + diff --git a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts index 5cfb392f..41578430 100644 --- a/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts +++ b/openvidu-testapp/src/app/components/openvidu-instance/openvidu-instance.component.ts @@ -6,7 +6,7 @@ import { import { OpenVidu, Session, Subscriber, Publisher, Event, StreamEvent, ConnectionEvent, SessionDisconnectedEvent, SignalEvent, RecordingEvent, - PublisherSpeakingEvent, PublisherProperties, StreamPropertyChangedEvent, ConnectionPropertyChangedEvent, OpenViduError + PublisherSpeakingEvent, PublisherProperties, StreamPropertyChangedEvent, ConnectionPropertyChangedEvent, OpenViduError, NetworkQualityLevelChangedEvent } from 'openvidu-browser'; import { OpenVidu as OpenViduAPI, @@ -116,6 +116,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { streamDestroyed: true, streamPropertyChanged: true, connectionPropertyChanged: true, + networkQualityLevelChanged: true, recordingStarted: true, recordingStopped: true, signal: true, @@ -225,6 +226,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { streamDestroyed: false, streamPropertyChanged: false, connectionPropertyChanged: false, + networkQualityLevelChanged: false, recordingStarted: false, recordingStopped: false, signal: false, @@ -383,6 +385,15 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { } } + if (this.sessionEvents.networkQualityLevelChanged !== oldValues.networkQualityLevelChanged || firstTime) { + this.session.off('networkQualityLevelChanged'); + if (this.sessionEvents.networkQualityLevelChanged) { + this.session.on('networkQualityLevelChanged', (event: NetworkQualityLevelChangedEvent) => { + this.updateEventList('networkQualityLevelChanged', event.connection.connectionId + ' [new:' + event.newValue + ',old:' + event.oldValue + ']', event); + }); + } + } + if (this.sessionEvents.connectionCreated !== oldValues.connectionCreated || firstTime) { this.session.off('connectionCreated'); if (this.sessionEvents.connectionCreated) { @@ -638,6 +649,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { streamDestroyed: this.sessionEvents.streamDestroyed, streamPropertyChanged: this.sessionEvents.streamPropertyChanged, connectionPropertyChanged: this.sessionEvents.connectionPropertyChanged, + networkQualityLevelChanged: this.sessionEvents.networkQualityLevelChanged, recordingStarted: this.sessionEvents.recordingStarted, recordingStopped: this.sessionEvents.recordingStopped, signal: this.sessionEvents.signal, @@ -671,6 +683,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy { streamDestroyed: result.streamDestroyed, streamPropertyChanged: result.streamPropertyChanged, connectionPropertyChanged: result.connectionPropertyChanged, + networkQualityLevelChanged: result.networkQualityLevelChanged, recordingStarted: result.recordingStarted, recordingStopped: result.recordingStopped, signal: result.signal, diff --git a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts index 6db82d6c..4bff8df3 100644 --- a/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts +++ b/openvidu-testapp/src/app/components/test-sessions/test-sessions.component.ts @@ -38,7 +38,19 @@ export class TestSessionsComponent implements OnInit, OnDestroy { this.eventsInfoSubscription = this.testFeedService.newLastEvent$.subscribe( newEvent => { - (window as any).myEvents += ('' + this.stringifyEventNoCircularDependencies(newEvent)); + const getCircularReplacer = () => { + const seen = new WeakSet(); + return (key, value) => { + if (typeof value === "object" && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + return value; + }; + }; + (window as any).myEvents += ('' + JSON.stringify(newEvent, getCircularReplacer())); }); } @@ -100,28 +112,4 @@ export class TestSessionsComponent implements OnInit, OnDestroy { this.loadSubs(subs); } - stringifyEventNoCircularDependencies(event: Event): string { - const cache = []; - return JSON.stringify(event, function (key, value) { - if (key !== 'ee' && key !== 'openvidu') { - if (typeof value === 'object' && value !== null) { - if (cache.indexOf(value) !== -1) { - // Duplicate reference found - try { - // If this value does not reference a parent - return JSON.parse(JSON.stringify(value)); - } catch (error) { - return; - } - } - // Store value in our collection - cache.push(value); - } - return value; - } else { - return; - } - }); - } - }