Browse Source

Merge remote-tracking branch 'upstream/develop/3.5' into feature-alarm-assigning

pull/8090/head
zbeacon 4 years ago
parent
commit
5710f01c03
  1. 88
      .github/release.yml
  2. 6
      application/pom.xml
  3. 3
      application/src/main/data/upgrade/3.4.1/schema_update.sql
  4. 9
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  5. 47
      application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
  6. 9
      application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
  7. 5
      application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
  8. 9
      application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
  9. 4
      application/src/main/java/org/thingsboard/server/service/install/update/DefaultCacheCleanupService.java
  10. 10
      application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java
  11. 5
      application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java
  12. 6
      application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java
  13. 6
      application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java
  14. 12
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
  15. 116
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  16. 22
      application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java
  17. 12
      application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java
  18. 38
      application/src/test/java/org/thingsboard/server/controller/BaseWebsocketApiTest.java
  19. 19
      application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java
  20. 4
      application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java
  21. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestCallback.java
  22. 14
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestClient.java
  23. 7
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java
  24. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java
  25. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestIntegrationTest.java
  26. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestJsonIntegrationTest.java
  27. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestProtoIntegrationTest.java
  28. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java
  29. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesIntegrationTest.java
  30. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java
  31. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java
  32. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimBackwardCompatibilityDeviceTest.java
  33. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimDeviceTest.java
  34. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimJsonDeviceTest.java
  35. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimProtoDeviceTest.java
  36. 50
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/AbstractMqttClientConnectionTest.java
  37. 48
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/MqttClientConnectionTest.java
  38. 16
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/credentials/BasicMqttCredentialsTest.java
  39. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java
  40. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java
  41. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java
  42. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java
  43. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcDefaultIntegrationTest.java
  44. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcJsonIntegrationTest.java
  45. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcProtoIntegrationTest.java
  46. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesIntegrationTest.java
  47. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesJsonIntegrationTest.java
  48. 2
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesProtoIntegrationTest.java
  49. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java
  50. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java
  51. 6
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java
  52. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java
  53. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java
  54. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java
  55. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java
  56. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java
  57. 4
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java
  58. 21
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/AbstractMqttV5Test.java
  59. 110
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestCallback.java
  60. 175
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestClient.java
  61. 161
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java
  62. 43
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/updates/AttributesUpdatesTest.java
  63. 38
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/upload/AttributesPublishTest.java
  64. 101
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/AbstractMqttV5ClaimTest.java
  65. 39
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/MqttV5ClaimTest.java
  66. 111
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java
  67. 60
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/MqttV5ClientConnectionTest.java
  68. 77
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/AbstractMqttV5ClientPublishTest.java
  69. 49
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/MqttV5ClientPublishTest.java
  70. 63
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java
  71. 44
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/MqttV5ClientSubscriptionTest.java
  72. 60
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java
  73. 44
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/MqttV5ClientUnsubscribeTest.java
  74. 94
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/provision/MqttV5ProvisionDeviceTest.java
  75. 98
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java
  76. 43
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/MqttV5RpcTest.java
  77. 132
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/AbstractMqttV5TimeseriesTest.java
  78. 39
      application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/MqttV5TimeseriesTest.java
  79. 2
      common/actor/pom.xml
  80. 2
      common/cache/pom.xml
  81. 2
      common/cluster-api/pom.xml
  82. 2
      common/coap-server/pom.xml
  83. 6
      common/dao-api/pom.xml
  84. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
  85. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java
  86. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java
  87. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java
  88. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java
  89. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java
  90. 4
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java
  91. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java
  92. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java
  93. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java
  94. 43
      common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityServiceBeanFactory.java
  95. 28
      common/dao-api/src/main/java/org/thingsboard/server/dao/entity/TbEntityService.java
  96. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java
  97. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java
  98. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java
  99. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java
  100. 3
      common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java

88
.github/release.yml

@ -0,0 +1,88 @@
#
# Copyright © 2016-2022 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
changelog:
exclude:
labels:
- Ignore for release
categories:
- title: 'Major Core & Rule Engine'
labels:
- 'Major Core'
- 'Major Rule Engine'
exclude:
labels:
- 'Bug'
- title: 'Major UI'
labels:
- 'Major UI'
exclude:
labels:
- 'Bug'
- title: 'Major Transport'
labels:
- 'Major Transport'
exclude:
labels:
- 'Bug'
- title: 'Major Edge'
labels:
- 'Major Edge'
exclude:
labels:
- 'Bug'
- title: 'Core & Rule Engine'
labels:
- 'Core'
- 'Rule Engine'
exclude:
labels:
- 'Bug'
- title: 'UI'
labels:
- 'UI'
exclude:
labels:
- 'Bug'
- title: 'Transport'
labels:
- 'Transport'
exclude:
labels:
- 'Bug'
- title: 'Edge'
labels:
- 'Edge'
exclude:
labels:
- 'Bug'
- title: 'Bug: Core & Rule Engine'
labels:
- 'Core'
- 'Rule Engine'
- 'Bug'
- title: 'Bug: UI'
labels:
- 'UI'
- 'Bug'
- title: 'Bug: Transport'
labels:
- 'Transport'
- 'Bug'
- title: 'Bug: Edge'
labels:
- 'Edge'
- 'Bug'

6
application/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>thingsboard</artifactId>
</parent>
<artifactId>application</artifactId>
@ -140,6 +140,10 @@
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.mqttv5.client</artifactId>
</dependency>
<dependency>
<groupId>org.cassandraunit</groupId>
<artifactId>cassandra-unit</artifactId>

3
application/src/main/data/upgrade/3.4.1/schema_update.sql

@ -22,6 +22,8 @@ $$
-- in case of running the upgrade script a second time:
IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_audit_log')) THEN
ALTER TABLE audit_log RENAME TO old_audit_log;
CREATE INDEX IF NOT EXISTS idx_old_audit_log_created_time ON old_audit_log(created_time);
ALTER INDEX IF EXISTS idx_audit_log_tenant_id_and_created_time RENAME TO idx_old_audit_log_tenant_id_and_created_time;
FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts
@ -86,6 +88,7 @@ $$
-- in case of running the upgrade script a second time:
IF NOT (SELECT exists(SELECT FROM pg_tables WHERE tablename = 'old_edge_event')) THEN
ALTER TABLE edge_event RENAME TO old_edge_event;
CREATE INDEX IF NOT EXISTS idx_old_blob_entity_created_time_tmp ON old_blob_entity(created_time);
ALTER INDEX IF EXISTS idx_edge_event_tenant_id_and_created_time RENAME TO idx_old_edge_event_tenant_id_and_created_time;
FOR table_partition IN SELECT tablename AS name, split_part(tablename, '_', 3) AS partition_ts

