Browse Source

Merge branch 'master' of github.com:thingsboard/thingsboard into feature/jwt-version-update

pull/10671/head
YevhenBondarenko 2 years ago
parent
commit
61306c8026
  1. 5
      application/src/main/data/json/system/widget_bundles/charts.json
  2. 33
      application/src/main/data/json/system/widget_types/radar.json
  3. 25
      application/src/main/data/json/system/widget_types/radar_deprecated.json
  4. 17
      application/src/main/data/upgrade/3.6.4/schema_update.sql
  5. 28
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  6. 2
      application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java
  7. 2
      application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java
  8. 6
      application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java
  9. 1
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java
  10. 60
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java
  11. 3
      application/src/main/java/org/thingsboard/server/service/notification/channels/MobileAppNotificationChannel.java
  12. 28
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java
  13. 2
      application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java
  14. 21
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java
  15. 7
      application/src/main/java/org/thingsboard/server/service/ttl/AuditLogsCleanUpService.java
  16. 10
      application/src/main/resources/thingsboard.yml
  17. 81
      application/src/test/java/org/thingsboard/server/controller/AuditLogControllerTest.java
  18. 6
      application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java
  19. 27
      application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java
  20. 38
      application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java
  21. 163
      application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java
  22. 13
      application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java
  23. 2
      application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java
  24. 17
      application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java
  25. 5
      common/actor/pom.xml
  26. 69
      common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java
  27. 9
      common/actor/src/test/java/org/thingsboard/server/actors/SlowCreateActor.java
  28. 3
      common/actor/src/test/resources/junit-platform.properties
  29. 0
      common/actor/src/test/resources/logback-test.xml
  30. 5
      common/cache/pom.xml
  31. 14
      common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCacheEvictEvent.java
  32. 42
      common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCacheKey.java
  33. 33
      common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCaffeineCache.java
  34. 35
      common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerRedisCache.java
  35. 21
      common/cache/src/main/java/org/thingsboard/server/cache/user/UserCacheEvictEvent.java
  36. 42
      common/cache/src/main/java/org/thingsboard/server/cache/user/UserCacheKey.java
  37. 33
      common/cache/src/main/java/org/thingsboard/server/cache/user/UserCaffeineCache.java
  38. 35
      common/cache/src/main/java/org/thingsboard/server/cache/user/UserRedisCache.java
  39. 5
      common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java
  40. 3
      common/cache/src/test/resources/junit-platform.properties
  41. 0
      common/cache/src/test/resources/logback-test.xml
  42. 5
      common/cluster-api/pom.xml
  43. 10
      common/coap-server/pom.xml
  44. 2
      common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java
  45. 62
      common/coap-server/src/test/java/org/thingsboard/server/coapserver/TbCoapDtlsSettingsTest.java
  46. 5
      common/dao-api/pom.xml
  47. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
  48. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java
  49. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  50. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  51. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  52. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
  53. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java
  54. 5
      common/data/pom.xml
  55. 2
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  56. 4
      common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java
  57. 12
      common/data/src/main/java/org/thingsboard/server/common/data/HasDefaultOption.java
  58. 3
      common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java
  59. 9
      common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java
  60. 14
      common/data/src/test/java/org/thingsboard/server/common/data/DynamicProtoUtilsTest.java
  61. 17
      common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java
  62. 6
      common/data/src/test/java/org/thingsboard/server/common/data/id/EntityIdTest.java
  63. 3
      common/data/src/test/resources/junit-platform.properties
  64. 14
      common/data/src/test/resources/logback-test.xml
  65. 5
      common/message/pom.xml
  66. 8
      common/message/src/test/java/org/thingsboard/server/common/msg/TbMsgMetaDataTest.java
  67. 2
      common/message/src/test/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfoTest.java
  68. 2
      common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java
  69. 3
      common/message/src/test/resources/junit-platform.properties
  70. 14
      common/message/src/test/resources/logback-test.xml
  71. 5
      common/proto/pom.xml
  72. 4
      common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java
  73. 28
      common/proto/src/test/java/org/thingsboard/server/common/adaptor/JsonConverterTest.java
  74. 3
      common/proto/src/test/resources/junit-platform.properties
  75. 14
      common/proto/src/test/resources/logback-test.xml
  76. 5
      common/queue/pom.xml
  77. 19
      common/queue/src/test/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplateTest.java
  78. 15
      common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java
  79. 2
      common/queue/src/test/java/org/thingsboard/server/queue/memory/DefaultInMemoryStorageTest.java
  80. 3
      common/queue/src/test/resources/junit-platform.properties
  81. 5
      common/script/remote-js-client/pom.xml
  82. 5
      common/script/script-api/pom.xml
  83. 14
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java
  84. 416
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java
  85. 262
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java
  86. 3
      common/script/script-api/src/test/resources/junit-platform.properties
  87. 14
      common/script/script-api/src/test/resources/logback-test.xml
  88. 5
      common/stats/pom.xml
  89. 5
      common/transport/coap/pom.xml
  90. 3
      common/transport/coap/src/test/resources/junit-platform.properties
  91. 14
      common/transport/coap/src/test/resources/logback-test.xml
  92. 5
      common/transport/http/pom.xml
  93. 3
      common/transport/http/src/test/resources/junit-platform.properties
  94. 5
      common/transport/lwm2m/pom.xml
  95. 2
      common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientTest.java
  96. 9
      common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/store/util/LwM2MClientSerDesTest.java
  97. 3
      common/transport/lwm2m/src/test/resources/junit-platform.properties
  98. 14
      common/transport/lwm2m/src/test/resources/logback-test.xml
  99. 5
      common/transport/mqtt/pom.xml
  100. 24
      common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java

5
application/src/main/data/json/system/widget_bundles/charts.json

@ -21,7 +21,7 @@
"doughnut",
"horizontal_doughnut",
"polar_area",
"charts.radar_chart_js",
"radar",
"charts.basic_timeseries",
"charts.state_chart",
"charts.timeseries_bars_flot",
@ -29,6 +29,7 @@
"charts.pie",
"charts.pie_chart_js",
"charts.doughnut_chart_js",
"charts.polar_area_chart_js"
"charts.polar_area_chart_js",
"charts.radar_chart_js"
]
}

33
application/src/main/data/json/system/widget_types/radar.json

File diff suppressed because one or more lines are too long

25
application/src/main/data/json/system/widget_types/radar_deprecated.json

File diff suppressed because one or more lines are too long

17
application/src/main/data/upgrade/3.6.4/schema_update.sql

@ -14,6 +14,23 @@
-- limitations under the License.
--
-- UPDATE PUBLIC CUSTOMERS START
DO
$$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_name = 'customer' AND column_name = 'is_public'
) THEN
ALTER TABLE customer ADD COLUMN is_public boolean DEFAULT false;
UPDATE customer SET is_public = true WHERE title = 'Public';
END IF;
END;
$$;
-- UPDATE PUBLIC CUSTOMERS END
-- create new attribute_kv table schema
DO
$$

28
application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java

