Merge branch 'master' into fix_bug_lwm2m_profile_update_dynamic

This commit is contained in:
nick 2025-01-08 16:17:56 +02:00
commit df8d9e2540
12 changed files with 53 additions and 1716 deletions

View File

@ -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;
}
}

View File

@ -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> 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<UUID, SessionInfo> subscriptions = (Map<UUID, SessionInfo>) ReflectionTestUtils.getField(processor, getMapName(featureType));

View File

@ -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;

View File

@ -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;

View File

@ -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<UUID, String> scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash");
Map<String, TbelScript> scriptMap = getFieldValue(invokeService, "scriptMap");
Cache<String, Serializable> compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache");
Map<UUID, String> scriptIdToHash = (Map<UUID, String>) ReflectionTestUtils.getField(invokeService, "scriptIdToHash");
Map<String, TbelScript> scriptMap = (Map<String, TbelScript>) ReflectionTestUtils.getField(invokeService, "scriptMap");
Cache<String, Serializable> compiledScriptsCache = (Cache<String, Serializable>) ReflectionTestUtils.getField(invokeService, "compiledScriptsCache");
String scriptHash = scriptIdToHash.get(scriptsIds.get(0));
@ -140,9 +139,9 @@ class TbelInvokeServiceTest extends AbstractTbelInvokeTest {
scriptsIds.add(scriptId);
}
Map<UUID, String> scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash");
Map<String, TbelScript> scriptMap = getFieldValue(invokeService, "scriptMap");
Cache<String, Serializable> compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache");
Map<UUID, String> scriptIdToHash = (Map<UUID, String>) ReflectionTestUtils.getField(invokeService, "scriptIdToHash");
Map<String, TbelScript> scriptMap = (Map<String, TbelScript>) ReflectionTestUtils.getField(invokeService, "scriptMap");
Cache<String, Serializable> compiledScriptsCache = (Cache<String, Serializable>) 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<UUID, String> scriptIdToHash = getFieldValue(invokeService, "scriptIdToHash");
Cache<String, Serializable> compiledScriptsCache = getFieldValue(invokeService, "compiledScriptsCache");
Map<UUID, String> scriptIdToHash = (Map<UUID, String>) ReflectionTestUtils.getField(invokeService, "scriptIdToHash");
Cache<String, Serializable> compiledScriptsCache = (Cache<String, Serializable>) ReflectionTestUtils.getField(invokeService, "compiledScriptsCache");
List<UUID> scriptsIds = new ArrayList<>();
for (int i = 0; i < 110; i++) { // tbel.compiled_scripts_cache_size = 100

View File

@ -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());
}
}

View File

@ -16,8 +16,6 @@
export interface TbMessage {
scriptIdMSB: string; // deprecated
scriptIdLSB: string; // deprecated
scriptHash: string;
}

View File

@ -18,7 +18,7 @@ import config from 'config';
import { _logger } from '../config/logger';
import { JsExecutor, TbScript } from './jsExecutor';
import { performance } from 'perf_hooks';
import { isString, parseJsErrorDetails, toUUIDString, UUIDFromBuffer, UUIDToBits, isNotUUID } from './utils';
import { isString, parseJsErrorDetails, UUIDFromBuffer, UUIDToBits } from './utils';
import { IQueue } from '../queue/queue.models';
import {
JsCompileRequest,
@ -306,26 +306,12 @@ export class JsInvokeMessageProcessor {
}
private static createCompileResponse(scriptId: string, success: boolean, errorCode?: number, err?: any): JsCompileResponse {
if (isNotUUID(scriptId)) {
return {
errorCode: errorCode,
success: success,
errorDetails: parseJsErrorDetails(err),
scriptIdMSB: "0",
scriptIdLSB: "0",
scriptHash: scriptId
};
} else { // this is for backward compatibility (to be able to work with tb-node of previous version) - todo: remove in the next release
let scriptIdBits = UUIDToBits(scriptId);
return {
errorCode: errorCode,
success: success,
errorDetails: parseJsErrorDetails(err),
scriptIdMSB: scriptIdBits[0],
scriptIdLSB: scriptIdBits[1],
scriptHash: ""
};
}
return {
errorCode: errorCode,
success: success,
errorDetails: parseJsErrorDetails(err),
scriptHash: scriptId
};
}
private static createInvokeResponse(result: string | undefined, success: boolean, errorCode?: number, err?: any): JsInvokeResponse {
@ -338,26 +324,14 @@ export class JsInvokeMessageProcessor {
}
private static createReleaseResponse(scriptId: string, success: boolean): JsReleaseResponse {
if (isNotUUID(scriptId)) {
return {
success: success,
scriptIdMSB: "0",
scriptIdLSB: "0",
scriptHash: scriptId,
};
} else { // todo: remove in the next release
let scriptIdBits = UUIDToBits(scriptId);
return {
success: success,
scriptIdMSB: scriptIdBits[0],
scriptIdLSB: scriptIdBits[1],
scriptHash: ""
}
}
return {
success: success,
scriptHash: scriptId,
};
}
private static getScriptId(request: TbMessage): string {
return request.scriptHash ? request.scriptHash : toUUIDString(request.scriptIdMSB, request.scriptIdLSB);
return request.scriptHash;
}
private incrementUseScriptId(scriptId: string) {

View File

@ -17,13 +17,6 @@
import Long from 'long';
import uuidParse from 'uuid-parse';
export function toUUIDString(mostSigBits: string, leastSigBits: string): string {
const msbBytes = Long.fromValue(mostSigBits, false).toBytes(false);
const lsbBytes = Long.fromValue(leastSigBits, false).toBytes(false);
const uuidBytes = msbBytes.concat(lsbBytes);
return uuidParse.unparse(uuidBytes as any);
}
export function UUIDFromBuffer(buf: Buffer): string {
return uuidParse.unparse(buf);
}
@ -59,10 +52,6 @@ export function parseJsErrorDetails(err: any): string | undefined {
return details;
}
export function isNotUUID(candidate: string) {
return candidate.length != 36 || !candidate.includes('-');
}
export function isNotEmptyStr(value: any): boolean {
return typeof value === 'string' && value.trim().length > 0;
}

View File

@ -13,17 +13,12 @@
"build": "tsc"
},
"dependencies": {
"@aws-sdk/client-sqs": "^3.682.0",
"@azure/service-bus": "^7.9.5",
"@google-cloud/pubsub": "^4.8.0",
"amqplib": "^0.10.4",
"config": "^3.3.12",
"express": "^4.21.1",
"js-yaml": "^4.1.0",
"kafkajs": "^2.2.4",
"long": "^5.2.3",
"uuid-parse": "^1.1.0",
"uuid-random": "^1.3.2",
"winston": "^3.16.0",
"winston-daily-rotate-file": "^5.0.0"
},
@ -36,7 +31,6 @@
]
},
"devDependencies": {
"@types/amqplib": "^0.10.5",
"@types/config": "^3.3.5",
"@types/express": "~4.17.21",
"@types/node": "~20.17.6",

View File

@ -35,7 +35,6 @@ import { KeyObject } from 'tls';
import process, { exit, kill } from 'process';
// TODO: remove dependencies for other queue types
export class KafkaTemplate implements IQueue {
private logger = _logger(`kafkaTemplate`);

File diff suppressed because it is too large Load Diff