9
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -120,6 +120,7 @@ import org.thingsboard.server.dao.queue.QueueService;
import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.dao.rpc.RpcService;
import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.dao.tenant.TenantService;
@ -131,7 +132,6 @@ import org.thingsboard.server.queue.discovery.PartitionService;
import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.component.ComponentDiscoveryService;
import org.thingsboard.server.service.edge.EdgeNotificationService;
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
import org.thingsboard.server.service.entitiy.TbNotificationEntityService;
import org.thingsboard.server.service.ota.OtaPackageStateService;
@ -417,9 +417,12 @@ public abstract class BaseController {
}
PageLink createPageLink(int pageSize, int page, String textSearch, String sortProperty, String sortOrder) throws ThingsboardException {
if (!StringUtils.isEmpty(sortProperty)) {
if (StringUtils.isNotEmpty(sortProperty)) {
if (!Validator.isValidProperty(sortProperty)) {
throw new IllegalArgumentException("Invalid sort property");
}
SortOrder.Direction direction = SortOrder.Direction.ASC;
if (!StringUtils.isEmpty(sortOrder)) {
if (StringUtils.isNotEmpty(sortOrder)) {
try {
direction = SortOrder.Direction.valueOf(sortOrder.toUpperCase());
} catch (IllegalArgumentException e) {

47
application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java

@ -28,10 +28,12 @@ import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.adapter.NativeWebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.msg.tools.TbRateLimits;
import org.thingsboard.server.config.WebSocketConfiguration;
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
@ -50,6 +52,7 @@ import javax.websocket.Session;
import java.io.IOException;
import java.net.URI;
import java.security.InvalidParameterException;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
@ -136,8 +139,9 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
if (!checkLimits(session, sessionRef)) {
return;
}
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef, tenantProfileConfiguration.getWsMsgQueueLimitPerSession() > 0 ?
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
internalSessionMap.put(internalSessionId, new SessionMetaData(session, sessionRef,
tenantProfileConfiguration != null && tenantProfileConfiguration.getWsMsgQueueLimitPerSession() > 0 ?
tenantProfileConfiguration.getWsMsgQueueLimitPerSession() : 500));
externalSessionMap.put(externalSessionId, internalSessionId);
@ -316,22 +320,24 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
if (internalId != null) {
SessionMetaData sessionMd = internalSessionMap.get(internalId);
if (sessionMd != null) {
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
if (StringUtils.isNotEmpty(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit())) {
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit()));
if (!rateLimits.tryConsume()) {
if (blacklistedSessions.putIfAbsent(externalId, sessionRef) == null) {
log.info("[{}][{}][{}] Failed to process session update. Max session updates limit reached"
, sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
sessionMd.sendMsg("{\"subscriptionId\":" + subscriptionId + ", \"errorCode\":" + ThingsboardErrorCode.TOO_MANY_UPDATES.getErrorCode() + ", \"errorMsg\":\"Too many updates!\"}");
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
if (tenantProfileConfiguration != null) {
if (StringUtils.isNotEmpty(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit())) {
TbRateLimits rateLimits = perSessionUpdateLimits.computeIfAbsent(sessionRef.getSessionId(), sid -> new TbRateLimits(tenantProfileConfiguration.getWsUpdatesPerSessionRateLimit()));
if (!rateLimits.tryConsume()) {
if (blacklistedSessions.putIfAbsent(externalId, sessionRef) == null) {
log.info("[{}][{}][{}] Failed to process session update. Max session updates limit reached"
, sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
sessionMd.sendMsg("{\"subscriptionId\":" + subscriptionId + ", \"errorCode\":" + ThingsboardErrorCode.TOO_MANY_UPDATES.getErrorCode() + ", \"errorMsg\":\"Too many updates!\"}");
}
return;
} else {
log.debug("[{}][{}][{}] Session is no longer blacklisted.", sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
blacklistedSessions.remove(externalId);
}
return;
} else {
log.debug("[{}][{}][{}] Session is no longer blacklisted.", sessionRef.getSecurityCtx().getTenantId(), sessionRef.getSecurityCtx().getId(), externalId);
blacklistedSessions.remove(externalId);
perSessionUpdateLimits.remove(sessionRef.getSessionId());
}
} else {
perSessionUpdateLimits.remove(sessionRef.getSessionId());
}
sessionMd.sendMsg(msg);
} else {
@ -376,8 +382,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
private boolean checkLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) throws Exception {
var tenantProfileConfiguration =
tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
if (tenantProfileConfiguration == null) {
return true;
}
@ -444,7 +449,8 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
private void cleanupLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) {
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
if (tenantProfileConfiguration == null) return;
String sessionId = session.getId();
perSessionUpdateLimits.remove(sessionRef.getSessionId());
@ -477,4 +483,9 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
}
private DefaultTenantProfileConfiguration getTenantProfileConfiguration(TelemetryWebSocketSessionRef sessionRef) {
return Optional.ofNullable(tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()))
.map(TenantProfile::getDefaultProfileConfiguration).orElse(null);
}
}

9
application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java

@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfilePr
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.lwm2m.OtherConfiguration;
import org.thingsboard.server.common.data.device.profile.lwm2m.TelemetryMappingConfiguration;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
@ -104,7 +105,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
protected Device saveEntity(SecurityUser user, Device entity, Map<BulkImportColumnType, String> fields) {
DeviceCredentials deviceCredentials;
try {
deviceCredentials = createDeviceCredentials(fields);
deviceCredentials = createDeviceCredentials(entity.getTenantId(), entity.getId(), fields);
deviceCredentialsService.formatCredentials(deviceCredentials);
} catch (Exception e) {
throw new DeviceCredentialsValidationException("Invalid device credentials: " + e.getMessage());
@ -136,7 +137,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
}
@SneakyThrows
private DeviceCredentials createDeviceCredentials(Map<BulkImportColumnType, String> fields) {
private DeviceCredentials createDeviceCredentials(TenantId tenantId, DeviceId deviceId, Map<BulkImportColumnType, String> fields) {
DeviceCredentials credentials = new DeviceCredentials();
if (fields.containsKey(BulkImportColumnType.LWM2M_CLIENT_ENDPOINT)) {
credentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS);
@ -147,7 +148,9 @@ public class DeviceBulkImportService extends AbstractBulkImportService<Device> {
} else if (CollectionUtils.containsAny(fields.keySet(), EnumSet.of(BulkImportColumnType.MQTT_CLIENT_ID, BulkImportColumnType.MQTT_USER_NAME, BulkImportColumnType.MQTT_PASSWORD))) {
credentials.setCredentialsType(DeviceCredentialsType.MQTT_BASIC);
setUpBasicMqttCredentials(fields, credentials);
} else {
} else if (deviceId != null && !fields.containsKey(BulkImportColumnType.ACCESS_TOKEN)) {
credentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId);
} else {
credentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
setUpAccessTokenCredentials(fields, credentials);
}

5
application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java

@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
import org.thingsboard.server.service.profile.TbAssetProfileCache;
@ -63,6 +64,8 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
autoCommit(user, savedAsset.getId());
notificationEntityService.notifyCreateOrUpdateEntity(tenantId, savedAsset.getId(), savedAsset,
asset.getCustomerId(), actionType, user);
tbClusterService.broadcastEntityStateChangeEvent(tenantId, savedAsset.getId(),
asset.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
return savedAsset;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), asset, actionType, user, e);
@ -79,7 +82,7 @@ public class DefaultTbAssetService extends AbstractTbEntityService implements Tb
assetService.deleteAsset(tenantId, assetId);
notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(),
ActionType.DELETED, relatedEdgeIds, user, assetId.toString());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, assetId, ComponentLifecycleEvent.DELETED);
return removeAlarmsByEntityId(tenantId, assetId);
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.ASSET), ActionType.DELETED, user, e,

9
application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java

@ -76,17 +76,18 @@ public class DefaultTbDeviceService extends AbstractTbEntityService implements T
@Override
public Device saveDeviceWithCredentials(Device device, DeviceCredentials credentials, User user) throws ThingsboardException {
ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
boolean isCreate = device.getId() == null;
ActionType actionType = isCreate ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = device.getTenantId();
try {
Device oldDevice = isCreate ? null : deviceService.findDeviceById(tenantId, device.getId());
Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials));
notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
savedDevice, device, actionType, user);
savedDevice, oldDevice, actionType, user);
return savedDevice;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device,
actionType, user, e);
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.DEVICE), device, actionType, user, e);
throw e;
}
}

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

@ -78,6 +78,10 @@ public class DefaultCacheCleanupService implements CacheCleanupService {
clearCacheByName("assets");
clearCacheByName("repositorySettings");
break;
case "3.4.2":
log.info("Clearing cache to upgrade from version 3.4.2 to 3.4.3 ...");
clearCacheByName("repositorySettings");
break;
default:
//Do nothing, since cache cleanup is optional.
}

10
application/src/main/java/org/thingsboard/server/service/subscription/DefaultTbEntityDataSubscriptionService.java

@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -562,8 +563,13 @@ public class DefaultTbEntityDataSubscriptionService implements TbEntityDataSubsc
if (queryResults != null) {
for (ReadTsKvQueryResult queryResult : queryResults) {
String queryKey = queriesKeys.get(queryResult.getQueryId());
entityData.getTimeseries().put(queryKey, queryResult.toTsValues());
lastTsMap.put(queryKey, queryResult.getLastEntryTs());
if (queryKey != null) {
entityData.getTimeseries().merge(queryKey, queryResult.toTsValues(), ArrayUtils::addAll);
lastTsMap.merge(queryKey, queryResult.getLastEntryTs(), Math::max);
} else {
log.warn("ReadTsKvQueryResult for {} {} has queryId not matching the initial query",
entityData.getEntityId().getEntityType(), entityData.getEntityId());
}
}
}
// Populate with empty values if no data found.

5
application/src/main/java/org/thingsboard/server/service/subscription/TbAbstractDataSubCtx.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.subscription;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AbstractDataQuery;
import org.thingsboard.server.common.data.query.EntityData;
@ -197,6 +198,9 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
entityData.getTimeseries().forEach((k, v) -> {
long ts = Arrays.stream(v).map(TsValue::getTs).max(Long::compareTo).orElse(0L);
log.trace("[{}][{}] Updating key: {} with ts: {}", serviceId, cmdId, k, ts);
if (!Aggregation.NONE.equals(getCurrentAggregation()) && ts < endTs) {
ts = endTs;
}
keyStates.put(k, ts);
});
}
@ -247,4 +251,5 @@ public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery<? extends
abstract void sendWsMsg(String sessionId, TelemetrySubscriptionUpdate subscriptionUpdate, EntityKeyType keyType, boolean resultToLatestValues);
protected abstract Aggregation getCurrentAggregation();
}

6
application/src/main/java/org/thingsboard/server/service/subscription/TbAlarmDataSubCtx.java

