diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/TokenOutdatingService.java b/application/src/main/java/org/thingsboard/server/service/security/auth/TokenOutdatingService.java index 173e3fa25d..a623fc6862 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/auth/TokenOutdatingService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/auth/TokenOutdatingService.java @@ -40,23 +40,23 @@ public class TokenOutdatingService { private final CacheManager cacheManager; private final JwtTokenFactory tokenFactory; private final JwtSettings jwtSettings; - private Cache tokenOutdatageTimeCache; + private Cache usersUpdateTimeCache; @PostConstruct protected void initCache() { - tokenOutdatageTimeCache = cacheManager.getCache(CacheConstants.TOKEN_OUTDATAGE_TIME_CACHE); + usersUpdateTimeCache = cacheManager.getCache(CacheConstants.USERS_UPDATE_TIME_CACHE); } @EventListener(classes = UserAuthDataChangedEvent.class) - public void onUserAuthDataChanged(UserAuthDataChangedEvent userAuthDataChangedEvent) { - outdateOldUserTokens(userAuthDataChangedEvent.getUserId()); + public void onUserAuthDataChanged(UserAuthDataChangedEvent event) { + usersUpdateTimeCache.put(toKey(event.getUserId()), event.getTs()); } public boolean isOutdated(JwtToken token, UserId userId) { Claims claims = tokenFactory.parseTokenClaims(token).getBody(); long issueTime = claims.getIssuedAt().getTime(); - return Optional.ofNullable(tokenOutdatageTimeCache.get(toKey(userId), Long.class)) + return Optional.ofNullable(usersUpdateTimeCache.get(toKey(userId), Long.class)) .map(outdatageTime -> { if (System.currentTimeMillis() - outdatageTime <= SECONDS.toMillis(jwtSettings.getRefreshTokenExpTime())) { return MILLISECONDS.toSeconds(issueTime) < MILLISECONDS.toSeconds(outdatageTime); @@ -68,17 +68,13 @@ public class TokenOutdatingService { * as all the tokens issued before the outdatage time * are now expired by themselves * */ - tokenOutdatageTimeCache.evict(toKey(userId)); + usersUpdateTimeCache.evict(toKey(userId)); return false; } }) .orElse(false); } - public void outdateOldUserTokens(UserId userId) { - tokenOutdatageTimeCache.put(toKey(userId), System.currentTimeMillis()); - } - private String toKey(UserId userId) { return userId.getId().toString(); } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 766b393e78..2384e5d625 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -28,7 +28,7 @@ server: # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) - type: "${SSL_CREDENTIALS_TYPE:PEM}" + type: "${SSL_CREDENTIALS_TYPE:PEM}" # PEM server credentials pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) @@ -397,15 +397,19 @@ cache: tenants: timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" + tenantsExist: + # environment variables are intentionally the same as in 'tenants' cache to be equal. + timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" + maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" deviceProfiles: timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_PROFILES_TTL:1440}" maxSize: "${CACHE_SPECS_DEVICE_PROFILES_MAX_SIZE:10000}" attributes: timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" - tokensOutdatageTime: - timeToLiveInMinutes: "${CACHE_SPECS_TOKENS_OUTDATAGE_TIME_TTL:20000}" - maxSize: "${CACHE_SPECS_TOKENS_OUTDATAGE_TIME_MAX_SIZE:10000}" + usersUpdateTime: + timeToLiveInMinutes: "${CACHE_SPECS_USERS_UPDATE_TIME_TTL:20000}" + maxSize: "${CACHE_SPECS_USERS_UPDATE_TIME_MAX_SIZE:10000}" otaPackages: timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_TTL:60}" maxSize: "${CACHE_SPECS_OTA_PACKAGES_MAX_SIZE:10}" @@ -669,7 +673,7 @@ transport: # Server SSL credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) - type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}" + type: "${MQTT_SSL_CREDENTIALS_TYPE:PEM}" # PEM server credentials pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) @@ -712,7 +716,7 @@ transport: # Server DTLS credentials credentials: # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) - type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}" + type: "${COAP_DTLS_CREDENTIALS_TYPE:PEM}" # PEM server credentials pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) @@ -790,7 +794,7 @@ transport: # Whether to enable LWM2M bootstrap server X509 Certificate/RPK support enabled: "${LWM2M_BS_CREDENTIALS_ENABLED:false}" # Server credentials type (PEM - pem certificate file; KEYSTORE - java keystore) - type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" + type: "${LWM2M_BS_CREDENTIALS_TYPE:PEM}" # PEM server credentials pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) @@ -817,7 +821,7 @@ transport: # Whether to load X509 trust certificates enabled: "${LWM2M_TRUST_CREDENTIALS_ENABLED:false}" # Trust certificates store type (PEM - pem certificates file; KEYSTORE - java keystore) - type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" + type: "${LWM2M_TRUST_CREDENTIALS_TYPE:PEM}" # PEM certificates pem: # Path to the certificates file (holds trust certificates) @@ -841,8 +845,8 @@ transport: psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside -# - key: "PROTOCOL_STAGE_THREAD_COUNT" -# value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" + # - key: "PROTOCOL_STAGE_THREAD_COUNT" + # value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}" snmp: enabled: "${SNMP_ENABLED:true}" response_processing: @@ -928,9 +932,9 @@ queue: tb_version_control: - key: max.poll.interval.ms value: "${TB_QUEUE_KAFKA_VC_MAX_POLL_INTERVAL_MS:600000}" -# tb_rule_engine.sq: -# - key: max.poll.records -# value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}" + # tb_rule_engine.sq: + # - key: max.poll.records + # value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}" other: # In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside - key: "request.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms value: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) diff --git a/application/src/test/java/org/thingsboard/server/service/security/auth/TokenOutdatingTest.java b/application/src/test/java/org/thingsboard/server/service/security/auth/TokenOutdatingTest.java index 82f3e2ebcd..f804d4dcfd 100644 --- a/application/src/test/java/org/thingsboard/server/service/security/auth/TokenOutdatingTest.java +++ b/application/src/test/java/org/thingsboard/server/service/security/auth/TokenOutdatingTest.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.UserCredentials; +import org.thingsboard.server.common.data.security.event.UserAuthDataChangedEvent; import org.thingsboard.server.common.data.security.model.JwtToken; import org.thingsboard.server.config.JwtSettings; import org.thingsboard.server.dao.customer.CustomerService; @@ -99,7 +100,7 @@ public class TokenOutdatingTest { JwtToken jwtToken = createAccessJwtToken(userId); SECONDS.sleep(1); // need to wait before outdating so that outdatage time is strictly after token issue time - tokenOutdatingService.outdateOldUserTokens(userId); + tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(userId)); assertTrue(tokenOutdatingService.isOutdated(jwtToken, userId)); SECONDS.sleep(1); @@ -117,7 +118,7 @@ public class TokenOutdatingTest { }); SECONDS.sleep(1); - tokenOutdatingService.outdateOldUserTokens(userId); + tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(userId)); assertThrows(JwtExpiredTokenException.class, () -> { accessTokenAuthenticationProvider.authenticate(new JwtAuthenticationToken(accessJwtToken)); @@ -133,7 +134,7 @@ public class TokenOutdatingTest { }); SECONDS.sleep(1); - tokenOutdatingService.outdateOldUserTokens(userId); + tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(userId)); assertThrows(CredentialsExpiredException.class, () -> { refreshTokenAuthenticationProvider.authenticate(new RefreshAuthenticationToken(refreshJwtToken)); @@ -145,20 +146,20 @@ public class TokenOutdatingTest { JwtToken jwtToken = createAccessJwtToken(userId); SECONDS.sleep(1); - tokenOutdatingService.outdateOldUserTokens(userId); + tokenOutdatingService.onUserAuthDataChanged(new UserAuthDataChangedEvent(userId)); - int refreshTokenExpirationTime = 5; + int refreshTokenExpirationTime = 3; jwtSettings.setRefreshTokenExpTime(refreshTokenExpirationTime); SECONDS.sleep(refreshTokenExpirationTime - 2); assertTrue(tokenOutdatingService.isOutdated(jwtToken, userId)); - assertNotNull(cacheManager.getCache(CacheConstants.TOKEN_OUTDATAGE_TIME_CACHE).get(userId.getId().toString())); + assertNotNull(cacheManager.getCache(CacheConstants.USERS_UPDATE_TIME_CACHE).get(userId.getId().toString())); SECONDS.sleep(3); assertFalse(tokenOutdatingService.isOutdated(jwtToken, userId)); - assertNull(cacheManager.getCache(CacheConstants.TOKEN_OUTDATAGE_TIME_CACHE).get(userId.getId().toString())); + assertNull(cacheManager.getCache(CacheConstants.USERS_UPDATE_TIME_CACHE).get(userId.getId().toString())); } private JwtToken createAccessJwtToken(UserId userId) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java index c473bcbd6c..3d5578adf8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java @@ -27,9 +27,10 @@ public class CacheConstants { public static final String SECURITY_SETTINGS_CACHE = "securitySettings"; public static final String TENANT_PROFILE_CACHE = "tenantProfiles"; public static final String TENANTS_CACHE = "tenants"; + public static final String TENANTS_EXIST_CACHE = "tenantsExist"; public static final String DEVICE_PROFILE_CACHE = "deviceProfiles"; public static final String ATTRIBUTES_CACHE = "attributes"; - public static final String TOKEN_OUTDATAGE_TIME_CACHE = "tokensOutdatageTime"; + public static final String USERS_UPDATE_TIME_CACHE = "usersUpdateTime"; public static final String OTA_PACKAGE_CACHE = "otaPackages"; public static final String OTA_PACKAGE_DATA_CACHE = "otaPackagesData"; public static final String REPOSITORY_SETTINGS_CACHE = "repositorySettings"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/event/UserAuthDataChangedEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/event/UserAuthDataChangedEvent.java index ec19089cab..2dcd95f435 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/event/UserAuthDataChangedEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/event/UserAuthDataChangedEvent.java @@ -15,16 +15,17 @@ */ package org.thingsboard.server.common.data.security.event; +import lombok.Data; import org.thingsboard.server.common.data.id.UserId; +@Data public class UserAuthDataChangedEvent { private final UserId userId; + private final long ts; public UserAuthDataChangedEvent(UserId userId) { this.userId = userId; + this.ts = System.currentTimeMillis(); } - public UserId getUserId() { - return userId; - } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java deleted file mode 100644 index 8a0af86faa..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCacheKey.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright © 2016-2022 The Thingsboard Authors - * - * 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.thingsboard.server.dao.tenant; - -import lombok.AllArgsConstructor; -import lombok.Data; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.TenantProfileId; - -import java.io.Serializable; - -@Data -@AllArgsConstructor -public class TenantCacheKey implements Serializable { - - private static final long serialVersionUID = -121787454251592384L; - - private final TenantId tenantId; - private final TenantCacheKeyPrefix keyPrefix; - - public static TenantCacheKey fromId(TenantId tenantId) { - return new TenantCacheKey(tenantId, TenantCacheKeyPrefix.TENANT); - } - - public static TenantCacheKey fromIdExists(TenantId tenantId) { - return new TenantCacheKey(tenantId, TenantCacheKeyPrefix.EXISTS); - } - - public enum TenantCacheKeyPrefix { - TENANT, EXISTS - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java index e6ae0d930f..8a0e24f2c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantCaffeineCache.java @@ -21,10 +21,11 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.cache.CaffeineTbTransactionalCache; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.TenantId; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) @Service("TenantCache") -public class TenantCaffeineCache extends CaffeineTbTransactionalCache { +public class TenantCaffeineCache extends CaffeineTbTransactionalCache { public TenantCaffeineCache(CacheManager cacheManager) { super(cacheManager, CacheConstants.TENANTS_CACHE); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java index 2bd28ae511..b11497898a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantEvictEvent.java @@ -21,6 +21,5 @@ import org.thingsboard.server.common.data.id.TenantId; @Data public class TenantEvictEvent { private final TenantId tenantId; - // for exists tenant cache - private final boolean isExistsTenant; + private final boolean invalidateExists; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java index c7b25a5059..579afd9a11 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsCaffeineCache.java @@ -21,13 +21,15 @@ import org.springframework.stereotype.Service; import org.thingsboard.server.cache.CaffeineTbTransactionalCache; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantInfo; +import org.thingsboard.server.common.data.id.TenantId; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true) @Service("TenantExistsCache") -public class TenantExistsCaffeineCache extends CaffeineTbTransactionalCache { +public class TenantExistsCaffeineCache extends CaffeineTbTransactionalCache { public TenantExistsCaffeineCache(CacheManager cacheManager) { - super(cacheManager, CacheConstants.TENANTS_CACHE); + super(cacheManager, CacheConstants.TENANTS_EXIST_CACHE); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java index 46d5ef2964..1b41379753 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantExistsRedisCache.java @@ -23,12 +23,13 @@ import org.thingsboard.server.cache.RedisTbTransactionalCache; import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.cache.TbFSTRedisSerializer; import org.thingsboard.server.common.data.CacheConstants; +import org.thingsboard.server.common.data.id.TenantId; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") @Service("TenantExistsCache") -public class TenantExistsRedisCache extends RedisTbTransactionalCache { +public class TenantExistsRedisCache extends RedisTbTransactionalCache { public TenantExistsRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { - super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); + super(CacheConstants.TENANTS_EXIST_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java index 1794da2674..87b791427f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantRedisCache.java @@ -24,10 +24,11 @@ import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.cache.TbFSTRedisSerializer; import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.id.TenantId; @ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis") @Service("TenantCache") -public class TenantRedisCache extends RedisTbTransactionalCache { +public class TenantRedisCache extends RedisTbTransactionalCache { public TenantRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) { super(CacheConstants.TENANTS_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>()); diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 45127d9517..6da185ed19 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -55,7 +55,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId; @Service @Slf4j -public class TenantServiceImpl extends AbstractCachedEntityService implements TenantService { +public class TenantServiceImpl extends AbstractCachedEntityService implements TenantService { private static final String DEFAULT_TENANT_REGION = "Global"; public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; @@ -115,15 +115,15 @@ public class TenantServiceImpl extends AbstractCachedEntityService existsTenantCache; + protected TbTransactionalCache existsTenantCache; @TransactionalEventListener(classes = TenantEvictEvent.class) @Override public void handleEvictEvent(TenantEvictEvent event) { TenantId tenantId = event.getTenantId(); - cache.evict(TenantCacheKey.fromId(tenantId)); - if (event.isExistsTenant()) { - existsTenantCache.evict(TenantCacheKey.fromIdExists(tenantId)); + cache.evict(tenantId); + if (event.isInvalidateExists()) { + existsTenantCache.evict(tenantId); } } @@ -132,8 +132,7 @@ public class TenantServiceImpl extends AbstractCachedEntityService tenantDao.findById(tenantId, tenantId.getId()), true); + return cache.getAndPutInTransaction(tenantId, () -> tenantDao.findById(tenantId, tenantId.getId()), true); } @Override @@ -160,8 +159,9 @@ public class TenantServiceImpl extends AbstractCachedEntityService tenantDao.existsById(tenantId, tenantId.getId()), false); + return existsTenantCache.getAndPutInTransaction(tenantId, () -> tenantDao.existsById(tenantId, tenantId.getId()), false); } private PaginatedRemover tenantsRemover = new PaginatedRemover<>() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java index d893a1ba40..93ed013771 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseTenantServiceTest.java @@ -17,17 +17,12 @@ package org.thingsboard.server.dao.service; import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.cache.Cache; -import org.springframework.cache.CacheManager; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.server.cache.TbCacheValueWrapper; import org.thingsboard.server.cache.TbTransactionalCache; -import org.thingsboard.server.common.data.CacheConstants; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; @@ -61,19 +56,17 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.exception.DataValidationException; -import org.thingsboard.server.dao.tenant.TenantCacheKey; import org.thingsboard.server.dao.tenant.TenantDao; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.Set; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; -import static org.assertj.core.api.Assertions.assertThat; public abstract class BaseTenantServiceTest extends AbstractServiceTest { @@ -83,10 +76,10 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { protected TenantDao tenantDao; @Autowired - protected TbTransactionalCache cache; + protected TbTransactionalCache cache; @Autowired - protected TbTransactionalCache existsTenantCache; + protected TbTransactionalCache existsTenantCache; @Test public void testSaveTenant() { @@ -97,15 +90,15 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertNotNull(savedTenant.getId()); Assert.assertTrue(savedTenant.getCreatedTime() > 0); Assert.assertEquals(tenant.getTitle(), savedTenant.getTitle()); - + savedTenant.setTitle("My new tenant"); tenantService.saveTenant(savedTenant); Tenant foundTenant = tenantService.findTenantById(savedTenant.getId()); Assert.assertEquals(foundTenant.getTitle(), savedTenant.getTitle()); - + tenantService.deleteTenant(savedTenant.getId()); } - + @Test public void testFindTenantById() { Tenant tenant = new Tenant(); @@ -127,13 +120,13 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertEquals(new TenantInfo(savedTenant, "Default"), foundTenant); tenantService.deleteTenant(savedTenant.getId()); } - + @Test(expected = DataValidationException.class) public void testSaveTenantWithEmptyTitle() { Tenant tenant = new Tenant(); tenantService.saveTenant(tenant); } - + @Test(expected = DataValidationException.class) public void testSaveTenantWithInvalidEmail() { Tenant tenant = new Tenant(); @@ -141,7 +134,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenant.setEmail("invalid@mail"); tenantService.saveTenant(tenant); } - + @Test public void testDeleteTenant() { Tenant tenant = new Tenant(); @@ -151,7 +144,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Tenant foundTenant = tenantService.findTenantById(savedTenant.getId()); Assert.assertNull(foundTenant); } - + @Test public void testFindTenants() { List tenants = new ArrayList<>(); @@ -160,13 +153,13 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); tenants.addAll(pageData.getData()); - - for (int i=0;i<156;i++) { + + for (int i = 0; i < 156; i++) { Tenant tenant = new Tenant(); - tenant.setTitle("Tenant"+i); + tenant.setTitle("Tenant" + i); tenants.add(tenantService.saveTenant(tenant)); } - + List loadedTenants = new ArrayList<>(); pageLink = new PageLink(17); do { @@ -176,46 +169,46 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { pageLink = pageLink.nextPageLink(); } } while (pageData.hasNext()); - + Collections.sort(tenants, idComparator); Collections.sort(loadedTenants, idComparator); - + Assert.assertEquals(tenants, loadedTenants); - + for (Tenant tenant : loadedTenants) { tenantService.deleteTenant(tenant.getId()); } - + pageLink = new PageLink(17); pageData = tenantService.findTenants(pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertTrue(pageData.getData().isEmpty()); - + } - + @Test public void testFindTenantsByTitle() { String title1 = "Tenant title 1"; List tenantsTitle1 = new ArrayList<>(); - for (int i=0;i<134;i++) { + for (int i = 0; i < 134; i++) { Tenant tenant = new Tenant(); - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); - String title = title1+suffix; + String suffix = RandomStringUtils.randomAlphanumeric((int) (Math.random() * 15)); + String title = title1 + suffix; title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); tenant.setTitle(title); tenantsTitle1.add(tenantService.saveTenant(tenant)); } String title2 = "Tenant title 2"; List tenantsTitle2 = new ArrayList<>(); - for (int i=0;i<127;i++) { + for (int i = 0; i < 127; i++) { Tenant tenant = new Tenant(); - String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); - String title = title2+suffix; + String suffix = RandomStringUtils.randomAlphanumeric((int) (Math.random() * 15)); + String title = title2 + suffix; title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); tenant.setTitle(title); tenantsTitle2.add(tenantService.saveTenant(tenant)); } - + List loadedTenantsTitle1 = new ArrayList<>(); PageLink pageLink = new PageLink(15, 0, title1); PageData pageData = null; @@ -226,12 +219,12 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { pageLink = pageLink.nextPageLink(); } } while (pageData.hasNext()); - + Collections.sort(tenantsTitle1, idComparator); Collections.sort(loadedTenantsTitle1, idComparator); - + Assert.assertEquals(tenantsTitle1, loadedTenantsTitle1); - + List loadedTenantsTitle2 = new ArrayList<>(); pageLink = new PageLink(4, 0, title2); do { @@ -244,22 +237,22 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Collections.sort(tenantsTitle2, idComparator); Collections.sort(loadedTenantsTitle2, idComparator); - + Assert.assertEquals(tenantsTitle2, loadedTenantsTitle2); for (Tenant tenant : loadedTenantsTitle1) { tenantService.deleteTenant(tenant.getId()); } - + pageLink = new PageLink(4, 0, title1); pageData = tenantService.findTenants(pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(0, pageData.getData().size()); - + for (Tenant tenant : loadedTenantsTitle2) { tenantService.deleteTenant(tenant.getId()); } - + pageLink = new PageLink(4, 0, title2); pageData = tenantService.findTenants(pageLink); Assert.assertFalse(pageData.hasNext()); @@ -276,9 +269,9 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Assert.assertTrue(pageData.getData().isEmpty()); tenants.addAll(pageData.getData()); - for (int i=0;i<156;i++) { + for (int i = 0; i < 156; i++) { Tenant tenant = new Tenant(); - tenant.setTitle("Tenant"+i); + tenant.setTitle("Tenant" + i); tenants.add(new TenantInfo(tenantService.saveTenant(tenant), "Default")); } @@ -338,7 +331,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantService.findTenantById(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).findById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - var cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); + var cachedTenant = cache.get(savedTenant.getId()); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", cachedTenant); Assert.assertEquals(savedTenant, cachedTenant.get()); @@ -358,13 +351,13 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); //fromIdExists invoked from device profile validator - existsTenantCache.evict(TenantCacheKey.fromIdExists(savedTenant.getTenantId())); + existsTenantCache.evict(savedTenant.getTenantId()); verify(tenantDao, Mockito.times(0)).existsById(any(), any()); tenantService.tenantExists(savedTenant.getId()); verify(tenantDao, Mockito.times(1)).existsById(eq(savedTenant.getId()), eq(savedTenant.getId().getId())); - var isExists = existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); + var isExists = existsTenantCache.get(savedTenant.getId()); Assert.assertNotNull("Getting an existing Tenant doesn't add it to the cache!", isExists); for (int i = 0; i < 100; i++) { @@ -383,7 +376,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantService.findTenantById(savedTenant.getId()); - var cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); + var cachedTenant = cache.get(savedTenant.getId()); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); Assert.assertEquals(savedTenant, cachedTenant.get()); @@ -392,7 +385,7 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { Mockito.reset(tenantDao); - cachedTenant = cache.get(TenantCacheKey.fromId(savedTenant.getId())); + cachedTenant = cache.get(savedTenant.getId()); Assert.assertNull("Updating a Tenant doesn't evict the cache!", cachedTenant); verify(tenantDao, Mockito.times(0)).findById(any(), any()); @@ -411,18 +404,18 @@ public abstract class BaseTenantServiceTest extends AbstractServiceTest { tenantService.findTenantById(savedTenant.getId()); tenantService.tenantExists(savedTenant.getId()); - var cachedTenant = - cache.get(TenantCacheKey.fromId(savedTenant.getId())); + var cachedTenant = + cache.get(savedTenant.getId()); var cachedExists = - existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); + existsTenantCache.get(savedTenant.getId()); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedTenant); Assert.assertNotNull("Saving a Tenant doesn't add it to the cache!", cachedExists); tenantService.deleteTenant(savedTenant.getId()); cachedTenant = - cache.get(TenantCacheKey.fromId(savedTenant.getId())); + cache.get(savedTenant.getId()); cachedExists = - existsTenantCache.get(TenantCacheKey.fromIdExists(savedTenant.getId())); + existsTenantCache.get(savedTenant.getId()); Assert.assertNull("Removing a Tenant doesn't evict the cache!", cachedTenant); diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties index 063b1275d1..bf4178ec44 100644 --- a/dao/src/test/resources/application-test.properties +++ b/dao/src/test/resources/application-test.properties @@ -38,6 +38,9 @@ cache.specs.claimDevices.maxSize=100000 cache.specs.tenants.timeToLiveInMinutes=1440 cache.specs.tenants.maxSize=100000 +cache.specs.tenantsExist.timeToLiveInMinutes=1440 +cache.specs.tenantsExist.maxSize=100000 + cache.specs.securitySettings.timeToLiveInMinutes=1440 cache.specs.securitySettings.maxSize=100000