You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2021/03/16 15:18:03 UTC

[openmeetings] 01/01: [OPENMEETINGS-2588] non-beans are injected, tests are green

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch injected-fields
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit 5fe24e4ea4045af308f3668dc52096b68e6158cc
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Tue Mar 16 22:17:42 2021 +0700

    [OPENMEETINGS-2588] non-beans are injected, tests are green
---
 openmeetings-core/pom.xml                          |  5 ++
 .../org/apache/openmeetings/core/remote/KRoom.java | 59 ++++++++++++----------
 .../apache/openmeetings/core/remote/KStream.java   | 33 ++++++++----
 .../openmeetings/core/remote/KTestStream.java      | 16 ++++--
 .../openmeetings/core/remote/KurentoHandler.java   | 24 +--------
 .../openmeetings/core/remote/StreamProcessor.java  |  2 +-
 .../core/remote/StreamProcessorActions.java        |  2 +-
 .../core/remote/TestStreamProcessor.java           |  2 +-
 .../openmeetings/core/remote/BaseMockedTest.java   | 50 ++++++++++++++++++
 9 files changed, 125 insertions(+), 68 deletions(-)

diff --git a/openmeetings-core/pom.xml b/openmeetings-core/pom.xml
index dfb1100..7b61a40 100644
--- a/openmeetings-core/pom.xml
+++ b/openmeetings-core/pom.xml
@@ -77,6 +77,11 @@
 			<version>${wicket.version}</version>
 		</dependency>
 		<dependency>
+			<groupId>org.apache.wicket</groupId>
+			<artifactId>wicket-ioc</artifactId>
+			<version>${wicket.version}</version>
+		</dependency>
+		<dependency>
 			<groupId>org.apache.directory.api</groupId>
 			<artifactId>api-all</artifactId>
 			<version>${api-all.version}</version>
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
index 3de644f..04c9a08 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java
@@ -27,10 +27,12 @@ import java.util.Date;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import javax.inject.Inject;
+
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.openmeetings.IApplication;
 import org.apache.openmeetings.core.util.WebSocketHelper;
-import org.apache.openmeetings.db.dao.record.RecordingChunkDao;
+import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.basic.Client.Activity;
 import org.apache.openmeetings.db.entity.basic.Client.StreamDesc;
@@ -43,6 +45,7 @@ import org.apache.openmeetings.db.manager.IClientManager;
 import org.apache.openmeetings.db.util.FormatHelper;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