@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataPageLink;
@ -204,6 +205,11 @@ public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx<AlarmDataQuery> {
}
}
@Override
protected Aggregation getCurrentAggregation() {
return Aggregation.NONE;
}
private void sendWsMsg(String sessionId, AlarmSubscriptionUpdate subscriptionUpdate) {
AlarmInfo alarmInfo = subscriptionUpdate.getAlarmInfo();
AlarmId alarmId = alarmInfo.getId();

6
application/src/main/java/org/thingsboard/server/service/subscription/TbEntityDataSubCtx.java

@ -19,6 +19,7 @@ import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.EntityData;
import org.thingsboard.server.common.data.query.EntityDataQuery;
@ -86,6 +87,11 @@ public class TbEntityDataSubCtx extends TbAbstractDataSubCtx<EntityDataQuery> {
}
}
@Override
protected Aggregation getCurrentAggregation() {
return (this.curTsCmd == null || this.curTsCmd.getAgg() == null) ? Aggregation.NONE : this.curTsCmd.getAgg();
}
private void sendLatestWsMsg(EntityId entityId, String sessionId, TelemetrySubscriptionUpdate subscriptionUpdate, EntityKeyType keyType) {
Map<String, TsValue> latestUpdate = new HashMap<>();
subscriptionUpdate.getData().forEach((k, v) -> {

12
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java

@ -31,6 +31,7 @@ import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -316,7 +317,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
}
private void processSessionClose(TelemetryWebSocketSessionRef sessionRef) {
var tenantProfileConfiguration = tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
if (tenantProfileConfiguration != null) {
String sessionId = "[" + sessionRef.getSessionId() + "]";
@ -350,7 +351,8 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
}
private boolean processSubscription(TelemetryWebSocketSessionRef sessionRef, SubscriptionCmd cmd) {
var tenantProfileConfiguration = (DefaultTenantProfileConfiguration) tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()).getDefaultProfileConfiguration();
var tenantProfileConfiguration = getTenantProfileConfiguration(sessionRef);
if (tenantProfileConfiguration == null) return true;
String subId = "[" + sessionRef.getSessionId() + "]:[" + cmd.getCmdId() + "]";
try {
@ -932,4 +934,10 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
private int getLimit(int limit) {
return limit == 0 ? DEFAULT_LIMIT : limit;
}
private DefaultTenantProfileConfiguration getTenantProfileConfiguration(TelemetryWebSocketSessionRef sessionRef) {
return Optional.ofNullable(tenantProfileCache.get(sessionRef.getSecurityCtx().getTenantId()))
.map(TenantProfile::getDefaultProfileConfiguration).orElse(null);
}
}

116
application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java

@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.OtaPackageInfo;
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
import org.thingsboard.server.common.data.SaveOtaPackageInfoRequest;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
@ -55,6 +56,9 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.dao.device.DeviceDao;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
@ -180,6 +184,58 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
}
@Test
public void testSaveDeviceWithCredentials() throws Exception {
String testToken = "TEST_TOKEN";
Device device = new Device();
device.setName("My device");
device.setType("default");
DeviceCredentials deviceCredentials = new DeviceCredentials();
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId(testToken);
SaveDeviceWithCredentialsRequest saveRequest = new SaveDeviceWithCredentialsRequest(device, deviceCredentials);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device savedDevice = readResponse(doPost("/api/device-with-credentials", saveRequest).andExpect(status().isOk()), Device.class);
Device oldDevice = new Device(savedDevice);
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
testNotificationUpdateGatewayNever();
Assert.assertNotNull(savedDevice);
Assert.assertNotNull(savedDevice.getId());
Assert.assertTrue(savedDevice.getCreatedTime() > 0);
Assert.assertEquals(savedTenant.getId(), savedDevice.getTenantId());
Assert.assertNotNull(savedDevice.getCustomerId());
Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId());
Assert.assertEquals(device.getName(), savedDevice.getName());
DeviceCredentials foundDeviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertNotNull(foundDeviceCredentials);
Assert.assertNotNull(foundDeviceCredentials.getId());
Assert.assertEquals(savedDevice.getId(), foundDeviceCredentials.getDeviceId());
Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, foundDeviceCredentials.getCredentialsType());
Assert.assertEquals(testToken, foundDeviceCredentials.getCredentialsId());
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
savedDevice.setName("My new device");
doPost("/api/device", savedDevice, Device.class);
testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
testNotificationUpdateGatewayOneTime(savedDevice, oldDevice);
}
@Test
public void saveDeviceWithViolationOfValidation() throws Exception {
Device device = new Device();
@ -1235,6 +1291,66 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
testEntityDaoWithRelationsTransactionalException(deviceDao, savedTenant.getId(), deviceId, "/api/device/" + deviceId);
}
@Test
public void testBulkImportDeviceWithoutCredentials() throws Exception {
String deviceName = "some_device";
String deviceType = "some_type";
BulkImportRequest request = new BulkImportRequest();
request.setFile(String.format("NAME,TYPE\n%s,%s", deviceName, deviceType));
BulkImportRequest.Mapping mapping = new BulkImportRequest.Mapping();
BulkImportRequest.ColumnMapping name = new BulkImportRequest.ColumnMapping();
name.setType(BulkImportColumnType.NAME);
BulkImportRequest.ColumnMapping type = new BulkImportRequest.ColumnMapping();
type.setType(BulkImportColumnType.TYPE);
List<BulkImportRequest.ColumnMapping> columns = new ArrayList<>();
columns.add(name);
columns.add(type);
mapping.setColumns(columns);
mapping.setDelimiter(',');
mapping.setUpdate(true);
mapping.setHeader(true);
request.setMapping(mapping);
BulkImportResult<Device> deviceBulkImportResult = doPostWithTypedResponse("/api/device/bulk_import", request, new TypeReference<>() {});
Assert.assertEquals(1, deviceBulkImportResult.getCreated().get());
Assert.assertEquals(0, deviceBulkImportResult.getErrors().get());
Assert.assertEquals(0, deviceBulkImportResult.getUpdated().get());
Assert.assertTrue(deviceBulkImportResult.getErrorsList().isEmpty());
Device savedDevice = doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class);
Assert.assertNotNull(savedDevice);
Assert.assertEquals(deviceName, savedDevice.getName());
Assert.assertEquals(deviceType, savedDevice.getType());
DeviceCredentials savedCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertNotNull(savedCredentials);
Assert.assertNotNull(savedCredentials.getId());
Assert.assertEquals(savedDevice.getId(), savedCredentials.getDeviceId());
Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, savedCredentials.getCredentialsType());
Assert.assertNotNull(savedCredentials.getCredentialsId());
Assert.assertEquals(20, savedCredentials.getCredentialsId().length());
deviceBulkImportResult = doPostWithTypedResponse("/api/device/bulk_import", request, new TypeReference<>() {});
Assert.assertEquals(0, deviceBulkImportResult.getCreated().get());
Assert.assertEquals(0, deviceBulkImportResult.getErrors().get());
Assert.assertEquals(1, deviceBulkImportResult.getUpdated().get());
Assert.assertTrue(deviceBulkImportResult.getErrorsList().isEmpty());
Device updatedDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedDevice, updatedDevice);
DeviceCredentials updatedCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedCredentials, updatedCredentials);
}
private Device createDevice(String name) {
Device device = new Device();
device.setName(name);

22
application/src/test/java/org/thingsboard/server/controller/BaseEntityQueryControllerTest.java

@ -22,6 +22,7 @@ import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
@ -55,6 +56,7 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseEntityQueryControllerTest extends AbstractControllerTest {
@ -381,4 +383,24 @@ public abstract class BaseEntityQueryControllerTest extends AbstractControllerTe
Assert.assertEquals("1" + i, alarmActiveTime);
}
}
@Test
public void givenInvalidEntityDataPageLink_thenReturnError() throws Exception {
DeviceTypeFilter filter = new DeviceTypeFilter();
filter.setDeviceType("default");
filter.setDeviceNameFilter("");
String invalidSortProperty = "created(Time)";
EntityDataSortOrder sortOrder = new EntityDataSortOrder(
new EntityKey(EntityKeyType.ENTITY_FIELD, invalidSortProperty), EntityDataSortOrder.Direction.ASC
);
EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder);
List<EntityKey> entityFields = Collections.singletonList(new EntityKey(EntityKeyType.ENTITY_FIELD, "name"));
List<EntityKey> latestValues = Collections.singletonList(new EntityKey(EntityKeyType.ATTRIBUTE, "temperature"));
EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, latestValues, null);
ResultActions result = doPost("/api/entitiesQuery/find", query).andExpect(status().isBadRequest());
assertThat(getErrorMessage(result)).contains("Invalid").contains("sort property");
}
}