@ -72,12 +72,11 @@ public class ThingsboardSecurityConfiguration {
public static final String JWT_TOKEN_HEADER_PARAM_V2 = "Authorization";
public static final String JWT_TOKEN_QUERY_PARAM = "token";
public static final String WEBJARS_ENTRY_POINT = "/webjars/**";
public static final String DEVICE_API_ENTRY_POINT = "/api/v1/**";
public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login";
public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public";
public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token";
protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**", "/api/images/public/**"};
protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[]{"/index.html", "/assets/**", "/static/**", "/api/noauth/**", "/webjars/**", "/api/license/**", "/api/images/public/**"};
public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**";
public static final String WS_ENTRY_POINT = "/api/ws/**";
public static final String MAIL_OAUTH2_PROCESSING_ENTRY_POINT = "/api/admin/mail/oauth2/code";
@ -153,7 +152,7 @@ public class ThingsboardSecurityConfiguration {
protected JwtTokenAuthenticationProcessingFilter buildJwtTokenAuthenticationProcessingFilter() throws Exception {
List<String> pathsToSkip = new ArrayList<>(Arrays.asList(NON_TOKEN_BASED_AUTH_ENTRY_POINTS));
pathsToSkip.addAll(Arrays.asList(WS_ENTRY_POINT, TOKEN_REFRESH_ENTRY_POINT, FORM_BASED_LOGIN_ENTRY_POINT,
PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, WEBJARS_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT,
PUBLIC_LOGIN_ENTRY_POINT, DEVICE_API_ENTRY_POINT, MAIL_OAUTH2_PROCESSING_ENTRY_POINT,
DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT));
SkipPathRequestMatcher matcher = new SkipPathRequestMatcher(pathsToSkip, TOKEN_BASED_AUTH_ENTRY_POINT);
JwtTokenAuthenticationProcessingFilter filter
@ -210,18 +209,17 @@ public class ThingsboardSecurityConfiguration {
.exceptionHandling(config -> {})
.sessionManagement(config -> config.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(config -> config
.requestMatchers(WEBJARS_ENTRY_POINT).permitAll() // Webjars
.requestMatchers(DEVICE_API_ENTRY_POINT).permitAll() // Device HTTP Transport API
.requestMatchers(FORM_BASED_LOGIN_ENTRY_POINT).permitAll() // Login end-point
.requestMatchers(PUBLIC_LOGIN_ENTRY_POINT).permitAll() // Public login end-point
.requestMatchers(TOKEN_REFRESH_ENTRY_POINT).permitAll() // Token refresh end-point
.requestMatchers(MAIL_OAUTH2_PROCESSING_ENTRY_POINT).permitAll() // Mail oauth2 code processing url
.requestMatchers(DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT).permitAll() // Device connectivity certificate (public)
.requestMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points
.requestMatchers(WS_ENTRY_POINT).permitAll() // Protected WebSocket API End-points
.requestMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated()) // Protected API End-points
.formLogin(form -> form
.loginPage("/login").permitAll())
.requestMatchers(NON_TOKEN_BASED_AUTH_ENTRY_POINTS).permitAll() // static resources, user activation and password reset end-points (webjars included)
.requestMatchers(
DEVICE_API_ENTRY_POINT, // Device HTTP Transport API
FORM_BASED_LOGIN_ENTRY_POINT, // Login end-point
PUBLIC_LOGIN_ENTRY_POINT, // Public login end-point
TOKEN_REFRESH_ENTRY_POINT, // Token refresh end-point
MAIL_OAUTH2_PROCESSING_ENTRY_POINT, // Mail oauth2 code processing url
DEVICE_CONNECTIVITY_CERTIFICATE_DOWNLOAD_ENTRY_POINT, // Device connectivity certificate (public)
WS_ENTRY_POINT).permitAll() // Protected WebSocket API End-points
.requestMatchers(TOKEN_BASED_AUTH_ENTRY_POINT).authenticated() // Protected API End-points
.anyRequest().permitAll())
.exceptionHandling(config -> config.accessDeniedHandler(restAccessDeniedHandler))
.addFilterBefore(buildRestLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(buildRestPublicLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class)

2
application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java

@ -133,6 +133,8 @@ public class ThingsboardInstallService {
case "3.6.4":
log.info("Upgrading ThingsBoard from version 3.6.4 to 3.7.0 ...");
databaseEntitiesUpgradeService.upgradeDatabase("3.6.4");
dataUpdateService.updateData("3.6.4");
entityDatabaseSchemaService.createCustomerTitleUniqueConstraintIfNotExists();
systemDataLoaderService.updateDefaultNotificationConfigs(false);
systemDataLoaderService.updateJwtSettings();
//TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache

2
application/src/main/java/org/thingsboard/server/service/install/EntityDatabaseSchemaService.java

@ -21,4 +21,6 @@ public interface EntityDatabaseSchemaService extends DatabaseSchemaService {
void createOrUpdateViewsAndFunctions() throws Exception;
void createCustomerTitleUniqueConstraintIfNotExists();
}

6
application/src/main/java/org/thingsboard/server/service/install/SqlEntityDatabaseSchemaService.java

@ -52,4 +52,10 @@ public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSer
log.info("Installing SQL DataBase schema views and functions: " + SCHEMA_VIEWS_AND_FUNCTIONS_SQL);
executeQueryFromFile(SCHEMA_VIEWS_AND_FUNCTIONS_SQL);
}
@Override
public void createCustomerTitleUniqueConstraintIfNotExists() {
executeQuery("DO $$ BEGIN IF NOT EXISTS(SELECT 1 FROM pg_constraint WHERE conname = 'customer_title_unq_key') THEN " +
"ALTER TABLE customer ADD CONSTRAINT customer_title_unq_key UNIQUE(tenant_id, title); END IF; END; $$;");
}
}

1
application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java

@ -27,7 +27,6 @@ import org.springframework.stereotype.Service;
import java.util.Objects;
import java.util.Optional;
import static org.thingsboard.server.common.data.CacheConstants.ATTRIBUTES_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.RESOURCE_INFO_CACHE;
import static org.thingsboard.server.common.data.CacheConstants.SECURITY_SETTINGS_CACHE;

60
application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java

@ -26,12 +26,15 @@ import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.id.RuleNodeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable;
import org.thingsboard.server.common.data.query.DynamicValue;
import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.dao.customer.CustomerDao;
import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.device.DeviceConnectivityConfiguration;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.settings.AdminSettingsService;
@ -42,6 +45,7 @@ import org.thingsboard.server.utils.TbNodeUpgradeUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
@Service
@ -67,6 +71,13 @@ public class DefaultDataUpdateService implements DataUpdateService {
@Autowired
DeviceConnectivityConfiguration connectivityConfiguration;
@Autowired
private CustomerDao customerDao;
@Autowired
private CustomerService customerService;
@Override
public void updateData(String fromVersion) throws Exception {
switch (fromVersion) {
@ -74,11 +85,60 @@ public class DefaultDataUpdateService implements DataUpdateService {
log.info("Updating data from version 3.6.0 to 3.6.1 ...");
migrateDeviceConnectivity();
break;
case "3.6.4":
log.info("Updating data from version 3.6.4 to 3.7.0 ...");
updateCustomersWithTheSameTitle();
break;
default:
throw new RuntimeException("Unable to update data, unsupported fromVersion: " + fromVersion);
}
}
private void updateCustomersWithTheSameTitle() {
var customers = new ArrayList<Customer>();
new PageDataIterable<>(pageLink ->
customerDao.findCustomersWithTheSameTitle(pageLink), DEFAULT_PAGE_SIZE
).forEach(customers::add);
if (customers.isEmpty()) {
return;
}
var firstCustomer = customers.get(0);
var titleToDeduplicate = firstCustomer.getTitle();
var tenantIdToDeduplicate = firstCustomer.getTenantId();
int duplicateCounter = 1;
for (int i = 1; i < customers.size(); i++) {
var currentCustomer = customers.get(i);
if (currentCustomer.getTitle().equals(titleToDeduplicate) && currentCustomer.getTenantId().equals(tenantIdToDeduplicate)) {
duplicateCounter++;
String currentTitle = currentCustomer.getTitle();
String newTitle = currentTitle + " " + duplicateCounter;
try {
Optional<Customer> customerOpt = customerService.findCustomerByTenantIdAndTitle(tenantIdToDeduplicate, newTitle);
if (customerOpt.isPresent()) {
// fallback logic: customer with title 'currentTitle + " " + duplicateCounter;' might be another duplicate.
newTitle = currentTitle + "_" + currentCustomer.getId();
}
} catch (Exception e) {
log.trace("Failed to find customer with title due to: ", e);
// fallback logic: customer with title 'currentTitle + " " + duplicateCounter;' might be another duplicate.
newTitle = currentTitle + "_" + currentCustomer.getId();
}
currentCustomer.setTitle(newTitle);
try {
customerService.saveCustomer(currentCustomer);
} catch (Exception e) {
log.error("[{}] Failed to update customer with id and title: {}, oldTitle: {}, due to: ",
currentCustomer.getTenantId(), newTitle, currentTitle, e);
}
continue;
}
titleToDeduplicate = currentCustomer.getTitle();
tenantIdToDeduplicate = currentCustomer.getTenantId();
duplicateCounter = 1;
}
}
private void migrateDeviceConnectivity() {
if (adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "connectivity") == null) {
AdminSettings connectivitySettings = new AdminSettings();

3
application/src/main/java/org/thingsboard/server/service/notification/channels/MobileAppNotificationChannel.java

@ -105,9 +105,10 @@ public class MobileAppNotificationChannel implements NotificationChannel<User, M
firebaseService.sendMessage(ctx.getTenantId(), credentials, token, subject, body, data, unreadCount);
} catch (FirebaseMessagingException e) {
MessagingErrorCode errorCode = e.getMessagingErrorCode();
if (errorCode == MessagingErrorCode.UNREGISTERED || errorCode == MessagingErrorCode.INVALID_ARGUMENT) {
if (errorCode == MessagingErrorCode.UNREGISTERED || errorCode == MessagingErrorCode.INVALID_ARGUMENT || errorCode == MessagingErrorCode.SENDER_ID_MISMATCH) {
validTokens.remove(token);
userService.removeMobileSession(recipient.getTenantId(), token);
log.debug("[{}][{}] Removed invalid FCM token due to {} {} ({})", recipient.getTenantId(), recipient.getId(), errorCode, e.getMessage(), token);
continue;
}
throw new RuntimeException("Failed to send message via FCM: " + e.getMessage(), e);

28
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/DefaultExportableEntitiesService.java

@ -108,34 +108,40 @@ public class DefaultExportableEntitiesService implements ExportableEntitiesServi
return entity;
}
@Override
public <E extends ExportableEntity<I>, I extends EntityId> E findDefaultEntityByTenantId(TenantId tenantId, EntityType entityType) {
ExportableEntityDao<I, E> dao = getExportableEntityDao(entityType);
if (dao == null) {
return null;
}
return dao.findDefaultEntityByTenantId(tenantId.getId());
}
@Override
public <E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) {
ExportableEntityDao<I, E> dao = getExportableEntityDao(entityType);
if (dao != null) {
return dao.findByTenantId(tenantId.getId(), pageLink);
} else {
return new PageData<>();
if (dao == null) {
return PageData.emptyPageData();
}
return dao.findByTenantId(tenantId.getId(), pageLink);
}
@Override
public <I extends EntityId> PageData<I> findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink) {
ExportableEntityDao<I, ?> dao = getExportableEntityDao(entityType);
if (dao != null) {
return dao.findIdsByTenantId(tenantId.getId(), pageLink);
} else {
return new PageData<>();
if (dao == null) {
return PageData.emptyPageData();
}
return dao.findIdsByTenantId(tenantId.getId(), pageLink);
}
@Override
public <I extends EntityId> I getExternalIdByInternal(I internalId) {
ExportableEntityDao<I, ?> dao = getExportableEntityDao(internalId.getEntityType());
if (dao != null) {
return dao.getExternalIdByInternal(internalId);
} else {
if (dao == null) {
return null;
}
return dao.getExternalIdByInternal(internalId);
}
private boolean belongsToTenant(HasId<? extends EntityId> entity, TenantId tenantId) {

2
application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/ExportableEntitiesService.java

@ -33,6 +33,8 @@ public interface ExportableEntitiesService {
<E extends ExportableEntity<I>, I extends EntityId> E findEntityByTenantIdAndName(TenantId tenantId, EntityType entityType, String name);
<E extends ExportableEntity<I>, I extends EntityId> E findDefaultEntityByTenantId(TenantId tenantId, EntityType entityType);
<E extends ExportableEntity<I>, I extends EntityId> PageData<E> findEntitiesByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);
<I extends EntityId> PageData<I> findEntitiesIdsByTenantId(TenantId tenantId, EntityType entityType, PageLink pageLink);

21
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/BaseEntityImportService.java

@ -27,6 +27,7 @@ import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasDefaultOption;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
@ -73,7 +74,7 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@Autowired
@Lazy
private ExportableEntitiesService exportableEntitiesService;
private ExportableEntitiesService entitiesService;
@Autowired
private RelationService relationService;
@Autowired
@ -274,22 +275,30 @@ public abstract class BaseEntityImportService<I extends EntityId, E extends Expo
@SuppressWarnings("unchecked")
protected E findExistingEntity(EntitiesImportCtx ctx, E entity, IdProvider idProvider) {
return (E) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(ctx.getTenantId(), entity.getId()))
.or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entity.getId())))
return (E) Optional.ofNullable(entitiesService.findEntityByTenantIdAndExternalId(ctx.getTenantId(), entity.getId()))
.or(() -> Optional.ofNullable(entitiesService.findEntityByTenantIdAndId(ctx.getTenantId(), entity.getId())))
.or(() -> {
if (ctx.isFindExistingByName()) {
return Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndName(ctx.getTenantId(), getEntityType(), entity.getName()));
return Optional.ofNullable(entitiesService.findEntityByTenantIdAndName(ctx.getTenantId(), getEntityType(), entity.getName()));
} else {
return Optional.empty();
}
})
.or(() -> {
if (entity instanceof HasDefaultOption hasDefaultOption) {
if (hasDefaultOption.isDefault()) {
return Optional.ofNullable(entitiesService.findDefaultEntityByTenantId(ctx.getTenantId(), getEntityType()));
}
}
return Optional.empty();
})
.orElse(null);
}
@SuppressWarnings("unchecked")
private <ID extends EntityId> HasId<ID> findInternalEntity(TenantId tenantId, ID externalId) {
return (HasId<ID>) Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndExternalId(tenantId, externalId))
.or(() -> Optional.ofNullable(exportableEntitiesService.findEntityByTenantIdAndId(tenantId, externalId)))
return (HasId<ID>) Optional.ofNullable(entitiesService.findEntityByTenantIdAndExternalId(tenantId, externalId))
.or(() -> Optional.ofNullable(entitiesService.findEntityByTenantIdAndId(tenantId, externalId)))
.orElseThrow(() -> new MissingEntityException(externalId));
}

7
application/src/main/java/org/thingsboard/server/service/ttl/AuditLogsCleanUpService.java

@ -50,7 +50,8 @@ public class AuditLogsCleanUpService extends AbstractCleanUpService {
@Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.audit_logs.checking_interval_ms})}",
fixedDelayString = "${sql.ttl.audit_logs.checking_interval_ms}")
public void cleanUp() {
long auditLogsExpTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec);
long auditLogsExpTime = getCurrentTimeMillis() - TimeUnit.SECONDS.toMillis(ttlInSec);
log.debug("cleanup {}", auditLogsExpTime);
if (isSystemTenantPartitionMine()) {
auditLogDao.cleanUpAuditLogs(auditLogsExpTime);
} else {
@ -58,4 +59,8 @@ public class AuditLogsCleanUpService extends AbstractCleanUpService {
}
}
public long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
}

10
application/src/main/resources/thingsboard.yml

@ -505,6 +505,12 @@ cache:
assets:
timeToLiveInMinutes: "${CACHE_SPECS_ASSETS_TTL:1440}" # Asset cache TTL
maxSize: "${CACHE_SPECS_ASSETS_MAX_SIZE:10000}" # 0 means the cache is disabled
customers:
timeToLiveInMinutes: "${CACHE_SPECS_CUSTOMERS_TTL:1440}" # Customer cache TTL
maxSize: "${CACHE_SPECS_CUSTOMERS_MAX_SIZE:10000}" # 0 means the cache is disabled
users:
timeToLiveInMinutes: "${CACHE_SPECS_USERS_TTL:1440}" # User cache TTL
maxSize: "${CACHE_SPECS_USERS_MAX_SIZE:10000}" # 0 means the cache is disabled
entityViews:
timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_VIEWS_TTL:1440}" # Entity view cache TTL
maxSize: "${CACHE_SPECS_ENTITY_VIEWS_MAX_SIZE:10000}" # 0 means the cache is disabled
@ -1767,3 +1773,7 @@ management:
exposure:
# Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics).
include: '${METRICS_ENDPOINTS_EXPOSE:info}'
health:
elasticsearch:
# Enable the org.springframework.boot.actuate.elasticsearch.ElasticsearchRestClientHealthIndicator.doHealthCheck
enabled: "false"

81
application/src/test/java/org/thingsboard/server/controller/AuditLogControllerTest.java

@ -15,7 +15,9 @@
*/
package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@ -28,6 +30,7 @@ import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.id.AuditLogId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
@ -38,18 +41,21 @@ import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository;
import org.thingsboard.server.service.ttl.AuditLogsCleanUpService;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.apache.commons.lang3.time.DateFormatUtils.ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@Slf4j
@DaoSqlTest
public class AuditLogControllerTest extends AbstractControllerTest {
@ -60,7 +66,7 @@ public class AuditLogControllerTest extends AbstractControllerTest {
private AuditLogDao auditLogDao;
@SpyBean
private SqlPartitioningRepository partitioningRepository;
@Autowired
@SpyBean
private AuditLogsCleanUpService auditLogsCleanUpService;
@Value("#{${sql.audit_logs.partition_size} * 60 * 60 * 1000}")
@ -96,7 +102,7 @@ public class AuditLogControllerTest extends AbstractControllerTest {
@Test
public void testAuditLogs() throws Exception {
for (int i = 0; i < 178; i++) {
for (int i = 0; i < 11; i++) {
Device device = new Device();
device.setName("Device" + i);
device.setType("default");
@ -104,7 +110,7 @@ public class AuditLogControllerTest extends AbstractControllerTest {
}
List<AuditLog> loadedAuditLogs = new ArrayList<>();
TimePageLink pageLink = new TimePageLink(23);
TimePageLink pageLink = new TimePageLink(5);
PageData<AuditLog> pageData;
do {
pageData = doGetTypedWithTimePageLink("/api/audit/logs?",
@ -116,10 +122,10 @@ public class AuditLogControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
Assert.assertEquals(178, loadedAuditLogs.size());
Assert.assertEquals(11, loadedAuditLogs.size());
loadedAuditLogs = new ArrayList<>();
pageLink = new TimePageLink(23);
pageLink = new TimePageLink(5);
do {
pageData = doGetTypedWithTimePageLink("/api/audit/logs/customer/" + ModelConstants.NULL_UUID + "?",
new TypeReference<PageData<AuditLog>>() {
@ -130,10 +136,10 @@ public class AuditLogControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
Assert.assertEquals(178, loadedAuditLogs.size());
Assert.assertEquals(11, loadedAuditLogs.size());
loadedAuditLogs = new ArrayList<>();
pageLink = new TimePageLink(23);
pageLink = new TimePageLink(5);
do {
pageData = doGetTypedWithTimePageLink("/api/audit/logs/user/" + tenantAdmin.getId().getId().toString() + "?",
new TypeReference<PageData<AuditLog>>() {
@ -144,7 +150,7 @@ public class AuditLogControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
Assert.assertEquals(178, loadedAuditLogs.size());
Assert.assertEquals(11, loadedAuditLogs.size());
}
@Test
@ -153,13 +159,13 @@ public class AuditLogControllerTest extends AbstractControllerTest {
device.setName("Device name");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
for (int i = 0; i < 178; i++) {
for (int i = 0; i < 11; i++) {
savedDevice.setName("Device name" + i);
doPost("/api/device", savedDevice, Device.class);
}
List<AuditLog> loadedAuditLogs = new ArrayList<>();
TimePageLink pageLink = new TimePageLink(23);
TimePageLink pageLink = new TimePageLink(5);
PageData<AuditLog> pageData;
do {
pageData = doGetTypedWithTimePageLink("/api/audit/logs/entity/DEVICE/" + savedDevice.getId().getId() + "?",
@ -171,54 +177,62 @@ public class AuditLogControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
Assert.assertEquals(179, loadedAuditLogs.size());
Assert.assertEquals(11 + 1, loadedAuditLogs.size());
}
@Test
public void whenSavingNewAuditLog_thenCheckAndCreatePartitionIfNotExists() {
public void whenSavingNewAuditLog_thenCheckAndCreatePartitionIfNotExists() throws ParseException {
long entityTs = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.parse("2024-01-01T01:43:11Z").getTime();
reset(partitioningRepository);
AuditLog auditLog = createAuditLog(ActionType.LOGIN, tenantAdminUserId);
AuditLog auditLog = createAuditLog(ActionType.LOGIN, tenantAdminUserId, entityTs);
verify(partitioningRepository).createPartitionIfNotExists(eq("audit_log"), eq(auditLog.getCreatedTime()), eq(partitionDurationInMs));
List<Long> partitions = partitioningRepository.fetchPartitions("audit_log");
assertThat(partitions).singleElement().satisfies(partitionStartTs -> {
assertThat(partitionStartTs).isEqualTo(partitioningRepository.calculatePartitionStartTime(auditLog.getCreatedTime(), partitionDurationInMs));
});
assertThat(partitions).contains(partitioningRepository.calculatePartitionStartTime(auditLog.getCreatedTime(), partitionDurationInMs));
}
@Test
public void whenCleaningUpAuditLogsByTtl_thenDropOldPartitions() {
long oldAuditLogTs = LocalDate.of(2020, 10, 1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli();
long partitionStartTs = partitioningRepository.calculatePartitionStartTime(oldAuditLogTs, partitionDurationInMs);
public void whenCleaningUpAuditLogsByTtl_thenDropOldPartitions() throws ParseException {
final long oldAuditLogTs = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.parse("2020-10-01T00:00:00Z").getTime();
final long currentTimeMillis = oldAuditLogTs + TimeUnit.SECONDS.toMillis(auditLogsTtlInSec) * 2;
final long partitionStartTs = partitioningRepository.calculatePartitionStartTime(oldAuditLogTs, partitionDurationInMs);
partitioningRepository.createPartitionIfNotExists("audit_log", oldAuditLogTs, partitionDurationInMs);
List<Long> partitions = partitioningRepository.fetchPartitions("audit_log");
assertThat(partitions).contains(partitionStartTs);
willReturn(currentTimeMillis).given(auditLogsCleanUpService).getCurrentTimeMillis();
auditLogsCleanUpService.cleanUp();
partitions = partitioningRepository.fetchPartitions("audit_log");
assertThat(partitions).doesNotContain(partitionStartTs);
assertThat(partitions).allSatisfy(partitionsStart -> {
assertThat(partitions).as("partitions cleared").doesNotContain(partitionStartTs);
assertThat(partitions).as("only newer partitions left").allSatisfy(partitionsStart -> {
long partitionEndTs = partitionsStart + partitionDurationInMs;
assertThat(partitionEndTs).isGreaterThan(System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(auditLogsTtlInSec));
assertThat(partitionEndTs).isGreaterThan(currentTimeMillis - TimeUnit.SECONDS.toMillis(auditLogsTtlInSec));
});
}
@Test
public void whenSavingAuditLogAndPartitionSaveErrorOccurred_thenSaveAuditLogAnyway() throws Exception {
// creating partition bigger than sql.audit_logs.partition_size
partitioningRepository.createPartitionIfNotExists("audit_log", System.currentTimeMillis(), TimeUnit.DAYS.toMillis(7));
long entityTs = ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.parse("2022-04-29T07:43:11Z").getTime();
//the partition 7 days is overlapping default partition size 1 day, use in the far past to not affect other tests
partitioningRepository.createPartitionIfNotExists("audit_log", entityTs, TimeUnit.DAYS.toMillis(7));
List<Long> partitions = partitioningRepository.fetchPartitions("audit_log");
assertThat(partitions).size().isOne();
partitioningRepository.cleanupPartitionsCache("audit_log", System.currentTimeMillis(), 0);
log.warn("entityTs [{}], fetched partitions {}", entityTs, partitions);
assertThat(partitions).contains(ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.parse("2022-04-28T00:00:00Z").getTime());
partitioningRepository.cleanupPartitionsCache("audit_log", entityTs, 0);
assertDoesNotThrow(() -> {
// expecting partition overlap error on partition save
createAuditLog(ActionType.LOGIN, tenantAdminUserId);
createAuditLog(ActionType.LOGIN, tenantAdminUserId, entityTs);
});
assertThat(partitioningRepository.fetchPartitions("audit_log")).isEqualTo(partitions);
assertThat(partitioningRepository.fetchPartitions("audit_log"))
.contains(ISO_8601_EXTENDED_DATETIME_TIME_ZONE_FORMAT.parse("2022-04-28T00:00:00Z").getTime());;
}
private AuditLog createAuditLog(ActionType actionType, EntityId entityId) {
private AuditLog createAuditLog(ActionType actionType, EntityId entityId, long entityTs) {
AuditLog auditLog = new AuditLog();
auditLog.setTenantId(tenantId);
auditLog.setCustomerId(null);
@ -226,6 +240,13 @@ public class AuditLogControllerTest extends AbstractControllerTest {
auditLog.setEntityId(entityId);
auditLog.setUserName(tenantAdmin.getEmail());
auditLog.setActionType(actionType);
if (entityTs > 0) {
UUID uuid = Uuids.startOf(entityTs);
auditLog.setId(new AuditLogId(uuid));
auditLog.setCreatedTime(Uuids.unixTimestamp(uuid));
}
return auditLogDao.save(tenantId, auditLog);
}

6
application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java

@ -167,4 +167,10 @@ public class AuthControllerTest extends AbstractControllerTest {
.andExpect(jsonPath("$.message",
is("Password must be no more than 72 characters in length.")));
}
@Test
public void testGetPageWithoutRedirect() throws Exception {
doGet("/login").andExpect(status().isOk());
doGet("/home").andExpect(status().isOk());
}
}

27
application/src/test/java/org/thingsboard/server/controller/CustomerControllerTest.java

@ -352,7 +352,7 @@ public class CustomerControllerTest extends AbstractControllerTest {
}
@Test
public void testFindCustomersByTitle() throws Exception {
public void testFindCustomersWithTitleAsTextSearch() throws Exception {
TenantId tenantId = savedTenant.getId();
String title1 = "Customer title 1";
@ -424,6 +424,31 @@ public class CustomerControllerTest extends AbstractControllerTest {
Assert.assertEquals(0, pageData.getData().size());
}
@Test
public void testFindCustomerByTitle() throws Exception {
Customer customer = new Customer();
customer.setTitle("My customer");
Mockito.reset(tbClusterService, auditLogService);
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
testNotifyEntityAllOneTime(savedCustomer, savedCustomer.getId(), savedCustomer.getId(), savedCustomer.getTenantId(),
new CustomerId(CustomerId.NULL_UUID), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
Assert.assertNotNull(savedCustomer);
Assert.assertNotNull(savedCustomer.getId());
Assert.assertTrue(savedCustomer.getCreatedTime() > 0);
Assert.assertEquals(customer.getTitle(), savedCustomer.getTitle());
Customer foundCustomer = doGet("/api/tenant/customers?customerTitle=" + savedCustomer.getTitle(), Customer.class);
Assert.assertEquals(foundCustomer, savedCustomer);
doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isOk());
}
@Test
public void testDeleteCustomerWithDeleteRelationsOk() throws Exception {
CustomerId customerId = createCustomer("Customer for Test WithRelationsOk").getId();

38
application/src/test/java/org/thingsboard/server/controller/DeviceControllerTest.java

@ -84,6 +84,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
@ -1541,17 +1542,24 @@ public class DeviceControllerTest extends AbstractControllerTest {
Device savedDevice = doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class);
//check server attribute value
List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<>() {
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> {
Map<String, Object> actualAttribute = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<List<Map<String, Object>>>() {}).stream()
.filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(attributeValue, actualAttribute.get("value"));
});
Map<String, Object> serverAttribute = values.stream().filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(attributeValue, serverAttribute.get("value"));
//update server attribute value
String newAttributeValue = "testValue2";
JsonNode content = JacksonUtil.toJsonNode("{\"DATA\": \"" + newAttributeValue + "\"}");
doPost("/api/plugins/telemetry/" + EntityType.DEVICE.name() + "/" + savedDevice.getUuidId() + "/SERVER_SCOPE", content)
.andExpect(status().isOk());
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> {
Map<String, Object> actualAttribute = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<List<Map<String, Object>>>() {}).stream()
.filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(newAttributeValue, actualAttribute.get("value"));
});
//reimport devices
String deviceName2 = "secondDevice";
@ -1563,19 +1571,19 @@ public class DeviceControllerTest extends AbstractControllerTest {
doPostWithTypedResponse("/api/device/bulk_import", request, new TypeReference<>() {});
Device savedDevice2 = doGet("/api/tenant/devices?deviceName=" + deviceName2, Device.class);
//check attribute value was not changed after reimport
List<Map<String, Object>> values2 = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<>() {
});
Map<String, Object> retrievedServerAttribute2 = values2.stream().filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(newAttributeValue, retrievedServerAttribute2.get("value"));
//check attribute for second device
List<Map<String, Object>> values3 = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice2.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<>() {
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> {
Map<String, Object> actualAttribute = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice2.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<List<Map<String, Object>>>() {}).stream()
.filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(attributeValue2, actualAttribute.get("value"));
});
Map<String, Object> retrievedServerAttribute3 = values3.stream().filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(attributeValue2, retrievedServerAttribute3.get("value"));
//check attribute value was not changed after reimport
Map<String, Object> actualAttribute = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + savedDevice.getId() +
"/values/attributes/SERVER_SCOPE", new TypeReference<List<Map<String, Object>>>() {}).stream()
.filter(att -> att.get("key").equals("DATA")).findFirst().get();
Assert.assertEquals(newAttributeValue, actualAttribute.get("value"));
}
private Device createDevice(String name) {

163
application/src/test/java/org/thingsboard/server/controller/EntityQueryControllerTest.java

@ -52,6 +52,7 @@ import org.thingsboard.server.common.data.query.EntityTypeFilter;
import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.query.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.query.StringFilterPredicate;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.data.queue.QueueStats;
import org.thingsboard.server.common.data.security.Authority;
@ -642,4 +643,166 @@ public class EntityQueryControllerTest extends AbstractControllerTest {
Assert.assertEquals(97, count.longValue());
}
@Test
public void testFindDevicesCountByOwnerNameAndOwnerType() throws Exception {
loginTenantAdmin();
int numOfDevices = 8;
for (int i = 0; i < numOfDevices; i++) {
Device device = new Device();
String name = "Device" + i;
device.setName(name);
device.setType("default");
Device savedDevice = doPost("/api/device?accessToken=" + name, device, Device.class);
JsonNode content = JacksonUtil.toJsonNode("{\"alarmActiveTime\": 1" + i + "}");
doPost("/api/plugins/telemetry/" + EntityType.DEVICE.name() + "/" + savedDevice.getUuidId() + "/SERVER_SCOPE", content)
.andExpect(status().isOk());
}
DeviceTypeFilter filter = new DeviceTypeFilter();
filter.setDeviceTypes(List.of("default"));
filter.setDeviceNameFilter("");
KeyFilter activeAlarmTimeFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 5);
KeyFilter activeAlarmTimeToLongFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 30);
KeyFilter tenantOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", TEST_TENANT_NAME);
KeyFilter wrongOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", "wrongName");
KeyFilter tenantOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "TENANT");
KeyFilter customerOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "CUSTOMER");
// all devices with ownerName = TEST TENANT
EntityCountQuery query = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, tenantOwnerNameFilter));
checkEntitiesCount(query, numOfDevices);
// all devices with ownerName = TEST TENANT
EntityCountQuery activeAlarmTimeToLongQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeToLongFilter, tenantOwnerNameFilter));
checkEntitiesCount(activeAlarmTimeToLongQuery, 0);
// all devices with wrong ownerName
EntityCountQuery wrongTenantNameQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, wrongOwnerNameFilter));
checkEntitiesCount(wrongTenantNameQuery, 0);
// all devices with owner type = TENANT
EntityCountQuery tenantEntitiesQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, tenantOwnerTypeFilter));
checkEntitiesCount(tenantEntitiesQuery, numOfDevices);
// all devices with owner type = CUSTOMER
EntityCountQuery customerEntitiesQuery = new EntityCountQuery(filter, List.of(activeAlarmTimeFilter, customerOwnerTypeFilter));
checkEntitiesCount(customerEntitiesQuery, 0);
}
@Test
public void testFindDevicesByOwnerNameAndOwnerType() throws Exception {
loginTenantAdmin();
int numOfDevices = 3;
for (int i = 0; i < numOfDevices; i++) {
Device device = new Device();
String name = "Device" + i;
device.setName(name);
device.setType("default");
Device savedDevice = doPost("/api/device?accessToken=" + name, device, Device.class);
JsonNode content = JacksonUtil.toJsonNode("{\"alarmActiveTime\": 1" + i + "}");
doPost("/api/plugins/telemetry/" + EntityType.DEVICE.name() + "/" + savedDevice.getUuidId() + "/SERVER_SCOPE", content)
.andExpect(status().isOk());
}
DeviceTypeFilter filter = new DeviceTypeFilter();
filter.setDeviceTypes(List.of("default"));
filter.setDeviceNameFilter("");
KeyFilter activeAlarmTimeFilter = getServerAttributeNumericGreaterThanKeyFilter("alarmActiveTime", 5);
KeyFilter tenantOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", TEST_TENANT_NAME);
KeyFilter wrongOwnerNameFilter = getEntityFieldStringEqualToKeyFilter("ownerName", "wrongName");
KeyFilter tenantOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "TENANT");
KeyFilter customerOwnerTypeFilter = getEntityFieldStringEqualToKeyFilter("ownerType", "CUSTOMER");
EntityDataSortOrder sortOrder = new EntityDataSortOrder(
new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"), EntityDataSortOrder.Direction.ASC
);
EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder);
List<EntityKey> entityFields = List.of(new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), new EntityKey(EntityKeyType.ENTITY_FIELD, "ownerName"),
new EntityKey(EntityKeyType.ENTITY_FIELD, "ownerType"));
List<EntityKey> latestValues = Collections.singletonList(new EntityKey(EntityKeyType.ATTRIBUTE, "alarmActiveTime"));
// all devices with ownerName = TEST TENANT
EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, tenantOwnerNameFilter));
checkEntitiesByQuery(query, numOfDevices, TEST_TENANT_NAME, "TENANT");
// all devices with wrong ownerName
EntityDataQuery wrongTenantNameQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, wrongOwnerNameFilter));
checkEntitiesByQuery(wrongTenantNameQuery, 0, null, null);
// all devices with owner type = TENANT
EntityDataQuery tenantEntitiesQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, tenantOwnerTypeFilter));
checkEntitiesByQuery(tenantEntitiesQuery, numOfDevices, TEST_TENANT_NAME, "TENANT");
// all devices with owner type = CUSTOMER
EntityDataQuery customerEntitiesQuery = new EntityDataQuery(filter, pageLink, entityFields, latestValues, List.of(activeAlarmTimeFilter, customerOwnerTypeFilter));
checkEntitiesByQuery(customerEntitiesQuery, 0, null, null);
}
private void checkEntitiesByQuery(EntityDataQuery query, int expectedNumOfDevices, String expectedOwnerName, String expectedOwnerType) throws Exception {
Awaitility.await()
.alias("data by query")
.atMost(30, TimeUnit.SECONDS)
.until(() -> {
var data = doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference<PageData<EntityData>>() {});
var loadedEntities = new ArrayList<>(data.getData());
return loadedEntities.size() == expectedNumOfDevices;
});
if (expectedNumOfDevices == 0) {
return;
}
var data = doPostWithTypedResponse("/api/entitiesQuery/find", query, new TypeReference<PageData<EntityData>>() {});
var loadedEntities = new ArrayList<>(data.getData());
Assert.assertEquals(expectedNumOfDevices, loadedEntities.size());
for (int i = 0; i < expectedNumOfDevices; i++) {
var entity = loadedEntities.get(i);
String name = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("name", new TsValue(0, "Invalid")).getValue();
String ownerName = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("ownerName", new TsValue(0, "Invalid")).getValue();
String ownerType = entity.getLatest().get(EntityKeyType.ENTITY_FIELD).getOrDefault("ownerType", new TsValue(0, "Invalid")).getValue();
String alarmActiveTime = entity.getLatest().get(EntityKeyType.ATTRIBUTE).getOrDefault("alarmActiveTime", new TsValue(0, "-1")).getValue();
Assert.assertEquals("Device" + i, name);
Assert.assertEquals( expectedOwnerName, ownerName);
Assert.assertEquals( expectedOwnerType, ownerType);
Assert.assertEquals("1" + i, alarmActiveTime);
}
}
private void checkEntitiesCount(EntityCountQuery query, int expectedNumOfDevices) {
Awaitility.await()
.alias("count by query")
.atMost(30, TimeUnit.SECONDS)
.until(() -> {
var count = doPost("/api/entitiesQuery/count", query, Integer.class);
return count == expectedNumOfDevices;
});
}
private KeyFilter getEntityFieldStringEqualToKeyFilter(String keyName, String value) {
KeyFilter tenantOwnerNameFilter = new KeyFilter();
tenantOwnerNameFilter.setKey(new EntityKey(EntityKeyType.ENTITY_FIELD, keyName));
StringFilterPredicate ownerNamePredicate = new StringFilterPredicate();
ownerNamePredicate.setValue(FilterPredicateValue.fromString(value));
ownerNamePredicate.setOperation(StringFilterPredicate.StringOperation.EQUAL);
tenantOwnerNameFilter.setPredicate(ownerNamePredicate);
return tenantOwnerNameFilter;
}
private KeyFilter getServerAttributeNumericGreaterThanKeyFilter(String attribute, int value) {
KeyFilter numericFilter = new KeyFilter();
numericFilter.setKey(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, attribute));
NumericFilterPredicate predicate = new NumericFilterPredicate();
predicate.setValue(FilterPredicateValue.fromDouble(value));
predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
numericFilter.setPredicate(predicate);
return numericFilter;
}
}

