From 6c200e3767a5746e160629e1957998e35aed8b44 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Feb 2026 17:53:36 +0200 Subject: [PATCH 1/4] Fixed sync of AdminSettings to Edge in realtime --- .../service/edge/rpc/EdgeSyncCursor.java | 4 +- .../fetch/AdminSettingsEdgeEventFetcher.java | 34 ++------ .../rpc/fetch/OAuth2EdgeEventFetcher.java | 2 +- .../settings/AdminSettingsEdgeProcessor.java | 4 +- .../server/edge/AdminSettingsEdgeTest.java | 79 +++++++++++++++++++ .../dao/settings/AdminSettingsService.java | 4 + .../common/data/edge/EdgeEventType.java | 2 +- .../common/data/id/EntityIdFactory.java | 1 + .../server/dao/settings/AdminSettingsDao.java | 4 + .../settings/AdminSettingsServiceImpl.java | 19 ++++- .../dao/service/AdminSettingsServiceTest.java | 25 ++++++ 11 files changed, 146 insertions(+), 32 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/edge/AdminSettingsEdgeTest.java diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java index bf3c94ca44..ce175957f6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeSyncCursor.java @@ -19,6 +19,7 @@ import lombok.Getter; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.rpc.fetch.AdminSettingsEdgeEventFetcher; import org.thingsboard.server.service.edge.rpc.fetch.AssetProfilesEdgeEventFetcher; @@ -62,7 +63,8 @@ public class EdgeSyncCursor { fetchers.add(new TenantEdgeEventFetcher(ctx.getTenantService())); fetchers.add(new QueuesEdgeEventFetcher(ctx.getQueueService())); fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService())); - fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService())); + fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), TenantId.SYS_TENANT_ID)); + fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService(), edge.getTenantId())); fetchers.add(new TenantAdminUsersEdgeEventFetcher(ctx.getUserService())); } Customer publicCustomer = ctx.getCustomerService().findPublicCustomer(edge.getTenantId()); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java index 7e4b463573..b18c05cd53 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java @@ -17,50 +17,32 @@ package org.thingsboard.server.service.edge.rpc.fetch; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.settings.AdminSettingsService; -import java.util.ArrayList; -import java.util.List; - @AllArgsConstructor @Slf4j -public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher { +public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher { private final AdminSettingsService adminSettingsService; + private final TenantId tenantId; @Override - public PageLink getPageLink(int pageSize) { - return null; - } - - public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { - List result = fetchAdminSettingsForKeys(tenantId, edge.getId(), List.of("general", "mail", "connectivity", "jwt")); - - // return PageData object to be in sync with other fetchers - return new PageData<>(result, 1, result.size(), false); + PageData fetchEntities(TenantId tenantId, Edge edge, PageLink pageLink) { + return adminSettingsService.findAllByTenantId(this.tenantId, pageLink); } - private List fetchAdminSettingsForKeys(TenantId tenantId, EdgeId edgeId, List keys) { - List result = new ArrayList<>(); - for (String key : keys) { - AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key); - if (adminSettings != null) { - result.add(EdgeUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.ADMIN_SETTINGS, - EdgeEventActionType.UPDATED, null, JacksonUtil.valueToTree(adminSettings))); - } - } - return result; + @Override + EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, AdminSettings adminSettings) { + return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, + EdgeEventActionType.UPDATED, adminSettings.getId(), null); } - } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java index b7337173cd..6c65d141d8 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/OAuth2EdgeEventFetcher.java @@ -41,7 +41,7 @@ public class OAuth2EdgeEventFetcher extends BasePageableEdgeEventFetcher findAllByTenantId(TenantId tenantId, PageLink pageLink); + AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings); boolean deleteAdminSettingsByTenantIdAndKey(TenantId tenantId, String key); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java index eff86ee5d8..5f8d57f6f8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeEventType.java @@ -38,7 +38,7 @@ public enum EdgeEventType { TENANT_PROFILE(true, EntityType.TENANT_PROFILE), WIDGETS_BUNDLE(true, EntityType.WIDGETS_BUNDLE), WIDGET_TYPE(true, EntityType.WIDGET_TYPE), - ADMIN_SETTINGS(true, null), + ADMIN_SETTINGS(true, EntityType.ADMIN_SETTINGS), OTA_PACKAGE(true, EntityType.OTA_PACKAGE), QUEUE(true, EntityType.QUEUE), NOTIFICATION_RULE(true, EntityType.NOTIFICATION_RULE), diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index 11c33c9cdd..65432f6b7f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -113,6 +113,7 @@ public class EntityIdFactory { case OAUTH2_CLIENT -> new OAuth2ClientId(uuid); case DOMAIN -> new DomainId(uuid); case CALCULATED_FIELD -> new CalculatedFieldId(uuid); + case ADMIN_SETTINGS -> new AdminSettingsId(uuid); default -> throw new IllegalArgumentException("EdgeEventType " + edgeEventType + " is not supported!"); }; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java index 2c814ef50a..ee8510a851 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsDao.java @@ -17,6 +17,8 @@ package org.thingsboard.server.dao.settings; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.Dao; import java.util.UUID; @@ -27,6 +29,8 @@ public interface AdminSettingsDao extends Dao { AdminSettings findByTenantIdAndKey(UUID tenantId, String key); + PageData findAllByTenantId(TenantId tenantId, PageLink pageLink); + boolean removeByTenantIdAndKey(UUID tenantId, String key); void removeByTenantId(UUID tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java index d6708aabfe..71f0eb268e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/settings/AdminSettingsServiceImpl.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.FluentFuture; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.EntityType; @@ -27,6 +28,9 @@ import org.thingsboard.server.common.data.id.AdminSettingsId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.Validator; @@ -44,6 +48,9 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { @Autowired private DataValidator adminSettingsValidator; + @Autowired + protected ApplicationEventPublisher eventPublisher; + @Override public AdminSettings findAdminSettingsById(TenantId tenantId, AdminSettingsId adminSettingsId) { log.trace("Executing findAdminSettingsById [{}]", adminSettingsId); @@ -63,10 +70,15 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { return adminSettingsDao.findByTenantIdAndKey(tenantId.getId(), key); } + @Override + public PageData findAllByTenantId(TenantId tenantId, PageLink pageLink) { + return adminSettingsDao.findAllByTenantId(tenantId, pageLink); + } + @Override public AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings) { log.trace("Executing saveAdminSettings [{}]", adminSettings); - adminSettingsValidator.validate(adminSettings, data -> tenantId); + AdminSettings oldAdminSettings = adminSettingsValidator.validate(adminSettings, data -> tenantId); if (adminSettings.getKey().equals("mail")) { AdminSettings mailSettings = findAdminSettingsByKey(tenantId, "mail"); if (mailSettings != null) { @@ -84,7 +96,10 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { if (adminSettings.getTenantId() == null) { adminSettings.setTenantId(TenantId.SYS_TENANT_ID); } - return adminSettingsDao.save(tenantId, adminSettings); + AdminSettings savedAdminSettings = adminSettingsDao.save(tenantId, adminSettings); + eventPublisher.publishEvent(SaveEntityEvent.builder().tenantId(savedAdminSettings.getTenantId()).entityId(savedAdminSettings.getId()) + .entity(savedAdminSettings).oldEntity(oldAdminSettings).created(adminSettings.getId() == null).build()); + return savedAdminSettings; } @Override diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java index 2c5851eb82..043e01f482 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -25,12 +26,16 @@ import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.settings.AdminSettingsService; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +@Slf4j @DaoSqlTest public class AdminSettingsServiceTest extends AbstractServiceTest { @@ -113,4 +118,24 @@ public class AdminSettingsServiceTest extends AbstractServiceTest { }).hasMessageContaining("already exists"); } + @Test + public void testFindAllByTenantId() { + int pageSize = 10; + int totalElements = 100; + + for (int i = 0; i < totalElements; i++) { + AdminSettings settings = new AdminSettings(); + settings.setTenantId(tenantId); + String key = RandomStringUtils.randomAlphanumeric(15); + settings.setKey(key); + settings.setJsonValue(JacksonUtil.newObjectNode().put("value", i)); + adminSettingsService.saveAdminSettings(tenantId, settings); + } + + PageData pageData = adminSettingsService.findAllByTenantId(tenantId, new PageLink(pageSize)); + assertThat(pageData.getData().size()).isEqualTo(pageSize); + assertThat(pageData.getTotalElements()).isEqualTo(totalElements); + + } + } From 17d5db7aa126e64541d237677321e50c2d55c523 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Feb 2026 18:29:36 +0200 Subject: [PATCH 2/4] Copilot review changes --- .../edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java | 4 ++-- .../processor/settings/AdminSettingsEdgeProcessor.java | 10 ++++++++-- .../server/dao/service/AdminSettingsServiceTest.java | 2 -- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java index b18c05cd53..47e004ac82 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java @@ -33,11 +33,11 @@ import org.thingsboard.server.dao.settings.AdminSettingsService; public class AdminSettingsEdgeEventFetcher extends BasePageableEdgeEventFetcher { private final AdminSettingsService adminSettingsService; - private final TenantId tenantId; + private final TenantId fetcherTenantId; @Override PageData fetchEntities(TenantId tenantId, Edge edge, PageLink pageLink) { - return adminSettingsService.findAllByTenantId(this.tenantId, pageLink); + return adminSettingsService.findAllByTenantId(fetcherTenantId, pageLink); } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java index 96210e6325..2e0a65f324 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/settings/AdminSettingsEdgeProcessor.java @@ -36,8 +36,14 @@ public class AdminSettingsEdgeProcessor extends BaseEdgeProcessor { @Override public DownlinkMsg convertEdgeEventToDownlink(EdgeEvent edgeEvent, EdgeVersion edgeVersion) { - AdminSettingsId adminSettingsId = new AdminSettingsId(edgeEvent.getEntityId()); - AdminSettings adminSettings = edgeCtx.getAdminSettingsService().findAdminSettingsById(edgeEvent.getTenantId(), adminSettingsId); + AdminSettings adminSettings = null; + if (edgeEvent.getEntityId() != null) { + AdminSettingsId adminSettingsId = new AdminSettingsId(edgeEvent.getEntityId()); + adminSettings = edgeCtx.getAdminSettingsService().findAdminSettingsById(edgeEvent.getTenantId(), adminSettingsId); + } else if (edgeEvent.getBody() != null && !edgeEvent.getBody().isEmpty()) { + // legacy + adminSettings = JacksonUtil.convertValue(edgeEvent.getBody(), AdminSettings.class); + } if (adminSettings == null) { return null; } diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java index 043e01f482..1b7924aad6 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/AdminSettingsServiceTest.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.service; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.extern.slf4j.Slf4j; import org.junit.Assert; import org.junit.Test; import org.junit.jupiter.api.Assertions; @@ -35,7 +34,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -@Slf4j @DaoSqlTest public class AdminSettingsServiceTest extends AbstractServiceTest { From ed7156b89a67bf503560eb19cae563ceb9bcf474 Mon Sep 17 00:00:00 2001 From: Dmytro Khylko Date: Thu, 26 Feb 2026 14:34:34 +0200 Subject: [PATCH 3/4] Exported WebSocket configuration variables --- .../server/config/WebSocketConfiguration.java | 10 ++++++++-- application/src/main/resources/thingsboard.yml | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java index 3cd1e2a6e3..38f37cf35d 100644 --- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java +++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java @@ -17,6 +17,7 @@ package org.thingsboard.server.config; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.WebSocketHandler; @@ -40,11 +41,16 @@ public class WebSocketConfiguration implements WebSocketConfigurer { private final WebSocketHandler wsHandler; + @Value("${server.ws.max_text_message_buffer_size:32768}") + private int maxTextMessageBufferSize; + @Value("${server.ws.max_binary_message_buffer_size:32768}") + private int maxBinaryMessageBufferSize; + @Bean public ServletServerContainerFactoryBean createWebSocketContainer() { ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); - container.setMaxTextMessageBufferSize(32768); - container.setMaxBinaryMessageBufferSize(32768); + container.setMaxTextMessageBufferSize(maxTextMessageBufferSize); + container.setMaxBinaryMessageBufferSize(maxBinaryMessageBufferSize); return container; } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 4485297083..8adcc6a6af 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -78,6 +78,10 @@ server: max_entities_per_data_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_DATA_SUBSCRIPTION:10000}" # Maximum number of alarms returned for single alarm subscription. For example, no more than 10,000 alarms on the alarm widget max_entities_per_alarm_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_ALARM_SUBSCRIPTION:10000}" + # Maximum size (bytes) of incoming WS text message + max_text_message_buffer_size: "${TB_SERVER_WS_MAX_TEXT_MESSAGE_BUFFER_SIZE:32768}" + # Maximum size (bytes) of incoming WS binary message + max_binary_message_buffer_size: "${TB_SERVER_WS_MAX_BINARY_MESSAGE_BUFFER_SIZE:32768}" # Maximum queue size of the websocket updates per session. This restriction prevents infinite updates of WS max_queue_messages_per_session: "${TB_SERVER_WS_DEFAULT_QUEUE_MESSAGES_PER_SESSION:1000}" # Maximum time between WS session opening and sending auth command From 0d23685b622407b54832c2aac7786ddd77253d09 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 4 Mar 2026 14:33:53 +0200 Subject: [PATCH 4/4] Fix flaky SsrfProtectionValidatorTest by moving @ResourceLock to class level Tests that read shared static state (e.g. testAllowedUrls with 8.8.8.8) could run concurrently with tests that mutate it (e.g. testAdditionalBlockedSingleIp), causing intermittent failures. Class-level @ResourceLock serializes all tests. Co-Authored-By: Claude Opus 4.6 --- .../common/util/SsrfProtectionValidatorTest.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/common/util/src/test/java/org/thingsboard/common/util/SsrfProtectionValidatorTest.java b/common/util/src/test/java/org/thingsboard/common/util/SsrfProtectionValidatorTest.java index ec6e51db6d..6cb2d21a9a 100644 --- a/common/util/src/test/java/org/thingsboard/common/util/SsrfProtectionValidatorTest.java +++ b/common/util/src/test/java/org/thingsboard/common/util/SsrfProtectionValidatorTest.java @@ -27,12 +27,9 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; +@ResourceLock("SsrfProtectionValidatorTest") // some tests mutate static additional-blocked-hosts public class SsrfProtectionValidatorTest { - // JUnit 5 @ResourceLock ensures that tests modifying SsrfProtectionValidator's static - // additional blocked hosts never run concurrently with each other (parallel execution is enabled). - private static final String SYNC_LOCK = "SsrfProtectionValidatorTest"; - @ParameterizedTest @ValueSource(strings = { "http://example.com", @@ -207,7 +204,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedSingleIp() { try { SsrfProtectionValidator.setAdditionalBlockedHosts(List.of("8.8.8.8")); @@ -222,7 +218,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedCidrSlash10() { try { // Use 44.0.0.0/10 (not blocked by default) to verify CIDR /10 matching @@ -243,7 +238,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedCidrSlash24() { try { SsrfProtectionValidator.setAdditionalBlockedHosts(List.of("198.51.100.0/24")); @@ -261,7 +255,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedHostnameViaValidateUri() { try { SsrfProtectionValidator.setAdditionalBlockedHosts(List.of("evil.corp")); @@ -275,7 +268,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedHostnameCaseInsensitive() { try { SsrfProtectionValidator.setAdditionalBlockedHosts(List.of("My-Service.Corp")); @@ -289,7 +281,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testSetAdditionalBlockedHostsEmptyAndNull() { // Should not throw SsrfProtectionValidator.setAdditionalBlockedHosts(Collections.emptyList()); @@ -307,7 +298,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedCidrViaValidateUri() { // 203.0.113.0/24 (TEST-NET-3) is not blocked by default URI uri = URI.create("http://203.0.113.1"); @@ -323,7 +313,6 @@ public class SsrfProtectionValidatorTest { } @Test - @ResourceLock(SYNC_LOCK) void testAdditionalBlockedMixedConfig() { try { SsrfProtectionValidator.setAdditionalBlockedHosts(List.of("203.0.113.0/24", "evil.corp", "8.8.8.8"));