12
application/src/test/java/org/thingsboard/server/controller/BaseUserControllerTest.java

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpHeaders;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
@ -729,6 +730,17 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
testEntityDaoWithRelationsTransactionalException(userDao, tenantId, userId, "/api/user/" + userId);
}
@Test
public void givenInvalidPageLink_thenReturnError() throws Exception {
loginTenantAdmin();
String invalidSortProperty = "abc(abc)";
ResultActions result = doGet("/api/users?page={page}&pageSize={pageSize}&sortProperty={sortProperty}", 0, 100, invalidSortProperty)
.andExpect(status().isBadRequest());
assertThat(getErrorMessage(result)).containsIgnoringCase("invalid sort property");
}
private User createUser() throws Exception {
loginSysAdmin();
String email = "tenant2@thingsboard.org";

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.FutureCallback;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
@ -23,11 +24,15 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.LongDataEntry;
import org.thingsboard.server.common.data.kv.StringDataEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.DeviceTypeFilter;
@ -41,12 +46,14 @@ import org.thingsboard.server.common.data.query.EntityKeyValueType;
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.SingleEntityFilter;
import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode;
import java.util.Arrays;
import java.util.Collections;
@ -54,6 +61,8 @@ import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatNoException;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j
@ -78,6 +87,7 @@ public abstract class BaseWebsocketApiTest extends AbstractControllerTest {
@After
public void tearDown() throws Exception {
loginTenantAdmin();
doDelete("/api/device/" + device.getId().getId())
.andExpect(status().isOk());
}
@ -532,6 +542,28 @@ public abstract class BaseWebsocketApiTest extends AbstractControllerTest {
Assert.assertEquals(new TsValue(dataPoint5.getLastUpdateTs(), dataPoint5.getValueAsString()), attrValue);
}
@Test
public void testAttributesSubscription_sysAdmin() throws Exception {
loginSysAdmin();
SingleEntityFilter entityFilter = new SingleEntityFilter();
entityFilter.setSingleEntity(tenantId);
assertThatNoException().isThrownBy(() -> {
JsonNode update = getWsClient().subscribeForAttributes(tenantId, TbAttributeSubscriptionScope.SERVER_SCOPE.name(), List.of("attr"));
assertThat(update.get("errorMsg").isNull()).isTrue();
assertThat(update.get("errorCode").asInt()).isEqualTo(SubscriptionErrorCode.NO_ERROR.getCode());
});
getWsClient().registerWaitForUpdate();
String expectedAttrValue = "42";
sendAttributes(TenantId.SYS_TENANT_ID, tenantId, TbAttributeSubscriptionScope.SERVER_SCOPE, List.of(
new BaseAttributeKvEntry(System.currentTimeMillis(), new StringDataEntry("attr", expectedAttrValue))
));
JsonNode update = JacksonUtil.toJsonNode(getWsClient().waitForUpdate());
assertThat(update).isNotNull();
assertThat(update.get("data").get("attr").get(0).get(1).asText()).isEqualTo(expectedAttrValue);
}
private void sendTelemetry(Device device, List<TsKvEntry> tsData) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
tsService.saveAndNotify(device.getTenantId(), null, device.getId(), tsData, 0, new FutureCallback<Void>() {
@ -549,8 +581,12 @@ public abstract class BaseWebsocketApiTest extends AbstractControllerTest {
}
private void sendAttributes(Device device, TbAttributeSubscriptionScope scope, List<AttributeKvEntry> attrData) throws InterruptedException {
sendAttributes(device.getTenantId(), device.getId(), scope, attrData);
}
private void sendAttributes(TenantId tenantId, EntityId entityId, TbAttributeSubscriptionScope scope, List<AttributeKvEntry> attrData) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
tsService.saveAndNotify(device.getTenantId(), device.getId(), scope.name(), attrData, new FutureCallback<Void>() {
tsService.saveAndNotify(tenantId, entityId, scope.name(), attrData, new FutureCallback<Void>() {
@Override
public void onSuccess(@Nullable Void result) {
latch.countDown();

19
application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java

@ -15,16 +15,20 @@
*/
package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.query.EntityDataPageLink;
import org.thingsboard.server.common.data.query.EntityDataQuery;
import org.thingsboard.server.common.data.query.EntityFilter;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper;
import org.thingsboard.server.service.telemetry.cmd.v1.AttributesSubscriptionCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd;
@ -177,6 +181,21 @@ public class TbTestWebSocketClient extends WebSocketClient {
return parseDataReply(waitForReply());
}
public JsonNode subscribeForAttributes(EntityId entityId, String scope, List<String> keys) {
AttributesSubscriptionCmd cmd = new AttributesSubscriptionCmd();
cmd.setCmdId(1);
cmd.setEntityType(entityId.getEntityType().toString());
cmd.setEntityId(entityId.getId().toString());
cmd.setScope(scope);
cmd.setKeys(String.join(",", keys));
TelemetryPluginCmdsWrapper cmdsWrapper = new TelemetryPluginCmdsWrapper();
cmdsWrapper.setAttrSubCmds(List.of(cmd));
JsonNode msg = JacksonUtil.valueToTree(cmdsWrapper);
((ObjectNode) msg.get("attrSubCmds").get(0)).remove("type");
send(msg.toString());
return JacksonUtil.toJsonNode(waitForReply());
}
public EntityDataUpdate sendHistoryCmd(List<String> keys, long startTs, long timeWindow) {
return sendHistoryCmd(keys, startTs, timeWindow, (EntityDataQuery) null);
}

4
application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java

@ -57,8 +57,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.edge.v1.UplinkMsg;
import org.thingsboard.server.gen.edge.v1.UplinkResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import java.util.List;
import java.util.Map;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestCallback.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestCallback.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt;
package org.thingsboard.server.transport.mqtt.mqttv3;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

14
application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestClient.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestClient.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt;
package org.thingsboard.server.transport.mqtt.mqttv3;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
@ -104,6 +104,10 @@ public class MqttTestClient {
return client.subscribe(topic, qoS.value());
}
public boolean isConnected() {
return client.isConnected();
}
public void enableManualAcks() {
client.setManualAcks(true);
}
@ -112,6 +116,10 @@ public class MqttTestClient {
client.messageArrivedComplete(mqttMessage.getId(), mqttMessage.getQos());
}
private MqttAsyncClient createClient() throws MqttException {
return createClient(null);
}
private MqttAsyncClient createClient(String clientId) throws MqttException {
if (StringUtils.isEmpty(clientId)) {
clientId = MqttAsyncClient.generateClientId();
@ -119,8 +127,4 @@ public class MqttTestClient {
return new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence());
}
private MqttAsyncClient createClient() throws MqttException {
return createClient(null);
}
}

7
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes;
import com.github.os72.protobuf.dynamic.DynamicSchema;
import com.google.protobuf.Descriptors;
@ -22,7 +22,6 @@ import com.google.protobuf.InvalidProtocolBufferException;
import com.squareup.wire.schema.internal.parser.ProtoFileElement;
import io.netty.handler.codec.mqtt.MqttQoS;
import lombok.extern.slf4j.Slf4j;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DynamicProtoUtils;
@ -41,8 +40,8 @@ import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import java.util.ArrayList;
import java.util.List;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.request;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import java.util.ArrayList;
import java.util.List;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.request;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -21,7 +21,7 @@ import org.junit.Test;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
@Slf4j
@DaoSqlTest

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestJsonIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.request;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
@Slf4j
@DaoSqlTest

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestProtoIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.request;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import java.util.ArrayList;
import java.util.List;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.updates;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.updates;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -21,7 +21,7 @@ import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.updates;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -21,7 +21,7 @@ import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.attributes.updates;
package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -21,7 +21,7 @@ import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimBackwardCompatibilityDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimBackwardCompatibilityDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.claim;
package org.thingsboard.server.transport.mqtt.mqttv3.claim;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.claim;
package org.thingsboard.server.transport.mqtt.mqttv3.claim;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -28,7 +28,7 @@ import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import static org.junit.Assert.assertEquals;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimJsonDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimJsonDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.claim;
package org.thingsboard.server.transport.mqtt.mqttv3.claim;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimProtoDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimProtoDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.claim;
package org.thingsboard.server.transport.mqtt.mqttv3.claim;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@ -21,7 +21,7 @@ import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@Slf4j

50
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/AbstractMqttClientConnectionTest.java

@ -0,0 +1,50 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv3.client;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.junit.Assert;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
public abstract class AbstractMqttClientConnectionTest extends AbstractMqttIntegrationTest {
protected void processClientWithCorrectAccessTokenTest() throws Exception {
MqttTestClient client = new MqttTestClient();
client.connectAndWait(accessToken);
Assert.assertTrue(client.isConnected());
client.disconnect();
}
protected void processClientWithWrongAccessTokenTest() throws Exception {
MqttTestClient client = new MqttTestClient();
try {
client.connectAndWait("wrongAccessToken");
} catch (MqttException e) {
Assert.assertEquals(MqttException.REASON_CODE_FAILED_AUTHENTICATION, e.getReasonCode());
}
}
protected void processClientWithWrongClientIdAndEmptyUsernamePasswordTest() throws Exception {
MqttTestClient client = new MqttTestClient("unknownClientId");
try {
client.connectAndWait();
} catch (MqttException e) {
Assert.assertEquals(MqttException.REASON_CODE_INVALID_CLIENT_ID, e.getReasonCode());
}
}
}

48
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/MqttClientConnectionTest.java

@ -0,0 +1,48 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv3.client;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttClientConnectionTest extends AbstractMqttClientConnectionTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test MqttV5 client device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testClientWithCorrectAccessToken() throws Exception {
processClientWithCorrectAccessTokenTest();
}
@Test
public void testClientWithWrongAccessToken() throws Exception {
processClientWithWrongAccessTokenTest();
}
@Test
public void testClientWithWrongClientIdAndEmptyUsernamePassword() throws Exception {
processClientWithWrongClientIdAndEmptyUsernamePasswordTest();
}
}

16
application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/credentials/BasicMqttCredentialsTest.java

@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.credentials;
package org.thingsboard.server.transport.mqtt.mqttv3.credentials;
import com.fasterxml.jackson.core.type.TypeReference;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil;
@ -27,7 +28,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import java.util.Arrays;
import java.util.HashSet;
@ -114,11 +115,16 @@ public class BasicMqttCredentialsTest extends AbstractMqttIntegrationTest {
testTelemetryIsDelivered(accessToken2Device, mqttTestClient5);
}
@Test(expected = MqttSecurityException.class)
@Test(expected = MqttException.class)
public void testCorrectClientIdAndUserNameButWrongPassword() throws Exception {
// Not correct. Correct clientId and username, but wrong password
MqttTestClient mqttTestClient = new MqttTestClient(CLIENT_ID);
mqttTestClient.connectAndWait(USER_NAME3, "WRONG PASSWORD");
try {
mqttTestClient.connectAndWait(USER_NAME3, "WRONG PASSWORD");
Assert.fail(); // This should not happens, because we have a wrong password
} catch (MqttException e) {
Assert.assertEquals(4, e.getReasonCode()); // 4 - Reason code for bad username or password in MQTT v3
}
testTelemetryIsNotDelivered(clientIdAndUserNameAndPasswordDevice3, mqttTestClient);
}

6
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionJsonDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.provision;
package org.thingsboard.server.transport.mqtt.mqttv3.provision;
import com.fasterxml.jackson.databind.JsonNode;
import io.netty.handler.codec.mqtt.MqttQoS;
@ -33,8 +33,8 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.concurrent.TimeUnit;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionProtoDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.provision;
package org.thingsboard.server.transport.mqtt.mqttv3.provision;
import io.netty.handler.codec.mqtt.MqttQoS;
import lombok.extern.slf4j.Slf4j;
@ -41,8 +41,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCre
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.concurrent.TimeUnit;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.rpc;
package org.thingsboard.server.transport.mqtt.mqttv3.rpc;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@ -39,8 +39,8 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import java.util.ArrayList;
import java.util.List;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.rpc;
package org.thingsboard.server.transport.mqtt.mqttv3.rpc;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcDefaultIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcDefaultIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.rpc;
package org.thingsboard.server.transport.mqtt.mqttv3.rpc;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import lombok.extern.slf4j.Slf4j;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcJsonIntegrationTest.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.rpc;
package org.thingsboard.server.transport.mqtt.mqttv3.rpc;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcProtoIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.rpc;
package org.thingsboard.server.transport.mqtt.mqttv3.rpc;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.attributes;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.Arrays;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesJsonIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.attributes;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;

2
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesProtoIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.attributes;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes;
import com.github.os72.protobuf.dynamic.DynamicSchema;
import com.google.protobuf.Descriptors;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries;
import com.fasterxml.jackson.core.type.TypeReference;
import io.netty.handler.codec.mqtt.MqttQoS;
@ -23,8 +23,8 @@ import org.junit.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.Arrays;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.Arrays;

6
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries;
import com.github.os72.protobuf.dynamic.DynamicSchema;
import com.google.protobuf.Descriptors;
@ -31,8 +31,8 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.mqtt.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.MqttTestClient;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback;
import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import java.util.Arrays;

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
@DaoNoSqlTest
public class MqttTimeseriesNoSqlIntegrationTest extends AbstractMqttTimeseriesIntegrationTest {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
@DaoNoSqlTest
public class MqttTimeseriesNoSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql;
import org.thingsboard.server.dao.service.DaoNoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
@DaoNoSqlTest
public class MqttTimeseriesNoSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest;
@DaoSqlTest
public class MqttTimeseriesSqlIntegrationTest extends AbstractMqttTimeseriesIntegrationTest {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest;
@DaoSqlTest
public class MqttTimeseriesSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest {

4
application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java

@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql;
package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest;
@DaoSqlTest
public class MqttTimeseriesSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest {

21
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/AbstractMqttV5Test.java

@ -0,0 +1,21 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
public abstract class AbstractMqttV5Test extends AbstractMqttIntegrationTest {
}

110
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestCallback.java

@ -0,0 +1,110 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttCallback;
import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.packet.MqttProperties;
import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage;
import java.util.concurrent.CountDownLatch;
@Slf4j
@Data
public class MqttV5TestCallback implements MqttCallback {
protected CountDownLatch subscribeLatch;
protected final CountDownLatch deliveryLatch;
protected int qoS;
protected byte[] payloadBytes;
protected String awaitSubTopic;
protected boolean pubAckReceived;
protected MqttMessage lastReceivedMessage;
public MqttV5TestCallback() {
this.subscribeLatch = new CountDownLatch(1);
this.deliveryLatch = new CountDownLatch(1);
}
public MqttV5TestCallback(int subscribeCount) {
this.subscribeLatch = new CountDownLatch(subscribeCount);
this.deliveryLatch = new CountDownLatch(1);
}
public MqttV5TestCallback(String awaitSubTopic) {
this.subscribeLatch = new CountDownLatch(1);
this.deliveryLatch = new CountDownLatch(1);
this.awaitSubTopic = awaitSubTopic;
}
@Override
public void disconnected(MqttDisconnectResponse mqttDisconnectResponse) {
if (mqttDisconnectResponse.getException() != null) {
log.warn("connectionLost: ", mqttDisconnectResponse.getException());
deliveryLatch.countDown();
}
log.warn("Disconnected with reason: {}", mqttDisconnectResponse.getReasonString());
}
@Override
public void mqttErrorOccurred(MqttException e) {
log.warn("Error occurred:", e);
}
@Override
public void messageArrived(String requestTopic, MqttMessage mqttMessage) {
lastReceivedMessage = mqttMessage;
if (awaitSubTopic == null) {
log.warn("messageArrived on topic: {}", requestTopic);
qoS = mqttMessage.getQos();
payloadBytes = mqttMessage.getPayload();
subscribeLatch.countDown();
} else {
messageArrivedOnAwaitSubTopic(requestTopic, mqttMessage);
}
}
protected void messageArrivedOnAwaitSubTopic(String requestTopic, MqttMessage mqttMessage) {
log.warn("messageArrived on topic: {}, awaitSubTopic: {}", requestTopic, awaitSubTopic);
if (awaitSubTopic.equals(requestTopic)) {
qoS = mqttMessage.getQos();
payloadBytes = mqttMessage.getPayload();
subscribeLatch.countDown();
}
}
@Override
public void deliveryComplete(IMqttToken iMqttToken) {
log.warn("delivery complete: {}", iMqttToken.getResponse());
pubAckReceived = iMqttToken.getResponse().getType() == MqttWireMessage.MESSAGE_TYPE_PUBACK;
deliveryLatch.countDown();
}
@Override
public void connectComplete(boolean reconnect, String serverURI) {
log.warn("Connect completed: reconnect - {}, serverURI - {}", reconnect, serverURI);
}
@Override
public void authPacketArrived(int reasonCode, MqttProperties mqttProperties) {
log.warn("Auth package received: reasonCode - {}, mqtt properties - {}", reasonCode, mqttProperties);
}
}

175
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestClient.java

@ -0,0 +1,175 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttAsyncClient;
import org.eclipse.paho.mqttv5.client.MqttCallback;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.thingsboard.server.common.data.StringUtils;
import java.util.concurrent.TimeUnit;
public class MqttV5TestClient { // We should copy part of MqttV3TestClient, due to different package names in import
private static final String MQTT_URL = "tcp://localhost:1883";
private static final int TIMEOUT = 30; // seconds
private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(TIMEOUT);
private final MqttAsyncClient client;
public void setCallback(MqttCallback callback) {
client.setCallback(callback);
}
public MqttV5TestClient() throws MqttException {
this.client = createClient();
}
public MqttV5TestClient(String clientId) throws MqttException {
this.client = createClient(clientId);
}
public MqttV5TestClient(boolean generateClientId) throws MqttException {
this.client = createClient(generateClientId);
}
public IMqttToken connectAndWait(String userName, String password) throws MqttException {
IMqttToken connect = connect(userName, password);
connect.waitForCompletion(TIMEOUT_MS);
return connect;
}
public IMqttToken connectAndWait(String userName) throws MqttException {
return connectAndWait(userName, null);
}
public IMqttToken connectAndWait() throws MqttException {
return connectAndWait(null, null);
}
public IMqttToken connectAndWait(MqttConnectionOptions options) throws MqttException {
IMqttToken iMqttToken = connect(options);
iMqttToken.waitForCompletion(TIMEOUT_MS);
return iMqttToken;
}
private IMqttToken connect(String userName, String password) throws MqttException {
if (client == null) {
throw new RuntimeException("Failed to connect! MqttAsyncClient is not initialized!");
}
MqttConnectionOptions options = new MqttConnectionOptions();
if (StringUtils.isNotEmpty(userName)) {
options.setUserName(userName);
}
if (StringUtils.isNotEmpty(password)) {
options.setPassword(password.getBytes());
}
return client.connect(options);
}
public IMqttToken connect(MqttConnectionOptions options) throws MqttException {
if (client == null) {
throw new RuntimeException("Failed to connect! MqttAsyncClient is not initialized!");
}
return client.connect(options);
}
public void disconnectAndWait() throws MqttException {
disconnect().waitForCompletion(TIMEOUT_MS);
}
public IMqttToken disconnect() throws MqttException {
return client.disconnect();
}
public void disconnectForcibly() throws MqttException {
client.disconnectForcibly(TIMEOUT_MS);
}
public IMqttToken publishAndWait(String topic, byte[] payload) throws MqttException {
IMqttToken iMqttToken = publish(topic, payload);
iMqttToken.waitForCompletion(TIMEOUT_MS);
return iMqttToken;
}
public IMqttToken publish(String topic, byte[] payload) throws MqttException {
MqttMessage message = new MqttMessage();
message.setPayload(payload);
return publish(topic, message);
}
public IMqttToken publish(String topic, MqttMessage message) throws MqttException {
return publish(topic, message.getPayload(), message.getQos(), message.isRetained());
}
public IMqttToken publish(String topic, byte[] payload, int qos, boolean retain) throws MqttException {
return client.publish(topic, payload, qos, retain);
}
public IMqttToken subscribeAndWait(String topic, MqttQoS qoS) throws MqttException {
IMqttToken iMqttToken = subscribe(topic, qoS);
iMqttToken.waitForCompletion(TIMEOUT_MS);
return iMqttToken;
}
public IMqttToken subscribe(String topic, MqttQoS qoS) throws MqttException {
return client.subscribe(topic, qoS.value());
}
public IMqttToken unsubscribeAndWait(String topic) throws MqttException {
IMqttToken iMqttToken = unsubscribe(topic);
iMqttToken.waitForCompletion(TIMEOUT_MS);
return iMqttToken;
}
public IMqttToken unsubscribe(String topic) throws MqttException {
return client.unsubscribe(topic);
}
public boolean isConnected() {
return client.isConnected();
}
public void enableManualAcks() {
client.setManualAcks(true);
}
public void messageArrivedComplete(MqttMessage mqttMessage) throws MqttException {
client.messageArrivedComplete(mqttMessage.getId(), mqttMessage.getQos());
}
private MqttAsyncClient createClient() throws MqttException {
return createClient(true);
}
private MqttAsyncClient createClient(boolean generateClientId) throws MqttException {
String clientId = null;
if (generateClientId) {
clientId = "test" + System.nanoTime();
}
return createClient(clientId);
}
private MqttAsyncClient createClient(String clientId) throws MqttException {
return new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence());
}
}

161
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java

@ -0,0 +1,161 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.attributes;
import com.fasterxml.jackson.core.type.TypeReference;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.junit.Before;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class AbstractAttributesMqttV5Test extends AbstractMqttV5Test {
private static final String SHARED_ATTRIBUTES_PAYLOAD = "{\"sharedStr\":\"value1\",\"sharedBool\":true,\"sharedDbl\":42.0,\"sharedLong\":73," +
"\"sharedJson\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}";
private static final String SHARED_ATTRIBUTES_DELETED_RESPONSE = "{\"deleted\":[\"sharedJson\"]}";
protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Post Attributes device")
.build();
processBeforeTest(configProperties);
}
protected void processAttributesPublishTest() throws Exception {
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, PAYLOAD_VALUES_STR.getBytes());
client.disconnectAndWait();
DeviceId deviceId = savedDevice.getId();
long start = System.currentTimeMillis();
long end = System.currentTimeMillis() + 5000;
List<String> actualKeys = null;
while (start <= end) {
actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() {
});
if (actualKeys.size() == expectedKeys.size()) {
break;
}
Thread.sleep(100);
start += 100;
}
assertNotNull(actualKeys);
Set<String> actualKeySet = new HashSet<>(actualKeys);
Set<String> expectedKeySet = new HashSet<>(expectedKeys);
assertEquals(expectedKeySet, actualKeySet);
String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet);
List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {
});
assertAttributesValues(values, actualKeySet);
String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
doDelete(deleteAttributesUrl);
}
protected void processAttributesUpdatesTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback();
client.setCallback(onUpdateCallback);
client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE);
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk());
onUpdateCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
validateUpdateAttributesResponse(onUpdateCallback, SHARED_ATTRIBUTES_PAYLOAD);
MqttV5TestCallback onDeleteCallback = new MqttV5TestCallback();
client.setCallback(onDeleteCallback);
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class);
onDeleteCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
validateUpdateAttributesResponse(onDeleteCallback, SHARED_ATTRIBUTES_DELETED_RESPONSE);
client.disconnect();
}
private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) {
return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet);
}
protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> keySet) {
for (Map<String, Object> map : deviceValues) {
String key = (String) map.get("key");
Object value = map.get("value");
assertTrue(keySet.contains(key));
switch (key) {
case "key1":
assertEquals("value1", value);
break;
case "key2":
assertEquals(true, value);
break;
case "key3":
assertEquals(3.0, value);
break;
case "key4":
assertEquals(4, value);
break;
case "key5":
assertNotNull(value);
assertEquals(3, ((LinkedHashMap) value).size());
assertEquals(42, ((LinkedHashMap) value).get("someNumber"));
assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray"));
LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject");
assertEquals("value", someNestedObject.get("key"));
break;
}
}
}
protected void validateUpdateAttributesResponse(MqttV5TestCallback callback, String expectedResponse) {
assertNotNull(callback.getPayloadBytes());
assertEquals(JacksonUtil.toJsonNode(expectedResponse), JacksonUtil.fromBytes(callback.getPayloadBytes()));
}
}