+import org.apache.wicket.injection.Injector;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,8 +58,15 @@ import com.github.openjson.JSONObject;
 public class KRoom {
 	private static final Logger log = LoggerFactory.getLogger(KRoom.class);
 
-	private final StreamProcessor processor;
-	private final RecordingChunkDao chunkDao;
+	@Inject
+	private KurentoHandler kHandler;
+	@Inject
+	private StreamProcessor processor;
+	@Inject
+	private RecordingDao recDao;
+	@Inject
+	private IClientManager cm;
+
 	private final Room room;
 	private final AtomicBoolean recordingStarted = new AtomicBoolean(false);
 	private final AtomicBoolean sharingStarted = new AtomicBoolean(false);
@@ -65,10 +75,9 @@ public class KRoom {
 	private JSONObject recordingUser = new JSONObject();
 	private JSONObject sharingUser = new JSONObject();
 
-	public KRoom(KurentoHandler handler, Room r) {
-		this.processor = handler.getStreamProcessor();
-		this.chunkDao = handler.getChunkDao();
+	public KRoom(Room r) {
 		this.room = r;
+		Injector.get().inject(this);
 		log.info("ROOM {} has been created", room.getId());
 	}
 
@@ -80,13 +89,9 @@ public class KRoom {
 		return recordingId;
 	}
 
-	public RecordingChunkDao getChunkDao() {
-		return chunkDao;
-	}
-
-	public KStream join(final StreamDesc sd, KurentoHandler kHandler) {
+	public KStream join(final StreamDesc sd) {
 		log.info("ROOM {}: join client {}, stream: {}", room.getId(), sd.getClient(), sd.getUid());
-		final KStream stream = new KStream(sd, this, kHandler);
+		final KStream stream = new KStream(sd, this);
 		processor.addStream(stream);
 		return stream;
 	}
@@ -144,11 +149,11 @@ public class KRoom {
 			Optional<StreamDesc> osd = c.getScreenStream();
 			if (osd.isPresent()) {
 				osd.get().addActivity(Activity.RECORD);
-				processor.getClientManager().update(c);
+				cm.update(c);
 				rec.setWidth(osd.get().getWidth());
 				rec.setHeight(osd.get().getHeight());
 			}
-			rec = processor.getRecordingDao().update(rec);
+			rec = recDao.update(rec);
 			// Receive recordingId
 			recordingId = rec.getId();
 			processor.getByRoom(room.getId()).forEach(KStream::startRecord);
@@ -163,9 +168,9 @@ public class KRoom {
 		if (recordingStarted.compareAndSet(true, false)) {
 			log.debug("##REC:: recording in room {} is stopping {} ::", room.getId(), recordingId);
 			processor.getByRoom(room.getId()).forEach(KStream::stopRecord);
-			Recording rec = processor.getRecordingDao().get(recordingId);
+			Recording rec = recDao.get(recordingId);
 			rec.setRecordEnd(new Date());
-			rec = processor.getRecordingDao().update(rec);
+			rec = recDao.update(rec);
 			recordingUser = new JSONObject();
 			recordingId = null;
 
@@ -178,8 +183,8 @@ public class KRoom {
 				Optional<StreamDesc> osd = c.getScreenStream();
 				if (osd.isPresent()) {
 					osd.get().removeActivity(Activity.RECORD);
-					processor.getClientManager().update(c);
-					processor.getHandler().sendShareUpdated(osd.get());
+					cm.update(c);
+					kHandler.sendShareUpdated(osd.get());
 				}
 			}
 			// Send notification to all users that the recording has been started
@@ -203,29 +208,28 @@ public class KRoom {
 		return new JSONObject(sharingUser.toString());
 	}
 
-	public void startSharing(StreamProcessor processor, IClientManager cm, Client c, Optional<StreamDesc> osd, JSONObject msg, Activity a) {
+	public void startSharing(Client c, Optional<StreamDesc> osd, JSONObject msg, Activity a) {
 		StreamDesc sd;
-		KurentoHandler h = processor.getHandler();
 		if (sharingStarted.compareAndSet(false, true)) {
 			sharingUser.put("sid", c.getSid());
 			sd = c.addStream(StreamType.SCREEN, a);
 			cm.update(c);
 			log.debug("Stream.UID {}: sharing has been started, activity: {}", sd.getUid(), a);
-			h.sendClient(sd.getSid(), newKurentoMsg()
+			kHandler.sendClient(sd.getSid(), newKurentoMsg()
 					.put("id", "broadcast")
 					.put("stream", sd.toJson()
 							.put("shareType", msg.getString("shareType"))
 							.put("fps", msg.getString("fps")))
-					.put(PARAM_ICE, h.getTurnServers(c)));
+					.put(PARAM_ICE, kHandler.getTurnServers(c)));
 		} else if (osd.isPresent() && !osd.get().hasActivity(a)) {
 			sd = osd.get();
 			sd.addActivity(a);
 			cm.update(c);
-			h.sendShareUpdated(sd);
+			kHandler.sendShareUpdated(sd);
 			WebSocketHelper.sendRoom(new TextRoomMessage(c.getRoomId(), c, RoomMessage.Type.RIGHT_UPDATED, c.getUid()));
 			WebSocketHelper.sendRoomOthers(room.getId(), c.getUid(), newKurentoMsg()
 					.put("id", "newStream")
-					.put(PARAM_ICE, processor.getHandler().getTurnServers(c))
+					.put(PARAM_ICE, kHandler.getTurnServers(c))
 					.put("stream", sd.toJson()));
 		}
 	}
@@ -245,17 +249,16 @@ public class KRoom {
 		if (count != sipCount) {
 			processor.getByRoom(room.getId()).forEach(stream -> stream.addSipProcessor(count));
 			if (sipCount == 0) {
-				processor.getClientManager()
-					.streamByRoom(room.getId())
+				cm.streamByRoom(room.getId())
 					.filter(Client::isSip)
 					.findAny()
 					.ifPresent(c -> {
 						StreamDesc sd = c.addStream(StreamType.WEBCAM, Activity.AUDIO);
 						sd.setWidth(120).setHeight(90);
 						c.restoreActivities(sd);
-						KStream stream = join(sd, processor.getHandler());
+						KStream stream = join(sd);
 						stream.startBroadcast(sd, "", () -> {});
-						processor.getClientManager().update(c);
+						cm.update(c);
 					});
 			}
 			sipCount = count;
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
index 56f2a58..f461c6d 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java
@@ -43,9 +43,13 @@ import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
+import javax.inject.Inject;
+
 import org.apache.openmeetings.core.sip.ISipCallbacks;
+import org.apache.openmeetings.core.sip.SipManager;
 import org.apache.openmeetings.core.sip.SipStackProcessor;
 import org.apache.openmeetings.core.util.WebSocketHelper;
+import org.apache.openmeetings.db.dao.record.RecordingChunkDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.basic.Client.Activity;
 import org.apache.openmeetings.db.entity.basic.Client.StreamDesc;
@@ -54,6 +58,7 @@ import org.apache.openmeetings.db.entity.record.RecordingChunk.Type;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.util.OmFileHelper;
+import org.apache.wicket.injection.Injector;
 import org.kurento.client.BaseRtpEndpoint;
 import org.kurento.client.Continuation;
 import org.kurento.client.IceCandidate;
@@ -75,7 +80,15 @@ import com.github.openjson.JSONObject;
 public class KStream extends AbstractStream implements ISipCallbacks {
 	private static final Logger log = LoggerFactory.getLogger(KStream.class);
 
-	private final KurentoHandler kHandler;
+	@Inject
+	private KurentoHandler kHandler;
+	@Inject
+	private StreamProcessor processor;
+	@Inject
+	private RecordingChunkDao chunkDao;
+	@Inject
+	private SipManager sipManager;
+
 	private final KRoom kRoom;
 	private final Date connectedSince;
 	private final StreamType streamType;
@@ -96,12 +109,12 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 	private boolean hasScreen;
 	private boolean sipClient;
 
-	public KStream(final StreamDesc sd, KRoom kRoom, KurentoHandler kHandler) {
+	public KStream(final StreamDesc sd, KRoom kRoom) {
 		super(sd.getSid(), sd.getUid());
 		this.kRoom = kRoom;
 		streamType = sd.getType();
 		this.connectedSince = new Date();
-		this.kHandler = kHandler;
+		Injector.get().inject(this);
 		//TODO Min/MaxVideoSendBandwidth
 		//TODO Min/Max Audio/Video RecvBandwidth
 	}
@@ -189,7 +202,7 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 				flowoutFuture = Optional.of(new CompletableFuture<>().completeAsync(() -> {
 					log.warn("KStream will be dropped {}, sid {}, uid {}", sd, sid, uid);
 					if (StreamType.SCREEN == streamType) {
-						kHandler.getStreamProcessor().doStopSharing(sid, uid);
+						processor.doStopSharing(sid, uid);
 					}
 					stopBroadcast();
 					return null;
@@ -275,7 +288,7 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 		listeners.put(uid, listener);
 
 		log.debug("PARTICIPANT {}: obtained endpoint for {}", uid, this.uid);
-		Client cur = kHandler.getStreamProcessor().getBySid(this.sid);
+		Client cur = processor.getBySid(this.sid);
 		if (cur == null) {
 			log.warn("Client for endpoint dooesn't exists");
 		} else {
@@ -338,9 +351,9 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 		recorder = createRecorderEndpoint(pipeline, getRecUri(getRecordingChunk(getRoomId(), chunkUid)), profile);
 		setTags(recorder, uid);
 
-		recorder.addRecordingListener(evt -> chunkId = kRoom.getChunkDao().start(kRoom.getRecordingId(), type, chunkUid, sid));
+		recorder.addRecordingListener(evt -> chunkId = chunkDao.start(kRoom.getRecordingId(), type, chunkUid, sid));
 		recorder.addStoppedListener(evt -> {
-			kRoom.getChunkDao().stop(chunkId);
+			chunkDao.stop(chunkId);
 			chunkId = null;
 		});
 		switch (profile) {
@@ -459,7 +472,7 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 
 	private void doRemove(boolean remove) {
 		if (remove) {
-			kHandler.getStreamProcessor().release(this, false);
+			processor.release(this, false);
 		}
 	}
 
@@ -606,7 +619,7 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 		if (count > 0) {
 			if (sipProcessor.isEmpty()) {
 				try {
-					sipProcessor = kHandler.getSipManager().createSipStackProcessor(
+					sipProcessor = sipManager.createSipStackProcessor(
 							randomUUID().toString()
 							, kRoom.getRoom()
 							, this);
@@ -644,7 +657,7 @@ public class KStream extends AbstractStream implements ISipCallbacks {
 		answerConsumer.accept(answer);
 		log.debug(answer);
 		if (sipClient) {
-			StreamDesc sd = kHandler.getStreamProcessor().getBySid(sid).getStream(uid);
+			StreamDesc sd = processor.getBySid(sid).getStream(uid);
 			try {
 				outgoingMedia = rtpEndpoint;
 				internalStartBroadcast(sd, sdp);
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java
index 741c1f6..57111ed 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java
@@ -36,9 +36,12 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
+import javax.inject.Inject;
+
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.entity.basic.IWsClient;
 import org.apache.openmeetings.util.OmFileHelper;
+import org.apache.wicket.injection.Injector;
 import org.kurento.client.Continuation;
 import org.kurento.client.IceCandidate;
 import org.kurento.client.MediaPipeline;
@@ -55,7 +58,12 @@ import com.github.openjson.JSONObject;
 public class KTestStream extends AbstractStream {
 	private static final Logger log = LoggerFactory.getLogger(KTestStream.class);
 	private static final Map<String, String> TAGS = Map.of(TAG_MODE, MODE_TEST, TAG_ROOM, MODE_TEST);
-	private final KurentoHandler kHandler;
+
+	@Inject
+	private KurentoHandler kHandler;
+	@Inject
+	private TestStreamProcessor processor;
+
 	private MediaPipeline pipeline;
 	private WebRtcEndpoint webRtcEndpoint;
 	private PlayerEndpoint player;
@@ -65,9 +73,9 @@ public class KTestStream extends AbstractStream {
 	private ScheduledFuture<?> recHandle;
 	private int recTime;
 
-	public KTestStream(IWsClient c, JSONObject msg, KurentoHandler kHandler) {
+	public KTestStream(IWsClient c, JSONObject msg) {
 		super(null, c.getUid());
-		this.kHandler = kHandler;
+		Injector.get().inject(this);
 		createPipeline(() -> startTestRecording(c, msg));
 	}
 
@@ -251,7 +259,7 @@ public class KTestStream extends AbstractStream {
 		releasePlayer();
 		releaseRecorder();
 		if (remove) {
-			kHandler.getTestProcessor().release(this, true);
+			processor.release(this, true);
 		}
 	}
 }
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
index 1e8ebb4..a301dce 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KurentoHandler.java
@@ -41,9 +41,7 @@ import javax.annotation.PreDestroy;
 import javax.crypto.Mac;
 import javax.crypto.spec.SecretKeySpec;
 
-import org.apache.openmeetings.core.sip.SipManager;
 import org.apache.openmeetings.core.util.WebSocketHelper;
-import org.apache.openmeetings.db.dao.record.RecordingChunkDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.basic.Client.Activity;
@@ -125,13 +123,9 @@ public class KurentoHandler {
 	@Autowired
 	private RoomDao roomDao;
 	@Autowired
-	private RecordingChunkDao chunkDao;
-	@Autowired
 	private TestStreamProcessor testProcessor;
 	@Autowired
 	private StreamProcessor streamProcessor;
-	@Autowired
-	private SipManager sipManager;
 
 	boolean isConnected() {
 		boolean connctd = connected.get() && client != null && !client.isClosed();
@@ -309,7 +303,7 @@ public class KurentoHandler {
 		return rooms.computeIfAbsent(roomId, k -> {
 			log.debug("Room {} does not exist. Will create now!", roomId);
 			Room r = roomDao.get(roomId);
-			return new KRoom(this, r);
+			return new KRoom(r);
 		});
 	}
 
@@ -397,22 +391,6 @@ public class KurentoHandler {
 		return kuid;
 	}
 
-	public TestStreamProcessor getTestProcessor() {
-		return testProcessor;
-	}
-
-	StreamProcessor getStreamProcessor() {
-		return streamProcessor;
-	}
-
-	SipManager getSipManager() {
-		return sipManager;
-	}
-
-	RecordingChunkDao getChunkDao() {
-		return chunkDao;
-	}
-
 	static int getFlowoutTimeout() {
 		return flowoutTimeout;
 	}
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessor.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessor.java
index 3771c0c..d99edb9 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessor.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessor.java
@@ -322,7 +322,7 @@ public class StreamProcessor implements IStreamProcessor {
 
 	private void startSharing(Client c, Optional<StreamDesc> osd, JSONObject msg, Activity a) {
 		if (kHandler.isConnected() && c.getRoomId() != null) {
-			kHandler.getRoom(c.getRoomId()).startSharing(this, cm, c, osd, msg, a);
+			kHandler.getRoom(c.getRoomId()).startSharing(c, osd, msg, a);
 		}
 	}
 
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessorActions.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessorActions.java
index 8608485..b80a290 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessorActions.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/StreamProcessorActions.java
@@ -107,7 +107,7 @@ public class StreamProcessorActions {
 		try {
 			if (sender == null) {
 				KRoom room = kHandler.getRoom(c.getRoomId());
-				sender = room.join(sd, kHandler);
+				sender = room.join(sd);
 			}
 			if (msg.has("width")) {
 				sd.setWidth(msg.getInt("width")).setHeight(msg.getInt("height"));
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/TestStreamProcessor.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/TestStreamProcessor.java
index 499d772..3bd7bde 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/TestStreamProcessor.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/TestStreamProcessor.java
@@ -56,7 +56,7 @@ class TestStreamProcessor implements IStreamProcessor {
 				if (user != null) {
 					user.release();
 				}
-				user = new KTestStream(c, msg, kHandler);
+				user = new KTestStream(c, msg);
 				streamByUid.put(c.getUid(), user);
 				break;
 			case "iceCandidate":
diff --git a/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java b/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java
index 4d94aa0..86f0211 100644
--- a/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java
+++ b/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java
@@ -22,11 +22,18 @@ package org.apache.openmeetings.core.remote;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.withSettings;
+import static org.mockito.internal.util.collections.Sets.newMockSafeHashSet;
 
+import java.lang.reflect.Field;
 import java.util.Locale;
+import java.util.Set;
+
+import javax.inject.Inject;
 
 import org.apache.openmeetings.IApplication;
 import org.apache.openmeetings.core.util.WebSocketHelper;
@@ -34,6 +41,7 @@ import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.entity.basic.IWsClient;
 import org.apache.openmeetings.db.entity.label.OmLanguage;
 import org.apache.openmeetings.db.util.ApplicationHelper;
+import org.apache.wicket.injection.Injector;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.kurento.client.KurentoClient;
@@ -49,14 +57,18 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockedStatic;
 import org.mockito.Spy;
+import org.mockito.internal.configuration.injection.scanner.MockScanner;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.stubbing.Answer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.github.openjson.JSONObject;
 
 @ExtendWith(MockitoExtension.class)
 public class BaseMockedTest {
+	private static final Logger log = LoggerFactory.getLogger(BaseMockedTest.class);
 	@Mock
 	protected RomManager romManager;
 	@Mock
@@ -90,8 +102,12 @@ public class BaseMockedTest {
 				MockedStatic<WebSocketHelper> wsHelperMock = mockStatic(WebSocketHelper.class);
 				MockedStatic<LabelDao> labelMock = mockStatic(LabelDao.class);
 				MockedStatic<ApplicationHelper> appHelpMock = mockStatic(ApplicationHelper.class);
+				MockedStatic<Injector> injectMock = mockStatic(Injector.class)
 				)
 		{
+			Set<Object> mocks = newMockSafeHashSet();
+			new MockScanner(this, BaseMockedTest.class).addPreparedMocks(mocks);
+			new MockScanner(this, this.getClass()).addPreparedMocks(mocks);
 			wsHelperMock.when(() -> WebSocketHelper.sendClient(any(IWsClient.class), any(JSONObject.class))).thenAnswer(new Answer<Void>() {
 				@Override
 				public Void answer(InvocationOnMock invocation) throws Throwable {
@@ -104,7 +120,41 @@ public class BaseMockedTest {
 
 			labelMock.when(() -> LabelDao.getLanguage(any(Long.class))).thenReturn(new OmLanguage(1L, Locale.ENGLISH));
 			appHelpMock.when(() -> ApplicationHelper.ensureApplication(any(Long.class))).thenReturn(mock(IApplication.class));
+			Injector injector = mock(Injector.class, withSettings().lenient());
+			doAnswer(new Answer<Void>() {
+				@Override
+				public Void answer(InvocationOnMock invocation) throws Throwable {
+					Object o = invocation.getArgument(0);
+					if (forInjection(o)) {
+						inject(o, mocks);
+					}
+					return null;
+				}
+			}).when(injector).inject(any());
+			injectMock.when(() -> Injector.get()).thenReturn(injector);
 			task.run();
 		}
 	}
+
+	private boolean forInjection(Object o) {
+		return o instanceof KRoom || o instanceof KStream || o instanceof KTestStream;
+	}
+
+	private void inject(Object o, Set<Object> mocks) {
+		for (Field f : o.getClass().getDeclaredFields()) {
+			if (f.isAnnotationPresent(Inject.class)) {
+				mocks.stream()
+						.filter(mock -> f.getType().isAssignableFrom(mock.getClass()))
+						.findAny()
+						.ifPresent(mock -> {
+							try {
+								f.setAccessible(true);
+								f.set(o, mock);
+							} catch (Exception e) {
+								log.error("Fail to set mock {} {}", f, mock);
+							}
+						});
+			}
+		}
+	}
 }