/* * (C) Copyright 2014 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.stability.pipeline; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Ignore; import org.kurento.client.EventListener; import org.kurento.client.IceCandidateFoundEvent; import org.kurento.client.IceComponentState; import org.kurento.client.IceComponentStateChangeEvent; import org.kurento.client.ListenerSubscription; import org.kurento.client.MediaPipeline; import org.kurento.client.ObjectCreatedEvent; import org.kurento.client.ObjectDestroyedEvent; import org.kurento.client.WebRtcEndpoint; /** * Stability test for Pipelines and WebRtcEndpoints. Connect by pairs and establish the connection * <br/> * * * <pre> * Pipeline: * WebRtc1 <-> WebRtc2 WebRtc3 <-> WebRtc4 ..... WebRtcN-1 <-> WebRtcN * </pre> * * Test logic: <br/> * <ul> * <li>The test procedure will be repeated during i iterations</li> * <li>N is 2^i</li> * </ul> * * Test procedure: <br/> * <ol> * <li>Create M pipelines</li> * <li>Create N webRtcEndpoints in each pipeline</li> * <li>Connect by pairs and establish the connection</li> * <li>Release N webRtcEndpoints. Depends of the test, this point will be executed or not</li> * <li>Release M pipelines</li> * </ol> * * Main assertion(s): * <ul> * <li>((M * N) + M) Object_Created are received</li> * <li>((M * N) + M) Object_Destroyed are received</li> * <li>N CONNECTED are received</li> * <li>The % of the memory is between 0 and 10. * </ul> * * * @author Raul Benitez (rbenitez@gsyc.es) * @since 6.5.1 */ @Ignore public class PipelineStabilityCreateDestroyWebRtcAndEstablishConnectionTest extends BasePipeline { private int INCREASE_EXPONENTIAL = 2; private int ITERATIONS = 11; private int M = 4; private ObjectsLatch objectsLatch; @Ignore public void testCreateDestroyWebRtcAndEstablishConnectionOnePipelineDestroyPipeline() throws Exception { // Stabilize the memory on the KMS doTest(1, false, false); // Use the assert for checking memory doTest(1, false, true); } @Ignore public void testCreateDestroyWebRtcAndEstablishConnectionOnePipelineDestroyEachWebRtc() throws Exception { // Stabilize the memory on the KMS doTest(1, true, false); // Use the assert for checking memory doTest(1, true, true); } @Ignore public void testCreateDestroyWebRtcAndEstablishConnectionWebRtcMPipelineDestroyPipeline() throws Exception { // Stabilize the memory on the KMS doTest(M, false, false); // Use the assert for checking memory doTest(M, false, true); } @Ignore public void testCreateDestroyWebRtcAndEstablishConnectionMPipelineDestroyEachWebRtc() throws Exception { // Stabilize the memory on the KMS doTest(M, true, false); // Use the assert for checking memory doTest(M, true, true); } /** * * @param numPipelinesToCreate * Define the number of the pipelines that will be created * @param destroyEachWebRtc * Define if each webRtc will be released one by one * @param checkMemory * Activate the memory assert. * @throws Exception */ private void doTest(int numPipelinesToCreate, boolean destroyEachWebRtc, boolean checkMemory) throws Exception { initMemory(); ListenerSubscription listenerObjectCreated = getServerManager().addObjectCreatedListener(new EventListener<ObjectCreatedEvent>() { @Override public void onEvent(ObjectCreatedEvent event) { objectsLatch.getObjectsCreatedLatch().countDown(); } }); ListenerSubscription listenerObjectDestroyed = getServerManager().addObjectDestroyedListener(new EventListener<ObjectDestroyedEvent>() { @Override public void onEvent(ObjectDestroyedEvent event) { objectsLatch.getObjectsDestroyedLatch().countDown(); } }); int webRtcEndpointToCreate = 0; int objectsToCreate = 0; for (int i = 1; i <= ITERATIONS; i++) { webRtcEndpointToCreate = (int) Math.pow(INCREASE_EXPONENTIAL, i); objectsToCreate = (webRtcEndpointToCreate * numPipelinesToCreate) + numPipelinesToCreate; log.debug( "Create {} MediaPipelines; Create {} WebRtcEndpoints by MediaPipeline; Total: {} objects", numPipelinesToCreate, webRtcEndpointToCreate, objectsToCreate); ArrayList<WebRtcEndpoint> webRtcEndpoints = new ArrayList<WebRtcEndpoint>(); ArrayList<MediaPipeline> mediaPipelines = new ArrayList<MediaPipeline>(); final Set<WebRtcEndpoint> webRtcEndpointsConnected = new HashSet<WebRtcEndpoint>(); objectsLatch = new ObjectsLatch(objectsToCreate); final CountDownLatch connectedLatch = new CountDownLatch(webRtcEndpointToCreate); for (int j = 0; j < numPipelinesToCreate; j++) { MediaPipeline mp = kurentoClient.createMediaPipeline(); mediaPipelines.add(mp); for (int k = 0; k < webRtcEndpointToCreate; k++) { final WebRtcEndpoint webRtcEp = new WebRtcEndpoint.Builder(mp).build(); webRtcEndpoints.add(webRtcEp); webRtcEp.addIceComponentStateChangeListener( new EventListener<IceComponentStateChangeEvent>() { private boolean executed = false; @Override public void onEvent(IceComponentStateChangeEvent event) { // Only executes once when the state is CONNECTED if (!executed) { if (event.getState().equals(IceComponentState.CONNECTED)) { if (!webRtcEndpointsConnected.contains(event.getSource())) { connectedLatch.countDown(); } webRtcEndpointsConnected.add((WebRtcEndpoint) event.getSource()); executed = true; } } } }); } for (int k = 0; k < webRtcEndpoints.size(); k = k + 2) { final WebRtcEndpoint webRtcEp1 = webRtcEndpoints.get(k); final WebRtcEndpoint webRtcEp2 = webRtcEndpoints.get(k + 1); webRtcEp1.addIceCandidateFoundListener(new EventListener<IceCandidateFoundEvent>() { @Override public void onEvent(IceCandidateFoundEvent event) { webRtcEp2.addIceCandidate(event.getCandidate()); } }); webRtcEp2.addIceCandidateFoundListener(new EventListener<IceCandidateFoundEvent>() { @Override public void onEvent(IceCandidateFoundEvent event) { webRtcEp1.addIceCandidate(event.getCandidate()); } }); webRtcEp1.connect(webRtcEp2); webRtcEp2.connect(webRtcEp1); String sdpOffer = webRtcEp1.generateOffer(); String sdpAnswer = webRtcEp2.processOffer(sdpOffer); webRtcEp2.gatherCandidates(); webRtcEp1.processAnswer(sdpAnswer); webRtcEp1.gatherCandidates(); } } // Wait to all objects are created Assert.assertTrue( "The Objects are not created properly. Expected: " + objectsToCreate + ". No received " + (objectsToCreate - objectsLatch.getObjectsCreatedLatch().getCount()) + " ObjectCreated event(s)", objectsLatch.getObjectsCreatedLatch().await(TIMEOUT, TimeUnit.SECONDS)); // Wait to all connected events are received Assert.assertTrue( "All connections are wrong. Expected: " + webRtcEndpointToCreate + ". No received " + (webRtcEndpointToCreate - connectedLatch.getCount()) + " CONNECTED event(s)", connectedLatch.await(TIMEOUT, TimeUnit.SECONDS)); Assert.assertTrue( (webRtcEndpointToCreate - webRtcEndpointsConnected.size()) + " webRtcEndpoint(s) weren't connected", webRtcEndpointsConnected.size() == webRtcEndpointToCreate); if (destroyEachWebRtc) { // Release all webRtcEndpoints for (WebRtcEndpoint webRtcEp : webRtcEndpoints) { webRtcEp.release(); } } // Release each MediaPipeline for (MediaPipeline pipeline : mediaPipelines) { pipeline.release(); } Assert.assertTrue( "The Objects are not destroyed properly. Expected: " + objectsToCreate + ". No received " + (objectsToCreate - objectsLatch.getObjectsDestroyedLatch().getCount()) + " ObjectDestroyed event(s)", objectsLatch.getObjectsDestroyedLatch().await(TIMEOUT, TimeUnit.SECONDS)); // Verify the memory double percentageMemory = getMemoryIncrease(); if (checkMemory) { Assert.assertTrue( "The memory increases more than 0%. The percentage memory was " + percentageMemory, percentageMemory >= 0.0 && percentageMemory <= 10.0); } } getServerManager().removeObjectCreatedListener(listenerObjectCreated); getServerManager().removeObjectDestroyedListener(listenerObjectDestroyed); } }