43
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/updates/AttributesUpdatesTest.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.attributes.updates;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.mqttv5.attributes.AbstractAttributesMqttV5Test;
@Slf4j
@DaoSqlTest
public class AttributesUpdatesTest extends AbstractAttributesMqttV5Test {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Subscribe to attribute updates")
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
}
@Test
public void testAttributeMqttV5SimpleClientUpdates() throws Exception {
processAttributesUpdatesTest();
}
}

38
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/upload/AttributesPublishTest.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.attributes.upload;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.mqttv5.attributes.AbstractAttributesMqttV5Test;
@DaoSqlTest
public class AttributesPublishTest extends AbstractAttributesMqttV5Test {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Post Attributes device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testMqttV5AttributePublishTest() throws Exception {
processAttributesPublishTest();
}
}

101
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/AbstractMqttV5ClaimTest.java

@ -0,0 +1,101 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.claim;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.ClaimRequest;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_CLAIM_TOPIC;
@Slf4j
public abstract class AbstractMqttV5ClaimTest extends AbstractMqttV5Test {
protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!";
protected User customerAdmin;
protected Customer savedCustomer;
protected void processTestClaimingDevice() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
byte[] payloadBytes;
byte[] failurePayloadBytes;
payloadBytes = "{\"secretKey\":\"value\", \"durationMs\":60000}".getBytes();
failurePayloadBytes = "{\"secretKey\":\"value\", \"durationMs\":1}".getBytes();
validateClaimResponse(client, payloadBytes, failurePayloadBytes);
}
protected void validateClaimResponse(MqttV5TestClient client, byte[] payloadBytes, byte[] failurePayloadBytes) throws Exception {
client.publishAndWait(DEVICE_CLAIM_TOPIC, failurePayloadBytes);
loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD);
ClaimRequest claimRequest = new ClaimRequest("value");
ClaimResponse claimResponse = doExecuteWithRetriesAndInterval(
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()),
20,
100
);
assertEquals(claimResponse, ClaimResponse.FAILURE);
client.publishAndWait(DEVICE_CLAIM_TOPIC, payloadBytes);
client.disconnect();
ClaimResult claimResult = doExecuteWithRetriesAndInterval(
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResult.class, status().isOk()),
20,
100
);
assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS);
Device claimedDevice = claimResult.getDevice();
assertNotNull(claimedDevice);
assertNotNull(claimedDevice.getCustomerId());
assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId());
claimResponse = doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest());
assertEquals(claimResponse, ClaimResponse.CLAIMED);
}
protected void createCustomerAndUser() throws Exception {
Customer customer = new Customer();
customer.setTenantId(tenantId);
customer.setTitle("Test Claiming Customer");
savedCustomer = doPost("/api/customer", customer, Customer.class);
assertNotNull(savedCustomer);
assertEquals(tenantId, savedCustomer.getTenantId());
User user = new User();
user.setAuthority(Authority.CUSTOMER_USER);
user.setTenantId(tenantId);
user.setCustomerId(savedCustomer.getId());
user.setEmail("customer@thingsboard.org");
customerAdmin = createUser(user, CUSTOMER_USER_PASSWORD);
assertNotNull(customerAdmin);
assertEquals(customerAdmin.getCustomerId(), savedCustomer.getId());
}
}