13
application/src/test/java/org/thingsboard/server/controller/EntityViewControllerTest.java

@ -275,10 +275,9 @@ public class EntityViewControllerTest extends AbstractControllerTest {
}
@Test
public void testAssignAndUnAssignedEntityViewToCustomer() throws Exception {
public void testAssignAndUnassignEntityViewToCustomer() throws Exception {
EntityView view = getNewSavedEntityView("Test entity view");
Customer savedCustomer = doPost("/api/customer", getNewCustomer("My customer"), Customer.class);
view.setCustomerId(savedCustomer.getId());
Mockito.reset(tbClusterService, auditLogService);
@ -304,17 +303,17 @@ public class EntityViewControllerTest extends AbstractControllerTest {
ActionType.ASSIGNED_TO_CUSTOMER, ActionType.UPDATED,
foundView.getId().getId().toString(), foundView.getCustomerId().getId().toString(), savedCustomer.getTitle());
EntityView unAssignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(ModelConstants.NULL_UUID, unAssignedView.getCustomerId().getId());
EntityView unassignedView = doDelete("/api/customer/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(ModelConstants.NULL_UUID, unassignedView.getCustomerId().getId());
foundView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(ModelConstants.NULL_UUID, foundView.getCustomerId().getId());
testBroadcastEntityStateChangeEventTime(foundView.getId(), foundView.getTenantId(), 1);
testNotifyAssignUnassignEntityAllOneTime(unAssignedView, savedView.getId(), savedView.getId(),
tenantId, savedView.getCustomerId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
testNotifyAssignUnassignEntityAllOneTime(unassignedView, unassignedView.getId(), unassignedView.getId(),
tenantId, savedCustomer.getId(), tenantAdminUserId, TENANT_ADMIN_EMAIL,
ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UPDATED,
assignedView.getId().getId().toString(), savedView.getCustomerId().getId().toString(), savedCustomer.getTitle());
assignedView.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
}
@Test

2
application/src/test/java/org/thingsboard/server/controller/UserControllerTest.java

@ -279,7 +279,7 @@ public class UserControllerTest extends AbstractControllerTest {
user.setTenantId(tenantId);
user.setEmail(TENANT_ADMIN_EMAIL);
String msgError = "User with email '" + TENANT_ADMIN_EMAIL + "' already present in database";
String msgError = "User with email '" + TENANT_ADMIN_EMAIL + "' already present in database!";
doPost("/api/user", user)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));

17
application/src/test/java/org/thingsboard/server/service/sync/ie/ExportImportServiceSqlTest.java

@ -532,20 +532,19 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest {
@Test
public void testExportImportDeviceProfile_betweenTenants_findExistingByName() throws Exception {
public void testExportImportDefaultDeviceProfile_betweenTenants_findExisting() throws Exception {
DeviceProfile defaultDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId1);
defaultDeviceProfile.setName("non-default-name");
deviceProfileService.saveDeviceProfile(defaultDeviceProfile);
EntityExportData<DeviceProfile> deviceProfileExportData = exportEntity(tenantAdmin1, defaultDeviceProfile.getId());
assertThatThrownBy(() -> {
importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder()
.findExistingByName(false)
.build());
}).hasMessageContaining("default device profile is present");
importEntity(tenantAdmin2, deviceProfileExportData, EntityImportSettings.builder()
.findExistingByName(true)
.findExistingByName(false)
.build());
checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, deviceProfileService.findDefaultDeviceProfile(tenantId2));
DeviceProfile importedDeviceProfile = deviceProfileService.findDefaultDeviceProfile(tenantId2);
assertThat(importedDeviceProfile.isDefault()).isTrue();
assertThat(importedDeviceProfile.getName()).isEqualTo(defaultDeviceProfile.getName());
checkImportedEntity(tenantId1, defaultDeviceProfile, tenantId2, importedDeviceProfile);
}

5
common/actor/pom.xml

@ -65,11 +65,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

69
common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java

@ -16,12 +16,11 @@
package org.thingsboard.server.actors;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.id.DeviceId;
@ -37,29 +36,31 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import static org.assertj.core.api.Assertions.assertThat;
@Slf4j
@RunWith(MockitoJUnitRunner.class)
public class ActorSystemTest {
public static final String ROOT_DISPATCHER = "root-dispatcher";
private static final int _100K = 100 * 1024;
public static final int TIMEOUT_AWAIT_MAX_SEC = 100;
public static final int TIMEOUT_AWAIT_MAX_SEC = 30;
private volatile TbActorSystem actorSystem;
private volatile ExecutorService submitPool;
private ExecutorService executor;
private int parallelism;
@Before
@BeforeEach
public void initActorSystem() {
int cores = Runtime.getRuntime().availableProcessors();
parallelism = Math.max(2, cores / 2);
log.debug("parallelism {}", parallelism);
TbActorSystemSettings settings = new TbActorSystemSettings(5, parallelism, 42);
actorSystem = new DefaultTbActorSystem(settings);
submitPool = Executors.newFixedThreadPool(parallelism, ThingsBoardThreadFactory.forName(getClass().getSimpleName() + "-submit-test-scope")); //order guaranteed
}
@After
@AfterEach
public void shutdownActorSystem() {
actorSystem.stop();
submitPool.shutdownNow();
@ -126,8 +127,8 @@ public class ActorSystemTest {
actorId2.tell(new IntTbActorMsg(42));
actorSystem.stop(actorId1);
Assert.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
Assert.assertFalse(testCtx1.getLatch().await(1, TimeUnit.SECONDS));
Assertions.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
Assertions.assertFalse(testCtx1.getLatch().await(1, TimeUnit.SECONDS));
}
@Test
@ -136,25 +137,39 @@ public class ActorSystemTest {
actorSystem.createDispatcher(ROOT_DISPATCHER, executor);
ActorTestCtx testCtx1 = getActorTestCtx(1);
ActorTestCtx testCtx2 = getActorTestCtx(1);
assertThat(testCtx1.getLatch().getCount()).as("testCtx1 latch initial state").isEqualTo(1);
assertThat(testCtx2.getLatch().getCount()).as("testCtx2 latch initial state").isEqualTo(1);
TbActorId actorId = new TbEntityActorId(new DeviceId(UUID.randomUUID()));
final CountDownLatch initLatch = new CountDownLatch(1);
final CountDownLatch actorsReadyLatch = new CountDownLatch(2);
submitPool.submit(() -> {
log.info("submit 1");
actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx1, initLatch));
actorsReadyLatch.countDown();
log.info("done 1");
});
submitPool.submit(() -> {
log.info("submit 2");
actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx2, initLatch));
actorsReadyLatch.countDown();
log.info("done 2");
});
initLatch.countDown(); //replacement for Thread.wait(500) in the SlowCreateActorCreator
Assert.assertTrue(actorsReadyLatch.await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
Assertions.assertTrue(actorsReadyLatch.await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
log.info("actorsReadyLatch ok");
actorSystem.tell(actorId, new IntTbActorMsg(42));
Assert.assertTrue(testCtx1.getLatch().await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
Assert.assertFalse(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
//only one of two contexts are initialized. no matter Ctx1 or Ctx2
Awaitility.await("one of two actors latch zeroed").atMost(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS)
.until(() -> testCtx1.getLatch().getCount() + testCtx2.getLatch().getCount() == 1);
Thread.yield();
if (testCtx1.getLatch().getCount() == 0) {
assertThat(testCtx2.getLatch().await(100, TimeUnit.MILLISECONDS)).as("testCtx2 never latched").isFalse();
} else {
assertThat(testCtx1.getLatch().await(100, TimeUnit.MILLISECONDS)).as("testCtx1 never latched").isFalse();
}
}
@Test
@ -173,13 +188,13 @@ public class ActorSystemTest {
});
}
initLatch.countDown();
Assert.assertTrue(actorsReadyLatch.await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
Assertions.assertTrue(actorsReadyLatch.await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
actorSystem.tell(actorId, new IntTbActorMsg(42));
Assert.assertTrue(testCtx.getLatch().await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
Assertions.assertTrue(testCtx.getLatch().await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS));
//One for creation and one for message
Assert.assertEquals(2, testCtx.getInvocationCount().get());
Assertions.assertEquals(2, testCtx.getInvocationCount().get());
}
@Test
@ -197,9 +212,9 @@ public class ActorSystemTest {
actorId1.tell(new IntTbActorMsg(42));
actorId2.tell(new IntTbActorMsg(42));
Assert.assertFalse(testCtx1.getLatch().await(2, TimeUnit.SECONDS));
Assert.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
Assert.assertTrue(testCtx1.getLatch().await(3, TimeUnit.SECONDS));
Assertions.assertFalse(testCtx1.getLatch().await(2, TimeUnit.SECONDS));
Assertions.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
Assertions.assertTrue(testCtx1.getLatch().await(3, TimeUnit.SECONDS));
}
@ -233,16 +248,16 @@ public class ActorSystemTest {
log.info("Submitted all messages");
testCtxes.forEach(ctx -> {
try {
boolean success = ctx.getLatch().await(1, TimeUnit.MINUTES);
boolean success = ctx.getLatch().await(TIMEOUT_AWAIT_MAX_SEC, TimeUnit.SECONDS);
if (!success) {
log.warn("Failed: {}, {}", ctx.getActual().get(), ctx.getInvocationCount().get());
}
Assert.assertTrue(success);
Assert.assertEquals(expected, ctx.getActual().get());
Assert.assertEquals(msgNumber, ctx.getInvocationCount().get());
Assertions.assertTrue(success);
Assertions.assertEquals(expected, ctx.getActual().get());
Assertions.assertEquals(msgNumber, ctx.getInvocationCount().get());
ctx.clear();
} catch (InterruptedException e) {
e.printStackTrace();
log.error("interrupted", e);
}
});
long duration = System.nanoTime() - start;

9
common/actor/src/test/java/org/thingsboard/server/actors/SlowCreateActor.java

@ -28,11 +28,13 @@ public class SlowCreateActor extends TestRootActor {
public SlowCreateActor(TbActorId actorId, ActorTestCtx testCtx, CountDownLatch initLatch) {
super(actorId, testCtx);
try {
log.info("awaiting on latch {} ...", initLatch);
initLatch.await(TIMEOUT_AWAIT_MAX_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
log.error("interrupted", e);
}
testCtx.getInvocationCount().incrementAndGet();
log.info("finished {} ...", initLatch);
}
public static class SlowCreateActorCreator implements TbActorCreator {
@ -54,7 +56,10 @@ public class SlowCreateActor extends TestRootActor {
@Override
public TbActor createActor() {
return new SlowCreateActor(actorId, testCtx, initLatch);
log.info("creating slow actor...");
SlowCreateActor slowCreateActor = new SlowCreateActor(actorId, testCtx, initLatch);
log.info("created slow actor {}", slowCreateActor);
return slowCreateActor;
}
}
}

3
common/actor/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

0
common/actor/src/test/resources/logback.xml → common/actor/src/test/resources/logback-test.xml

5
common/cache/pom.xml

@ -97,11 +97,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

14
netty-mqtt/src/test/java/org/thingsboard/mqtt/integration/IntegrationTestSuite.java → common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCacheEvictEvent.java

@ -13,15 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.mqtt.integration;
package org.thingsboard.server.cache.customer;
import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith;
import org.thingsboard.server.common.data.id.TenantId;
@RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({
"org.thingsboard.mqtt.integration.*Test",
})
public class IntegrationTestSuite {
}
public record CustomerCacheEvictEvent(TenantId tenantId, String newTitle, String oldTitle) {
}

42
common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCacheKey.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2024 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.cache.customer;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.thingsboard.server.common.data.id.TenantId;
import java.io.Serial;
import java.io.Serializable;
@EqualsAndHashCode
@RequiredArgsConstructor
public class CustomerCacheKey implements Serializable {
@Serial
private static final long serialVersionUID = 5706958428811356925L;
@NonNull
private final TenantId tenantId;
private final String title;
@Override
public String toString() {
return tenantId.getId() + "_" + title;
}
}

33
common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerCaffeineCache.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2024 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.cache.customer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.Customer;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
@Service("CustomerCache")
public class CustomerCaffeineCache extends CaffeineTbTransactionalCache<CustomerCacheKey, Customer> {
public CustomerCaffeineCache(CacheManager cacheManager) {
super(cacheManager, CacheConstants.CUSTOMER_CACHE);
}
}

35
common/cache/src/main/java/org/thingsboard/server/cache/customer/CustomerRedisCache.java

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2024 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.cache.customer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CacheSpecsMap;
import org.thingsboard.server.cache.RedisTbTransactionalCache;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.cache.TbJsonRedisSerializer;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.Customer;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
@Service("CustomerCache")
public class CustomerRedisCache extends RedisTbTransactionalCache<CustomerCacheKey, Customer> {
public CustomerRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
super(CacheConstants.CUSTOMER_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbJsonRedisSerializer<>(Customer.class));
}
}

21
common/cache/src/main/java/org/thingsboard/server/cache/user/UserCacheEvictEvent.java

@ -0,0 +1,21 @@
/**
* Copyright © 2016-2024 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.cache.user;
import org.thingsboard.server.common.data.id.TenantId;
public record UserCacheEvictEvent(TenantId tenantId, String newEmail, String oldEmail) {
}

42
common/cache/src/main/java/org/thingsboard/server/cache/user/UserCacheKey.java

@ -0,0 +1,42 @@
/**
* Copyright © 2016-2024 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.cache.user;
import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.thingsboard.server.common.data.id.TenantId;
import java.io.Serial;
import java.io.Serializable;
@EqualsAndHashCode
@RequiredArgsConstructor
public class UserCacheKey implements Serializable {
@Serial
private static final long serialVersionUID = 7357353074893750678L;
@NonNull
private final TenantId tenantId;
private final String email;
@Override
public String toString() {
return tenantId.getId() + "_" + email;
}
}

33
common/cache/src/main/java/org/thingsboard/server/cache/user/UserCaffeineCache.java

@ -0,0 +1,33 @@
/**
* Copyright © 2016-2024 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.cache.user;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.User;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
@Service("UserCache")
public class UserCaffeineCache extends CaffeineTbTransactionalCache<UserCacheKey, User> {
public UserCaffeineCache(CacheManager cacheManager) {
super(cacheManager, CacheConstants.USER_CACHE);
}
}

35
common/cache/src/main/java/org/thingsboard/server/cache/user/UserRedisCache.java

@ -0,0 +1,35 @@
/**
* Copyright © 2016-2024 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.cache.user;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CacheSpecsMap;
import org.thingsboard.server.cache.RedisTbTransactionalCache;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.cache.TbJsonRedisSerializer;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.User;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
@Service("UserCache")
public class UserRedisCache extends RedisTbTransactionalCache<UserCacheKey, User> {
public UserRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
super(CacheConstants.USER_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbJsonRedisSerializer<>(User.class));
}
}

5
common/cache/src/test/java/org/thingsboard/server/cache/CacheSpecsMapTest.java

@ -26,6 +26,7 @@ import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.thingsboard.server.common.data.CacheConstants;
import static org.assertj.core.api.Assertions.assertThat;
@ -53,8 +54,8 @@ public class CacheSpecsMapTest {
@Test
public void givenCacheConfig_whenCacheManagerReady_thenVerifyExistedCachesWithNoTransactionAwareCacheDecorator() {
// We no longer use built-in transaction support for the caches, because we have our own cache cleanup and transaction logic that implements CAS.
assertThat(cacheManager.getCache("relations")).isInstanceOf(CaffeineCache.class);
assertThat(cacheManager.getCache("devices")).isInstanceOf(CaffeineCache.class);
assertThat(cacheManager.getCache(CacheConstants.RELATIONS_CACHE)).isInstanceOf(CaffeineCache.class);
assertThat(cacheManager.getCache(CacheConstants.DEVICE_CACHE)).isInstanceOf(CaffeineCache.class);
}
@Test

3
common/cache/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

0
common/cache/src/test/resources/logback.xml → common/cache/src/test/resources/logback-test.xml

5
common/cluster-api/pom.xml

@ -109,11 +109,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

10
common/coap-server/pom.xml

@ -67,6 +67,16 @@
<groupId>org.eclipse.californium</groupId>
<artifactId>scandium</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.coapserver;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.util.SslContextUtil;
@ -47,6 +48,7 @@ import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RETRANSMIS
import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_ROLE;
import static org.eclipse.californium.scandium.config.DtlsConfig.DtlsRole.SERVER_ONLY;
@Getter
@Slf4j
@ConditionalOnProperty(prefix = "transport.coap.dtls", value = "enabled", havingValue = "true", matchIfMissing = false)
@Component

62
common/coap-server/src/test/java/org/thingsboard/server/coapserver/TbCoapDtlsSettingsTest.java

@ -0,0 +1,62 @@
/**
* Copyright © 2016-2024 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.coapserver;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(classes = TbCoapDtlsSettings.class)
@TestPropertySource(properties = {
"transport.coap.dtls.enabled=true",
"transport.coap.dtls.bind_address=192.168.1.1",
"transport.coap.dtls.bind_port=1234",
"transport.coap.dtls.retransmission_timeout=100",
"transport.coap.dtls.connection_id_length=500",
"transport.coap.dtls.x509.skip_validity_check_for_client_cert=true",
"transport.coap.dtls.x509.dtls_session_inactivity_timeout=1000",
"transport.coap.dtls.x509.dtls_session_report_timeout=3000",
})
class TbCoapDtlsSettingsTest {
@Autowired
TbCoapDtlsSettings coapDtlsSettings;
@MockBean
SslCredentialsConfig sslCredentialsConfig;
@MockBean
private TransportService transportService;
@MockBean
private TbServiceInfoProvider serviceInfoProvider;
@Test
public void testCoapDtlsProperties() {
assertThat(coapDtlsSettings).as("bean created").isNotNull();
assertThat(coapDtlsSettings.getHost()).as("host").isEqualTo("192.168.1.1");
assertThat(coapDtlsSettings.getPort()).as("port").isEqualTo(1234);
assertThat(coapDtlsSettings.getDtlsRetransmissionTimeout()).as("retransmission_timeout").isEqualTo(100);
assertThat(coapDtlsSettings.isSkipValidityCheckForClientCert()).as("skip_validity_check_for_client_cert").isTrue();
assertThat(coapDtlsSettings.getDtlsSessionInactivityTimeout()).as("dtls_session_inactivity_timeout").isEqualTo(1000);
assertThat(coapDtlsSettings.getDtlsSessionReportTimeout()).as("dtls_session_report_timeout").isEqualTo(3000);
}
}

5
common/dao-api/pom.xml

@ -105,11 +105,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

2
common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java

@ -41,6 +41,8 @@ public interface AssetService extends EntityDaoService {
Asset findAssetByTenantIdAndName(TenantId tenantId, String name);
ListenableFuture<Asset> findAssetByTenantIdAndNameAsync(TenantId tenantId, String name);
Asset saveAsset(Asset asset, boolean doValidate);
Asset saveAsset(Asset asset);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java

@ -31,6 +31,8 @@ public interface CustomerService extends EntityDaoService {
Optional<Customer> findCustomerByTenantIdAndTitle(TenantId tenantId, String title);
ListenableFuture<Optional<Customer>> findCustomerByTenantIdAndTitleAsync(TenantId tenantId, String title);
ListenableFuture<Customer> findCustomerByIdAsync(TenantId tenantId, CustomerId customerId);
Customer saveCustomer(Customer customer);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java

@ -72,6 +72,8 @@ public interface DashboardService extends EntityDaoService {
DashboardInfo findFirstDashboardInfoByTenantIdAndName(TenantId tenantId, String name);
ListenableFuture<DashboardInfo> findFirstDashboardInfoByTenantIdAndNameAsync(TenantId tenantId, String name);
List<Dashboard> findTenantDashboardsByTitle(TenantId tenantId, String title);
}

2
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java

@ -49,6 +49,8 @@ public interface DeviceService extends EntityDaoService {
Device findDeviceByTenantIdAndName(TenantId tenantId, String name);
ListenableFuture<Device> findDeviceByTenantIdAndNameAsync(TenantId tenantId, String name);
Device saveDevice(Device device);
Device saveDevice(Device device, boolean doValidate);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java

@ -42,6 +42,8 @@ public interface EdgeService extends EntityDaoService {
Edge findEdgeByTenantIdAndName(TenantId tenantId, String name);
ListenableFuture<Edge> findEdgeByTenantIdAndNameAsync(TenantId tenantId, String name);
Optional<Edge> findEdgeByRoutingKey(TenantId tenantId, String routingKey);
Edge saveEdge(Edge edge);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java

@ -54,6 +54,8 @@ public interface EntityViewService extends EntityDaoService {
EntityView findEntityViewByTenantIdAndName(TenantId tenantId, String name);
ListenableFuture<EntityView> findEntityViewByTenantIdAndNameAsync(TenantId tenantId, String name);
PageData<EntityView> findEntityViewByTenantId(TenantId tenantId, PageLink pageLink);
PageData<EntityViewInfo> findEntityViewInfosByTenantId(TenantId tenantId, PageLink pageLink);

2
common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java

@ -41,6 +41,8 @@ public interface UserService extends EntityDaoService {
User findUserByTenantIdAndEmail(TenantId tenantId, String email);
ListenableFuture<User> findUserByTenantIdAndEmailAsync(TenantId tenantId, String email);
User saveUser(TenantId tenantId, User user);
UserCredentials findUserCredentialsByUserId(TenantId tenantId, UserId userId);

5
common/data/pom.xml

@ -73,11 +73,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

2
common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java

@ -21,6 +21,8 @@ public class CacheConstants {
public static final String DEVICE_CACHE = "devices";
public static final String SESSIONS_CACHE = "sessions";
public static final String ASSET_CACHE = "assets";
public static final String CUSTOMER_CACHE = "customers";
public static final String USER_CACHE = "users";
public static final String ENTITY_VIEW_CACHE = "entityViews";
public static final String EDGE_CACHE = "edges";
public static final String CLAIM_DEVICES_CACHE = "claimDevices";

4
common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java

@ -18,6 +18,7 @@ package org.thingsboard.server.common.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@ -33,7 +34,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
import jakarta.validation.Valid;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -42,7 +42,7 @@ import java.io.IOException;
@ToString(exclude = {"image", "profileDataBytes"})
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName, HasTenantId, HasOtaPackage, HasRuleEngineProfile, ExportableEntity<DeviceProfileId>, HasImage {
public class DeviceProfile extends BaseData<DeviceProfileId> implements HasName, HasTenantId, HasOtaPackage, HasRuleEngineProfile, ExportableEntity<DeviceProfileId>, HasImage, HasDefaultOption {
private static final long serialVersionUID = 6998485460273302018L;

12
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/util/EntityContainer.java → common/data/src/main/java/org/thingsboard/server/common/data/HasDefaultOption.java

@ -13,16 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.rule.engine.util;
package org.thingsboard.server.common.data;
import lombok.Data;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
public interface HasDefaultOption {
@Data
public class EntityContainer {
private EntityId entityId;
private EntityType entityType;
boolean isDefault();
}

3
common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetProfile.java

@ -22,6 +22,7 @@ import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasDefaultOption;
import org.thingsboard.server.common.data.HasImage;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasRuleEngineProfile;
@ -38,7 +39,7 @@ import org.thingsboard.server.common.data.validation.NoXss;
@ToString(exclude = {"image"})
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class AssetProfile extends BaseData<AssetProfileId> implements HasName, HasTenantId, HasRuleEngineProfile, ExportableEntity<AssetProfileId>, HasImage {
public class AssetProfile extends BaseData<AssetProfileId> implements HasName, HasTenantId, HasRuleEngineProfile, ExportableEntity<AssetProfileId>, HasImage, HasDefaultOption {
private static final long serialVersionUID = 6998485460273302018L;

9
common/data/src/main/java/org/thingsboard/server/common/data/rule/RuleChain.java

@ -23,6 +23,7 @@ import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.BaseDataWithAdditionalInfo;
import org.thingsboard.server.common.data.ExportableEntity;
import org.thingsboard.server.common.data.HasDefaultOption;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.RuleChainId;
@ -35,7 +36,7 @@ import org.thingsboard.server.common.data.validation.NoXss;
@Data
@EqualsAndHashCode(callSuper = true)
@Slf4j
public class RuleChain extends BaseDataWithAdditionalInfo<RuleChainId> implements HasName, HasTenantId, ExportableEntity<RuleChainId> {
public class RuleChain extends BaseDataWithAdditionalInfo<RuleChainId> implements HasName, HasTenantId, ExportableEntity<RuleChainId>, HasDefaultOption {
private static final long serialVersionUID = -5656679015121935465L;
@ -108,4 +109,10 @@ public class RuleChain extends BaseDataWithAdditionalInfo<RuleChainId> implement
setJson(data, json -> this.configuration = json, bytes -> this.configurationBytes = bytes);
}
@JsonIgnore
@Override
public boolean isDefault() {
return root && type == RuleChainType.CORE;
}
}

14
common/data/src/test/java/org/thingsboard/server/common/data/DynamicProtoUtilsTest.java

@ -19,18 +19,18 @@ import com.github.os72.protobuf.dynamic.DynamicSchema;
import com.google.protobuf.Descriptors;
import com.google.protobuf.DynamicMessage;
import com.squareup.wire.schema.internal.parser.ProtoFileElement;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class DynamicProtoUtilsTest {
@Test

17
common/data/src/test/java/org/thingsboard/server/common/data/UUIDConverterTest.java

@ -16,11 +16,10 @@
package org.thingsboard.server.common.data;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Random;
import java.util.UUID;
@ -28,14 +27,14 @@ import java.util.UUID;
/**
* Created by ashvayka on 14.07.17.
*/
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension .class)
public class UUIDConverterTest {
@Test
public void basicUuidToStringTest() {
UUID original = UUID.fromString("58e0a7d7-eebc-11d8-9669-0800200c9a66");
String result = UUIDConverter.fromTimeUUID(original);
Assert.assertEquals("1d8eebc58e0a7d796690800200c9a66", result);
Assertions.assertEquals("1d8eebc58e0a7d796690800200c9a66", result);
}
@ -47,13 +46,13 @@ public class UUIDConverterTest {
@Test
public void basicUuidConversion() {
UUID original = UUID.fromString("3dd11790-abf2-11ea-b151-83a091b9d4cc");
Assert.assertEquals(Uuids.unixTimestamp(original), 1591886749577L);
Assertions.assertEquals(Uuids.unixTimestamp(original), 1591886749577L);
}
@Test
public void basicStringToUUIDTest() {
UUID result = UUIDConverter.fromString("1d8eebc58e0a7d796690800200c9a66");
Assert.assertEquals(UUID.fromString("58e0a7d7-eebc-11d8-9669-0800200c9a66"), result);
Assertions.assertEquals(UUID.fromString("58e0a7d7-eebc-11d8-9669-0800200c9a66"), result);
}
@Test
@ -83,7 +82,7 @@ public class UUIDConverterTest {
System.out.println("Before: " + before + " | " + beforeStr);
System.out.println("After: " + after + " | " + afterStr);
}
Assert.assertTrue(afterStr.compareTo(beforeStr) >= 0);
Assertions.assertTrue(afterStr.compareTo(beforeStr) >= 0);
}
}

6
common/data/src/test/java/org/thingsboard/server/common/data/id/EntityIdTest.java

@ -15,14 +15,14 @@
*/
package org.thingsboard.server.common.data.id;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class EntityIdTest {
@Test
public void givenConstantNullUuid_whenCompare_thenToStringEqualsPredefinedUuid() {
Assert.assertEquals("13814000-1dd2-11b2-8080-808080808080", EntityId.NULL_UUID.toString());
Assertions.assertEquals("13814000-1dd2-11b2-8080-808080808080", EntityId.NULL_UUID.toString());
}
}

3
common/data/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/data/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/message/pom.xml

@ -74,11 +74,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

8
common/message/src/test/java/org/thingsboard/server/common/msg/TbMsgMetaDataTest.java

@ -18,12 +18,12 @@ package org.thingsboard.server.common.msg;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TbMsgMetaDataTest {
@ -32,7 +32,7 @@ public class TbMsgMetaDataTest {
private JsonNode metadataJson;
private Map<String, String> metadataExpected;
@Before
@BeforeEach
public void startInit() throws Exception {
metadataJson = objectMapper.readValue(metadataJsonStr, JsonNode.class);
metadataExpected = objectMapper.convertValue(metadataJson, new TypeReference<>() {

2
common/message/src/test/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfoTest.java

@ -15,7 +15,7 @@
*/
package org.thingsboard.server.common.msg.queue;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.common.data.id.TenantId;
import static org.hamcrest.CoreMatchers.is;

2
common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java

@ -16,7 +16,7 @@
package org.thingsboard.server.common.msg.tools;
import org.awaitility.pollinterval.FixedPollInterval;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;

3
common/message/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/message/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/proto/pom.xml

@ -66,11 +66,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

4
common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java

@ -590,11 +590,11 @@ public class JsonConverter {
return GSON.fromJson(element, type);
}
public static void setTypeCastEnabled(boolean enabled) {
static void setTypeCastEnabled(boolean enabled) {
isTypeCastEnabled = enabled;
}
public static void setMaxStringValueLength(int length) {
static void setMaxStringValueLength(int length) {
maxStringValueLength = length;
}

28
common/proto/src/test/java/org/thingsboard/server/common/adaptor/JsonConverterTest.java

@ -17,13 +17,15 @@ package org.thingsboard.server.common.adaptor;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import java.util.ArrayList;
@Isolated("JsonConverter static settings being modified")
public class JsonConverterTest {
@BeforeEach
@ -31,58 +33,64 @@ public class JsonConverterTest {
JsonConverter.setTypeCastEnabled(true);
}
@AfterEach
public void after() {
//restore default state for a static class
JsonConverter.setTypeCastEnabled(true);
}
@Test
public void testParseBigDecimalAsLong() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 1E+1}"), 0L);
Assert.assertEquals(10L, result.get(0L).get(0).getLongValue().get().longValue());
Assertions.assertEquals(10L, result.get(0L).get(0).getLongValue().get().longValue());
}
@Test
public void testParseBigDecimalAsDouble() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 101E-1}"), 0L);
Assert.assertEquals(10.1, result.get(0L).get(0).getDoubleValue().get(), 0.0);
Assertions.assertEquals(10.1, result.get(0L).get(0).getDoubleValue().get(), 0.0);
}
@Test
public void testParseAttributesBigDecimalAsLong() {
var result = new ArrayList<>(JsonConverter.convertToAttributes(JsonParser.parseString("{\"meterReadingDelta\": 1E1}")));
Assert.assertEquals(10L, result.get(0).getLongValue().get().longValue());
Assertions.assertEquals(10L, result.get(0).getLongValue().get().longValue());
}
@Test
public void testParseAsDoubleWithZero() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 42.0}"), 0L);
Assert.assertEquals(42.0, result.get(0L).get(0).getDoubleValue().get(), 0.0);
Assertions.assertEquals(42.0, result.get(0L).get(0).getDoubleValue().get(), 0.0);
}
@Test
public void testParseAsDouble() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 1.1}"), 0L);
Assert.assertEquals(1.1, result.get(0L).get(0).getDoubleValue().get(), 0.0);
Assertions.assertEquals(1.1, result.get(0L).get(0).getDoubleValue().get(), 0.0);
}
@Test
public void testParseAsLong() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 11}"), 0L);
Assert.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());
Assertions.assertEquals(11L, result.get(0L).get(0).getLongValue().get().longValue());
}
@Test
public void testParseBigDecimalAsStringOutOfLongRange() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 9.9701010061400066E19}"), 0L);
Assert.assertEquals("99701010061400066000", result.get(0L).get(0).getStrValue().get());
Assertions.assertEquals("99701010061400066000", result.get(0L).get(0).getStrValue().get());
}
@Test
public void testParseBigDecimalAsStringOutOfLongRange2() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 99701010061400066001}"), 0L);
Assert.assertEquals("99701010061400066001", result.get(0L).get(0).getStrValue().get());
Assertions.assertEquals("99701010061400066001", result.get(0L).get(0).getStrValue().get());
}
@Test
public void testParseBigDecimalAsStringOutOfLongRange3() {
var result = JsonConverter.convertToTelemetry(JsonParser.parseString("{\"meterReadingDelta\": 1E19}"), 0L);
Assert.assertEquals("10000000000000000000", result.get(0L).get(0).getStrValue().get());
Assertions.assertEquals("10000000000000000000", result.get(0L).get(0).getStrValue().get());
}
@Test

