From 527f7176c54710b395bbb332bfed3e3a35441657 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 1 Jan 2025 14:25:28 +0100 Subject: [PATCH 1/2] tbel test refactored to not use sql and all controllers. reflection utils used --- .../script/AbstractTbelInvokeTest.java | 5 ++++- .../service/script/TbelInvokeDocsIoTest.java | 2 -- .../service/script/TbelInvokeServiceTest.java | 19 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java b/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java index 11b61f64c4..dcd73bac50 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java @@ -16,8 +16,10 @@ package org.thingsboard.server.service.script; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.ScriptType; +import org.thingsboard.script.api.tbel.DefaultTbelInvokeService; import org.thingsboard.script.api.tbel.TbelInvokeService; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.controller.AbstractControllerTest; @@ -28,7 +30,8 @@ import java.util.concurrent.ExecutionException; import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; -public abstract class AbstractTbelInvokeTest extends AbstractControllerTest { +@SpringBootTest(classes = DefaultTbelInvokeService.class) +public abstract class AbstractTbelInvokeTest { @Autowired protected TbelInvokeService invokeService; diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java index d72dd87992..cc51a7063c 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java @@ -18,7 +18,6 @@ package org.thingsboard.server.service.script; import org.junit.jupiter.api.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.tbel.TbDate; -import org.thingsboard.server.dao.service.DaoSqlTest; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -34,7 +33,6 @@ import java.util.concurrent.atomic.AtomicReference; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; -@DaoSqlTest class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { private String decoderStr; diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java index 071fdf77fc..62170236e0 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java @@ -22,9 +22,9 @@ import org.junit.Ignore; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.TestPropertySource; +import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.tbel.TbelScript; -import org.thingsboard.server.dao.service.DaoSqlTest; import java.io.Serializable; import java.util.ArrayList; @@ -38,7 +38,6 @@ import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -@DaoSqlTest @TestPropertySource(properties = { "tbel.max_script_body_size=100", "tbel.max_total_args_size=50", @@ -120,9 +119,9 @@ class TbelInvokeServiceTest extends AbstractTbelInvokeTest { scriptsIds.add(scriptId); } - Map scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash"); - Map scriptMap = getFieldValue(invokeService, "scriptMap"); - Cache compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache"); + Map scriptIdToHash = (Map) ReflectionTestUtils.getField(invokeService, "scriptIdToHash"); + Map scriptMap = (Map) ReflectionTestUtils.getField(invokeService, "scriptMap"); + Cache compiledScriptsCache = (Cache) ReflectionTestUtils.getField(invokeService, "compiledScriptsCache"); String scriptHash = scriptIdToHash.get(scriptsIds.get(0)); @@ -140,9 +139,9 @@ class TbelInvokeServiceTest extends AbstractTbelInvokeTest { scriptsIds.add(scriptId); } - Map scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash"); - Map scriptMap = getFieldValue(invokeService, "scriptMap"); - Cache compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache"); + Map scriptIdToHash = (Map) ReflectionTestUtils.getField(invokeService, "scriptIdToHash"); + Map scriptMap = (Map) ReflectionTestUtils.getField(invokeService, "scriptMap"); + Cache compiledScriptsCache = (Cache) ReflectionTestUtils.getField(invokeService, "compiledScriptsCache"); String scriptHash = scriptIdToHash.get(scriptsIds.get(0)); for (int i = 0; i < 9; i++) { @@ -163,8 +162,8 @@ class TbelInvokeServiceTest extends AbstractTbelInvokeTest { @Ignore("This test is based on assumption that Caffeine cache is LRU based but in fact it is based on " + "Tiny LFU which is the cause that the tests fail sometime: https://arxiv.org/pdf/1512.00727.pdf") public void whenCompiledScriptsCacheIsTooBig_thenRemoveRarelyUsedScripts() throws Exception { - Map scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash"); - Cache compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache"); + Map scriptIdToHash = (Map) ReflectionTestUtils.getField(invokeService, "scriptIdToHash"); + Cache compiledScriptsCache = (Cache) ReflectionTestUtils.getField(invokeService, "compiledScriptsCache"); List scriptsIds = new ArrayList<>(); for (int i = 0; i < 110; i++) { // tbel.compiled_scripts_cache_size = 100 From e1b29b500446943a2ca646bb56341c89cb8ba5d4 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 1 Jan 2025 14:28:38 +0100 Subject: [PATCH 2/2] removed custom reflection methods in favour ReflectionUtils --- .../service/ttl/AlarmsCleanUpService.java | 10 ++++-- .../server/controller/AbstractWebTest.java | 31 ------------------- .../service/ttl/AlarmsCleanUpServiceTest.java | 17 +++++----- 3 files changed, 17 insertions(+), 41 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java index dd80eba6bc..75a459c283 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.ttl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -66,7 +67,7 @@ public class AlarmsCleanUpService { try { cleanUp(tenantId); } catch (Exception e) { - log.warn("Failed to clean up alarms by ttl for tenant {}", tenantId, e); + getLogger().warn("Failed to clean up alarms by ttl for tenant {}", tenantId, e); } } } @@ -105,8 +106,13 @@ public class AlarmsCleanUpService { alarmService.delAlarmTypes(tenantId, typesToRemove); if (totalRemoved > 0) { - log.info("Removed {} outdated alarm(s) for tenant {} older than {}", totalRemoved, tenantId, new Date(expirationTime)); + getLogger().info("Removed {} outdated alarm(s) for tenant {} older than {}", totalRemoved, tenantId, new Date(expirationTime)); } } + // wrapper for tests to spy on static logger + Logger getLogger() { + return log; + } + } diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index aef4772053..5649caee5a 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -149,10 +149,6 @@ import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.sql.SQLException; import java.util.ArrayList; @@ -1053,33 +1049,6 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { throw new AssertionError("Unexpected status " + mvcResult.getResponse().getStatus()); } - protected static T getFieldValue(Object target, String fieldName) throws Exception { - Field field = target.getClass().getDeclaredField(fieldName); - field.setAccessible(true); - return (T) field.get(target); - } - - protected static void setStaticFieldValue(Class targetCls, String fieldName, Object value) throws Exception { - Field field = targetCls.getDeclaredField(fieldName); - field.setAccessible(true); - field.set(null, value); - } - - protected static void setStaticFinalFieldValue(Class targetCls, String fieldName, Object value) throws Exception { - Field field = targetCls.getDeclaredField(fieldName); - field.setAccessible(true); - // Get the VarHandle for the 'modifiers' field in the Field class - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup()); - VarHandle modifiersHandle = lookup.findVarHandle(Field.class, "modifiers", int.class); - - // Remove the final modifier from the field - int currentModifiers = field.getModifiers(); - modifiersHandle.set(field, currentModifiers & ~Modifier.FINAL); - - // Set the new value - field.set(null, value); - } - protected int getDeviceActorSubscriptionCount(DeviceId deviceId, FeatureType featureType) { DeviceActorMessageProcessor processor = getDeviceActorProcessor(deviceId); Map subscriptions = (Map) ReflectionTestUtils.getField(processor, getMapName(featureType)); diff --git a/application/src/test/java/org/thingsboard/server/service/ttl/AlarmsCleanUpServiceTest.java b/application/src/test/java/org/thingsboard/server/service/ttl/AlarmsCleanUpServiceTest.java index 7b9cb0ed4d..6206523d4d 100644 --- a/application/src/test/java/org/thingsboard/server/service/ttl/AlarmsCleanUpServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/ttl/AlarmsCleanUpServiceTest.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.service.ttl; -import org.junit.BeforeClass; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.slf4j.Logger; @@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.startsWith; +import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -49,19 +50,19 @@ import static org.mockito.Mockito.verify; }) public class AlarmsCleanUpServiceTest extends AbstractControllerTest { - @Autowired + @SpyBean private AlarmsCleanUpService alarmsCleanUpService; @SpyBean private AlarmService alarmService; @Autowired private AlarmDao alarmDao; - private static Logger cleanUpServiceLogger; + private Logger cleanUpServiceLoggerSpy; - @BeforeClass - public static void before() throws Exception { - cleanUpServiceLogger = Mockito.spy(LoggerFactory.getLogger(AlarmsCleanUpService.class)); - setStaticFinalFieldValue(AlarmsCleanUpService.class, "log", cleanUpServiceLogger); + @Before + public void beforeEach() throws Exception { + cleanUpServiceLoggerSpy = Mockito.spy(LoggerFactory.getLogger(AlarmsCleanUpService.class)); + willReturn(cleanUpServiceLoggerSpy).given(alarmsCleanUpService).getLogger(); } @Test @@ -110,7 +111,7 @@ public class AlarmsCleanUpServiceTest extends AbstractControllerTest { verify(alarmService, never()).delAlarm(eq(tenantId), eq(freshAlarm), eq(false)); } - verify(cleanUpServiceLogger).info(startsWith("Removed {} outdated alarm"), eq((long) count), eq(tenantId), any()); + verify(cleanUpServiceLoggerSpy).info(startsWith("Removed {} outdated alarm"), eq((long) count), eq(tenantId), any()); } }