39
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/MqttV5ClaimTest.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.claim;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5ClaimTest extends AbstractMqttV5ClaimTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Claim device")
.build();
processBeforeTest(configProperties);
createCustomerAndUser();
}
@Test
public void testClaimingDevice() throws Exception {
processTestClaimingDevice();
}
}

111
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java

@ -0,0 +1,111 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.connection;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.packet.MqttConnAck;
import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode;
import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage;
import org.junit.Assert;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import java.util.concurrent.TimeUnit;
import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_CONNACK;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class AbstractMqttV5ClientConnectionTest extends AbstractMqttIntegrationTest {
protected void processClientWithCorrectAccessTokenTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
IMqttToken connectionResult = client.connectAndWait(accessToken);
MqttWireMessage response = connectionResult.getResponse();
Assert.assertEquals(MESSAGE_TYPE_CONNACK, response.getType());
MqttConnAck connAckMsg = (MqttConnAck) response;
Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, connAckMsg.getReturnCode());
client.disconnect();
}
protected void processClientWithWrongAccessTokenTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
try {
client.connectAndWait("wrongAccessToken");
} catch (MqttException e) {
Assert.assertEquals(MqttReturnCode.RETURN_CODE_BAD_USERNAME_OR_PASSWORD, e.getReasonCode());
}
}
protected void processClientWithWrongClientIdAndEmptyUsernamePasswordTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient("unknownClientId");
try {
client.connectAndWait();
} catch (MqttException e) {
Assert.assertEquals(MqttReturnCode.RETURN_CODE_IDENTIFIER_NOT_VALID, e.getReasonCode());
}
}
protected void processClientWithNoCredentialsTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient(false);
try {
client.connectAndWait();
} catch (MqttException e) {
Assert.assertEquals(MqttReturnCode.RETURN_CODE_NOT_AUTHORIZED, e.getReasonCode());
}
}
protected void processClientWithPacketSizeLimitationTest() throws Exception {
int packetSizeLimit = 99;
MqttConnectionOptions options = new MqttConnectionOptions();
options.setMaximumPacketSize((long) packetSizeLimit);
options.setUserName(accessToken);
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(options);
MqttV5TestCallback possibleSizeCallback = updateAttributeWithStringValue(client, packetSizeLimit / 2);
Assert.assertTrue("Server should send messages if size less then limitation.", possibleSizeCallback.getPayloadBytes().length < packetSizeLimit);
MqttV5TestCallback bigMessageCallback = updateAttributeWithStringValue(client, packetSizeLimit * 2);
Assert.assertNull("Server should not send a message if the message size bigger then set limit.", bigMessageCallback.getLastReceivedMessage());
client.disconnect();
}
private MqttV5TestCallback updateAttributeWithStringValue(MqttV5TestClient client, int valueLen) throws Exception {
MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback();
client.setCallback(onUpdateCallback);
client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE);
String payload = "{\"sharedStr\":\"" + StringUtils.repeat("*", valueLen) + "\"}";
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", payload, String.class, status().isOk());
onUpdateCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
return onUpdateCallback;
}
}

60
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/MqttV5ClientConnectionTest.java