3
common/proto/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/proto/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/queue/pom.xml

@ -129,11 +129,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

19
common/queue/src/test/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplateTest.java

@ -16,13 +16,13 @@
package org.thingsboard.server.queue.common;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.thingsboard.server.queue.TbQueueAdmin;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.TbQueueMsg;
@ -48,6 +48,7 @@ import static org.mockito.BDDMockito.willDoNothing;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@ -56,7 +57,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.hamcrest.MockitoHamcrest.longThat;
@Slf4j
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class DefaultTbQueueRequestTemplateTest {
@Mock
@ -76,16 +77,16 @@ public class DefaultTbQueueRequestTemplateTest {
DefaultTbQueueRequestTemplate<TbQueueMsg, TbQueueMsg> inst;
@Before
@BeforeEach
public void setUp() throws Exception {
willReturn(topic).given(responseTemplate).getTopic();
lenient().doReturn(topic).when(responseTemplate).getTopic();
inst = spy(new DefaultTbQueueRequestTemplate<>(
queueAdmin, requestTemplate, responseTemplate,
maxRequestTimeout, maxPendingRequests, pollInterval, executorMock));
}
@After
@AfterEach
public void tearDown() throws Exception {
if (executor != null) {
executor.shutdownNow();

15
common/queue/src/test/java/org/thingsboard/server/queue/discovery/ZkDiscoveryServiceTest.java

@ -20,12 +20,13 @@ import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.test.util.ReflectionTestUtils;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
@ -39,8 +40,8 @@ import java.util.concurrent.ScheduledExecutorService;
import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_ADDED;
import static org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type.CHILD_REMOVED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@ -49,7 +50,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class ZkDiscoveryServiceTest {
@Mock
@ -78,7 +79,7 @@ public class ZkDiscoveryServiceTest {
final TransportProtos.ServiceInfo childInfo = TransportProtos.ServiceInfo.newBuilder().setServiceId("tb-rule-engine-1").build();
final ChildData childData = new ChildData("/thingsboard/nodes/0000000020", null, childInfo.toByteArray());
@Before
@BeforeEach
public void setup() {
zkDiscoveryService = Mockito.spy(new ZkDiscoveryService(applicationEventPublisher, serviceInfoProvider, partitionService));
ScheduledExecutorService zkExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("zk-discovery"));

2
common/queue/src/test/java/org/thingsboard/server/queue/memory/DefaultInMemoryStorageTest.java

@ -17,7 +17,7 @@ package org.thingsboard.server.queue.memory;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.queue.TbQueueMsg;
import org.thingsboard.server.queue.common.DefaultTbQueueMsg;

3
common/queue/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

5
common/script/remote-js-client/pom.xml

@ -66,11 +66,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

5
common/script/script-api/pom.xml

@ -106,11 +106,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

14
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateConstructorTest.java

@ -15,8 +15,8 @@
*/
package org.thingsboard.script.api.tbel;
import org.junit.Assert;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mvel2.CompileException;
@ -27,8 +27,8 @@ import org.mvel2.SandboxedParserConfiguration;
import java.io.Serializable;
import java.util.HashMap;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mvel2.MVEL.compileExpression;
import static org.mvel2.MVEL.executeTbExpression;
@ -56,14 +56,14 @@ public class TbDateConstructorTest {
String body = "var d = new Date(\"2023-08-06T04:04:05.123Z\"); \n" +
"d.toISOString()";
Object res = executeScript(body);
Assert.assertNotEquals("2023-08-06T04:04:05.123Z".length(), res);
Assertions.assertNotEquals("2023-08-06T04:04:05.123Z".length(), res);
// two: date in String + pattern
body = "var pattern = \"yyyy-MM-dd HH:mm:ss.SSSXXX\";\n" +
"var d = new Date(\"2023-08-06 04:04:05.000Z\", pattern);\n" +
"d.toISOString()";
res = executeScript(body);
Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res);
Assertions.assertNotEquals("2023-08-06T04:04:05Z".length(), res);
// three: date in String + pattern + locale
@ -71,14 +71,14 @@ public class TbDateConstructorTest {
"var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\");" +
"d.toISOString()";
res = executeScript(body);
Assert.assertNotEquals("2023-08-06T04:04:05Z".length(), res);
Assertions.assertNotEquals("2023-08-06T04:04:05Z".length(), res);
// four: date in String + pattern + locale + TimeZone
body = "var pattern = \"hh:mm:ss a, EEE M/d/uuuu\";\n" +
"var d = new Date(\"02:15:30 PM, Sun 10/09/2022\", pattern, \"en-US\", \"America/New_York\");" +
"d.toISOString()";
res = executeScript(body);
Assert.assertNotEquals("22022-10-09T18:15:30Z".length(), res);
Assertions.assertNotEquals("22022-10-09T18:15:30Z".length(), res);
}
@Test

416
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java

@ -21,10 +21,9 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.assertj.core.data.Offset;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mvel2.ConversionException;
import org.thingsboard.common.util.JacksonUtil;
@ -34,7 +33,6 @@ import java.time.Instant;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@ -43,8 +41,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Slf4j
class TbDateTest {
@ -129,7 +127,7 @@ class TbDateTest {
String tsStr = String.format(pattern, String.format("%02d", month), date, hrs); //Thu Feb 29 2024 14:35:42.987 GMT+0000
TbDate tbDate = new TbDate(tsStr);
long ts = 1709217342987L; //Thu Feb 29 2024 14:35:42.987 GMT+0000
Assert.assertEquals(ts, tbDate.parseSecondMilli());
Assertions.assertEquals(ts, tbDate.parseSecondMilli());
int offsetLocalSecond = tbDate.getLocaleZoneOffset().getTotalSeconds(); // for example 7200 for GMT + 2
String datePrefix = tsStr; //without time zone
@ -159,18 +157,18 @@ class TbDateTest {
int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
int hrs = 14 - localOffsetHrs;
String expected = "2022-10-09T" + hrs + ":15:30Z";
Assert.assertEquals(expected, d.toISOString());
Assertions.assertEquals(expected, d.toISOString());
// tz = "-04:00"
s = "2023-08-06T04:04:05.00-04:00";
d = new TbDate(s);
Assert.assertEquals("2023-08-06T08:04:05Z", d.toISOString());
Assertions.assertEquals("2023-08-06T08:04:05Z", d.toISOString());
s = "02:15:30 PM, Sun 10/09/2022";
d = new TbDate(s, pattern, "en-US", "-04:00");
Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString());
Assertions.assertEquals("2022-10-09T18:15:30Z", d.toISOString());
d = new TbDate(s, pattern,"en-US", "America/New_York");
Assert.assertEquals("2022-10-09T18:15:30Z", d.toISOString());
Assertions.assertEquals("2022-10-09T18:15:30Z", d.toISOString());
// tz = "+02:00"
/**
* For Java 11:
@ -181,7 +179,7 @@ class TbDateTest {
String s_ver = Runtime.version().feature() == 11 ? "09:15:30 nachm., So. 10/09/2022" :
"09:15:30 PM, So. 10/09/2022";
d = new TbDate(s_ver, pattern, "de","Europe/Berlin");
Assert.assertEquals("2022-10-09T19:15:30Z", d.toISOString());
Assertions.assertEquals("2022-10-09T19:15:30Z", d.toISOString());
s = "02:15:30 пп, середа, 4 жовтня 2023 р.";
pattern = "hh:mm:ss a, EEEE, d MMMM y 'р.'";
@ -189,50 +187,50 @@ class TbDateTest {
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
hrs = 14 - localOffsetHrs;
expected = "2023-10-04T" + hrs + ":15:30Z";
Assert.assertEquals(expected, d.toISOString());
Assertions.assertEquals(expected, d.toISOString());
d = new TbDate(1693962245000L);
Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-06T01:04:05Z", d.toISOString());
// Depends on time zone, so we just check it works;
Assert.assertNotNull(d.toLocaleDateString());
Assert.assertNotNull(d.toLocaleDateString("en-US"));
Assertions.assertNotNull(d.toLocaleDateString());
Assertions.assertNotNull(d.toLocaleDateString("en-US"));
Assert.assertEquals("9/5/23", d.toLocaleDateString("en-US", "America/New_York"));
Assert.assertEquals("23. 9. 5.", d.toLocaleDateString("ko-KR", "America/New_York"));
Assert.assertEquals("06.09.23", d.toLocaleDateString( "uk-UA", "Europe/Kiev"));
Assert.assertEquals("5\u200F/9\u200F/2023", d.toLocaleDateString( "ar-EG", "America/New_York"));
Assertions.assertEquals("9/5/23", d.toLocaleDateString("en-US", "America/New_York"));
Assertions.assertEquals("23. 9. 5.", d.toLocaleDateString("ko-KR", "America/New_York"));
Assertions.assertEquals("06.09.23", d.toLocaleDateString( "uk-UA", "Europe/Kiev"));
Assertions.assertEquals("5\u200F/9\u200F/2023", d.toLocaleDateString( "ar-EG", "America/New_York"));
Assert.assertEquals("Tuesday, September 5, 2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("Tuesday, September 5, 2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.toString()));
Assert.assertEquals("2023년 9월 5일 화요일", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("2023년 9월 5일 화요일", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.toString()));
Assert.assertEquals("середа, 6 вересня 2023 р.", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("середа, 6 вересня 2023 р.", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("dateStyle", "full")
.toString()));
Assert.assertEquals("الثلاثاء، 5 سبتمبر 2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals("الثلاثاء، 5 سبتمبر 2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.toString()));
Assert.assertEquals("Tuesday 9/5/2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("Tuesday 9/5/2023", d.toLocaleDateString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "EEEE M/d/yyyy")
.toString()));
Assert.assertEquals("화요일 9/5/2023", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("화요일 9/5/2023", d.toLocaleDateString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "EEEE M/d/yyyy")
.toString()));
Assert.assertEquals("середа 9/6/2023", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("середа 9/6/2023", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("pattern", "EEEE M/d/yyyy")
.toString()));
Assert.assertEquals("الثلاثاء 9/5/2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals("الثلاثاء 9/5/2023", d.toLocaleDateString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "EEEE M/d/yyyy")
.toString()));
@ -243,44 +241,44 @@ class TbDateTest {
TbDate d = new TbDate(1693962245000L);
// Depends on time zone, so we just check it works;
Assert.assertNotNull(d.toLocaleTimeString());
Assert.assertNotNull(d.toLocaleTimeString("en-US"));
Assertions.assertNotNull(d.toLocaleTimeString());
Assertions.assertNotNull(d.toLocaleTimeString("en-US"));
Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York"));
Assert.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York"));
Assert.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev"));
Assert.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York"));
Assertions.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York"));
Assertions.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York"));
Assertions.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev"));
Assertions.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York"));
Assert.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("04:04:05 за східноєвропейським літнім часом", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals("9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "h:mm:ss a")
.toString()));
Assert.assertEquals("9:04:05 오후", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("9:04:05 오후", d.toLocaleTimeString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "h:mm:ss a")
.toString()));
Assert.assertEquals("4:04:05 дп", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("4:04:05 дп", d.toLocaleTimeString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("pattern", "h:mm:ss a")
.toString()));
Assert.assertEquals("9:04:05 م", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals("9:04:05 م", d.toLocaleTimeString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "h:mm:ss a")
.toString()));
@ -291,27 +289,27 @@ class TbDateTest {
TbDate d = new TbDate(1693962245000L);
// Depends on time zone, so we just check it works;
Assert.assertNotNull(d.toLocaleString());
Assert.assertNotNull(d.toLocaleString("en-US"));
Assertions.assertNotNull(d.toLocaleString());
Assertions.assertNotNull(d.toLocaleString("en-US"));
Assert.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York"));
Assert.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York"));
Assert.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev"));
Assertions.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York"));
Assertions.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York"));
Assertions.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev"));
String expected_ver = Runtime.version().feature() == 11 ? "5\u200F/9\u200F/2023 9:04:05 م" :
"5\u200F/9\u200F/2023, 9:04:05 م";
Assert.assertEquals(expected_ver, d.toLocaleString( "ar-EG", "America/New_York"));
Assertions.assertEquals(expected_ver, d.toLocaleString( "ar-EG", "America/New_York"));
Assert.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("2023년 9월 5일 화요일 오후 9시 4분 5초 미 동부 하계 표준시", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("dateStyle", "full")
.put("timeStyle", "full")
@ -319,25 +317,25 @@ class TbDateTest {
expected_ver = Runtime.version().feature() == 11 ? "الثلاثاء، 5 سبتمبر 2023 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية" :
"الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية";
Assert.assertEquals(expected_ver, d.toLocaleString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals(expected_ver, d.toLocaleString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("dateStyle", "full")
.put("timeStyle", "full")
.toString()));
Assert.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleString("en-US", JacksonUtil.newObjectNode()
Assertions.assertEquals("9/5/2023, 9:04:05 PM", d.toLocaleString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "M/d/yyyy, h:mm:ss a")
.toString()));
Assert.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode()
Assertions.assertEquals("9/5/2023, 9:04:05 오후", d.toLocaleString("ko-KR", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "M/d/yyyy, h:mm:ss a")
.toString()));
Assert.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode()
Assertions.assertEquals("9/6/2023, 4:04:05 дп", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev")
.put("pattern", "M/d/yyyy, h:mm:ss a")
.toString()));
Assert.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode()
Assertions.assertEquals("9/5/2023, 9:04:05 م", d.toLocaleString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York")
.put("pattern", "M/d/yyyy, h:mm:ss a")
.toString()));
@ -347,51 +345,51 @@ class TbDateTest {
void TestFromString () {
String stringDateUTC = "2023-09-06T01:04:05.00Z";
TbDate d = new TbDate(stringDateUTC);
Assert.assertEquals("2023-09-06T01:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-06T01:04:05Z", d.toISOString());
String stringDateTZ = "2023-09-06T01:04:05.00+04:00:00";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-05T21:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-05T21:04:05Z", d.toISOString());
stringDateTZ = "2023-09-06T01:04:05.00+04";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-05T21:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-05T21:04:05Z", d.toISOString());
stringDateTZ = "2023-09-06T01:04:05.00-04:00";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-06T05:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-06T05:04:05Z", d.toISOString());
stringDateTZ = "2023-09-06T01:04:05.00+04:30:56";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-05T20:33:09Z", d.toISOString());
Assertions.assertEquals("2023-09-05T20:33:09Z", d.toISOString());
stringDateTZ = "2023-09-06T01:04:05.00-02:00";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-09-06T03:04:05Z", d.toISOString());
Assertions.assertEquals("2023-09-06T03:04:05Z", d.toISOString());
// Without_TZ
stringDateTZ = "2023-08-06T04:04:05.123";
d = new TbDate(stringDateTZ);
Assert.assertEquals("2023-08-06 04:04:05", d.toLocaleString());
Assertions.assertEquals("2023-08-06 04:04:05", d.toLocaleString());
// With TZ RFC_1123
String stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 GMT";
d = new TbDate(stringDateRFC_1123);
Assert.assertEquals("2023-06-03T11:05:30Z", d.toISOString());
Assertions.assertEquals("2023-06-03T11:05:30Z", d.toISOString());
stringDateRFC_1123 = "Sat, 3 Jun 2023 01:04:05 +043056";
d = new TbDate(stringDateRFC_1123);
Assert.assertEquals("2023-06-02T20:33:09Z", d.toISOString());
Assertions.assertEquals("2023-06-02T20:33:09Z", d.toISOString());
stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30 +0400";
d = new TbDate(stringDateRFC_1123);
Assert.assertEquals("2023-06-03T07:05:30Z", d.toISOString());
Assertions.assertEquals("2023-06-03T07:05:30Z", d.toISOString());
stringDateRFC_1123 = "Thu, 29 Feb 2024 11:05:30 -03";
d = new TbDate(stringDateRFC_1123);
Assert.assertEquals("2024-02-29T14:05:30Z", d.toISOString());
Assertions.assertEquals("2024-02-29T14:05:30Z", d.toISOString());
// Without TZ RFC_1123
stringDateRFC_1123 = "Sat, 3 Jun 2023 11:05:30";
d = new TbDate(stringDateRFC_1123);
Assert.assertEquals("2023-06-03 11:05:30", d.toLocaleString());
Assertions.assertEquals("2023-06-03 11:05:30", d.toLocaleString());
// With pattern + locale - ok
String pattern = "hh:mm:ss a, EEE M/d/uuuu";
String stringDate_ver_RFC_1123 = Runtime.version().feature() == 11 ? "09:15:30 nachm., So. 10/09/2022" :
"09:15:30 PM, So. 10/09/2022";
d = new TbDate(stringDate_ver_RFC_1123 , pattern, "de");
Assert.assertEquals("2022-10-09 21:15:30", d.toLocaleString());
Assertions.assertEquals("2022-10-09 21:15:30", d.toLocaleString());
// failed TZ
String expectedMessage = "Cannot parse value";
@ -434,10 +432,10 @@ class TbDateTest {
String stringDateStart = "1970-01-01T00:00:00Z";
TbDate d = new TbDate(stringDateStart);
long actualMillis = TbDate.parse("1970-01-01 T00:00:00");
Assert.assertEquals(-d.getLocaleZoneOffset().getTotalSeconds() * 1000, actualMillis);
Assertions.assertEquals(-d.getLocaleZoneOffset().getTotalSeconds() * 1000, actualMillis);
String pattern = "yyyy-MM-dd HH:mm:ss.SSS";
String stringDate = "1995-12-04 00:12:00.000";
Assert.assertNotEquals(-1L, TbDate.parse(stringDate, pattern));
Assertions.assertNotEquals(-1L, TbDate.parse(stringDate, pattern));
}
@Test
@ -451,67 +449,67 @@ class TbDateTest {
TbDate dLocal1 = new TbDate(d1.parseSecondMilli() + d1.getLocaleZoneOffset().getTotalSeconds()*1000);
TbDate dLocal2 = new TbDate(d2.parseSecondMilli() + d2.getLocaleZoneOffset().getTotalSeconds()*1000);
Assert.assertEquals(dLocal.getUTCFullYear(), d.getFullYear());
Assert.assertEquals(dLocal0.getUTCFullYear(), d0.getFullYear());
Assert.assertEquals(dLocal1.getUTCFullYear(), d1.getFullYear());
Assert.assertEquals(dLocal2.getUTCFullYear(), d2.getFullYear());
Assert.assertEquals(dLocal.getUTCMonth(), d.getMonth());
Assert.assertEquals(dLocal0.getUTCMonth(), d0.getMonth());
Assert.assertEquals(dLocal1.getUTCMonth(), d1.getMonth());
Assert.assertEquals(dLocal2.getUTCMonth(), d2.getMonth());
Assert.assertEquals(dLocal.getUTCDate(), d.getDate());
Assert.assertEquals(dLocal0.getUTCDate(), d0.getDate());
Assert.assertEquals(dLocal1.getUTCDate(), d1.getDate());
Assert.assertEquals(dLocal2.getUTCDate(), d2.getDate());
Assert.assertEquals(dLocal.getUTCDay(), d.getDay());
Assert.assertEquals(dLocal0.getUTCDay(), d0.getDay());
Assert.assertEquals(dLocal1.getUTCDay(), d1.getDay());
Assert.assertEquals(dLocal2.getUTCDay(), d2.getDay());
Assert.assertEquals(dLocal.getUTCHours(), d.getHours());
Assert.assertEquals(dLocal0.getUTCHours(), d0.getHours());
Assert.assertEquals(dLocal1.getUTCHours(), d1.getHours());
Assert.assertEquals(dLocal2.getUTCHours(), d2.getHours());
Assert.assertEquals(dLocal.getUTCMinutes(), d.getMinutes());
Assert.assertEquals(dLocal0.getUTCMinutes(), d0.getMinutes());
Assert.assertEquals(dLocal1.getUTCMinutes(), d1.getMinutes());
Assert.assertEquals(dLocal2.getUTCMinutes(), d2.getMinutes());
Assert.assertEquals(dLocal.getUTCSeconds(), d.getSeconds());
Assert.assertEquals(dLocal0.getUTCSeconds(), d0.getSeconds());
Assert.assertEquals(dLocal1.getUTCSeconds(), d1.getSeconds());
Assert.assertEquals(dLocal2.getUTCSeconds(), d2.getSeconds());
Assert.assertEquals(dLocal.getUTCMilliseconds(), d.getMilliseconds());
Assert.assertEquals(dLocal0.getUTCMilliseconds(), d0.getMilliseconds());
Assert.assertEquals(dLocal1.getUTCMilliseconds(), d1.getMilliseconds());
Assert.assertEquals(dLocal2.getUTCMilliseconds(), d2.getMilliseconds());
Assertions.assertEquals(dLocal.getUTCFullYear(), d.getFullYear());
Assertions.assertEquals(dLocal0.getUTCFullYear(), d0.getFullYear());
Assertions.assertEquals(dLocal1.getUTCFullYear(), d1.getFullYear());
Assertions.assertEquals(dLocal2.getUTCFullYear(), d2.getFullYear());
Assertions.assertEquals(dLocal.getUTCMonth(), d.getMonth());
Assertions.assertEquals(dLocal0.getUTCMonth(), d0.getMonth());
Assertions.assertEquals(dLocal1.getUTCMonth(), d1.getMonth());
Assertions.assertEquals(dLocal2.getUTCMonth(), d2.getMonth());
Assertions.assertEquals(dLocal.getUTCDate(), d.getDate());
Assertions.assertEquals(dLocal0.getUTCDate(), d0.getDate());
Assertions.assertEquals(dLocal1.getUTCDate(), d1.getDate());
Assertions.assertEquals(dLocal2.getUTCDate(), d2.getDate());
Assertions.assertEquals(dLocal.getUTCDay(), d.getDay());
Assertions.assertEquals(dLocal0.getUTCDay(), d0.getDay());
Assertions.assertEquals(dLocal1.getUTCDay(), d1.getDay());
Assertions.assertEquals(dLocal2.getUTCDay(), d2.getDay());
Assertions.assertEquals(dLocal.getUTCHours(), d.getHours());
Assertions.assertEquals(dLocal0.getUTCHours(), d0.getHours());
Assertions.assertEquals(dLocal1.getUTCHours(), d1.getHours());
Assertions.assertEquals(dLocal2.getUTCHours(), d2.getHours());
Assertions.assertEquals(dLocal.getUTCMinutes(), d.getMinutes());
Assertions.assertEquals(dLocal0.getUTCMinutes(), d0.getMinutes());
Assertions.assertEquals(dLocal1.getUTCMinutes(), d1.getMinutes());
Assertions.assertEquals(dLocal2.getUTCMinutes(), d2.getMinutes());
Assertions.assertEquals(dLocal.getUTCSeconds(), d.getSeconds());
Assertions.assertEquals(dLocal0.getUTCSeconds(), d0.getSeconds());
Assertions.assertEquals(dLocal1.getUTCSeconds(), d1.getSeconds());
Assertions.assertEquals(dLocal2.getUTCSeconds(), d2.getSeconds());
Assertions.assertEquals(dLocal.getUTCMilliseconds(), d.getMilliseconds());
Assertions.assertEquals(dLocal0.getUTCMilliseconds(), d0.getMilliseconds());
Assertions.assertEquals(dLocal1.getUTCMilliseconds(), d1.getMilliseconds());
Assertions.assertEquals(dLocal2.getUTCMilliseconds(), d2.getMilliseconds());
}
@Test
void Test_Year_Moth_Date_Hours_Min_Sec_Without_TZ() {
TbDate d = new TbDate(2023, 8, 18);
Assert.assertEquals("2023-08-18 00:00:00", d.toLocaleString());
Assertions.assertEquals("2023-08-18 00:00:00", d.toLocaleString());
d = new TbDate(2023, 9, 17, 17, 34);
Assert.assertEquals("2023-09-17 17:34:00", d.toLocaleString());
Assertions.assertEquals("2023-09-17 17:34:00", d.toLocaleString());
d = new TbDate(23, 9, 7, 8, 4);
Assert.assertEquals("2023-09-07 08:04:00", d.toLocaleString());
Assertions.assertEquals("2023-09-07 08:04:00", d.toLocaleString());
d = new TbDate(23, 9, 7, 8, 4, 5);
Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString());
Assertions.assertEquals("2023-09-07 08:04:05", d.toLocaleString());
d = new TbDate(23, 9, 7, 8, 4, 5, 567);
Assert.assertEquals("2023-09-07 08:04:05", d.toLocaleString());
Assertions.assertEquals("2023-09-07 08:04:05", d.toLocaleString());
}
@Test
void Test_DateString_With_Pattern() {
String pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX";
TbDate d = new TbDate("2023-08-06 04:04:05.000-04:00", pattern);
Assert.assertEquals("2023-08-06T08:04:05Z", d.toISOString());
Assertions.assertEquals("2023-08-06T08:04:05Z", d.toISOString());
}
@Test
void Test_DateString_With_TZ() {
@ -525,7 +523,7 @@ class TbDateTest {
int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
TbDateTestEntity tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
String expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
tz = +5;
tzStr = "+05:00";
@ -534,7 +532,7 @@ class TbDateTest {
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
tz = -2;
tzStr = "-02";
@ -543,7 +541,7 @@ class TbDateTest {
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
}
@Test
@ -557,13 +555,13 @@ class TbDateTest {
int localOffsetHrs = 0;
TbDateTestEntity tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
String expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
d = new TbDate(23, 9, date, hrs, 4, 5, tzStr);
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
tz = 3;
tzStr = "+03:00";
@ -571,7 +569,7 @@ class TbDateTest {
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
tz = -4;
tzStr = "-04:00";
@ -579,19 +577,19 @@ class TbDateTest {
localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds()/60/60;
tbDateTest = new TbDateTestEntity(23, 9, date, hrs + localOffsetHrs - tz);
expected = String.format(pattern, tbDateTest.geDateStr(), tbDateTest.geHoursStr());
Assert.assertEquals(expected, d.toLocaleString());
Assertions.assertEquals(expected, d.toLocaleString());
}
@Test
public void TestToUTC() {
Assert.assertEquals(-2209075200000L, TbDate.UTC(0));
Assert.assertEquals("1899-12-31T00:00:00Z", new TbDate(TbDate.UTC(0)).toJSON());
Assert.assertEquals("1996-02-02T03:04:05Z", new TbDate(TbDate.UTC(96, 2, 2, 3, 4, 5)).toJSON());
Assert.assertEquals("2022-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(22, 0, 0, 3, 4, 5, 678)).toJSON());
Assert.assertEquals("0903-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(903, 0, 0, 3, 4, 5, 678)).toJSON());
Assert.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON());
Assert.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON());
Assert.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON());
Assertions.assertEquals(-2209075200000L, TbDate.UTC(0));
Assertions.assertEquals("1899-12-31T00:00:00Z", new TbDate(TbDate.UTC(0)).toJSON());
Assertions.assertEquals("1996-02-02T03:04:05Z", new TbDate(TbDate.UTC(96, 2, 2, 3, 4, 5)).toJSON());
Assertions.assertEquals("2022-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(22, 0, 0, 3, 4, 5, 678)).toJSON());
Assertions.assertEquals("0903-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(903, 0, 0, 3, 4, 5, 678)).toJSON());
Assertions.assertEquals("1958-12-31T03:04:05.678Z", new TbDate(TbDate.UTC(1958, 0, 0, 3, 4, 5, 678)).toJSON());
Assertions.assertEquals("2032-04-05T03:04:05.678Z", new TbDate(TbDate.UTC(2032, 4, 5, 3, 4, 5, 678)).toJSON());
Assertions.assertEquals("2024-02-29T03:04:05.678Z", new TbDate(TbDate.UTC(2024, 2, 29, 3, 4, 5, 678)).toJSON());
Exception actual = assertThrows(DateTimeException.class, () -> {
TbDate.UTC(2023, 2, 29, 3, 4, 5, 678);
});
@ -602,16 +600,16 @@ class TbDateTest {
@Test
void TestMethodGetTimeUTC() {
TbDate ddUTC = new TbDate(TbDate.UTC(1996, 1, 2, 3, 4, 5));
Assert.assertEquals(820551845000L, ddUTC.valueOf());
Assertions.assertEquals(820551845000L, ddUTC.valueOf());
TbDate dd = new TbDate(1996, 1, 2, 3, 4, 5);
int localOffsetMilli = ZoneId.systemDefault().getRules().getOffset(dd.getInstant()).getTotalSeconds()*1000;
Assert.assertEquals((dd.valueOf() + localOffsetMilli), ddUTC.valueOf());
Assertions.assertEquals((dd.valueOf() + localOffsetMilli), ddUTC.valueOf());
ddUTC = new TbDate(TbDate.UTC(1969, 7, 20, 20, 17, 40));
Assert.assertEquals(-14182940000L, ddUTC.valueOf());
Assertions.assertEquals(-14182940000L, ddUTC.valueOf());
TbDate beforeStartUTC = new TbDate(1969, 7, 20, 20, 17, 40);
localOffsetMilli = ZoneId.systemDefault().getRules().getOffset(beforeStartUTC.getInstant()).getTotalSeconds()*1000;
Assert.assertEquals((beforeStartUTC.valueOf() + localOffsetMilli), ddUTC.valueOf());
Assertions.assertEquals((beforeStartUTC.valueOf() + localOffsetMilli), ddUTC.valueOf());
}
@Test
@ -715,20 +713,20 @@ class TbDateTest {
TbDate d1 = new TbDate(1975, 12, 31, 23, 15, 30, 567, "-03:00");
long dateMilliSecond = d1.getTime();
int fiveMinutesInMillis = 5 * 60 * 1000;
Assert.assertEquals(15, d1.getUTCMinutes());
Assert.assertEquals(4, d1.getUTCDay());
Assertions.assertEquals(15, d1.getUTCMinutes());
Assertions.assertEquals(4, d1.getUTCDay());
d1.setTime(dateMilliSecond + fiveMinutesInMillis);
Assert.assertEquals(20, d1.getUTCMinutes());
Assert.assertEquals(4, d1.getUTCDay());
Assertions.assertEquals(20, d1.getUTCMinutes());
Assertions.assertEquals(4, d1.getUTCDay());
d1.setTime(-378682769433L);
Assert.assertEquals(1958, d1.getUTCFullYear());
Assert.assertEquals(1, d1.getUTCMonth());
Assert.assertEquals(1, d1.getUTCDate());
Assert.assertEquals(2, d1.getUTCHours());
Assert.assertEquals(20, d1.getUTCMinutes());
Assert.assertEquals(30, d1.getUTCSeconds());
Assert.assertEquals(567, d1.getUTCMilliseconds());
Assert.assertEquals(3, d1.getUTCDay());
Assertions.assertEquals(1958, d1.getUTCFullYear());
Assertions.assertEquals(1, d1.getUTCMonth());
Assertions.assertEquals(1, d1.getUTCDate());
Assertions.assertEquals(2, d1.getUTCHours());
Assertions.assertEquals(20, d1.getUTCMinutes());
Assertions.assertEquals(30, d1.getUTCSeconds());
Assertions.assertEquals(567, d1.getUTCMilliseconds());
Assertions.assertEquals(3, d1.getUTCDay());
}
@Test
void TestMethodSeFullYearMonthDate() {
@ -788,95 +786,95 @@ class TbDateTest {
d1.setMinutes(5);
d2.setMinutes(15);
Assert.assertEquals(5, d1.getMinutes());
Assert.assertEquals(15, d2.getMinutes());
Assertions.assertEquals(5, d1.getMinutes());
Assertions.assertEquals(15, d2.getMinutes());
d1.setMinutes(5, 34);
d2.setMinutes(25, 43);
Assert.assertEquals(5, d1.getMinutes());
Assert.assertEquals(34, d1.getSeconds());
Assert.assertEquals(25, d2.getMinutes());
Assert.assertEquals(43, d2.getSeconds());
Assertions.assertEquals(5, d1.getMinutes());
Assertions.assertEquals(34, d1.getSeconds());
Assertions.assertEquals(25, d2.getMinutes());
Assertions.assertEquals(43, d2.getSeconds());
d1.setMinutes(25, 14, 567);
d2.setMinutes(45, 3, 876);
Assert.assertEquals(25, d1.getMinutes());
Assert.assertEquals(14, d1.getSeconds());
Assert.assertEquals(567, d1.getMilliseconds());
Assert.assertEquals(45, d2.getMinutes());
Assert.assertEquals(3, d2.getSeconds());
Assert.assertEquals(876, d2.getMilliseconds());
Assertions.assertEquals(25, d1.getMinutes());
Assertions.assertEquals(14, d1.getSeconds());
Assertions.assertEquals(567, d1.getMilliseconds());
Assertions.assertEquals(45, d2.getMinutes());
Assertions.assertEquals(3, d2.getSeconds());
Assertions.assertEquals(876, d2.getMilliseconds());
d1.setSeconds(5);
d2.setSeconds(23);
Assert.assertEquals(5, d1.getSeconds());
Assert.assertEquals(23, d2.getSeconds());
Assertions.assertEquals(5, d1.getSeconds());
Assertions.assertEquals(23, d2.getSeconds());
d1.setSeconds(45, 987);
d2.setSeconds(54, 842);
Assert.assertEquals(45, d1.getSeconds());
Assert.assertEquals(987, d1.getMilliseconds());
Assert.assertEquals(54, d2.getSeconds());
Assert.assertEquals(842, d2.getMilliseconds());
Assertions.assertEquals(45, d1.getSeconds());
Assertions.assertEquals(987, d1.getMilliseconds());
Assertions.assertEquals(54, d2.getSeconds());
Assertions.assertEquals(842, d2.getMilliseconds());
d1.setMilliseconds(675);
d2.setMilliseconds(923);
Assert.assertEquals(675, d1.getMilliseconds());
Assert.assertEquals(923, d2.getMilliseconds());
Assertions.assertEquals(675, d1.getMilliseconds());
Assertions.assertEquals(923, d2.getMilliseconds());
}
@Test
public void toStringAsJs() {
TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-04:00");
Assert.assertEquals("четвер, 1 січня 1976 р. о 06:15:30 за східноєвропейським стандартним часом", d1.toString("uk-UA", "Europe/Kyiv"));
Assert.assertEquals("Thursday, January 1, 1976 at 6:15:30 AM Eastern European Standard Time", d1.toString("en-US", "Europe/Kyiv"));
Assert.assertEquals("1976 Jan 1, Thu 06:15:30 Eastern European Time", d1.toString("UTC", "Europe/Kyiv"));
Assert.assertEquals("Wednesday, December 31, 1975 at 10:15:30 PM Eastern Standard Time", d1.toString("en-US", "America/New_York"));
Assert.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("GMT", "America/New_York"));
Assert.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("UTC", "America/New_York"));
Assert.assertEquals(d1.toUTCString("UTC"), d1.toUTCString());
Assert.assertEquals("четвер, 1 січня 1976 р., 03:15:30", d1.toUTCString("uk-UA"));
Assert.assertEquals("Thursday, January 1, 1976, 3:15:30 AM", d1.toUTCString("en-US"));
Assert.assertEquals("1976-01-01T03:15:30.567Z", d1.toJSON());
Assert.assertEquals("1976-01-01T03:15:30.567Z", d1.toISOString());
Assert.assertEquals("1976-01-01 06:15:30", d1.toLocaleString("UTC", "Europe/Kyiv"));
Assert.assertEquals("01.01.76, 06:15:30", d1.toLocaleString("uk-UA", "Europe/Kyiv"));
Assert.assertEquals("1975-12-31 22:15:30", d1.toLocaleString("UTC", "America/New_York"));
Assert.assertEquals("12/31/75, 10:15:30 PM", d1.toLocaleString("en-US", "America/New_York"));
Assert.assertEquals("1976 Jan 1, Thu", d1.toDateString("UTC", "Europe/Kyiv"));
Assert.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA", "Europe/Kyiv"));
Assert.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York"));
Assert.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York"));
Assert.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv"));
Assert.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv"));
Assert.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York"));
Assert.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York"));
Assert.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv"));
Assert.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv"));
Assert.assertEquals("10:15:30 PM Eastern Standard Time", d1.toTimeString("en-US", "America/New_York"));
Assert.assertEquals("22:15:30 Eastern Standard Time", d1.toTimeString("UTC", "America/New_York"));
Assertions.assertEquals("четвер, 1 січня 1976 р. о 06:15:30 за східноєвропейським стандартним часом", d1.toString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("Thursday, January 1, 1976 at 6:15:30 AM Eastern European Standard Time", d1.toString("en-US", "Europe/Kyiv"));
Assertions.assertEquals("1976 Jan 1, Thu 06:15:30 Eastern European Time", d1.toString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("Wednesday, December 31, 1975 at 10:15:30 PM Eastern Standard Time", d1.toString("en-US", "America/New_York"));
Assertions.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("GMT", "America/New_York"));
Assertions.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("UTC", "America/New_York"));
Assertions.assertEquals(d1.toUTCString("UTC"), d1.toUTCString());
Assertions.assertEquals("четвер, 1 січня 1976 р., 03:15:30", d1.toUTCString("uk-UA"));
Assertions.assertEquals("Thursday, January 1, 1976, 3:15:30 AM", d1.toUTCString("en-US"));
Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toJSON());
Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toISOString());
Assertions.assertEquals("1976-01-01 06:15:30", d1.toLocaleString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("01.01.76, 06:15:30", d1.toLocaleString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("1975-12-31 22:15:30", d1.toLocaleString("UTC", "America/New_York"));
Assertions.assertEquals("12/31/75, 10:15:30 PM", d1.toLocaleString("en-US", "America/New_York"));
Assertions.assertEquals("1976 Jan 1, Thu", d1.toDateString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York"));
Assertions.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York"));
Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York"));
Assertions.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York"));
Assertions.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("10:15:30 PM Eastern Standard Time", d1.toTimeString("en-US", "America/New_York"));
Assertions.assertEquals("22:15:30 Eastern Standard Time", d1.toTimeString("UTC", "America/New_York"));
}
@Test
public void testNow() {
Assertions.assertThat(TbDate.now()).isCloseTo(Instant.now().toEpochMilli(), Offset.offset(1000L));
assertThat(TbDate.now()).isCloseTo(Instant.now().toEpochMilli(), Offset.offset(1000L));
}
private void testResultChangeDateTime(TbDate d) {
int localOffset = ZoneId.systemDefault().getRules().getOffset(d.getInstant()).getTotalSeconds();
TbDateTestEntity tbDateTestEntity = new TbDateTestEntity(d.getFullYear(), d.getMonth(), d.getDate(), (d.getHours() - (localOffset/60/60)));
Assert.assertEquals(tbDateTestEntity.getYear(), d.getUTCFullYear());
Assert.assertEquals(tbDateTestEntity.getMonth(), d.getUTCMonth());
Assert.assertEquals(tbDateTestEntity.getDate(), d.getUTCDate());
Assert.assertEquals(tbDateTestEntity.getHours(), d.getUTCHours());
Assert.assertEquals(d.getMinutes(), d.getUTCMinutes());
Assert.assertEquals(d.getSeconds(), d.getUTCSeconds());
Assert.assertEquals(d.getMilliseconds(), d.getUTCMilliseconds());
Assertions.assertEquals(tbDateTestEntity.getYear(), d.getUTCFullYear());
Assertions.assertEquals(tbDateTestEntity.getMonth(), d.getUTCMonth());
Assertions.assertEquals(tbDateTestEntity.getDate(), d.getUTCDate());
Assertions.assertEquals(tbDateTestEntity.getHours(), d.getUTCHours());
Assertions.assertEquals(d.getMinutes(), d.getUTCMinutes());
Assertions.assertEquals(d.getSeconds(), d.getUTCSeconds());
Assertions.assertEquals(d.getMilliseconds(), d.getUTCMilliseconds());
}
@Test
@ -884,7 +882,7 @@ class TbDateTest {
String stringDateUTC = "2023-09-06T01:04:05.345Z";
TbDate expectedDate = new TbDate(stringDateUTC);
String serializedTbDate = JacksonUtil.toJsonNode(JacksonUtil.toString(Map.of("date", expectedDate))).get("date").asText();
Assert.assertNotNull(serializedTbDate);
Assert.assertEquals(expectedDate.toString(), serializedTbDate);
Assertions.assertNotNull(serializedTbDate);
Assertions.assertEquals(expectedDate.toString(), serializedTbDate);
}
}

262
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

@ -17,10 +17,10 @@ package org.thingsboard.script.api.tbel;
import com.google.common.primitives.Bytes;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.mvel2.ExecutionContext;
import org.mvel2.ParserContext;
import org.mvel2.SandboxedParserConfiguration;
@ -57,7 +57,7 @@ public class TbUtilsTest {
private final double doubleValRev = -2.7208640774822924E205;
@Before
@BeforeEach
public void before() {
SandboxedParserConfiguration parserConfig = ParserContext.enableSandboxedMode();
parserConfig.addImport("JSON", TbJson.class);
@ -70,76 +70,76 @@ public class TbUtilsTest {
log.error("Cannot register functions", e);
}
ctx = new ExecutionContext(parserConfig);
Assert.assertNotNull(ctx);
Assertions.assertNotNull(ctx);
}
@After
@AfterEach
public void after() {
ctx.stop();
}
@Test
public void parseHexToInt() {
Assert.assertEquals(0xAB, TbUtils.parseHexToInt("AB"));
Assert.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true));
Assert.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false));
Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true));
Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("CCBBAA", false));
Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("AABBCCDD", true));
Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("DDCCBBAA", false));
Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("DDCCBBAA", true));
Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("AABBCCDD", false));
Assertions.assertEquals(0xAB, TbUtils.parseHexToInt("AB"));
Assertions.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true));
Assertions.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false));
Assertions.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true));
Assertions.assertEquals(0xAABBCC, TbUtils.parseHexToInt("CCBBAA", false));
Assertions.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("AABBCCDD", true));
Assertions.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("DDCCBBAA", false));
Assertions.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("DDCCBBAA", true));
Assertions.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("AABBCCDD", false));
}
@Test
public void parseBytesToInt_checkPrimitives() {
int expected = 257;
byte[] data = ByteBuffer.allocate(4).putInt(expected).array();
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assertions.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
expected = Integer.MAX_VALUE;
data = ByteBuffer.allocate(4).putInt(expected).array();
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
expected = 0xAABBCCDD;
data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
data = new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
expected = 0xAABBCC;
data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
data = new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
}
@Test
public void parseBytesToInt_checkLists() {
int expected = 257;
List<Byte> data = toList(ByteBuffer.allocate(4).putInt(expected).array());
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assertions.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
expected = Integer.MAX_VALUE;
data = toList(ByteBuffer.allocate(4).putInt(expected).array());
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
expected = 0xAABBCCDD;
data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
data = toList(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
expected = 0xAABBCC;
data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
data = toList(new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
}
@Test
@ -183,7 +183,7 @@ public class TbUtilsTest {
ExecutionHashMap<String, Object> actualMapWithPaths = TbUtils.toFlatMap(ctx, inputMap, excludeList, true);
Assert.assertEquals(expectedMapWithPath, actualMapWithPaths);
Assertions.assertEquals(expectedMapWithPath, actualMapWithPaths);
ExecutionHashMap<String, Object> expectedMapWithoutPaths = new ExecutionHashMap<>(16, ctx);
expectedMapWithoutPaths.put("timezone", "UTC-5");
@ -199,153 +199,153 @@ public class TbUtilsTest {
ExecutionHashMap<String, Object> actualMapWithoutPaths = TbUtils.toFlatMap(ctx, inputMap, false);
Assert.assertEquals(expectedMapWithoutPaths, actualMapWithoutPaths);
Assertions.assertEquals(expectedMapWithoutPaths, actualMapWithoutPaths);
}
@Test
public void parseInt() {
Assert.assertNull(TbUtils.parseInt(null));
Assert.assertNull(TbUtils.parseInt(""));
Assert.assertNull(TbUtils.parseInt(" "));
Assertions.assertNull(TbUtils.parseInt(null));
Assertions.assertNull(TbUtils.parseInt(""));
Assertions.assertNull(TbUtils.parseInt(" "));
Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("0"));
Assert.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("-0"));
Assert.assertEquals(java.util.Optional.of(473).get(), TbUtils.parseInt("473"));
Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-0xFF"));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FF"));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFG"));
Assertions.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("0"));
Assertions.assertEquals(java.util.Optional.of(0).get(), TbUtils.parseInt("-0"));
Assertions.assertEquals(java.util.Optional.of(473).get(), TbUtils.parseInt("473"));
Assertions.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-0xFF"));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FF"));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("0xFG"));
Assert.assertEquals(java.util.Optional.of(102).get(), TbUtils.parseInt("1100110", 2));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("1100210", 2));
Assertions.assertEquals(java.util.Optional.of(102).get(), TbUtils.parseInt("1100110", 2));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("1100210", 2));
Assert.assertEquals(java.util.Optional.of(63).get(), TbUtils.parseInt("77", 8));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("18", 8));
Assertions.assertEquals(java.util.Optional.of(63).get(), TbUtils.parseInt("77", 8));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("18", 8));
Assert.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-FF", 16));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FG", 16));
Assertions.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-FF", 16));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("FG", 16));
Assert.assertEquals(java.util.Optional.of(Integer.MAX_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MAX_VALUE), 10));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10));
Assert.assertEquals(java.util.Optional.of(Integer.MIN_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MIN_VALUE), 10));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10));
Assertions.assertEquals(java.util.Optional.of(Integer.MAX_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MAX_VALUE), 10));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10));
Assertions.assertEquals(java.util.Optional.of(Integer.MIN_VALUE).get(), TbUtils.parseInt(Integer.toString(Integer.MIN_VALUE), 10));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt(BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10));
Assert.assertEquals(java.util.Optional.of(506070563).get(), TbUtils.parseInt("KonaIn", 30));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("KonaIn", 10));
Assertions.assertEquals(java.util.Optional.of(506070563).get(), TbUtils.parseInt("KonaIn", 30));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("KonaIn", 10));
}
@Test
public void parseFloat() {
Assert.assertEquals(java.util.Optional.of(floatVal).get(), TbUtils.parseFloat(floatValStr));
Assertions.assertEquals(java.util.Optional.of(floatVal).get(), TbUtils.parseFloat(floatValStr));
}
@Test
public void toFixedFloat() {
float actualF = TbUtils.toFixed(floatVal, 3);
Assert.assertEquals(1, Float.compare(floatVal, actualF));
Assert.assertEquals(0, Float.compare(29.298f, actualF));
Assertions.assertEquals(1, Float.compare(floatVal, actualF));
Assertions.assertEquals(0, Float.compare(29.298f, actualF));
}
@Test
public void parseHexToFloat() {
Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseHexToFloat(intValHex)));
Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseHexToFloat(intValHex, false)));
Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBigEndianHexToFloat(intValHex)));
Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseLittleEndianHexToFloat(floatValHexRev)));
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseHexToFloat(intValHex)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseHexToFloat(intValHex, false)));
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBigEndianHexToFloat(intValHex)));
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseLittleEndianHexToFloat(floatValHexRev)));
}
@Test
public void arseBytesToFloat() {
byte[] floatValByte = {65, -22, 98, -52};
Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0)));
Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false)));
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, false)));
List <Byte> floatVaList = Bytes.asList(floatValByte);
Assert.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0)));
Assert.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false)));
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatVaList, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatVaList, 0, false)));
}
@Test
public void parseLong() {
Assert.assertNull(TbUtils.parseLong(null));
Assert.assertNull(TbUtils.parseLong(""));
Assert.assertNull(TbUtils.parseLong(" "));
Assertions.assertNull(TbUtils.parseLong(null));
Assertions.assertNull(TbUtils.parseLong(""));
Assertions.assertNull(TbUtils.parseLong(" "));
Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("0"));
Assert.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("-0"));
Assert.assertEquals(java.util.Optional.of(473L).get(), TbUtils.parseLong("473"));
Assert.assertEquals(java.util.Optional.of(-65535L).get(), TbUtils.parseLong("-0xFFFF"));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FFFFFFFF"));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("0xFGFFFFFF"));
Assertions.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("0"));
Assertions.assertEquals(java.util.Optional.of(0L).get(), TbUtils.parseLong("-0"));
Assertions.assertEquals(java.util.Optional.of(473L).get(), TbUtils.parseLong("473"));
Assertions.assertEquals(java.util.Optional.of(-65535L).get(), TbUtils.parseLong("-0xFFFF"));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FFFFFFFF"));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("0xFGFFFFFF"));
Assert.assertEquals(java.util.Optional.of(13158L).get(), TbUtils.parseLong("11001101100110", 2));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("11001101100210", 2));
Assertions.assertEquals(java.util.Optional.of(13158L).get(), TbUtils.parseLong("11001101100110", 2));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("11001101100210", 2));
Assert.assertEquals(java.util.Optional.of(9223372036854775807L).get(), TbUtils.parseLong("777777777777777777777", 8));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("1787", 8));
Assertions.assertEquals(java.util.Optional.of(9223372036854775807L).get(), TbUtils.parseLong("777777777777777777777", 8));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("1787", 8));
Assert.assertEquals(java.util.Optional.of(-255L).get(), TbUtils.parseLong("-FF", 16));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FG", 16));
Assertions.assertEquals(java.util.Optional.of(-255L).get(), TbUtils.parseLong("-FF", 16));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("FG", 16));
Assert.assertEquals(java.util.Optional.of(Long.MAX_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MAX_VALUE), 10));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10));
Assert.assertEquals(java.util.Optional.of(Long.MIN_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MIN_VALUE), 10));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10));
Assertions.assertEquals(java.util.Optional.of(Long.MAX_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MAX_VALUE), 10));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.valueOf(1)).toString(10), 10));
Assertions.assertEquals(java.util.Optional.of(Long.MIN_VALUE).get(), TbUtils.parseLong(Long.toString(Long.MIN_VALUE), 10));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.valueOf(1)).toString(10), 10));
Assert.assertEquals(java.util.Optional.of(218840926543L).get(), TbUtils.parseLong("KonaLong", 27));
Assert.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("KonaLong", 10));
Assertions.assertEquals(java.util.Optional.of(218840926543L).get(), TbUtils.parseLong("KonaLong", 27));
Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseLong("KonaLong", 10));
}
@Test
public void parseHexToLong() {
Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHex));
Assert.assertEquals(longVal, TbUtils.parseHexToLong(longValHexRev, false));
Assert.assertEquals(longVal, TbUtils.parseBigEndianHexToLong(longValHex));
Assert.assertEquals(longVal, TbUtils.parseLittleEndianHexToLong(longValHexRev));
Assertions.assertEquals(longVal, TbUtils.parseHexToLong(longValHex));
Assertions.assertEquals(longVal, TbUtils.parseHexToLong(longValHexRev, false));
Assertions.assertEquals(longVal, TbUtils.parseBigEndianHexToLong(longValHex));
Assertions.assertEquals(longVal, TbUtils.parseLittleEndianHexToLong(longValHexRev));
}
@Test
public void parseBytesToLong() {
byte[] longValByte = {64, -101, 4, -79, 12, -78, -107, -22};
Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8));
Assertions.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8));
Bytes.reverse(longValByte);
Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8, false));
Assertions.assertEquals(longVal, TbUtils.parseBytesToLong(longValByte, 0, 8, false));
List <Byte> longVaList = Bytes.asList(longValByte);
Assert.assertEquals(longVal, TbUtils.parseBytesToLong(longVaList, 0, 8, false));
Assert.assertEquals(longValRev, TbUtils.parseBytesToLong(longVaList, 0, 8));
Assertions.assertEquals(longVal, TbUtils.parseBytesToLong(longVaList, 0, 8, false));
Assertions.assertEquals(longValRev, TbUtils.parseBytesToLong(longVaList, 0, 8));
}
@Test
public void parsDouble() {
Assert.assertEquals(java.util.Optional.of(doubleVal).get(), TbUtils.parseDouble(doubleValStr));
Assertions.assertEquals(java.util.Optional.of(doubleVal).get(), TbUtils.parseDouble(doubleValStr));
}
@Test
public void toFixedDouble() {
double actualD = TbUtils.toFixed(doubleVal, 3);
Assert.assertEquals(-1, Double.compare(doubleVal, actualD));
Assert.assertEquals(0, Double.compare(1729.173, actualD));
Assertions.assertEquals(-1, Double.compare(doubleVal, actualD));
Assertions.assertEquals(0, Double.compare(1729.173, actualD));
}
@Test
public void parseHexToDouble() {
Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseHexToDouble(longValHex)));
Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseHexToDouble(longValHex, false)));
Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBigEndianHexToDouble(longValHex)));
Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseLittleEndianHexToDouble(longValHexRev)));
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseHexToDouble(longValHex)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseHexToDouble(longValHex, false)));
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBigEndianHexToDouble(longValHex)));
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseLittleEndianHexToDouble(longValHexRev)));
}
@Test
public void parseBytesToDouble() {
byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22};
Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0)));
Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false)));
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, false)));
List <Byte> doubleVaList = Bytes.asList(doubleValByte);
Assert.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0)));
Assert.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false)));
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleVaList, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleVaList, 0, false)));
}
@Test
@ -355,7 +355,7 @@ public class TbUtilsTest {
expectedJson.put("hello", "world");
List<Byte> expectedBytes = TbUtils.stringToBytes(ctx, expectedStr);
Object actualJson = TbUtils.decodeToJson(ctx, expectedBytes);
Assert.assertEquals(expectedJson,actualJson);
Assertions.assertEquals(expectedJson,actualJson);
}
@Test
public void parseStringDecodeToJson() throws IOException {
@ -363,7 +363,7 @@ public class TbUtilsTest {
ExecutionHashMap<String, Object> expectedJson = new ExecutionHashMap<>(1, ctx);
expectedJson.put("hello", "world");
Object actualJson = TbUtils.decodeToJson(ctx, expectedStr);
Assert.assertEquals(expectedJson,actualJson);
Assertions.assertEquals(expectedJson,actualJson);
}
@Test
@ -373,15 +373,15 @@ public class TbUtilsTest {
byte[] arrayBytes = {119, 111, 114, 108, 100};
List<Byte> expectedBytes = Bytes.asList(arrayBytes);
List<Byte> actualBytes = TbUtils.stringToBytes(ctx, ((ExecutionHashMap) inputJson).get("hello"));
Assert.assertEquals(expectedBytes, actualBytes);
Assertions.assertEquals(expectedBytes, actualBytes);
actualBytes = TbUtils.stringToBytes(ctx, ((ExecutionHashMap) inputJson).get("hello"), "UTF-8");
Assert.assertEquals(expectedBytes, actualBytes);
Assertions.assertEquals(expectedBytes, actualBytes);
expectedStr = "{\"hello\": 1234}";
inputJson = TbUtils.decodeToJson(ctx, expectedStr);
Object finalInputJson = inputJson;
Assert.assertThrows(IllegalAccessException.class, () -> TbUtils.stringToBytes(ctx, ((ExecutionHashMap) finalInputJson).get("hello")));
Assert.assertThrows(IllegalAccessException.class, () -> TbUtils.stringToBytes(ctx, ((ExecutionHashMap) finalInputJson).get("hello"), "UTF-8"));
Assertions.assertThrows(IllegalAccessException.class, () -> TbUtils.stringToBytes(ctx, ((ExecutionHashMap) finalInputJson).get("hello")));
Assertions.assertThrows(IllegalAccessException.class, () -> TbUtils.stringToBytes(ctx, ((ExecutionHashMap) finalInputJson).get("hello"), "UTF-8"));
}
@Test
@ -394,13 +394,13 @@ public class TbUtilsTest {
for (Byte element : arrayBytes) {
listBytes.add(element);
}
Assert.assertEquals(expected, TbUtils.bytesToString(listBytes));
Assertions.assertEquals(expected, TbUtils.bytesToString(listBytes));
ArrayList<Object> listMix = new ArrayList<>(arrayMix.length);
for (Object element : arrayMix) {
listMix.add(element);
}
Assert.assertEquals(expected, TbUtils.bytesToString(listMix));
Assertions.assertEquals(expected, TbUtils.bytesToString(listMix));
}
@Test
@ -409,34 +409,34 @@ public class TbUtilsTest {
listHex.add("0xFG");
try {
TbUtils.bytesToString(listHex);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("Failed radix: [16] for value: \"FG\"!"));
Assertions.assertTrue(e.getMessage().contains("Failed radix: [16] for value: \"FG\"!"));
}
listHex.add(0, "1F");
try {
TbUtils.bytesToString(listHex);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("Failed radix: [10] for value: \"1F\"!"));
Assertions.assertTrue(e.getMessage().contains("Failed radix: [10] for value: \"1F\"!"));
}
List<String> listIntString = new ArrayList<>();
listIntString.add("-129");
try {
TbUtils.bytesToString(listIntString);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("The value '-129' could not be correctly converted to a byte. " +
Assertions.assertTrue(e.getMessage().contains("The value '-129' could not be correctly converted to a byte. " +
"Integer to byte conversion requires the use of only 8 bits (with a range of min/max = -128/255)!"));
}
listIntString.add(0, "256");
try {
TbUtils.bytesToString(listIntString);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("The value '256' could not be correctly converted to a byte. " +
Assertions.assertTrue(e.getMessage().contains("The value '256' could not be correctly converted to a byte. " +
"Integer to byte conversion requires the use of only 8 bits (with a range of min/max = -128/255)!"));
}
@ -444,18 +444,18 @@ public class TbUtilsTest {
listIntBytes.add(-129);
try {
TbUtils.bytesToString(listIntBytes);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("The value '-129' could not be correctly converted to a byte. " +
Assertions.assertTrue(e.getMessage().contains("The value '-129' could not be correctly converted to a byte. " +
"Integer to byte conversion requires the use of only 8 bits (with a range of min/max = -128/255)!"));
}
listIntBytes.add(0, 256);
try {
TbUtils.bytesToString(listIntBytes);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("The value '256' could not be correctly converted to a byte. " +
Assertions.assertTrue(e.getMessage().contains("The value '256' could not be correctly converted to a byte. " +
"Integer to byte conversion requires the use of only 8 bits (with a range of min/max = -128/255)!"));
}
@ -465,9 +465,9 @@ public class TbUtilsTest {
listObjects.add(listStringObjects);
try {
TbUtils.bytesToString(listObjects);
Assert.fail("Should throw NumberFormatException");
Assertions.fail("Should throw NumberFormatException");
} catch (NumberFormatException e) {
Assert.assertTrue(e.getMessage().contains("The value '[0xFD]' could not be correctly converted to a byte. " +
Assertions.assertTrue(e.getMessage().contains("The value '[0xFD]' could not be correctly converted to a byte. " +
"Must be a HexDecimal/String/Integer/Byte format !"));
}
}
@ -477,10 +477,10 @@ public class TbUtilsTest {
String uriOriginal = "-_.!~*'();/?:@&=+$,#ht://example.ж д a/path with spaces/?param1=Київ 1&param2=Україна2";
String uriEncodeExpected = "-_.!~*'();/?:@&=+$,#ht://example.%D0%B6%20%D0%B4%20a/path%20with%20spaces/?param1=%D0%9A%D0%B8%D1%97%D0%B2%201&param2=%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D0%B02";
String uriEncodeActual = TbUtils.encodeURI(uriOriginal);
Assert.assertEquals(uriEncodeExpected, uriEncodeActual);
Assertions.assertEquals(uriEncodeExpected, uriEncodeActual);
String uriDecodeActual = TbUtils.decodeURI(uriEncodeActual);
Assert.assertEquals(uriOriginal, uriDecodeActual);
Assertions.assertEquals(uriOriginal, uriDecodeActual);
}
private static List<Byte> toList(byte[] data) {
List<Byte> result = new ArrayList<>(data.length);

3
common/script/script-api/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/script/script-api/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/stats/pom.xml

@ -76,11 +76,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

5
common/transport/coap/pom.xml

@ -81,11 +81,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

3
common/transport/coap/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/transport/coap/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/transport/http/pom.xml

@ -66,11 +66,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

3
common/transport/http/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

5
common/transport/lwm2m/pom.xml

@ -89,11 +89,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

2
common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientTest.java

@ -19,7 +19,7 @@ import org.eclipse.leshan.core.endpoint.EndpointUriUtil;
import org.eclipse.leshan.core.link.Link;
import org.eclipse.leshan.core.peer.IpPeer;
import org.eclipse.leshan.server.registration.Registration;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import java.net.InetSocketAddress;

9
common/transport/lwm2m/src/test/java/org/thingsboard/server/transport/lwm2m/server/store/util/LwM2MClientSerDesTest.java

@ -25,8 +25,7 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.peer.IpPeer;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.server.registration.Registration;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.id.CustomerId;
@ -54,8 +53,8 @@ import java.util.Map.Entry;
import java.util.Optional;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
@ -119,7 +118,7 @@ public class LwM2MClientSerDesTest {
client.saveResourceValue("/17_1.0/0/0", multipleResource, provider, WriteRequest.Mode.UPDATE);
byte[] bytes = LwM2MClientSerDes.serialize(client);
Assert.assertNotNull(bytes);
assertNotNull(bytes);
LwM2mClient desClient = LwM2MClientSerDes.deserialize(bytes);

3
common/transport/lwm2m/src/test/resources/junit-platform.properties

@ -0,0 +1,3 @@
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent

14
common/transport/lwm2m/src/test/resources/logback-test.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
</root>
</configuration>

5
common/transport/mqtt/pom.xml

@ -87,11 +87,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>

24
common/transport/mqtt/src/test/java/org/thingsboard/server/transport/mqtt/MqttTransportHandlerTest.java

@ -28,13 +28,14 @@ import io.netty.handler.codec.mqtt.MqttPublishVariableHeader;
import io.netty.handler.codec.mqtt.MqttQoS;
import io.netty.handler.ssl.SslHandler;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
@ -58,16 +59,17 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.assertj.core.api.Assertions.fail;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.willDoNothing;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@ -75,7 +77,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Slf4j
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class MqttTransportHandlerTest {
public static final int MSG_QUEUE_LIMIT = 10;
@ -96,17 +98,17 @@ public class MqttTransportHandlerTest {
@Spy
TransportService transportService;
@Before
@BeforeEach
public void setUp() throws Exception {
willReturn(MSG_QUEUE_LIMIT).given(context).getMessageQueueSizePerDeviceLimit();
willReturn(transportService).given(context).getTransportService();
lenient().doReturn(MSG_QUEUE_LIMIT).when(context).getMessageQueueSizePerDeviceLimit();
lenient().doReturn(transportService).when(context).getTransportService();
handler = spy(new MqttTransportHandler(context, sslHandler));
willReturn(IP_ADDR).given(handler).getAddress(any());
lenient().doReturn(IP_ADDR).when(handler).getAddress(any());
}
@After
@AfterEach
public void tearDown() {
if (executor != null) {
executor.shutdownNow();

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save