@ -0,0 +1,60 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.connection;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5ClientConnectionTest extends AbstractMqttV5ClientConnectionTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test MqttV5 client device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testClientWithCorrectAccessToken() throws Exception {
processClientWithCorrectAccessTokenTest();
}
@Test
public void testClientWithWrongAccessToken() throws Exception {
processClientWithWrongAccessTokenTest();
}
@Test
public void testClientWithWrongClientIdAndEmptyUsernamePassword() throws Exception {
processClientWithWrongClientIdAndEmptyUsernamePasswordTest();
}
@Test
public void testClientWithNoCredentialsTest() throws Exception {
processClientWithNoCredentialsTest();
}
@Test
@Ignore("Not implemented on the server.")
public void testClientWithPacketSizeLimitation() throws Exception {
processClientWithPacketSizeLimitationTest();
}
}

77
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/AbstractMqttV5ClientPublishTest.java

@ -0,0 +1,77 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.publish;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.common.packet.MqttPubAck;
import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode;
import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage;
import org.junit.Assert;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_PUBACK;
public abstract class AbstractMqttV5ClientPublishTest extends AbstractMqttIntegrationTest {
protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
protected static final String INVALID_PAYLOAD_VALUES_STR = "\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
protected void processClientPublishToCorrectTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken publishResult = client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, PAYLOAD_VALUES_STR.getBytes());
MqttWireMessage response = publishResult.getResponse();
Assert.assertEquals(MESSAGE_TYPE_PUBACK, response.getType());
MqttPubAck pubAckMsg = (MqttPubAck) response;
Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, pubAckMsg.getReturnCode());
client.disconnect();
}
protected void processClientPublishToWrongTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken iMqttToken = client.publishAndWait("wrong/topic/", PAYLOAD_VALUES_STR.getBytes());
Assert.assertEquals(MESSAGE_TYPE_PUBACK,iMqttToken.getResponse().getType());
MqttPubAck pubAck = (MqttPubAck) iMqttToken.getResponse();
Assert.assertEquals(MqttReturnCode.RETURN_CODE_TOPIC_NAME_INVALID, pubAck.getReturnCode());
client.disconnect();
}
protected void processClientPublishWithInvalidPayloadTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken iMqttToken = client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, INVALID_PAYLOAD_VALUES_STR.getBytes());
Assert.assertEquals(MESSAGE_TYPE_PUBACK,iMqttToken.getResponse().getType());
MqttPubAck pubAck = (MqttPubAck) iMqttToken.getResponse();
Assert.assertEquals(MqttReturnCode.RETURN_CODE_PAYLOAD_FORMAT_INVALID, pubAck.getReturnCode());
client.disconnect();
}
}

49
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/MqttV5ClientPublishTest.java

@ -0,0 +1,49 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.publish;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5ClientPublishTest extends AbstractMqttV5ClientPublishTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test MqttV5 client device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testClientPublishToCorrectTopic() throws Exception {
processClientPublishToCorrectTopicTest();
}
@Test
public void testClientPublishToWrongTopic() throws Exception {
processClientPublishToWrongTopicTest();
}
@Test
public void testClientPublishWithInvalidPayload() throws Exception {
processClientPublishWithInvalidPayloadTest();
}
}

63
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java

@ -0,0 +1,63 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.subscribe;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode;
import org.eclipse.paho.mqttv5.common.packet.MqttSubAck;
import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage;
import org.junit.Assert;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_SUBACK;
public abstract class AbstractMqttV5ClientSubscriptionTest extends AbstractMqttIntegrationTest {
protected void processClientSubscriptionToCorrectTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken subscriptionResult = client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE);
MqttWireMessage response = subscriptionResult.getResponse();
Assert.assertEquals(MESSAGE_TYPE_SUBACK, response.getType());
MqttSubAck subAckMsg = (MqttSubAck) response;
Assert.assertEquals(1, subAckMsg.getReturnCodes().length);
Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, subAckMsg.getReturnCodes()[0]);
client.disconnect();
}
protected void processClientSubscriptionToWrongTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken iMqttToken = client.subscribeAndWait("wrong/topic/+", MqttQoS.AT_MOST_ONCE);
Assert.assertEquals(MESSAGE_TYPE_SUBACK,iMqttToken.getResponse().getType());
MqttSubAck subAck = (MqttSubAck) iMqttToken.getResponse();
Assert.assertEquals(1, subAck.getReturnCodes().length);
Assert.assertEquals(MqttReturnCode.RETURN_CODE_TOPIC_FILTER_NOT_VALID, subAck.getReturnCodes()[0]);
client.disconnect();
}
}

44
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/MqttV5ClientSubscriptionTest.java

@ -0,0 +1,44 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.subscribe;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5ClientSubscriptionTest extends AbstractMqttV5ClientSubscriptionTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test MqttV5 client device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testClientSubscriptionToCorrectTopic() throws Exception {
processClientSubscriptionToCorrectTopicTest();
}
@Test
public void testClientSubscriptionToWrongTopic() throws Exception {
processClientSubscriptionToWrongTopicTest();
}
}

60
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java

@ -0,0 +1,60 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.unsubscribe;
import io.netty.handler.codec.mqtt.MqttQoS;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode;
import org.eclipse.paho.mqttv5.common.packet.MqttUnsubAck;
import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage;
import org.junit.Assert;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_UNSUBACK;
public abstract class AbstractMqttV5ClientUnsubscribeTest extends AbstractMqttIntegrationTest {
protected void processClientUnsubscribeFromCorrectTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE);
IMqttToken unsubscribeResult = client.unsubscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
MqttWireMessage response = unsubscribeResult.getResponse();
Assert.assertEquals(MESSAGE_TYPE_UNSUBACK, response.getType());
MqttUnsubAck unsubAckMsg = (MqttUnsubAck) response;
Assert.assertEquals(1, unsubAckMsg.getReturnCodes().length);
Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, unsubAckMsg.getReturnCodes()[0]);
client.disconnect();
}
protected void processClientUnsubscribeWithoutSubscribeTopicTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
IMqttToken iMqttToken = client.unsubscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
Assert.assertEquals(MESSAGE_TYPE_UNSUBACK, iMqttToken.getResponse().getType());
MqttUnsubAck unsubAck = (MqttUnsubAck) iMqttToken.getResponse();
Assert.assertEquals(1, unsubAck.getReturnCodes().length);
Assert.assertEquals(MqttReturnCode.RETURN_CODE_NO_SUBSCRIPTION_EXISTED, unsubAck.getReturnCodes()[0]);
client.disconnect();
}
}

44
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/MqttV5ClientUnsubscribeTest.java

@ -0,0 +1,44 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.client.unsubscribe;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5ClientUnsubscribeTest extends AbstractMqttV5ClientUnsubscribeTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test MqttV5 client device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testClientUnsubscribeFromCorrectTopic() throws Exception {
processClientUnsubscribeFromCorrectTopicTest();
}
@Test
public void testClientUnsubscribeWithoutSubscribeTopic() throws Exception {
processClientUnsubscribeWithoutSubscribeTopicTest();
}
}

94
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/provision/MqttV5ProvisionDeviceTest.java

@ -0,0 +1,94 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.provision;
import com.fasterxml.jackson.databind.JsonNode;
import io.netty.handler.codec.mqtt.MqttQoS;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import java.util.concurrent.TimeUnit;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC;
@Slf4j
@DaoSqlTest
public class MqttV5ProvisionDeviceTest extends AbstractMqttV5Test {
@Autowired
DeviceCredentialsService deviceCredentialsService;
@Autowired
DeviceService deviceService;
@Test
public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
processTestProvisioningCreateNewDeviceWithoutCredentials();
}
protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Provision device3")
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
super.processBeforeTest(configProperties);
byte[] result = createMqttClientAndPublish();
JsonNode response = JacksonUtil.fromBytes(result);
Assert.assertTrue(response.hasNonNull("credentialsType"));
Assert.assertTrue(response.hasNonNull("status"));
Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").asText());
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").asText());
}
protected byte[] createMqttClientAndPublish() throws Exception {
String provisionRequestMsg = "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"}";
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait("provision");
MqttV5TestCallback onProvisionCallback = new MqttV5TestCallback(DEVICE_PROVISION_RESPONSE_TOPIC);
client.setCallback(onProvisionCallback);
client.subscribe(DEVICE_PROVISION_RESPONSE_TOPIC, MqttQoS.AT_MOST_ONCE);
client.publishAndWait(DEVICE_PROVISION_REQUEST_TOPIC, provisionRequestMsg.getBytes());
onProvisionCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
client.disconnect();
return onProvisionCallback.getPayloadBytes();
}
}

98
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java

@ -0,0 +1,98 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.rpc;
import com.nimbusds.jose.util.StandardCharset;
import io.netty.handler.codec.mqtt.MqttQoS;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC;
@Slf4j
public abstract class AbstractMqttV5RpcTest extends AbstractMqttV5Test {
private static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
protected void processOneWayRpcTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
MqttV5TestCallback callback = new MqttV5TestCallback(DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0"));
client.setCallback(callback);
client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_MOST_ONCE);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
String result = doPostAsync("/api/rpc/oneway/" + savedDevice.getId(), setGpioRequest, String.class, status().isOk());
assertTrue(StringUtils.isEmpty(result));
callback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
assertEquals(JacksonUtil.toJsonNode(setGpioRequest), JacksonUtil.fromBytes(callback.getPayloadBytes()));
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
client.disconnect();
}
protected void processJsonTwoWayRpcTest() throws Exception {
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_LEAST_ONCE);
MqttV5TestRpcCallback callback = new MqttV5TestRpcCallback(client, DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0"));
client.setCallback(callback);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
String actualRpcResponse = doPostAsync("/api/rpc/twoway/" + savedDevice.getId(), setGpioRequest, String.class, status().isOk());
callback.getSubscribeLatch().await(3, TimeUnit.SECONDS);
assertEquals(JacksonUtil.toJsonNode(setGpioRequest), JacksonUtil.fromBytes(callback.getPayloadBytes()));
assertEquals("{\"value1\":\"A\",\"value2\":\"B\"}", actualRpcResponse);
client.disconnect();
}
protected class MqttV5TestRpcCallback extends MqttV5TestCallback {
private final MqttV5TestClient client;
public MqttV5TestRpcCallback(MqttV5TestClient client, String awaitSubTopic) {
super(awaitSubTopic);
this.client = client;
}
@Override
protected void messageArrivedOnAwaitSubTopic(String requestTopic, MqttMessage mqttMessage) {
log.warn("messageArrived on topic: {}, awaitSubTopic: {}", requestTopic, awaitSubTopic);
if (awaitSubTopic.equals(requestTopic)) {
qoS = mqttMessage.getQos();
payloadBytes = mqttMessage.getPayload();
String responseTopic = requestTopic.replace("request", "response");
try {
client.publish(responseTopic, DEVICE_RESPONSE.getBytes(StandardCharset.UTF_8));
} catch (MqttException e) {
log.warn("Failed to publish response on topic: {} due to: ", responseTopic, e);
}
subscribeLatch.countDown();
}
}
}
}

43
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/MqttV5RpcTest.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.rpc;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5RpcTest extends AbstractMqttV5RpcTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("RPC test device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testServerMqttV5SimpleClientOneWayRpc() throws Exception {
processOneWayRpcTest();
}
@Test
public void testServerMqttV5SimpleClientTwoWayRpc() throws Exception {
processJsonTwoWayRpcTest();
}
}

132
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/AbstractMqttV5TimeseriesTest.java

@ -0,0 +1,132 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.timeseries;
import com.fasterxml.jackson.core.type.TypeReference;
import org.thingsboard.server.common.data.device.profile.MqttTopics;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test;
import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public abstract class AbstractMqttV5TimeseriesTest extends AbstractMqttV5Test {
protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," +
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
protected void processTimeseriesMqttV5UploadTest() throws Exception {
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
MqttV5TestClient client = new MqttV5TestClient();
client.connectAndWait(accessToken);
client.publishAndWait(MqttTopics.DEVICE_TELEMETRY_TOPIC, PAYLOAD_VALUES_STR.getBytes());
client.disconnect();
DeviceId deviceId = savedDevice.getId();
List<String> actualKeys = getActualKeysList(deviceId, expectedKeys);
assertNotNull(actualKeys);
Set<String> actualKeySet = new HashSet<>(actualKeys);
Set<String> expectedKeySet = new HashSet<>(expectedKeys);
assertEquals(expectedKeySet, actualKeySet);
String getTelemetryValuesUrl;
getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet);
long start = System.currentTimeMillis();
long end = System.currentTimeMillis() + 5000;
Map<String, List<Map<String, Object>>> values = null;
while (start <= end) {
values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() {
});
boolean valid = values.size() == expectedKeys.size();
if (valid) {
for (String key : expectedKeys) {
List<Map<String, Object>> tsValues = values.get(key);
if (tsValues != null && tsValues.size() > 0) {
Object ts = tsValues.get(0).get("ts");
if (ts == null) {
valid = false;
break;
}
} else {
valid = false;
break;
}
}
}
if (valid) {
break;
}
Thread.sleep(100);
start += 100;
}
assertNotNull(values);
assertValues(values);
}
private List<String> getActualKeysList(DeviceId deviceId, List<String> expectedKeys) throws Exception {
long start = System.currentTimeMillis();
long end = System.currentTimeMillis() + 3000;
List<String> actualKeys = null;
while (start <= end) {
actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() {
});
if (actualKeys.size() == expectedKeys.size()) {
break;
}
Thread.sleep(100);
start += 100;
}
return actualKeys;
}
private void assertValues(Map<String, List<Map<String, Object>>> deviceValues) {
for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) {
String key = entry.getKey();
List<Map<String, Object>> tsKv = entry.getValue();
String value = (String) tsKv.get(0).get("value");
switch (key) {
case "key1":
assertEquals("value1", value);
break;
case "key2":
assertEquals("true", value);
break;
case "key3":
assertEquals("3.0", value);
break;
case "key4":
assertEquals("4", value);
break;
case "key5":
assertEquals("{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value);
break;
}
}
}
}

39
application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/MqttV5TimeseriesTest.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.mqtt.mqttv5.timeseries;
import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties;
@DaoSqlTest
public class MqttV5TimeseriesTest extends AbstractMqttV5TimeseriesTest {
@Before
public void beforeTest() throws Exception {
MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder()
.deviceName("Test Post Telemetry device")
.build();
processBeforeTest(configProperties);
}
@Test
public void testTimeseriesMqttV5SimpleClientUpload() throws Exception {
processTimeseriesMqttV5UploadTest();
}
}

2
common/actor/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>

2
common/cache/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>

2
common/cluster-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>

2
common/coap-server/pom.xml

@ -22,7 +22,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>

6
common/dao-api/pom.xml

@ -20,7 +20,7 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>3.4.2</version>
<version>3.4.3-SNAPSHOT</version>
<artifactId>common</artifactId>
</parent>
<groupId>org.thingsboard.common</groupId>
@ -115,6 +115,10 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
</dependency>
</dependencies>
<build>

3
common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java

@ -31,13 +31,14 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.Collection;
/**
* Created by ashvayka on 11.05.17.
*/
public interface AlarmService {
public interface AlarmService extends TbEntityService {
AlarmOperationResult createOrUpdateAlarm(Alarm alarm);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java

@ -21,8 +21,9 @@ import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
public interface AssetProfileService {
public interface AssetProfileService extends TbEntityService {
AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId);

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

@ -27,10 +27,11 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface AssetService {
public interface AssetService extends TbEntityService {
AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java

@ -25,10 +25,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface AuditLogService {
public interface AuditLogService extends TbEntityService {
PageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, List<ActionType> actionTypes, TimePageLink pageLink);

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

@ -21,10 +21,11 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.Optional;
public interface CustomerService {
public interface CustomerService extends TbEntityService {
Customer findCustomerById(TenantId tenantId, CustomerId customerId);

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

@ -24,10 +24,11 @@ import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface DashboardService {
public interface DashboardService extends TbEntityService {
Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId);

4
common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java

@ -17,13 +17,13 @@ package org.thingsboard.server.dao.device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
public interface DeviceProfileService {
public interface DeviceProfileService extends TbEntityService {
DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId);

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

@ -33,11 +33,12 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.device.provision.ProvisionRequest;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
import java.util.UUID;
public interface DeviceService {
public interface DeviceService extends TbEntityService {
DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId);

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

@ -26,11 +26,12 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
import java.util.Optional;
public interface EdgeService {
public interface EdgeService extends TbEntityService {
Edge findEdgeById(TenantId tenantId, EdgeId edgeId);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.dao.entity;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
@ -28,7 +27,7 @@ import java.util.Optional;
public interface EntityService {
ListenableFuture<String> fetchEntityNameAsync(TenantId tenantId, EntityId entityId);
Optional<String> fetchEntityName(TenantId tenantId, EntityId entityId);
Optional<String> fetchEntityLabel(TenantId tenantId, EntityId entityId);

43
common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityServiceBeanFactory.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.entity;
import org.apache.commons.text.CaseUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
@Service
public class EntityServiceBeanFactory {
private static final String SERVICE_SUFFIX = "DaoService";
private final BeanFactory beanFactory;
public EntityServiceBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public TbEntityService getServiceByEntityType(EntityType entityType) {
String beanName = EntityType.RULE_NODE.equals(entityType) ? getBeanName(EntityType.RULE_CHAIN) : getBeanName(entityType);
return beanFactory.getBean(beanName, TbEntityService.class);
}
private String getBeanName(EntityType entityType) {
return CaseUtils.toCamelCase(entityType.name(), true, '_') + SERVICE_SUFFIX;
}
}

28
common/dao-api/src/main/java/org/thingsboard/server/dao/entity/TbEntityService.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.entity;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.Optional;
public interface TbEntityService {
Optional<HasId<?>> fetchEntity(TenantId tenantId, EntityId entityId);
}

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

@ -27,13 +27,14 @@ import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
/**
* Created by Victor Basanets on 8/27/2017.
*/
public interface EntityViewService {
public interface EntityViewService extends TbEntityService {
EntityView saveEntityView(EntityView entityView);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java

@ -24,10 +24,11 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface EventService {
public interface EventService extends TbEntityService {
ListenableFuture<Void> saveAsync(Event event);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java

@ -25,10 +25,11 @@ import org.thingsboard.server.common.data.ota.ChecksumAlgorithm;
import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.nio.ByteBuffer;
public interface OtaPackageService {
public interface OtaPackageService extends TbEntityService {
OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java

@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.queue.Queue;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface QueueService {
public interface QueueService extends TbEntityService {
Queue saveQueue(Queue queue);

3
common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java

@ -23,10 +23,11 @@ import org.thingsboard.server.common.data.id.TbResourceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.entity.TbEntityService;
import java.util.List;
public interface ResourceService {
public interface ResourceService extends TbEntityService {
TbResource saveResource(TbResource resource);
TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);

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

Loading…
Cancel
Save