Browse Source

Merge branch 'develop/3.4' of github.com:thingsboard/thingsboard into feature/6371

pull/6374/head
Dmitriymush 4 years ago
parent
commit
f5d837751b
  1. 4
      application/pom.xml
  2. 15
      application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json
  3. 30
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  4. 2
      application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
  5. 10
      application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
  6. 2
      application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
  7. 2
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  8. 24
      application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
  9. 74
      application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
  10. 4
      application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
  11. 48
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventUtils.java
  12. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  13. 11
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  14. 10
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
  15. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java
  16. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java
  17. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java
  18. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java
  19. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java
  20. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DeviceProfilesEdgeEventFetcher.java
  21. 4
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/RuleChainsEdgeEventFetcher.java
  22. 67
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java
  23. 41
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
  24. 16
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java
  25. 26
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java
  26. 71
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java
  27. 130
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java
  28. 37
      application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java
  29. 283
      application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
  30. 4
      application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java
  31. 186
      application/src/main/java/org/thingsboard/server/service/sms/smpp/SmppSmsSender.java
  32. 7
      application/src/main/resources/thingsboard.yml
  33. 57
      application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
  34. 16
      application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java
  35. 44
      application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
  36. 54
      application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java
  37. 34
      application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
  38. 96
      application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java
  39. 371
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  40. 57
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java
  41. 4
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java
  42. 4
      application/src/test/java/org/thingsboard/server/controller/BaseEdgeEventControllerTest.java
  43. 375
      application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java
  44. 2
      application/src/test/java/org/thingsboard/server/controller/BaseOtaPackageControllerTest.java
  45. 244
      application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java
  46. 382
      application/src/test/java/org/thingsboard/server/controller/BaseWebsocketApiTest.java
  47. 5
      application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java
  48. 119
      application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java
  49. 24
      application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java
  50. 4
      application/src/test/java/org/thingsboard/server/edge/EdgeSqlTestSuite.java
  51. 5
      application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java
  52. 5
      application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java
  53. 5
      application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java
  54. 50
      application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.java
  55. 121
      application/src/test/java/org/thingsboard/server/service/sms/smpp/SmppSmsSenderTest.java
  56. 2
      application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java
  57. 4
      application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java
  58. 5
      application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java
  59. 14
      application/src/test/java/org/thingsboard/server/transport/AbstractTransportIntegrationTest.java
  60. 5
      application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java
  61. 21
      application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java
  62. 202
      application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java
  63. 46
      application/src/test/java/org/thingsboard/server/transport/coap/CoapTestConfigProperties.java
  64. 12
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/AbstractCoapAttributesIntegrationTest.java
  65. 11
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestIntegrationTest.java
  66. 12
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestJsonIntegrationTest.java
  67. 14
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestProtoIntegrationTest.java
  68. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestJsonSqlIntegrationTest.java
  69. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestProtoSqlIntegrationTest.java
  70. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestSqlIntegrationTest.java
  71. 13
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesIntegrationTest.java
  72. 12
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesJsonIntegrationTest.java
  73. 12
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesProtoIntegrationTest.java
  74. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlIntegrationTest.java
  75. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlJsonIntegrationTest.java
  76. 23
      application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlProtoIntegrationTest.java
  77. 20
      application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimDeviceTest.java
  78. 12
      application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimJsonDeviceTest.java
  79. 13
      application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimProtoDeviceTest.java
  80. 23
      application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceJsonSqlTest.java
  81. 23
      application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceProtoSqlTest.java
  82. 23
      application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceSqlTest.java
  83. 80
      application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java
  84. 78
      application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java
  85. 23
      application/src/test/java/org/thingsboard/server/transport/coap/provision/sql/CoapProvisionDeviceJsonSqlTest.java
  86. 23
      application/src/test/java/org/thingsboard/server/transport/coap/provision/sql/CoapProvisionDeviceProtoSqlTest.java
  87. 9
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java
  88. 15
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcDefaultIntegrationTest.java
  89. 14
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcJsonIntegrationTest.java
  90. 25
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcProtoIntegrationTest.java
  91. 23
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcJsonSqlIntegrationTest.java
  92. 23
      application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcSqlIntegrationTest.java
  93. 11
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesIntegrationTest.java
  94. 12
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesJsonIntegrationTest.java
  95. 12
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesProtoIntegrationTest.java
  96. 26
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlIntegrationTest.java
  97. 26
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlJsonIntegrationTest.java
  98. 26
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlProtoIntegrationTest.java
  99. 8
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java
  100. 8
      application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesJsonIntegrationTest.java

4
application/pom.xml

@ -249,6 +249,10 @@
<groupId>io.grpc</groupId> <groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId> <artifactId>grpc-stub</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.opensmpp</groupId>
<artifactId>opensmpp-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<artifactId>springfox-boot-starter</artifactId> <artifactId>springfox-boot-starter</artifactId>

15
application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json

@ -156,6 +156,21 @@
"toIndex": 7, "toIndex": 7,
"type": "Attributes Updated" "type": "Attributes Updated"
}, },
{
"fromIndex": 3,
"toIndex": 7,
"type": "Attributes Deleted"
},
{
"fromIndex": 3,
"toIndex": 7,
"type": "Timeseries Deleted"
},
{
"fromIndex": 3,
"toIndex": 7,
"type": "Timeseries Updated"
},
{ {
"fromIndex": 4, "fromIndex": 4,
"toIndex": 7, "toIndex": 7,

30
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -35,6 +35,7 @@ import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -97,7 +98,6 @@ import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -107,6 +107,7 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -200,8 +201,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
boolean sent = false; boolean sent = false;
if (systemContext.isEdgesEnabled() && edgeId != null) { if (systemContext.isEdgesEnabled() && edgeId != null) {
log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId()); log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId());
saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId()); try {
sent = true; saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId()).get();
sent = true;
} catch (InterruptedException | ExecutionException e) {
String errMsg = String.format("[%s][%s][%s] Failed to save rpc request to edge queue %s", tenantId, deviceId, edgeId.getId(), request);
log.error(errMsg, e);
}
} else if (isSendNewRpcAvailable()) { } else if (isSendNewRpcAvailable()) {
sent = rpcSubscriptions.size() > 0; sent = rpcSubscriptions.size() > 0;
Set<UUID> syncSessionSet = new HashSet<>(); Set<UUID> syncSessionSet = new HashSet<>();
@ -810,13 +816,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
systemContext.getTbCoreToTransportService().process(nodeId, msg); systemContext.getTbCoreToTransportService().process(nodeId, msg);
} }
private void saveRpcRequestToEdgeQueue(ToDeviceRpcRequest msg, Integer requestId) { private ListenableFuture<Void> saveRpcRequestToEdgeQueue(ToDeviceRpcRequest msg, Integer requestId) {
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setAction(EdgeEventActionType.RPC_CALL);
edgeEvent.setEntityId(deviceId.getId());
edgeEvent.setType(EdgeEventType.DEVICE);
ObjectNode body = mapper.createObjectNode(); ObjectNode body = mapper.createObjectNode();
body.put("requestId", requestId); body.put("requestId", requestId);
body.put("requestUUID", msg.getId().toString()); body.put("requestUUID", msg.getId().toString());
@ -824,11 +824,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
body.put("expirationTime", msg.getExpirationTime()); body.put("expirationTime", msg.getExpirationTime());
body.put("method", msg.getBody().getMethod()); body.put("method", msg.getBody().getMethod());
body.put("params", msg.getBody().getParams()); body.put("params", msg.getBody().getParams());
edgeEvent.setBody(body);
edgeEvent.setEdgeId(edgeId); EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.DEVICE, EdgeEventActionType.RPC_CALL, deviceId, body);
systemContext.getEdgeEventService().save(edgeEvent);
systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId); return Futures.transform(systemContext.getEdgeEventService().saveAsync(edgeEvent), unused -> {
systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId);
return null;
}, systemContext.getDbCallbackExecutor());
} }
private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) { private List<TsKvProto> toTsKvProtos(@Nullable List<AttributeKvEntry> result) {

2
application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java

@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -84,6 +85,7 @@ import static springfox.documentation.builders.PathSelectors.regex;
@Slf4j @Slf4j
@Configuration @Configuration
@TbCoreComponent @TbCoreComponent
@Profile("!test")
public class SwaggerConfiguration { public class SwaggerConfiguration {
@Value("${swagger.api_path_regex}") @Value("${swagger.api_path_regex}")

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

@ -176,16 +176,16 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
} }
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**");
}
@Autowired @Autowired
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver; private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**")
.permitAll()
);
http.headers().cacheControl().and().frameOptions().disable() http.headers().cacheControl().and().frameOptions().disable()
.and() .and()
.cors() .cors()

2
application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java

@ -55,7 +55,7 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
@Override @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*") registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOriginPatterns("*")
.addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() { .addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() {
@Override @Override

2
application/src/main/java/org/thingsboard/server/controller/EdgeController.java

@ -180,7 +180,7 @@ public class EdgeController extends BaseController {
} }
} }
private void onEdgeCreatedOrUpdated(TenantId tenantId, Edge edge, RuleChain edgeTemplateRootRuleChain, boolean updated, SecurityUser user) throws IOException, ThingsboardException { private void onEdgeCreatedOrUpdated(TenantId tenantId, Edge edge, RuleChain edgeTemplateRootRuleChain, boolean updated, SecurityUser user) throws Exception {
if (!updated) { if (!updated) {
ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edge.getId()); ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edge.getId());
edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, edgeTemplateRootRuleChain.getId()); edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, edgeTemplateRootRuleChain.getId());

24
application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java

@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -49,6 +50,8 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES; import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_DESCRIPTION;
@ -105,7 +108,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)", @ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)",
notes = "Fetch the OTA Package Info object based on the provided OTA Package Id. " + notes = "Fetch the OTA Package Info object based on the provided OTA Package Id. " +
OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET) @RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -123,7 +126,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package (getOtaPackageById)", @ApiOperation(value = "Get OTA Package (getOtaPackageById)",
notes = "Fetch the OTA Package object based on the provided OTA Package Id. " + notes = "Fetch the OTA Package object based on the provided OTA Package Id. " +
"The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH, "The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET) @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -144,8 +147,8 @@ public class OtaPackageController extends BaseController {
"Specify existing OTA Package id to update the OTA Package Info. " + "Specify existing OTA Package id to update the OTA Package Info. " +
"Referencing non-existing OTA Package Id will cause 'Not Found' error. " + "Referencing non-existing OTA Package Id will cause 'Not Found' error. " +
"\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH, "\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json", produces = APPLICATION_JSON_VALUE,
consumes = "application/json") consumes = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST) @RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
@ResponseBody @ResponseBody
@ -168,9 +171,10 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Save OTA Package data (saveOtaPackageData)", @ApiOperation(value = "Save OTA Package data (saveOtaPackageData)",
notes = "Update the OTA Package. Adds the date to the existing OTA Package Info" + TENANT_AUTHORITY_PARAGRAPH, notes = "Update the OTA Package. Adds the date to the existing OTA Package Info" + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE,
consumes = MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST) @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST, consumes = MULTIPART_FORM_DATA_VALUE)
@ResponseBody @ResponseBody
public OtaPackageInfo saveOtaPackageData(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION) public OtaPackageInfo saveOtaPackageData(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId, @PathVariable(OTA_PACKAGE_ID) String strOtaPackageId,
@ -179,7 +183,7 @@ public class OtaPackageController extends BaseController {
@ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES) @ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES)
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr, @RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@ApiParam(value = "OTA Package data.") @ApiParam(value = "OTA Package data.")
@RequestBody MultipartFile file) throws ThingsboardException { @RequestPart MultipartFile file) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId); checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr); checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
try { try {
@ -221,7 +225,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)", @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " + notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET) @RequestMapping(value = "/otaPackages", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -246,7 +250,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)", @ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " + notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH, PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET) @RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET)
@ResponseBody @ResponseBody
@ -278,7 +282,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Delete OTA Package (deleteOtaPackage)", @ApiOperation(value = "Delete OTA Package (deleteOtaPackage)",
notes = "Deletes the OTA Package. Referencing non-existing OTA Package Id will cause an error. " + notes = "Deletes the OTA Package. Referencing non-existing OTA Package Id will cause an error. " +
"Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH, "Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH,
produces = "application/json") produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE) @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE)
@ResponseBody @ResponseBody

74
application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java

@ -16,11 +16,16 @@
package org.thingsboard.server.service.edge; package org.thingsboard.server.service.edge;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -42,7 +47,6 @@ import org.thingsboard.server.service.edge.rpc.processor.RelationEdgeProcessor;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -76,29 +80,29 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Autowired @Autowired
private CustomerEdgeProcessor customerProcessor; private CustomerEdgeProcessor customerProcessor;
private ExecutorService tsCallBackExecutor; private ExecutorService dbCallBackExecutor;
@PostConstruct @PostConstruct
public void initExecutor() { public void initExecutor() {
tsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications")); dbCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications"));
} }
@PreDestroy @PreDestroy
public void shutdownExecutor() { public void shutdownExecutor() {
if (tsCallBackExecutor != null) { if (dbCallBackExecutor != null) {
tsCallBackExecutor.shutdownNow(); dbCallBackExecutor.shutdownNow();
} }
} }
@Override @Override
public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException { public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws Exception {
edge.setRootRuleChainId(ruleChainId); edge.setRootRuleChainId(ruleChainId);
Edge savedEdge = edgeService.saveEdge(edge); Edge savedEdge = edgeService.saveEdge(edge);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, null); saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, null).get();
return savedEdge; return savedEdge;
} }
private void saveEdgeEvent(TenantId tenantId, private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId, EdgeId edgeId,
EdgeEventType type, EdgeEventType type,
EdgeEventActionType action, EdgeEventActionType action,
@ -107,17 +111,12 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body); tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = new EdgeEvent(); EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setTenantId(tenantId); return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
edgeEvent.setType(type); clusterService.onEdgeEventUpdate(tenantId, edgeId);
edgeEvent.setAction(action); return null;
if (entityId != null) { }, dbCallBackExecutor);
edgeEvent.setEntityId(entityId.getId());
}
edgeEvent.setBody(body);
edgeEventService.save(edgeEvent);
clusterService.onEdgeEventUpdate(tenantId, edgeId);
} }
@Override @Override
@ -126,9 +125,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
try { try {
TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB()));
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
ListenableFuture<Void> future;
switch (type) { switch (type) {
case EDGE: case EDGE:
edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg);
break; break;
case USER: case USER:
case ASSET: case ASSET:
@ -137,33 +137,47 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case ENTITY_VIEW: case ENTITY_VIEW:
case DASHBOARD: case DASHBOARD:
case RULE_CHAIN: case RULE_CHAIN:
entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg); future = entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break; break;
case CUSTOMER: case CUSTOMER:
customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg);
break; break;
case WIDGETS_BUNDLE: case WIDGETS_BUNDLE:
case WIDGET_TYPE: case WIDGET_TYPE:
entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg); future = entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
break; break;
case ALARM: case ALARM:
alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg);
break; break;
case RELATION: case RELATION:
relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg); future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg);
break; break;
default: default:
log.warn("Edge event type [{}] is not designed to be pushed to edge", type); log.warn("Edge event type [{}] is not designed to be pushed to edge", type);
future = Futures.immediateFuture(null);
} }
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Void unused) {
callback.onSuccess();
}
@Override
public void onFailure(Throwable throwable) {
callBackFailure(edgeNotificationMsg, callback, throwable);
}
}, dbCallBackExecutor);
} catch (Exception e) { } catch (Exception e) {
callback.onFailure(e); callBackFailure(edgeNotificationMsg, callback, e);
String errMsg = String.format("Can't push to edge updates, edgeNotificationMsg [%s]", edgeNotificationMsg);
log.error(errMsg, e);
} finally {
callback.onSuccess();
} }
} }
private void callBackFailure(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) {
String errMsg = String.format("Can't push to edge updates, edgeNotificationMsg [%s]", edgeNotificationMsg);
log.error(errMsg, throwable);
callback.onFailure(throwable);
}
} }

4
application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java

@ -21,11 +21,9 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import java.io.IOException;
public interface EdgeNotificationService { public interface EdgeNotificationService {
Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException; Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws Exception;
void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback); void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback);
} }

48
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventUtils.java

@ -1,48 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.service.edge.rpc;
import com.fasterxml.jackson.databind.JsonNode;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
public final class EdgeEventUtils {
private EdgeEventUtils() {
}
public static EdgeEvent constructEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
EntityId entityId,
JsonNode body) {
EdgeEvent edgeEvent = new EdgeEvent();
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId);
edgeEvent.setType(type);
edgeEvent.setAction(action);
if (entityId != null) {
edgeEvent.setEntityId(entityId.getId());
}
edgeEvent.setBody(body);
return edgeEvent;
}
}

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.service.edge.rpc; package org.thingsboard.server.service.edge.rpc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import io.grpc.Server; import io.grpc.Server;
@ -71,7 +70,6 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private final ConcurrentMap<EdgeId, Lock> sessionNewEventsLocks = new ConcurrentHashMap<>(); private final ConcurrentMap<EdgeId, Lock> sessionNewEventsLocks = new ConcurrentHashMap<>();
private final Map<EdgeId, Boolean> sessionNewEvents = new HashMap<>(); private final Map<EdgeId, Boolean> sessionNewEvents = new HashMap<>();
private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>(); private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>();
private static final ObjectMapper mapper = new ObjectMapper();
@Value("${edges.rpc.port}") @Value("${edges.rpc.port}")
private int rpcPort; private int rpcPort;
@ -159,7 +157,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
@Override @Override
public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) { public StreamObserver<RequestMsg> handleMsgs(StreamObserver<ResponseMsg> outputStream) {
return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper, sendDownlinkExecutorService).getInputStream(); return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, sendDownlinkExecutorService).getInputStream();
} }
@Override @Override

11
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -16,7 +16,6 @@
package org.thingsboard.server.service.edge.rpc; package org.thingsboard.server.service.edge.rpc;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -96,7 +95,6 @@ public final class EdgeGrpcSession implements Closeable {
private final UUID sessionId; private final UUID sessionId;
private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener; private final BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener;
private final Consumer<EdgeId> sessionCloseListener; private final Consumer<EdgeId> sessionCloseListener;
private final ObjectMapper mapper;
private final EdgeSessionState sessionState = new EdgeSessionState(); private final EdgeSessionState sessionState = new EdgeSessionState();
@ -112,13 +110,12 @@ public final class EdgeGrpcSession implements Closeable {
private ScheduledExecutorService sendDownlinkExecutorService; private ScheduledExecutorService sendDownlinkExecutorService;
EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener, EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, BiConsumer<EdgeId, EdgeGrpcSession> sessionOpenListener,
Consumer<EdgeId> sessionCloseListener, ObjectMapper mapper, ScheduledExecutorService sendDownlinkExecutorService) { Consumer<EdgeId> sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService) {
this.sessionId = UUID.randomUUID(); this.sessionId = UUID.randomUUID();
this.ctx = ctx; this.ctx = ctx;
this.outputStream = outputStream; this.outputStream = outputStream;
this.sessionOpenListener = sessionOpenListener; this.sessionOpenListener = sessionOpenListener;
this.sessionCloseListener = sessionCloseListener; this.sessionCloseListener = sessionCloseListener;
this.mapper = mapper;
this.sendDownlinkExecutorService = sendDownlinkExecutorService; this.sendDownlinkExecutorService = sendDownlinkExecutorService;
initInputStream(); initInputStream();
} }
@ -402,11 +399,11 @@ public final class EdgeGrpcSession implements Closeable {
Runnable sendDownlinkMsgsTask = () -> { Runnable sendDownlinkMsgsTask = () -> {
try { try {
if (isConnected() && sessionState.getPendingMsgsMap().values().size() > 0) { if (isConnected() && sessionState.getPendingMsgsMap().values().size() > 0) {
List<DownlinkMsg> copy = new ArrayList<>(sessionState.getPendingMsgsMap().values());
if (!firstRun) { if (!firstRun) {
log.warn("[{}] Failed to deliver the batch: {}", this.sessionId, sessionState.getPendingMsgsMap().values()); log.warn("[{}] Failed to deliver the batch: {}", this.sessionId, copy);
} }
log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, sessionState.getPendingMsgsMap().values().size()); log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, copy.size());
List<DownlinkMsg> copy = new ArrayList<>(sessionState.getPendingMsgsMap().values());
for (DownlinkMsg downlinkMsg : copy) { for (DownlinkMsg downlinkMsg : copy) {
sendDownlinkMsg(ResponseMsg.newBuilder() sendDownlinkMsg(ResponseMsg.newBuilder()
.setDownlinkMsg(downlinkMsg) .setDownlinkMsg(downlinkMsg)

10
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java

@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils; import org.apache.commons.lang3.text.WordUtils;
import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -35,7 +36,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.settings.AdminSettingsService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -80,19 +80,19 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
List<EdgeEvent> result = new ArrayList<>(); List<EdgeEvent> result = new ArrayList<>();
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail"); AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings))); EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue()); AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings))); EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
AdminSettings systemMailTemplates = loadMailTemplates(); AdminSettings systemMailTemplates = loadMailTemplates();
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates))); EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue()); AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS, result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates))); EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
// @voba - returns PageData object to be in sync with other fetchers // @voba - returns PageData object to be in sync with other fetchers

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
@ -41,7 +41,7 @@ public class AssetsEdgeEventFetcher extends BasePageableEdgeEventFetcher<Asset>
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Asset asset) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Asset asset) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET,
EdgeEventActionType.ADDED, asset.getId(), null); EdgeEventActionType.ADDED, asset.getId(), null);
} }
} }

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
@ -41,7 +41,7 @@ public abstract class BaseUsersEdgeEventFetcher extends BasePageableEdgeEventFet
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, User user) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, User user) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
EdgeEventActionType.ADDED, user.getId(), null); EdgeEventActionType.ADDED, user.getId(), null);
} }

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
@ -41,7 +41,7 @@ public abstract class BaseWidgetsBundlesEdgeEventFetcher extends BasePageableEdg
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, WidgetsBundle widgetsBundle) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, WidgetsBundle widgetsBundle) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE,
EdgeEventActionType.ADDED, widgetsBundle.getId(), null); EdgeEventActionType.ADDED, widgetsBundle.getId(), null);
} }

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -24,7 +25,6 @@ import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -41,7 +41,7 @@ public class CustomerEdgeEventFetcher implements EdgeEventFetcher {
@Override @Override
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
List<EdgeEvent> result = new ArrayList<>(); List<EdgeEvent> result = new ArrayList<>();
result.add(EdgeEventUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(), result.add(EdgeUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(),
EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null)); EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null));
// @voba - returns PageData object to be in sync with other fetchers // @voba - returns PageData object to be in sync with other fetchers
return new PageData<>(result, 1, result.size(), false); return new PageData<>(result, 1, result.size(), false);

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
@ -41,7 +41,7 @@ public class DashboardsEdgeEventFetcher extends BasePageableEdgeEventFetcher<Das
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DashboardInfo dashboardInfo) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DashboardInfo dashboardInfo) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DASHBOARD, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DASHBOARD,
EdgeEventActionType.ADDED, dashboardInfo.getId(), null); EdgeEventActionType.ADDED, dashboardInfo.getId(), null);
} }
} }

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DeviceProfilesEdgeEventFetcher.java

@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.device.DeviceProfileService; import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@AllArgsConstructor @AllArgsConstructor
@Slf4j @Slf4j
@ -41,7 +41,7 @@ public class DeviceProfilesEdgeEventFetcher extends BasePageableEdgeEventFetcher
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DeviceProfile deviceProfile) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, DeviceProfile deviceProfile) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE_PROFILE,
EdgeEventActionType.ADDED, deviceProfile.getId(), null); EdgeEventActionType.ADDED, deviceProfile.getId(), null);
} }
} }

4
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/RuleChainsEdgeEventFetcher.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@Slf4j @Slf4j
@AllArgsConstructor @AllArgsConstructor
@ -41,7 +41,7 @@ public class RuleChainsEdgeEventFetcher extends BasePageableEdgeEventFetcher<Rul
@Override @Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, RuleChain ruleChain) { EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, RuleChain ruleChain) {
return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN,
EdgeEventActionType.ADDED, ruleChain.getId(), null); EdgeEventActionType.ADDED, ruleChain.getId(), null);
} }
} }

67
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java

@ -16,11 +16,9 @@
package org.thingsboard.server.service.edge.rpc.processor; package org.thingsboard.server.service.edge.rpc.processor;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
@ -43,6 +41,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Component @Component
@ -148,49 +148,44 @@ public class AlarmEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg; return downlinkMsg;
} }
public void processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException { public ListenableFuture<Void> processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
switch (actionType) { switch (actionType) {
case DELETED: case DELETED:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
Alarm alarm = mapper.readValue(edgeNotificationMsg.getBody(), Alarm.class); Alarm deletedAlarm = mapper.readValue(edgeNotificationMsg.getBody(), Alarm.class);
saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, mapper.valueToTree(alarm)); return saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, mapper.valueToTree(deletedAlarm));
break;
default: default:
ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId); ListenableFuture<Alarm> alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
Futures.addCallback(alarmFuture, new FutureCallback<Alarm>() { return Futures.transformAsync(alarmFuture, alarm -> {
@Override if (alarm == null) {
public void onSuccess(@Nullable Alarm alarm) { return Futures.immediateFuture(null);
if (alarm != null) {
EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());
if (type != null) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<EdgeId> pageData;
do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId edgeId : pageData.getData()) {
saveEdgeEvent(tenantId,
edgeId,
EdgeEventType.ALARM,
EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
alarmId,
null);
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
}
}
} }
EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());
@Override if (type == null) {
public void onFailure(Throwable t) { return Futures.immediateFuture(null);
log.warn("[{}] can't find alarm by id [{}] {}", tenantId.getId(), alarmId.getId(), t);
} }
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<EdgeId> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId relatedEdgeId : pageData.getData()) {
futures.add(saveEdgeEvent(tenantId,
relatedEdgeId,
EdgeEventType.ALARM,
EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
alarmId,
null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
} }
} }

41
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java

@ -17,10 +17,13 @@ package org.thingsboard.server.service.edge.rpc.processor;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
@ -67,6 +70,9 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.state.DeviceStateService;
import java.util.ArrayList;
import java.util.List;
@Slf4j @Slf4j
public abstract class BaseEdgeProcessor { public abstract class BaseEdgeProcessor {
@ -179,27 +185,22 @@ public abstract class BaseEdgeProcessor {
@Autowired @Autowired
protected DbCallbackExecutorService dbCallbackExecutorService; protected DbCallbackExecutorService dbCallbackExecutorService;
protected void saveEdgeEvent(TenantId tenantId, protected ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId, EdgeId edgeId,
EdgeEventType type, EdgeEventType type,
EdgeEventActionType action, EdgeEventActionType action,
EntityId entityId, EntityId entityId,
JsonNode body) { JsonNode body) {
log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " + log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " +
"action [{}], entityId [{}], body [{}]", "action [{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body); tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = new EdgeEvent(); EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
edgeEvent.setTenantId(tenantId);
edgeEvent.setEdgeId(edgeId); return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
edgeEvent.setType(type); tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
edgeEvent.setAction(action); return null;
if (entityId != null) { }, dbCallbackExecutorService);
edgeEvent.setEntityId(entityId.getId());
}
edgeEvent.setBody(body);
edgeEventService.save(edgeEvent);
tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
} }
protected CustomerId getCustomerIdIfEdgeAssignedToCustomer(HasCustomerId hasCustomerIdEntity, Edge edge) { protected CustomerId getCustomerIdIfEdgeAssignedToCustomer(HasCustomerId hasCustomerIdEntity, Edge edge) {
@ -210,19 +211,21 @@ public abstract class BaseEdgeProcessor {
} }
} }
protected void processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) { protected ListenableFuture<Void> processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData; PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do { do {
pageData = edgeService.findEdgesByTenantId(tenantId, pageLink); pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (Edge edge : pageData.getData()) { for (Edge edge : pageData.getData()) {
saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null); futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null));
} }
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} }
} while (pageData != null && pageData.hasNext()); } while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
} }

16
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.service.edge.rpc.processor; package org.thingsboard.server.service.edge.rpc.processor;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
@ -35,6 +37,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Component @Component
@ -70,7 +74,7 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg; return downlinkMsg;
} }
public void processCustomerNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { public ListenableFuture<Void> processCustomerNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
UUID uuid = new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()); UUID uuid = new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB());
@ -79,22 +83,24 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
case UPDATED: case UPDATED:
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Edge> pageData; PageData<Edge> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do { do {
pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink); pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (Edge edge : pageData.getData()) { for (Edge edge : pageData.getData()) {
saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null); futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null));
} }
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} }
} while (pageData != null && pageData.hasNext()); } while (pageData != null && pageData.hasNext());
break; return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
case DELETED: case DELETED:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
saveEdgeEvent(tenantId, edgeId, type, actionType, customerId, null); return saveEdgeEvent(tenantId, edgeId, type, actionType, customerId, null);
break; default:
return Futures.immediateFuture(null);
} }
} }

26
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java

@ -84,7 +84,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
if (deviceAlreadyExistsForThisEdge) { if (deviceAlreadyExistsForThisEdge) {
log.info("[{}] Device with name '{}' already exists on the cloud, and related to this edge [{}]. " + log.info("[{}] Device with name '{}' already exists on the cloud, and related to this edge [{}]. " +
"deviceUpdateMsg [{}], Updating device", tenantId, deviceName, edge.getId(), deviceUpdateMsg); "deviceUpdateMsg [{}], Updating device", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
updateDevice(tenantId, edge, deviceUpdateMsg); return updateDevice(tenantId, edge, deviceUpdateMsg);
} else { } else {
log.info("[{}] Device with name '{}' already exists on the cloud, but not related to this edge [{}]. deviceUpdateMsg [{}]." + log.info("[{}] Device with name '{}' already exists on the cloud, but not related to this edge [{}]. deviceUpdateMsg [{}]." +
"Creating a new device with random prefix and relate to this edge", tenantId, deviceName, edge.getId(), deviceUpdateMsg); "Creating a new device with random prefix and relate to this edge", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
@ -99,8 +99,10 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
} }
ObjectNode body = mapper.createObjectNode(); ObjectNode body = mapper.createObjectNode();
body.put("conflictName", deviceName); body.put("conflictName", deviceName);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body); ListenableFuture<Void> input = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null); return Futures.transformAsync(input, unused ->
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null),
dbCallbackExecutorService);
} }
} else { } else {
log.info("[{}] Creating new device and replacing device entity on the edge [{}]", tenantId, deviceUpdateMsg); log.info("[{}] Creating new device and replacing device entity on the edge [{}]", tenantId, deviceUpdateMsg);
@ -111,24 +113,22 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
log.error(errMsg, e); log.error(errMsg, e);
return Futures.immediateFuture(null); return Futures.immediateFuture(null);
} }
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, device.getId(), null); return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, device.getId(), null);
} }
break;
case ENTITY_UPDATED_RPC_MESSAGE: case ENTITY_UPDATED_RPC_MESSAGE:
updateDevice(tenantId, edge, deviceUpdateMsg); return updateDevice(tenantId, edge, deviceUpdateMsg);
break;
case ENTITY_DELETED_RPC_MESSAGE: case ENTITY_DELETED_RPC_MESSAGE:
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
Device deviceToDelete = deviceService.findDeviceById(tenantId, deviceId); Device deviceToDelete = deviceService.findDeviceById(tenantId, deviceId);
if (deviceToDelete != null) { if (deviceToDelete != null) {
deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId()); deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
} }
break; return Futures.immediateFuture(null);
case UNRECOGNIZED: case UNRECOGNIZED:
default:
log.error("Unsupported msg type {}", deviceUpdateMsg.getMsgType()); log.error("Unsupported msg type {}", deviceUpdateMsg.getMsgType());
return Futures.immediateFailedFuture(new RuntimeException("Unsupported msg type " + deviceUpdateMsg.getMsgType())); return Futures.immediateFailedFuture(new RuntimeException("Unsupported msg type " + deviceUpdateMsg.getMsgType()));
} }
return Futures.immediateFuture(null);
} }
private boolean isDeviceAlreadyExistsOnCloudForThisEdge(TenantId tenantId, Edge edge, Device device) { private boolean isDeviceAlreadyExistsOnCloudForThisEdge(TenantId tenantId, Edge edge, Device device) {
@ -174,7 +174,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
} }
private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { private ListenableFuture<Void> updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB())); DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
Device device = deviceService.findDeviceById(tenantId, deviceId); Device device = deviceService.findDeviceById(tenantId, deviceId);
if (device != null) { if (device != null) {
@ -194,9 +194,11 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
} }
Device savedDevice = deviceService.saveDevice(device); Device savedDevice = deviceService.saveDevice(device);
tbClusterService.onDeviceUpdated(savedDevice, device); tbClusterService.onDeviceUpdated(savedDevice, device);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null); return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
} else { } else {
log.warn("[{}] can't find device [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId()); String errMsg = String.format("[%s] can't find device [%s], edge [%s]", tenantId, deviceUpdateMsg, edge.getId());
log.warn(errMsg);
return Futures.immediateFailedFuture(new RuntimeException(errMsg));
} }
} }

71
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java

@ -15,11 +15,9 @@
*/ */
package org.thingsboard.server.service.edge.rpc.processor; package org.thingsboard.server.service.edge.rpc.processor;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
@ -33,6 +31,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import java.util.UUID;
@Component @Component
@ -40,7 +40,7 @@ import java.util.UUID;
@TbCoreComponent @TbCoreComponent
public class EdgeProcessor extends BaseEdgeProcessor { public class EdgeProcessor extends BaseEdgeProcessor {
public void processEdgeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { public ListenableFuture<Void> processEdgeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
try { try {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
@ -49,54 +49,43 @@ public class EdgeProcessor extends BaseEdgeProcessor {
case ASSIGNED_TO_CUSTOMER: case ASSIGNED_TO_CUSTOMER:
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId); edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
Futures.addCallback(edgeFuture, new FutureCallback<Edge>() { return Futures.transformAsync(edgeFuture, edge -> {
@Override if (edge == null || customerId.isNullUid()) {
public void onSuccess(@Nullable Edge edge) { return Futures.immediateFuture(null);
if (edge != null && !customerId.isNullUid()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null);
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<User> pageData;
do {
pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null);
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
}
}
@Override
public void onFailure(Throwable t) {
log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
} }
List<ListenableFuture<Void>> futures = new ArrayList<>();
futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null));
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<User> pageData;
do {
pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
for (User user : pageData.getData()) {
futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
break;
case UNASSIGNED_FROM_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER:
CustomerId customerIdToDelete = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class); CustomerId customerIdToDelete = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId); edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
Futures.addCallback(edgeFuture, new FutureCallback<Edge>() { return Futures.transformAsync(edgeFuture, edge -> {
@Override if (edge == null || customerIdToDelete.isNullUid()) {
public void onSuccess(@Nullable Edge edge) { return Futures.immediateFuture(null);
if (edge != null && !customerIdToDelete.isNullUid()) {
saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null);
}
}
@Override
public void onFailure(Throwable t) {
log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
} }
return saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null);
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
break; default:
return Futures.immediateFuture(null);
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during processing edge event", e); log.error("Exception during processing edge event", e);
return Futures.immediateFailedFuture(e);
} }
} }
} }

130
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java

@ -15,11 +15,9 @@
*/ */
package org.thingsboard.server.service.edge.rpc.processor; package org.thingsboard.server.service.edge.rpc.processor;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
@ -45,6 +43,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -89,92 +88,107 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg; return downlinkMsg;
} }
public void processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { public ListenableFuture<Void> processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type,
new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
EdgeId edgeId = null; EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg);
if (edgeNotificationMsg.getEdgeIdMSB() != 0 && edgeNotificationMsg.getEdgeIdLSB() != 0) {
edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
}
switch (actionType) { switch (actionType) {
case ADDED: // used only for USER entity case ADDED: // used only for USER entity
case UPDATED: case UPDATED:
case CREDENTIALS_UPDATED: case CREDENTIALS_UPDATED:
pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType); return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
break;
case ASSIGNED_TO_CUSTOMER: case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER: case UNASSIGNED_FROM_CUSTOMER:
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); return pushNotificationToAllRelatedCustomerEdges(tenantId, edgeNotificationMsg, entityId, actionType, type);
PageData<EdgeId> pageData;
do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId relatedEdgeId : pageData.getData()) {
try {
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
ListenableFuture<Edge> future = edgeService.findEdgeByIdAsync(tenantId, relatedEdgeId);
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Edge edge) {
if (edge != null && edge.getCustomerId() != null &&
!edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) {
saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null);
}
}
@Override
public void onFailure(Throwable t) {
log.error("Failed to find edge by id [{}] {}", edgeNotificationMsg, t);
}
}, dbCallbackExecutorService);
} catch (Exception e) {
log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e);
}
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
break;
case DELETED: case DELETED:
if (edgeId != null) { if (edgeId != null) {
saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
} else { } else {
pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType); return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
} }
break;
case ASSIGNED_TO_EDGE: case ASSIGNED_TO_EDGE:
case UNASSIGNED_FROM_EDGE: case UNASSIGNED_FROM_EDGE:
saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null); ListenableFuture<Void> future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
if (type.equals(EdgeEventType.RULE_CHAIN)) { return Futures.transformAsync(future, unused -> {
updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId); if (type.equals(EdgeEventType.RULE_CHAIN)) {
return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
} else {
return Futures.immediateFuture(null);
}
}, dbCallbackExecutorService);
default:
return Futures.immediateFuture(null);
}
}
private ListenableFuture<Void> pushNotificationToAllRelatedCustomerEdges(TenantId tenantId,
TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg,
EntityId entityId,
EdgeEventActionType actionType,
EdgeEventType type) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<EdgeId> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId relatedEdgeId : pageData.getData()) {
try {
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
ListenableFuture<Edge> future = edgeService.findEdgeByIdAsync(tenantId, relatedEdgeId);
futures.add(Futures.transformAsync(future, edge -> {
if (edge != null && edge.getCustomerId() != null &&
!edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) {
return saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null);
} else {
return Futures.immediateFuture(null);
}
}, dbCallbackExecutorService));
} catch (Exception e) {
log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e);
return Futures.immediateFailedFuture(e);
}
} }
break; if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
private EdgeId safeGetEdgeId(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
if (edgeNotificationMsg.getEdgeIdMSB() != 0 && edgeNotificationMsg.getEdgeIdLSB() != 0) {
return new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
} else {
return null;
} }
} }
private void pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) { private ListenableFuture<Void> pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<EdgeId> pageData; PageData<EdgeId> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do { do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink); pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId relatedEdgeId : pageData.getData()) { for (EdgeId relatedEdgeId : pageData.getData()) {
saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null); futures.add(saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null));
} }
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} }
} while (pageData != null && pageData.hasNext()); } while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
private void updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) { private ListenableFuture<Void> updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<RuleChain> pageData; PageData<RuleChain> pageData;
List<ListenableFuture<Void>> futures = new ArrayList<>();
do { do {
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink); pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
@ -185,12 +199,12 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
if (connectionInfos != null && !connectionInfos.isEmpty()) { if (connectionInfos != null && !connectionInfos.isEmpty()) {
for (RuleChainConnectionInfo connectionInfo : connectionInfos) { for (RuleChainConnectionInfo connectionInfo : connectionInfos) {
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) { if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) {
saveEdgeEvent(tenantId, futures.add(saveEdgeEvent(tenantId,
edgeId, edgeId,
EdgeEventType.RULE_CHAIN_METADATA, EdgeEventType.RULE_CHAIN_METADATA,
EdgeEventActionType.UPDATED, EdgeEventActionType.UPDATED,
ruleChain.getId(), ruleChain.getId(),
null); null));
} }
} }
} }
@ -201,9 +215,10 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
} }
} }
} while (pageData != null && pageData.hasNext()); } while (pageData != null && pageData.hasNext());
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
public void processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) { public ListenableFuture<Void> processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()); EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB())); EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
@ -211,8 +226,9 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
case ADDED: case ADDED:
case UPDATED: case UPDATED:
case DELETED: case DELETED:
processActionForAllEdges(tenantId, type, actionType, entityId); return processActionForAllEdges(tenantId, type, actionType, entityId);
break; default:
return Futures.immediateFuture(null);
} }
} }
} }

37
application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java

@ -126,24 +126,29 @@ public class RelationEdgeProcessor extends BaseEdgeProcessor {
.build(); .build();
} }
public void processRelationNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException { public ListenableFuture<Void> processRelationNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
EntityRelation relation = mapper.readValue(edgeNotificationMsg.getBody(), EntityRelation.class); EntityRelation relation = mapper.readValue(edgeNotificationMsg.getBody(), EntityRelation.class);
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && if (relation.getFrom().getEntityType().equals(EntityType.EDGE) ||
!relation.getTo().getEntityType().equals(EntityType.EDGE)) { relation.getTo().getEntityType().equals(EntityType.EDGE)) {
Set<EdgeId> uniqueEdgeIds = new HashSet<>(); return Futures.immediateFuture(null);
uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getTo())); }
uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getFrom()));
if (!uniqueEdgeIds.isEmpty()) { Set<EdgeId> uniqueEdgeIds = new HashSet<>();
for (EdgeId edgeId : uniqueEdgeIds) { uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getTo()));
saveEdgeEvent(tenantId, uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getFrom()));
edgeId, if (uniqueEdgeIds.isEmpty()) {
EdgeEventType.RELATION, return Futures.immediateFuture(null);
EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()), }
null, List<ListenableFuture<Void>> futures = new ArrayList<>();
mapper.valueToTree(relation)); for (EdgeId edgeId : uniqueEdgeIds) {
} futures.add(saveEdgeEvent(tenantId,
} edgeId,
EdgeEventType.RELATION,
EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
null,
mapper.valueToTree(relation)));
} }
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
private List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) { private List<EdgeId> findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {

283
application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java

@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils; import org.thingsboard.server.common.data.EdgeUtils;
@ -71,9 +72,7 @@ import org.thingsboard.server.gen.edge.v1.RelationRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg; import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg; import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg; import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.cluster.TbClusterService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -122,13 +121,13 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override @Override
public ListenableFuture<Void> processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) { public ListenableFuture<Void> processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg); log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg);
if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) { if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() == 0 || ruleChainMetadataRequestMsg.getRuleChainIdLSB() == 0) {
RuleChainId ruleChainId = return Futures.immediateFuture(null);
new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
saveEdgeEvent(tenantId, edge.getId(),
EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null);
} }
return Futures.immediateFuture(null); RuleChainId ruleChainId =
new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
return saveEdgeEvent(tenantId, edge.getId(),
EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null);
} }
@Override @Override
@ -138,63 +137,72 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
EntityType.valueOf(attributesRequestMsg.getEntityType()), EntityType.valueOf(attributesRequestMsg.getEntityType()),
new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB())); new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB()));
final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
if (type != null) { if (type == null) {
SettableFuture<Void> futureToSet = SettableFuture.create(); log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType());
String scope = attributesRequestMsg.getScope(); return Futures.immediateFuture(null);
ListenableFuture<List<AttributeKvEntry>> findAttrFuture = attributesService.findAll(tenantId, entityId, scope); }
Futures.addCallback(findAttrFuture, new FutureCallback<List<AttributeKvEntry>>() { SettableFuture<Void> futureToSet = SettableFuture.create();
@Override String scope = attributesRequestMsg.getScope();
public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) { ListenableFuture<List<AttributeKvEntry>> findAttrFuture = attributesService.findAll(tenantId, entityId, scope);
if (ssAttributes != null && !ssAttributes.isEmpty()) { Futures.addCallback(findAttrFuture, new FutureCallback<>() {
try { @Override
Map<String, Object> entityData = new HashMap<>(); public void onSuccess(@Nullable List<AttributeKvEntry> ssAttributes) {
ObjectNode attributes = mapper.createObjectNode(); if (ssAttributes == null || ssAttributes.isEmpty()) {
for (AttributeKvEntry attr : ssAttributes) { log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId,
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { edge.getName(),
attributes.put(attr.getKey(), attr.getBooleanValue().get()); entityId.getEntityType(),
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { entityId.getId());
attributes.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
attributes.put(attr.getKey(), attr.getLongValue().get());
} else {
attributes.put(attr.getKey(), attr.getValueAsString());
}
}
entityData.put("kv", attributes);
entityData.put("scope", scope);
JsonNode body = mapper.valueToTree(entityData);
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
saveEdgeEvent(tenantId,
edge.getId(),
type,
EdgeEventActionType.ATTRIBUTES_UPDATED,
entityId,
body);
} catch (Exception e) {
log.error("[{}] Failed to save attribute updates to the edge", edge.getName(), e);
futureToSet.setException(new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e));
return;
}
} else {
log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId,
edge.getName(),
entityId.getEntityType(),
entityId.getId());
}
futureToSet.set(null); futureToSet.set(null);
return;
} }
@Override try {
public void onFailure(Throwable t) { Map<String, Object> entityData = new HashMap<>();
log.error("Can't find attributes [{}]", attributesRequestMsg, t); ObjectNode attributes = mapper.createObjectNode();
futureToSet.setException(t); for (AttributeKvEntry attr : ssAttributes) {
if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
attributes.put(attr.getKey(), attr.getBooleanValue().get());
} else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
attributes.put(attr.getKey(), attr.getDoubleValue().get());
} else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
attributes.put(attr.getKey(), attr.getLongValue().get());
} else {
attributes.put(attr.getKey(), attr.getValueAsString());
}
}
entityData.put("kv", attributes);
entityData.put("scope", scope);
JsonNode body = mapper.valueToTree(entityData);
log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
ListenableFuture<Void> future = saveEdgeEvent(tenantId, edge.getId(), type, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body);
Futures.addCallback(future, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable Void unused) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable throwable) {
String errMsg = String.format("[%s] Failed to save edge event [%s]", edge.getId(), attributesRequestMsg);
log.error(errMsg, throwable);
futureToSet.setException(new RuntimeException(errMsg, throwable));
}
}, dbCallbackExecutorService);
} catch (Exception e) {
String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg);
log.error(errMsg, e);
futureToSet.setException(new RuntimeException(errMsg, e));
} }
}, dbCallbackExecutorService); }
return futureToSet;
} else { @Override
log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType()); public void onFailure(Throwable t) {
return Futures.immediateFuture(null); String errMsg = String.format("[%s] Can't find attributes [%s]", edge.getId(), attributesRequestMsg);
} log.error(errMsg, t);
futureToSet.setException(new RuntimeException(errMsg, t));
}
}, dbCallbackExecutorService);
return futureToSet;
} }
@Override @Override
@ -209,33 +217,49 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
futures.add(findRelationByQuery(tenantId, edge, entityId, EntitySearchDirection.TO)); futures.add(findRelationByQuery(tenantId, edge, entityId, EntitySearchDirection.TO));
ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures); ListenableFuture<List<List<EntityRelation>>> relationsListFuture = Futures.allAsList(futures);
SettableFuture<Void> futureToSet = SettableFuture.create(); SettableFuture<Void> futureToSet = SettableFuture.create();
Futures.addCallback(relationsListFuture, new FutureCallback<List<List<EntityRelation>>>() { Futures.addCallback(relationsListFuture, new FutureCallback<>() {
@Override @Override
public void onSuccess(@Nullable List<List<EntityRelation>> relationsList) { public void onSuccess(@Nullable List<List<EntityRelation>> relationsList) {
try { try {
if (relationsList != null && !relationsList.isEmpty()) { if (relationsList != null && !relationsList.isEmpty()) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
for (List<EntityRelation> entityRelations : relationsList) { for (List<EntityRelation> entityRelations : relationsList) {
log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size()); log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
for (EntityRelation relation : entityRelations) { for (EntityRelation relation : entityRelations) {
try { try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) && if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) { !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
saveEdgeEvent(tenantId, futures.add(saveEdgeEvent(tenantId,
edge.getId(), edge.getId(),
EdgeEventType.RELATION, EdgeEventType.RELATION,
EdgeEventActionType.ADDED, EdgeEventActionType.ADDED,
null, null,
mapper.valueToTree(relation)); mapper.valueToTree(relation)));
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading relation [{}] to edge on sync!", relation, e); String errMsg = String.format("[%s] Exception during loading relation [%s] to edge on sync!", edge.getId(), relation);
futureToSet.setException(e); log.error(errMsg, e);
futureToSet.setException(new RuntimeException(errMsg, e));
return; return;
} }
} }
} }
Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List<Void> voids) {
futureToSet.set(null);
}
@Override
public void onFailure(Throwable throwable) {
String errMsg = String.format("[%s] Exception during saving edge events [%s]!", edge.getId(), relationRequestMsg);
log.error(errMsg, throwable);
futureToSet.setException(new RuntimeException(errMsg, throwable));
}
}, dbCallbackExecutorService);
} else {
futureToSet.set(null);
} }
futureToSet.set(null);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading relation(s) to edge on sync!", e); log.error("Exception during loading relation(s) to edge on sync!", e);
futureToSet.setException(e); futureToSet.setException(e);
@ -244,8 +268,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override @Override
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
log.error("[{}] Can't find relation by query. Entity id [{}]", tenantId, entityId, t); String errMsg = String.format("[%s] Can't find relation by query. Entity id [%s]!", tenantId, entityId);
futureToSet.setException(t); log.error(errMsg, t);
futureToSet.setException(new RuntimeException(errMsg, t));
} }
}, dbCallbackExecutorService); }, dbCallbackExecutorService);
return futureToSet; return futureToSet;
@ -261,40 +286,42 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override @Override
public ListenableFuture<Void> processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) { public ListenableFuture<Void> processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg); log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg);
if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) { if (deviceCredentialsRequestMsg.getDeviceIdMSB() == 0 || deviceCredentialsRequestMsg.getDeviceIdLSB() == 0) {
DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB())); return Futures.immediateFuture(null);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE,
EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null);
} }
return Futures.immediateFuture(null); DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE,
EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null);
} }
@Override @Override
public ListenableFuture<Void> processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) { public ListenableFuture<Void> processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg); log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg);
if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) { if (userCredentialsRequestMsg.getUserIdMSB() == 0 || userCredentialsRequestMsg.getUserIdLSB() == 0) {
UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB())); return Futures.immediateFuture(null);
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
EdgeEventActionType.CREDENTIALS_UPDATED, userId, null);
} }
return Futures.immediateFuture(null); UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
EdgeEventActionType.CREDENTIALS_UPDATED, userId, null);
} }
@Override @Override
public ListenableFuture<Void> processDeviceProfileDevicesRequestMsg(TenantId tenantId, Edge edge, DeviceProfileDevicesRequestMsg deviceProfileDevicesRequestMsg) { public ListenableFuture<Void> processDeviceProfileDevicesRequestMsg(TenantId tenantId, Edge edge, DeviceProfileDevicesRequestMsg deviceProfileDevicesRequestMsg) {
log.trace("[{}] processDeviceProfileDevicesRequestMsg [{}][{}]", tenantId, edge.getName(), deviceProfileDevicesRequestMsg); log.trace("[{}] processDeviceProfileDevicesRequestMsg [{}][{}]", tenantId, edge.getName(), deviceProfileDevicesRequestMsg);
if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() != 0 && deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() != 0) { if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() == 0 || deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() == 0) {
DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB())); return Futures.immediateFuture(null);
DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); }
if (deviceProfileById != null) { DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB()));
syncDevices(tenantId, edge, deviceProfileById.getName()); DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
} if (deviceProfileById == null) {
return Futures.immediateFuture(null);
} }
return Futures.immediateFuture(null); return syncDevices(tenantId, edge, deviceProfileById.getName());
} }
private void syncDevices(TenantId tenantId, Edge edge, String deviceType) { private ListenableFuture<Void> syncDevices(TenantId tenantId, Edge edge, String deviceType) {
log.trace("[{}] syncDevices [{}][{}]", tenantId, edge.getName(), deviceType); log.trace("[{}] syncDevices [{}][{}]", tenantId, edge.getName(), deviceType);
List<ListenableFuture<Void>> futures = new ArrayList<>();
try { try {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE); PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData<Device> pageData; PageData<Device> pageData;
@ -303,7 +330,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) { if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Device device : pageData.getData()) { for (Device device : pageData.getData()) {
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null); futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null));
} }
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -313,25 +340,26 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
} catch (Exception e) { } catch (Exception e) {
log.error("Exception during loading edge device(s) on sync!", e); log.error("Exception during loading edge device(s) on sync!", e);
} }
return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
@Override @Override
public ListenableFuture<Void> processWidgetBundleTypesRequestMsg(TenantId tenantId, Edge edge, public ListenableFuture<Void> processWidgetBundleTypesRequestMsg(TenantId tenantId, Edge edge,
WidgetBundleTypesRequestMsg widgetBundleTypesRequestMsg) { WidgetBundleTypesRequestMsg widgetBundleTypesRequestMsg) {
log.trace("[{}] processWidgetBundleTypesRequestMsg [{}][{}]", tenantId, edge.getName(), widgetBundleTypesRequestMsg); log.trace("[{}] processWidgetBundleTypesRequestMsg [{}][{}]", tenantId, edge.getName(), widgetBundleTypesRequestMsg);
List<ListenableFuture<Void>> futures = new ArrayList<>();
if (widgetBundleTypesRequestMsg.getWidgetBundleIdMSB() != 0 && widgetBundleTypesRequestMsg.getWidgetBundleIdLSB() != 0) { if (widgetBundleTypesRequestMsg.getWidgetBundleIdMSB() != 0 && widgetBundleTypesRequestMsg.getWidgetBundleIdLSB() != 0) {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(new UUID(widgetBundleTypesRequestMsg.getWidgetBundleIdMSB(), widgetBundleTypesRequestMsg.getWidgetBundleIdLSB())); WidgetsBundleId widgetsBundleId = new WidgetsBundleId(new UUID(widgetBundleTypesRequestMsg.getWidgetBundleIdMSB(), widgetBundleTypesRequestMsg.getWidgetBundleIdLSB()));
WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId); WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId);
if (widgetsBundleById != null) { if (widgetsBundleById != null) {
List<WidgetType> widgetTypesToPush = List<WidgetType> widgetTypesToPush =
widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias()); widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias());
for (WidgetType widgetType : widgetTypesToPush) { for (WidgetType widgetType : widgetTypesToPush) {
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null); futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null));
} }
} }
} }
return Futures.immediateFuture(null); return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
} }
@Override @Override
@ -344,46 +372,35 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
Futures.addCallback(entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), new FutureCallback<>() { Futures.addCallback(entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), new FutureCallback<>() {
@Override @Override
public void onSuccess(@Nullable List<EntityView> entityViews) { public void onSuccess(@Nullable List<EntityView> entityViews) {
try { if (entityViews == null || entityViews.isEmpty()) {
if (entityViews != null && !entityViews.isEmpty()) { futureToSet.set(null);
List<ListenableFuture<Boolean>> futures = new ArrayList<>(); return;
for (EntityView entityView : entityViews) { }
ListenableFuture<Boolean> future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(), List<ListenableFuture<Void>> futures = new ArrayList<>();
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE); for (EntityView entityView : entityViews) {
futures.add(future); ListenableFuture<Boolean> future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
Futures.addCallback(future, new FutureCallback<>() { EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
@Override futures.add(Futures.transformAsync(future, result -> {
public void onSuccess(@Nullable Boolean result) { if (Boolean.TRUE.equals(result)) {
if (Boolean.TRUE.equals(result)) { return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW,
saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW, EdgeEventActionType.ADDED, entityView.getId(), null);
EdgeEventActionType.ADDED, entityView.getId(), null); } else {
} return Futures.immediateFuture(null);
}
@Override
public void onFailure(Throwable t) {
// Do nothing - error handles in allAsList
}
}, dbCallbackExecutorService);
} }
Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() { }, dbCallbackExecutorService));
@Override }
public void onSuccess(@Nullable List<Boolean> result) { Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
futureToSet.set(null); @Override
} public void onSuccess(@Nullable List<Void> result) {
@Override
public void onFailure(Throwable t) {
log.error("Exception during loading relation [{}] to edge on sync!", t, t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
} else {
futureToSet.set(null); futureToSet.set(null);
} }
} catch (Exception e) {
log.error("Exception during loading relation(s) to edge on sync!", e); @Override
futureToSet.setException(e); public void onFailure(Throwable t) {
} log.error("Exception during loading relation to edge on sync!", t);
futureToSet.setException(t);
}
}, dbCallbackExecutorService);
} }
@Override @Override
@ -395,7 +412,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
return futureToSet; return futureToSet;
} }
private void saveEdgeEvent(TenantId tenantId, private ListenableFuture<Void> saveEdgeEvent(TenantId tenantId,
EdgeId edgeId, EdgeId edgeId,
EdgeEventType type, EdgeEventType type,
EdgeEventActionType action, EdgeEventActionType action,
@ -404,10 +421,12 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]", log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body); tenantId, edgeId, type, action, entityId, body);
EdgeEvent edgeEvent = EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body); EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
edgeEventService.save(edgeEvent); return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
tbClusterService.onEdgeEventUpdate(tenantId, edgeId); tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
return null;
}, dbCallbackExecutorService);
} }
} }

4
application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java

@ -19,9 +19,11 @@ import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.sms.SmsSender; import org.thingsboard.rule.engine.api.sms.SmsSender;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory; import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.server.common.data.sms.config.AwsSnsSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.AwsSnsSmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.SmppSmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.TwilioSmsProviderConfiguration; import org.thingsboard.server.common.data.sms.config.TwilioSmsProviderConfiguration;
import org.thingsboard.server.service.sms.aws.AwsSmsSender; import org.thingsboard.server.service.sms.aws.AwsSmsSender;
import org.thingsboard.server.service.sms.smpp.SmppSmsSender;
import org.thingsboard.server.service.sms.twilio.TwilioSmsSender; import org.thingsboard.server.service.sms.twilio.TwilioSmsSender;
@Component @Component
@ -34,6 +36,8 @@ public class DefaultSmsSenderFactory implements SmsSenderFactory {
return new AwsSmsSender((AwsSnsSmsProviderConfiguration)config); return new AwsSmsSender((AwsSnsSmsProviderConfiguration)config);
case TWILIO: case TWILIO:
return new TwilioSmsSender((TwilioSmsProviderConfiguration)config); return new TwilioSmsSender((TwilioSmsProviderConfiguration)config);
case SMPP:
return new SmppSmsSender((SmppSmsProviderConfiguration) config);
default: default:
throw new RuntimeException("Unknown SMS provider type " + config.getType()); throw new RuntimeException("Unknown SMS provider type " + config.getType());
} }

186
application/src/main/java/org/thingsboard/server/service/sms/smpp/SmppSmsSender.java

@ -0,0 +1,186 @@
/**
* 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.service.sms.smpp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.smpp.Connection;
import org.smpp.Data;
import org.smpp.Session;
import org.smpp.TCPIPConnection;
import org.smpp.TimeoutException;
import org.smpp.WrongSessionStateException;
import org.smpp.pdu.Address;
import org.smpp.pdu.BindReceiver;
import org.smpp.pdu.BindRequest;
import org.smpp.pdu.BindResponse;
import org.smpp.pdu.BindTransciever;
import org.smpp.pdu.BindTransmitter;
import org.smpp.pdu.PDUException;
import org.smpp.pdu.SubmitSM;
import org.smpp.pdu.SubmitSMResp;
import org.thingsboard.rule.engine.api.sms.exception.SmsException;
import org.thingsboard.server.common.data.sms.config.SmppSmsProviderConfiguration;
import org.thingsboard.server.service.sms.AbstractSmsSender;
import java.io.IOException;
import java.util.Optional;
@Slf4j
public class SmppSmsSender extends AbstractSmsSender {
protected SmppSmsProviderConfiguration config;
protected Session smppSession;
public SmppSmsSender(SmppSmsProviderConfiguration config) {
if (config.getBindType() == null) {
config.setBindType(SmppSmsProviderConfiguration.SmppBindType.TX);
}
if (StringUtils.isNotEmpty(config.getSourceAddress())) {
if (config.getSourceTon() == null) {
config.setSourceTon((byte) 5);
}
if (config.getSourceNpi() == null) {
config.setSourceNpi((byte) 0);
}
}
if (config.getDestinationTon() == null) {
config.setDestinationTon((byte) 5);
}
if (config.getDestinationNpi() == null) {
config.setDestinationNpi((byte) 0);
}
this.config = config;
this.smppSession = initSmppSession();
}
private SmppSmsSender() {} // for testing purposes
@Override
public int sendSms(String numberTo, String message) throws SmsException {
try {
checkSmppSession();
SubmitSM request = new SubmitSM();
if (StringUtils.isNotEmpty(config.getServiceType())) {
request.setServiceType(config.getServiceType());
}
if (StringUtils.isNotEmpty(config.getSourceAddress())) {
request.setSourceAddr(new Address(config.getSourceTon(), config.getSourceNpi(), config.getSourceAddress()));
}
request.setDestAddr(new Address(config.getDestinationTon(), config.getDestinationNpi(), prepareNumber(numberTo)));
request.setShortMessage(message);
request.setDataCoding(Optional.ofNullable(config.getCodingScheme()).orElse((byte) 0));
request.setReplaceIfPresentFlag((byte) 0);
request.setEsmClass((byte) 0);
request.setProtocolId((byte) 0);
request.setPriorityFlag((byte) 0);
request.setRegisteredDelivery((byte) 0);
request.setSmDefaultMsgId((byte) 0);
SubmitSMResp response = smppSession.submit(request);
log.debug("SMPP submit command status: {}", response.getCommandStatus());
} catch (Exception e) {
throw new RuntimeException(e);
}
return countMessageSegments(message);
}
private synchronized void checkSmppSession() {
if (smppSession == null || !smppSession.isOpened()) {
smppSession = initSmppSession();
}
}
protected Session initSmppSession() {
try {
Connection connection = new TCPIPConnection(config.getHost(), config.getPort());
Session session = new Session(connection);
BindRequest bindRequest;
switch (config.getBindType()) {
case TX:
bindRequest = new BindTransmitter();
break;
case RX:
bindRequest = new BindReceiver();
break;
case TRX:
bindRequest = new BindTransciever();
break;
default:
throw new UnsupportedOperationException("Unsupported bind type " + config.getBindType());
}
bindRequest.setSystemId(config.getSystemId());
bindRequest.setPassword(config.getPassword());
byte interfaceVersion;
switch (config.getProtocolVersion()) {
case "3.3":
interfaceVersion = Data.SMPP_V33;
break;
case "3.4":
interfaceVersion = Data.SMPP_V34;
break;
default:
throw new UnsupportedOperationException("Unsupported SMPP version: " + config.getProtocolVersion());
}
bindRequest.setInterfaceVersion(interfaceVersion);
if (StringUtils.isNotEmpty(config.getSystemType())) {
bindRequest.setSystemType(config.getSystemType());
}
if (StringUtils.isNotEmpty(config.getAddressRange())) {
bindRequest.setAddressRange(config.getDestinationTon(), config.getDestinationNpi(), config.getAddressRange());
}
BindResponse bindResponse = session.bind(bindRequest);
log.debug("SMPP bind response: {}", bindResponse.debugString());
if (bindResponse.getCommandStatus() != 0) {
throw new IllegalStateException("Error status when binding: " + bindResponse.getCommandStatus());
}
return session;
} catch (Exception e) {
throw new IllegalArgumentException("Failed to establish SMPP session: " + ExceptionUtils.getRootCauseMessage(e), e);
}
}
private String prepareNumber(String number) {
if (config.getDestinationTon() == Data.GSM_TON_INTERNATIONAL) {
return StringUtils.removeStart(number, "+");
}
return number;
}
@Override
public void destroy() {
try {
smppSession.unbind();
smppSession.close();
} catch (TimeoutException | PDUException | IOException | WrongSessionStateException e) {
throw new RuntimeException(e);
}
}
}

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

@ -283,6 +283,11 @@ sql:
batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}" batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}" stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
edge_events:
batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}"
batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_EDGE_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
# Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
batch_sort: "${SQL_BATCH_SORT:false}" batch_sort: "${SQL_BATCH_SORT:false}"
# Specify whether to remove null characters from strValue of attributes and timeseries before insert # Specify whether to remove null characters from strValue of attributes and timeseries before insert
@ -487,7 +492,7 @@ spring.mvc.cors:
# Intercept path # Intercept path
"[/api/**]": "[/api/**]":
#Comma-separated list of origins to allow. '*' allows all origins. When not set,CORS support is disabled. #Comma-separated list of origins to allow. '*' allows all origins. When not set,CORS support is disabled.
allowed-origins: "*" allowed-origin-patterns: "*"
#Comma-separated list of methods to allow. '*' allows all methods. #Comma-separated list of methods to allow. '*' allows all methods.
allowed-methods: "*" allowed-methods: "*"
#Comma-separated list of headers to allow in a request. '*' allows all headers. #Comma-separated list of headers to allow in a request. '*' allows all headers.

57
application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java

@ -16,16 +16,25 @@
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootContextLoader; import org.springframework.boot.test.context.SpringBootContextLoader;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.web.socket.config.annotation.EnableWebSocket;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
@ActiveProfiles("test") @ActiveProfiles("test")
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@ -33,9 +42,49 @@ import org.springframework.test.context.web.WebAppConfiguration;
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@Configuration @Configuration
@ComponentScan({"org.thingsboard.server"}) @ComponentScan({"org.thingsboard.server"})
@WebAppConfiguration @EnableWebSocket
@SpringBootTest() @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j @Slf4j
public abstract class AbstractControllerTest extends AbstractWebTest { public abstract class AbstractControllerTest extends AbstractWebTest {
public static final String WS_URL = "ws://localhost:";
@LocalServerPort
protected int wsPort;
private TbTestWebSocketClient wsClient; // lazy
public TbTestWebSocketClient getWsClient() {
if (wsClient == null) {
synchronized (this) {
try {
if (wsClient == null) {
wsClient = buildAndConnectWebSocketClient();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
return wsClient;
}
@Before
public void beforeWsTest() throws Exception {
// placeholder
}
@After
public void afterWsTest() throws Exception {
if (wsClient != null) {
wsClient.close();
}
}
private TbTestWebSocketClient buildAndConnectWebSocketClient() throws URISyntaxException, InterruptedException {
TbTestWebSocketClient wsClient = new TbTestWebSocketClient(new URI(WS_URL + wsPort + "/api/ws/plugins/telemetry?token=" + token));
assertThat(wsClient.connectBlocking(TIMEOUT, TimeUnit.SECONDS)).isTrue();
return wsClient;
}
} }

16
application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java

@ -23,20 +23,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
@Slf4j @Slf4j
public abstract class AbstractInMemoryStorageTest { public abstract class AbstractInMemoryStorageTest {
@Before
public void setUpInMemoryStorage() {
log.info("set up InMemoryStorage");
cleanupInMemStorage();
}
@After
public void tearDownInMemoryStorage() {
log.info("tear down InMemoryStorage");
cleanupInMemStorage();
}
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

44
application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java

@ -18,6 +18,9 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header; import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwt;
@ -67,6 +70,7 @@ import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
@ -97,6 +101,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
@Slf4j @Slf4j
public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
public static final int TIMEOUT = 30;
protected ObjectMapper mapper = new ObjectMapper(); protected ObjectMapper mapper = new ObjectMapper();
@ -106,7 +111,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
private static final String SYS_ADMIN_PASSWORD = "sysadmin"; private static final String SYS_ADMIN_PASSWORD = "sysadmin";
protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org"; protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
private static final String TENANT_ADMIN_PASSWORD = "tenant"; protected static final String TENANT_ADMIN_PASSWORD = "tenant";
protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org"; protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
private static final String CUSTOMER_USER_PASSWORD = "customer"; private static final String CUSTOMER_USER_PASSWORD = "customer";
@ -377,18 +382,23 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
} }
} }
protected DeviceProfile createDeviceProfile(String name) {
return createDeviceProfile(name, null);
}
protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) { protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
DeviceProfile deviceProfile = new DeviceProfile(); DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name); deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT); deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfile.setDescription(name + " Test"); deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData(); DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
deviceProfileData.setConfiguration(configuration); deviceProfileData.setConfiguration(configuration);
if (deviceProfileTransportConfiguration != null) { if (deviceProfileTransportConfiguration != null) {
deviceProfile.setTransportType(deviceProfileTransportConfiguration.getType());
deviceProfileData.setTransportConfiguration(deviceProfileTransportConfiguration); deviceProfileData.setTransportConfiguration(deviceProfileTransportConfiguration);
} else { } else {
deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration()); deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
} }
deviceProfile.setProfileData(deviceProfileData); deviceProfile.setProfileData(deviceProfileData);
@ -397,10 +407,11 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return deviceProfile; return deviceProfile;
} }
protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) { protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration, boolean sendAckOnValidationException) {
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration(); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC); mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC);
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
mqttDeviceProfileTransportConfiguration.setSendAckOnValidationException(sendAckOnValidationException);
mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration); mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
return mqttDeviceProfileTransportConfiguration; return mqttDeviceProfileTransportConfiguration;
} }
@ -503,16 +514,24 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType); return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType);
} }
protected <T> T doPost(String urlTemplate, Class<T> responseClass, String... params) throws Exception { protected <T> T doPost(String urlTemplate, Class<T> responseClass, String... params) {
return readResponse(doPost(urlTemplate, params).andExpect(status().isOk()), responseClass); try {
return readResponse(doPost(urlTemplate, params).andExpect(status().isOk()), responseClass);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception { protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, ResultMatcher resultMatcher, String... params) throws Exception {
return readResponse(doPost(urlTemplate, content, params).andExpect(resultMatcher), responseClass); return readResponse(doPost(urlTemplate, content, params).andExpect(resultMatcher), responseClass);
} }
protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, String... params) throws Exception { protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, String... params) {
return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass); try {
return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
protected <T, R> R doPostWithResponse(String urlTemplate, T content, Class<R> responseClass, String... params) throws Exception { protected <T, R> R doPostWithResponse(String urlTemplate, T content, Class<R> responseClass, String... params) throws Exception {
@ -633,4 +652,15 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
edge.setRoutingKey(RandomStringUtils.randomAlphanumeric(20)); edge.setRoutingKey(RandomStringUtils.randomAlphanumeric(20));
return edge; return edge;
} }
protected <T extends HasId<? extends UUIDBased>> ListenableFuture<List<ResultActions>> deleteEntitiesAsync(String urlTemplate, List<T> entities, ListeningExecutorService executor) {
List<ListenableFuture<ResultActions>> futures = new ArrayList<>(entities.size());
for (T entity : entities) {
futures.add(executor.submit(() ->
doDelete(urlTemplate + entity.getId().getId())
.andExpect(status().isOk())));
}
return Futures.allAsList(futures);
}
} }

54
application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java

@ -1,54 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootContextLoader;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import java.net.URI;
import java.net.URISyntaxException;
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = AbstractControllerTest.class, loader = SpringBootContextLoader.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@Configuration
@ComponentScan({"org.thingsboard.server"})
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
public abstract class AbstractWebsocketTest extends AbstractWebTest {
protected static final String WS_URL = "ws://localhost:";
@LocalServerPort
protected int wsPort;
protected TbTestWebSocketClient buildAndConnectWebSocketClient() throws URISyntaxException, InterruptedException {
TbTestWebSocketClient wsClient = new TbTestWebSocketClient(new URI(WS_URL + wsPort + "/api/ws/plugins/telemetry?token=" + token));
Assert.assertTrue(wsClient.connectBlocking());
return wsClient;
}
}

34
application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java

@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.Asset;
@ -182,6 +183,39 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test
public void testDeleteAssetAssignedToEntityView() throws Exception {
Asset asset1 = new Asset();
asset1.setName("My asset 1");
asset1.setType("default");
Asset savedAsset1 = doPost("/api/asset", asset1, Asset.class);
Asset asset2 = new Asset();
asset2.setName("My asset 2");
asset2.setType("default");
Asset savedAsset2 = doPost("/api/asset", asset2, Asset.class);
EntityView view = new EntityView();
view.setEntityId(savedAsset1.getId());
view.setTenantId(savedTenant.getId());
view.setName("My entity view");
view.setType("default");
EntityView savedView = doPost("/api/entityView", view, EntityView.class);
doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isBadRequest());
savedView.setEntityId(savedAsset2.getId());
doPost("/api/entityView", savedView, EntityView.class);
doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isNotFound());
}
@Test @Test
public void testSaveAssetWithEmptyType() throws Exception { public void testSaveAssetWithEmptyType() throws Exception {
Asset asset = new Asset(); Asset asset = new Asset();

96
application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java

@ -15,16 +15,17 @@
*/ */
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import static org.hamcrest.Matchers.containsString; import com.fasterxml.jackson.core.type.TypeReference;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList; import com.google.common.util.concurrent.ListeningExecutorService;
import java.util.Collections; import com.google.common.util.concurrent.MoreExecutors;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
@ -32,20 +33,28 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.junit.Assert;
import org.junit.Test;
import com.fasterxml.jackson.core.type.TypeReference; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseCustomerControllerTest extends AbstractControllerTest { public abstract class BaseCustomerControllerTest extends AbstractControllerTest {
static final TypeReference<PageData<Customer>> PAGE_DATA_CUSTOMER_TYPE_REFERENCE = new TypeReference<>() {
};
private IdComparator<Customer> idComparator = new IdComparator<>(); ListeningExecutorService executor;
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
@ -65,6 +74,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
executor.shutdownNow();
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
@ -83,11 +94,11 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
savedCustomer.setTitle("My new customer"); savedCustomer.setTitle("My new customer");
doPost("/api/customer", savedCustomer, Customer.class); doPost("/api/customer", savedCustomer, Customer.class);
Customer foundCustomer = doGet("/api/customer/"+savedCustomer.getId().getId().toString(), Customer.class); Customer foundCustomer = doGet("/api/customer/" + savedCustomer.getId().getId().toString(), Customer.class);
Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle()); Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle());
doDelete("/api/customer/"+savedCustomer.getId().getId().toString()) doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
@ -182,29 +193,30 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
public void testFindCustomers() throws Exception { public void testFindCustomers() throws Exception {
TenantId tenantId = savedTenant.getId(); TenantId tenantId = savedTenant.getId();
List<Customer> customers = new ArrayList<>(); List<ListenableFuture<Customer>> futures = new ArrayList<>(135);
for (int i = 0; i < 135; i++) { for (int i = 0; i < 135; i++) {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
customer.setTitle("Customer" + i); customer.setTitle("Customer" + i);
customers.add(doPost("/api/customer", customer, Customer.class)); futures.add(executor.submit(() ->
doPost("/api/customer", customer, Customer.class)));
} }
List<Customer> customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Customer> loadedCustomers = new ArrayList<>(); List<Customer> loadedCustomers = new ArrayList<>(135);
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Customer> pageData = null; PageData<Customer> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomers.addAll(pageData.getData()); loadedCustomers.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(customers, idComparator); assertThat(customers).containsExactlyInAnyOrderElementsOf(loadedCustomers);
Collections.sort(loadedCustomers, idComparator);
Assert.assertEquals(customers, loadedCustomers); deleteEntitiesAsync("/api/customer/", loadedCustomers, executor).get(TIMEOUT, TimeUnit.SECONDS);
} }
@Test @Test
@ -212,7 +224,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
TenantId tenantId = savedTenant.getId(); TenantId tenantId = savedTenant.getId();
String title1 = "Customer title 1"; String title1 = "Customer title 1";
List<Customer> customersTitle1 = new ArrayList<>(); List<ListenableFuture<Customer>> futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) { for (int i = 0; i < 143; i++) {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
@ -220,10 +232,13 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
String title = title1 + suffix; String title = title1 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
customer.setTitle(title); customer.setTitle(title);
customersTitle1.add(doPost("/api/customer", customer, Customer.class)); futures.add(executor.submit(() ->
doPost("/api/customer", customer, Customer.class)));
} }
List<Customer> customersTitle1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
String title2 = "Customer title 2"; String title2 = "Customer title 2";
List<Customer> customersTitle2 = new ArrayList<>(); futures = new ArrayList<>(175);
for (int i = 0; i < 175; i++) { for (int i = 0; i < 175; i++) {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTenantId(tenantId); customer.setTenantId(tenantId);
@ -231,57 +246,48 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
String title = title2 + suffix; String title = title2 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
customer.setTitle(title); customer.setTitle(title);
customersTitle2.add(doPost("/api/customer", customer, Customer.class)); futures.add(executor.submit(() ->
doPost("/api/customer", customer, Customer.class)));
} }
List<Customer> customersTitle2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Customer> loadedCustomersTitle1 = new ArrayList<>(); List<Customer> loadedCustomersTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Customer> pageData = null; PageData<Customer> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomersTitle1.addAll(pageData.getData()); loadedCustomersTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(customersTitle1, idComparator); assertThat(customersTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedCustomersTitle1);
Collections.sort(loadedCustomersTitle1, idComparator);
Assert.assertEquals(customersTitle1, loadedCustomersTitle1);
List<Customer> loadedCustomersTitle2 = new ArrayList<>(); List<Customer> loadedCustomersTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomersTitle2.addAll(pageData.getData()); loadedCustomersTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(customersTitle2, idComparator); assertThat(customersTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedCustomersTitle2);
Collections.sort(loadedCustomersTitle2, idComparator);
Assert.assertEquals(customersTitle2, loadedCustomersTitle2); deleteEntitiesAsync("/api/customer/", loadedCustomersTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
for (Customer customer : loadedCustomersTitle1) {
doDelete("/api/customer/" + customer.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Customer customer : loadedCustomersTitle2) { deleteEntitiesAsync("/api/customer/", loadedCustomersTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/customer/" + customer.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<PageData<Customer>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }

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

@ -17,11 +17,17 @@ package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
@ -41,22 +47,32 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@Slf4j
public abstract class BaseDeviceControllerTest extends AbstractControllerTest { public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
static final TypeReference<PageData<Device>> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {
};
private IdComparator<Device> idComparator = new IdComparator<>(); ListeningExecutorService executor;
List<ListenableFuture<Device>> futures;
PageData<Device> pageData;
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
log.debug("beforeTest");
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
@ -76,10 +92,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
log.debug("afterTest...");
executor.shutdownNow();
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
log.debug("afterTest done");
} }
@Test @Test
@ -98,7 +118,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(device.getName(), savedDevice.getName()); Assert.assertEquals(device.getName(), savedDevice.getName());
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertNotNull(deviceCredentials); Assert.assertNotNull(deviceCredentials);
Assert.assertNotNull(deviceCredentials.getId()); Assert.assertNotNull(deviceCredentials.getId());
@ -110,7 +130,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
savedDevice.setName("My new device"); savedDevice.setName("My new device");
doPost("/api/device", savedDevice, Device.class); doPost("/api/device", savedDevice, Device.class);
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
} }
@ -145,7 +165,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertNotNull(foundDevice); Assert.assertNotNull(foundDevice);
Assert.assertEquals(savedDevice, foundDevice); Assert.assertEquals(savedDevice, foundDevice);
} }
@ -180,6 +200,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals("typeA", deviceTypes.get(0).getType()); Assert.assertEquals("typeA", deviceTypes.get(0).getType());
Assert.assertEquals("typeB", deviceTypes.get(1).getType()); Assert.assertEquals("typeB", deviceTypes.get(1).getType());
Assert.assertEquals("typeC", deviceTypes.get(2).getType()); Assert.assertEquals("typeC", deviceTypes.get(2).getType());
deleteEntitiesAsync("/api/device/", devices, executor).get(TIMEOUT, TimeUnit.SECONDS);
} }
@Test @Test
@ -189,10 +211,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doDelete("/api/device/" + savedDevice.getId().getId().toString()) doDelete("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
doGet("/api/device/" + savedDevice.getId().getId().toString()) doGet("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@ -224,18 +246,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
customer.setTitle("My customer"); customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString() Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId());
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId());
Device unassignedDevice = Device unassignedDevice =
doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class); doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId());
foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId()); Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId());
} }
@ -246,7 +268,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + Uuids.timeBased().toString() doPost("/api/customer/" + Uuids.timeBased().toString()
+ "/device/" + savedDevice.getId().getId().toString()) + "/device/" + savedDevice.getId().getId())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@ -279,13 +301,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + savedCustomer.getId().getId().toString() doPost("/api/customer/" + savedCustomer.getId().getId()
+ "/device/" + savedDevice.getId().getId().toString()) + "/device/" + savedDevice.getId().getId())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden());
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedTenant2.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant2.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@ -296,7 +318,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
} }
@ -307,7 +329,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId("access_token"); deviceCredentials.setCredentialsId("access_token");
@ -315,7 +337,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
DeviceCredentials foundDeviceCredentials = DeviceCredentials foundDeviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(deviceCredentials, foundDeviceCredentials); Assert.assertEquals(deviceCredentials, foundDeviceCredentials);
} }
@ -334,7 +356,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsType(null); deviceCredentials.setCredentialsType(null);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
@ -348,7 +370,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsId(null); deviceCredentials.setCredentialsId(null);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
@ -362,7 +384,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(Uuids.timeBased())); DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(Uuids.timeBased()));
newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime()); newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime());
newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId()); newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId());
@ -380,7 +402,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased())); deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased()));
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
@ -388,19 +410,24 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Test @Test
public void testFindTenantDevices() throws Exception { public void testFindTenantDevices() throws Exception {
List<Device> devices = new ArrayList<>(); log.debug("testFindTenantDevices");
futures = new ArrayList<>(178);
for (int i = 0; i < 178; i++) { for (int i = 0; i < 178; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device" + i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
devices.add(doPost("/api/device", device, Device.class)); futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class)));
} }
List<Device> loadedDevices = new ArrayList<>(); log.debug("await create devices");
List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("start reading");
List<Device> loadedDevices = new ArrayList<>(178);
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevices.addAll(pageData.getData()); loadedDevices.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
@ -408,16 +435,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devices, idComparator); log.debug("asserting");
Collections.sort(loadedDevices, idComparator); assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
log.debug("delete devices async");
Assert.assertEquals(devices, loadedDevices); deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("done");
} }
@Test @Test
public void testFindTenantDevicesByName() throws Exception { public void testFindTenantDevicesByName() throws Exception {
String title1 = "Device title 1"; String title1 = "Device title 1";
List<Device> devicesTitle1 = new ArrayList<>();
futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -425,10 +454,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
devicesTitle1.add(doPost("/api/device", device, Device.class)); futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class)));
} }
List<Device> devicesTitle1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
String title2 = "Device title 2"; String title2 = "Device title 2";
List<Device> devicesTitle2 = new ArrayList<>(); futures = new ArrayList<>(75);
for (int i = 0; i < 75; i++) { for (int i = 0; i < 75; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -436,59 +468,50 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
devicesTitle2.add(doPost("/api/device", device, Device.class)); futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class)));
} }
List<Device> devicesTitle2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevicesTitle1 = new ArrayList<>(); List<Device> loadedDevicesTitle1 = new ArrayList<>(143);
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle1.addAll(pageData.getData()); loadedDevicesTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle1, idComparator); assertThat(devicesTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle1);
Collections.sort(loadedDevicesTitle1, idComparator);
Assert.assertEquals(devicesTitle1, loadedDevicesTitle1);
List<Device> loadedDevicesTitle2 = new ArrayList<>(); List<Device> loadedDevicesTitle2 = new ArrayList<>(75);
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle2.addAll(pageData.getData()); loadedDevicesTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle2, idComparator); assertThat(devicesTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle2);
Collections.sort(loadedDevicesTitle2, idComparator);
Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); deleteEntitiesAsync("/api/device/", loadedDevicesTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
for (Device device : loadedDevicesTitle1) {
doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesTitle2) { deleteEntitiesAsync("/api/device/", loadedDevicesTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -497,7 +520,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
public void testFindTenantDevicesByType() throws Exception { public void testFindTenantDevicesByType() throws Exception {
String title1 = "Device title 1"; String title1 = "Device title 1";
String type1 = "typeA"; String type1 = "typeA";
List<Device> devicesType1 = new ArrayList<>(); futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -505,11 +528,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type1); device.setType(type1);
devicesType1.add(doPost("/api/device", device, Device.class)); futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class)));
if (i == 0) {
futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
}
} }
List<Device> devicesType1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
String title2 = "Device title 2"; String title2 = "Device title 2";
String type2 = "typeB"; String type2 = "typeB";
List<Device> devicesType2 = new ArrayList<>(); futures = new ArrayList<>(75);
for (int i = 0; i < 75; i++) { for (int i = 0; i < 75; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -517,61 +546,54 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type2); device.setType(type2);
devicesType2.add(doPost("/api/device", device, Device.class)); futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class)));
if (i == 0) {
futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
}
} }
List<Device> loadedDevicesType1 = new ArrayList<>(); List<Device> devicesType2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevicesType1 = new ArrayList<>(143);
PageLink pageLink = new PageLink(15); PageLink pageLink = new PageLink(15);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type1); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type1);
loadedDevicesType1.addAll(pageData.getData()); loadedDevicesType1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesType1, idComparator); assertThat(devicesType1).as(title1).containsExactlyInAnyOrderElementsOf(loadedDevicesType1);
Collections.sort(loadedDevicesType1, idComparator);
Assert.assertEquals(devicesType1, loadedDevicesType1); List<Device> loadedDevicesType2 = new ArrayList<>(75);
List<Device> loadedDevicesType2 = new ArrayList<>();
pageLink = new PageLink(4); pageLink = new PageLink(4);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type2); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type2);
loadedDevicesType2.addAll(pageData.getData()); loadedDevicesType2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesType2, idComparator); assertThat(devicesType2).as(title2).containsExactlyInAnyOrderElementsOf(loadedDevicesType2);
Collections.sort(loadedDevicesType2, idComparator);
Assert.assertEquals(devicesType2, loadedDevicesType2);
for (Device device : loadedDevicesType1) { deleteEntitiesAsync("/api/device/", loadedDevicesType1, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type1); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type1);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesType2) { deleteEntitiesAsync("/api/device/", loadedDevicesType2, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type2); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type2);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -583,32 +605,35 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
customer = doPost("/api/customer", customer, Customer.class); customer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
List<Device> devices = new ArrayList<>(); futures = new ArrayList<>(128);
for (int i = 0; i < 128; i++) { for (int i = 0; i < 128; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device" + i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); ListenableFuture<Device> future = executor.submit(() -> doPost("/api/device", device, Device.class));
devices.add(doPost("/api/customer/" + customerId.getId().toString() futures.add(Futures.transform(future, (dev) ->
+ "/device/" + device.getId().getId().toString(), Device.class)); doPost("/api/customer/" + customerId.getId()
+ "/device/" + dev.getId().getId(), Device.class), MoreExecutors.directExecutor()));
} }
List<Device> loadedDevices = new ArrayList<>(); List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevices = new ArrayList<>(128);
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevices.addAll(pageData.getData()); loadedDevices.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devices, idComparator); assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
Collections.sort(loadedDevices, idComparator);
Assert.assertEquals(devices, loadedDevices); log.debug("delete devices async");
deleteEntitiesAsync("/api/customer/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("done");
} }
@Test @Test
@ -619,7 +644,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
String title1 = "Device title 1"; String title1 = "Device title 1";
List<Device> devicesTitle1 = new ArrayList<>(); futures = new ArrayList<>(125);
for (int i = 0; i < 125; i++) { for (int i = 0; i < 125; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -627,12 +652,15 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); ListenableFuture<Device> future = executor.submit(() -> doPost("/api/device", device, Device.class));
devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() futures.add(Futures.transform(future, (dev) ->
+ "/device/" + device.getId().getId().toString(), Device.class)); doPost("/api/customer/" + customerId.getId()
+ "/device/" + dev.getId().getId(), Device.class), MoreExecutors.directExecutor()));
} }
List<Device> devicesTitle1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
String title2 = "Device title 2"; String title2 = "Device title 2";
List<Device> devicesTitle2 = new ArrayList<>(); futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -640,61 +668,52 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType("default"); device.setType("default");
device = doPost("/api/device", device, Device.class); ListenableFuture<Device> future = executor.submit(() -> doPost("/api/device", device, Device.class));
devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() futures.add(Futures.transform(future, (dev) ->
+ "/device/" + device.getId().getId().toString(), Device.class)); doPost("/api/customer/" + customerId.getId()
+ "/device/" + dev.getId().getId(), Device.class), MoreExecutors.directExecutor()));
} }
List<Device> devicesTitle2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevicesTitle1 = new ArrayList<>(); List<Device> loadedDevicesTitle1 = new ArrayList<>(125);
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle1.addAll(pageData.getData()); loadedDevicesTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle1, idComparator); assertThat(devicesTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle1);
Collections.sort(loadedDevicesTitle1, idComparator);
Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); List<Device> loadedDevicesTitle2 = new ArrayList<>(143);
List<Device> loadedDevicesTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle2.addAll(pageData.getData()); loadedDevicesTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesTitle2, idComparator); assertThat(devicesTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle2);
Collections.sort(loadedDevicesTitle2, idComparator);
Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); deleteEntitiesAsync("/api/customer/device/", loadedDevicesTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
for (Device device : loadedDevicesTitle1) {
doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesTitle2) { deleteEntitiesAsync("/api/customer/device/", loadedDevicesTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
new TypeReference<PageData<Device>>(){}, pageLink); PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -708,7 +727,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
String title1 = "Device title 1"; String title1 = "Device title 1";
String type1 = "typeC"; String type1 = "typeC";
List<Device> devicesType1 = new ArrayList<>(); futures = new ArrayList<>(125);
for (int i = 0; i < 125; i++) { for (int i = 0; i < 125; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -716,13 +735,19 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type1); device.setType(type1);
device = doPost("/api/device", device, Device.class); ListenableFuture<Device> future = executor.submit(() -> doPost("/api/device", device, Device.class));
devicesType1.add(doPost("/api/customer/" + customerId.getId().toString() futures.add(Futures.transform(future, (dev) ->
+ "/device/" + device.getId().getId().toString(), Device.class)); doPost("/api/customer/" + customerId.getId()
+ "/device/" + dev.getId().getId(), Device.class), MoreExecutors.directExecutor()));
if (i == 0) {
futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
}
} }
List<Device> devicesType1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
String title2 = "Device title 2"; String title2 = "Device title 2";
String type2 = "typeD"; String type2 = "typeD";
List<Device> devicesType2 = new ArrayList<>(); futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) { for (int i = 0; i < 143; i++) {
Device device = new Device(); Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15); String suffix = RandomStringUtils.randomAlphanumeric(15);
@ -730,63 +755,55 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name); device.setName(name);
device.setType(type2); device.setType(type2);
device = doPost("/api/device", device, Device.class); ListenableFuture<Device> future = executor.submit(() -> doPost("/api/device", device, Device.class));
devicesType2.add(doPost("/api/customer/" + customerId.getId().toString() futures.add(Futures.transform(future, (dev) ->
+ "/device/" + device.getId().getId().toString(), Device.class)); doPost("/api/customer/" + customerId.getId()
+ "/device/" + dev.getId().getId(), Device.class), MoreExecutors.directExecutor()));
if (i == 0) {
futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
}
} }
List<Device> devicesType2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevicesType1 = new ArrayList<>(); List<Device> loadedDevicesType1 = new ArrayList<>(125);
PageLink pageLink = new PageLink(15); PageLink pageLink = new PageLink(15);
PageData<Device> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type1); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type1);
loadedDevicesType1.addAll(pageData.getData()); loadedDevicesType1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesType1, idComparator); assertThat(devicesType1).as(title1).containsExactlyInAnyOrderElementsOf(loadedDevicesType1);
Collections.sort(loadedDevicesType1, idComparator);
Assert.assertEquals(devicesType1, loadedDevicesType1); List<Device> loadedDevicesType2 = new ArrayList<>(143);
List<Device> loadedDevicesType2 = new ArrayList<>();
pageLink = new PageLink(4); pageLink = new PageLink(4);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type2); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type2);
loadedDevicesType2.addAll(pageData.getData()); loadedDevicesType2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(devicesType2, idComparator); assertThat(devicesType2).as(title2).containsExactlyInAnyOrderElementsOf(loadedDevicesType2);
Collections.sort(loadedDevicesType2, idComparator);
Assert.assertEquals(devicesType2, loadedDevicesType2);
for (Device device : loadedDevicesType1) { deleteEntitiesAsync("/api/customer/device/", loadedDevicesType1, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type1); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type1);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Device device : loadedDevicesType2) { deleteEntitiesAsync("/api/customer/device/", loadedDevicesType2, executor).get(TIMEOUT, TimeUnit.SECONDS);
doDelete("/api/customer/device/" + device.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?type={type}&",
new TypeReference<PageData<Device>>(){}, pageLink, type2); PAGE_DATA_DEVICE_TYPE_REF, pageLink, type2);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -828,17 +845,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
login("tenant2@thingsboard.org", "testPassword1"); login("tenant2@thingsboard.org", "testPassword1");
Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class); Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class);
doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class, status().isNotFound()); doGet("/api/device/" + assignedDevice.getId().getId(), Device.class, status().isNotFound());
login("tenant9@thingsboard.org", "testPassword1"); login("tenant9@thingsboard.org", "testPassword1");
Device foundDevice1 = doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class); Device foundDevice1 = doGet("/api/device/" + assignedDevice.getId().getId(), Device.class);
Assert.assertNotNull(foundDevice1); Assert.assertNotNull(foundDevice1);
doGet("/api/relation?fromId=" + savedDevice.getId().getId() + "&fromType=DEVICE&relationType=Contains&toId=" + savedAnotherDevice.getId().getId() + "&toType=DEVICE", EntityRelation.class, status().isNotFound()); doGet("/api/relation?fromId=" + savedDevice.getId().getId() + "&fromType=DEVICE&relationType=Contains&toId=" + savedAnotherDevice.getId().getId() + "&toType=DEVICE", EntityRelation.class, status().isNotFound());
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedDifferentTenant.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@ -852,19 +869,19 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default"); device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/edge/" + savedEdge.getId().getId().toString() doPost("/api/edge/" + savedEdge.getId().getId()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
PageData<Device> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?",
new TypeReference<PageData<Device>>() {}, new PageLink(100)); PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
doDelete("/api/edge/" + savedEdge.getId().getId().toString() doDelete("/api/edge/" + savedEdge.getId().getId()
+ "/device/" + savedDevice.getId().getId().toString(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/devices?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?",
new TypeReference<PageData<Device>>() {}, new PageLink(100)); PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }

57
application/src/test/java/org/thingsboard/server/controller/BaseDeviceProfileControllerTest.java

@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
@ -93,7 +94,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testSaveDeviceProfile() throws Exception { public void testSaveDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
Assert.assertNotNull(savedDeviceProfile.getId()); Assert.assertNotNull(savedDeviceProfile.getId());
@ -112,13 +113,13 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void saveDeviceProfileWithViolationOfValidation() throws Exception { public void saveDeviceProfileWithViolationOfValidation() throws Exception {
doPost("/api/deviceProfile", this.createDeviceProfile(RandomStringUtils.randomAlphabetic(300), null)) doPost("/api/deviceProfile", this.createDeviceProfile(RandomStringUtils.randomAlphabetic(300)))
.andExpect(statusReason(containsString("length of name must be equal or less than 255"))); .andExpect(statusReason(containsString("length of name must be equal or less than 255")));
} }
@Test @Test
public void testFindDeviceProfileById() throws Exception { public void testFindDeviceProfileById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertNotNull(foundDeviceProfile); Assert.assertNotNull(foundDeviceProfile);
@ -127,7 +128,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testFindDeviceProfileInfoById() throws Exception { public void testFindDeviceProfileInfoById() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class); DeviceProfileInfo foundDeviceProfileInfo = doGet("/api/deviceProfileInfo/"+savedDeviceProfile.getId().getId().toString(), DeviceProfileInfo.class);
Assert.assertNotNull(foundDeviceProfileInfo); Assert.assertNotNull(foundDeviceProfileInfo);
@ -149,7 +150,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testSetDefaultDeviceProfile() throws Exception { public void testSetDefaultDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile 1");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", DeviceProfile.class); DeviceProfile defaultDeviceProfile = doPost("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString()+"/default", DeviceProfile.class);
Assert.assertNotNull(defaultDeviceProfile); Assert.assertNotNull(defaultDeviceProfile);
@ -169,19 +170,19 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testSaveDeviceProfileWithSameName() throws Exception { public void testSaveDeviceProfileWithSameName() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile");
doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device profile with such name already exists"))); .andExpect(statusReason(containsString("Device profile with such name already exists")));
} }
@Test @Test
public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception { public void testSaveDeviceProfileWithSameProvisionDeviceKey() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey"); deviceProfile.setProvisionDeviceKey("testProvisionDeviceKey");
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk()); doPost("/api/deviceProfile", deviceProfile).andExpect(status().isOk());
DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2", null); DeviceProfile deviceProfile2 = this.createDeviceProfile("Device Profile 2");
deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey"); deviceProfile2.setProvisionDeviceKey("testProvisionDeviceKey");
doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest()) doPost("/api/deviceProfile", deviceProfile2).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device profile with such provision device key already exists"))); .andExpect(statusReason(containsString("Device profile with such provision device key already exists")));
@ -190,7 +191,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Ignore @Ignore
@Test @Test
public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception { public void testChangeDeviceProfileTypeWithExistingDevices() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device(); Device device = new Device();
device.setName("Test device"); device.setName("Test device");
@ -205,7 +206,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception { public void testChangeDeviceProfileTransportTypeWithExistingDevices() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device(); Device device = new Device();
device.setName("Test device"); device.setName("Test device");
@ -219,7 +220,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testDeleteDeviceProfileWithExistingDevice() throws Exception { public void testDeleteDeviceProfileWithExistingDevice() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Device device = new Device(); Device device = new Device();
@ -236,7 +237,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
@Test @Test
public void testDeleteDeviceProfile() throws Exception { public void testDeleteDeviceProfile() throws Exception {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString()) doDelete("/api/deviceProfile/" + savedDeviceProfile.getId().getId().toString())
@ -257,7 +258,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
deviceProfiles.addAll(pageData.getData()); deviceProfiles.addAll(pageData.getData());
for (int i=0;i<28;i++) { for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
} }
@ -302,7 +303,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
deviceProfiles.addAll(deviceProfilePageData.getData()); deviceProfiles.addAll(deviceProfilePageData.getData());
for (int i=0;i<28;i++) { for (int i=0;i<28;i++) {
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i, null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile"+i);
deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class)); deviceProfiles.add(doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class));
} }
@ -835,19 +836,35 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
"}", "[Transport Configuration] invalid rpc request proto schema provided! Failed to get field descriptor for field: params!"); "}", "[Transport Configuration] invalid rpc request proto schema provided! Failed to get field descriptor for field: params!");
} }
@Test
public void testSaveDeviceProfileWithSendAckOnValidationException() throws Exception {
JsonTransportPayloadConfiguration jsonTransportPayloadConfiguration = new JsonTransportPayloadConfiguration();
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(jsonTransportPayloadConfiguration, true);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(savedDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getTransportType(), DeviceTransportType.MQTT);
Assert.assertTrue(savedDeviceProfile.getProfileData().getTransportConfiguration() instanceof MqttDeviceProfileTransportConfiguration);
MqttDeviceProfileTransportConfiguration transportConfiguration = (MqttDeviceProfileTransportConfiguration) savedDeviceProfile.getProfileData().getTransportConfiguration();
Assert.assertTrue(transportConfiguration.isSendAckOnValidationException());
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+ savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
}
private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception { private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception {
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null); ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null);
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+savedDeviceProfile.getId().getId().toString(), DeviceProfile.class); Assert.assertNotNull(savedDeviceProfile);
Assert.assertEquals(savedDeviceProfile.getName(), foundDeviceProfile.getName()); DeviceProfile foundDeviceProfile = doGet("/api/deviceProfile/"+ savedDeviceProfile.getId().getId().toString(), DeviceProfile.class);
Assert.assertEquals(savedDeviceProfile, foundDeviceProfile);
return savedDeviceProfile; return savedDeviceProfile;
} }
private void testSaveDeviceProfileWithInvalidProtoSchema(String schema, String errorMsg) throws Exception { private void testSaveDeviceProfileWithInvalidProtoSchema(String schema, String errorMsg) throws Exception {
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null); ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, null, null);
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest()) doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(errorMsg))); .andExpect(statusReason(containsString(errorMsg)));
@ -855,7 +872,7 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController
private void testSaveDeviceProfileWithInvalidRpcRequestProtoSchema(String schema, String errorMsg) throws Exception { private void testSaveDeviceProfileWithInvalidRpcRequestProtoSchema(String schema, String errorMsg) throws Exception {
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, schema, null); ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema, schema, null);
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration); MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration, false);
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", mqttDeviceProfileTransportConfiguration);
doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest()) doPost("/api/deviceProfile", deviceProfile).andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(errorMsg))); .andExpect(statusReason(containsString(errorMsg)));

4
application/src/test/java/org/thingsboard/server/controller/BaseEdgeControllerTest.java

@ -23,6 +23,7 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
@ -54,6 +55,9 @@ import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@TestPropertySource(properties = {
"edges.enabled=true",
})
public abstract class BaseEdgeControllerTest extends AbstractControllerTest { public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
public static final String EDGE_HOST = "localhost"; public static final String EDGE_HOST = "localhost";

4
application/src/test/java/org/thingsboard/server/controller/BaseEdgeEventControllerTest.java

@ -22,6 +22,7 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.User;
@ -40,6 +41,9 @@ import java.util.concurrent.TimeUnit;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@TestPropertySource(properties = {
"edges.enabled=true",
})
@Slf4j @Slf4j
public abstract class BaseEdgeEventControllerTest extends AbstractControllerTest { public abstract class BaseEdgeEventControllerTest extends AbstractControllerTest {

375
application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java

@ -17,8 +17,13 @@ package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids; import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttMessage;
@ -27,6 +32,9 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
@ -39,70 +47,71 @@ import org.thingsboard.server.common.data.objects.AttributesEntityView;
import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.query.DeviceTypeFilter;
import org.thingsboard.server.common.data.query.EntityKey;
import org.thingsboard.server.common.data.query.EntityKeyType;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@TestPropertySource(properties = {
"transport.mqtt.enabled=true",
"js.evaluator=mock",
})
@Slf4j @Slf4j
public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { public abstract class BaseEntityViewControllerTest extends AbstractControllerTest {
static final TypeReference<PageData<EntityView>> PAGE_DATA_ENTITY_VIEW_TYPE_REF = new TypeReference<>() {
};
static final TypeReference<PageData<EntityViewInfo>> PAGE_DATA_ENTITY_VIEW_INFO_TYPE_REF = new TypeReference<>() {
};
private IdComparator<EntityView> idComparator;
private Tenant savedTenant;
private User tenantAdmin;
private Device testDevice; private Device testDevice;
private TelemetryEntityView telemetry; private TelemetryEntityView telemetry;
List<ListenableFuture<ResultActions>> deleteFutures = new ArrayList<>();
ListeningExecutorService executor;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
loginSysAdmin(); log.debug("beforeTest");
idComparator = new IdComparator<>(); executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
savedTenant = doPost("/api/tenant", getNewTenant("My tenant"), Tenant.class); loginTenantAdmin();
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
Device device = new Device(); Device device = new Device();
device.setName("Test device"); device.setName("Test device 4view");
device.setType("default"); device.setType("default");
testDevice = doPost("/api/device", device, Device.class); testDevice = doPost("/api/device", device, Device.class);
telemetry = new TelemetryEntityView( telemetry = new TelemetryEntityView(
Arrays.asList("tsKey1", "tsKey2", "tsKey3"), List.of("tsKey1", "tsKey2", "tsKey3"),
new AttributesEntityView( new AttributesEntityView(
Arrays.asList("caKey1", "caKey2", "caKey3", "caKey4"), List.of("caKey1", "caKey2", "caKey3", "caKey4"),
Arrays.asList("saKey1", "saKey2", "saKey3", "saKey4"), List.of("saKey1", "saKey2", "saKey3", "saKey4"),
Arrays.asList("shKey1", "shKey2", "shKey3", "shKey4"))); List.of("shKey1", "shKey2", "shKey3", "shKey4")));
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
loginSysAdmin(); executor.shutdownNow();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
} }
@Test @Test
@ -115,22 +124,29 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test @Test
public void testSaveEntityView() throws Exception { public void testSaveEntityView() throws Exception {
EntityView savedView = getNewSavedEntityView("Test entity view"); String name = "Test entity view";
EntityView savedView = getNewSavedEntityView(name);
Assert.assertNotNull(savedView); Assert.assertNotNull(savedView);
Assert.assertNotNull(savedView.getId()); Assert.assertNotNull(savedView.getId());
Assert.assertTrue(savedView.getCreatedTime() > 0); Assert.assertTrue(savedView.getCreatedTime() > 0);
assertEquals(savedTenant.getId(), savedView.getTenantId()); assertEquals(tenantId, savedView.getTenantId());
Assert.assertNotNull(savedView.getCustomerId()); Assert.assertNotNull(savedView.getCustomerId());
assertEquals(NULL_UUID, savedView.getCustomerId().getId()); assertEquals(NULL_UUID, savedView.getCustomerId().getId());
assertEquals(savedView.getName(), savedView.getName()); assertEquals(name, savedView.getName());
EntityView foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(savedView, foundEntityView);
savedView.setName("New test entity view"); savedView.setName("New test entity view");
doPost("/api/entityView", savedView, EntityView.class); doPost("/api/entityView", savedView, EntityView.class);
EntityView foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class); foundEntityView = doGet("/api/entityView/" + savedView.getId().getId().toString(), EntityView.class);
assertEquals(savedView, foundEntityView);
assertEquals(foundEntityView.getName(), savedView.getName()); doGet("/api/tenant/entityViews?entityViewName=" + name, EntityView.class, status().isNotFound());
assertEquals(foundEntityView.getKeys(), telemetry);
} }
@Test @Test
@ -221,7 +237,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
Customer customer = getNewCustomer("Different customer"); Customer customer = getNewCustomer("Different customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
login(tenantAdmin.getEmail(), "testPassword1"); login(TENANT_ADMIN_EMAIL, TENANT_ADMIN_PASSWORD);
EntityView savedView = getNewSavedEntityView("Test entity view"); EntityView savedView = getNewSavedEntityView("Test entity view");
@ -240,21 +256,18 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViewInfos?"; String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViewInfos?";
List<EntityViewInfo> views = new ArrayList<>(); List<ListenableFuture<EntityViewInfo>> viewFutures = new ArrayList<>(128);
for (int i = 0; i < 128; i++) { for (int i = 0; i < 128; i++) {
views.add( String entityName = "Test entity view " + i;
viewFutures.add(executor.submit(() ->
new EntityViewInfo(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/" new EntityViewInfo(doPost("/api/customer/" + customerId.getId().toString() + "/entityView/"
+ getNewSavedEntityView("Test entity view " + i).getId().getId().toString(), EntityView.class), + getNewSavedEntityView(entityName).getId().getId().toString(), EntityView.class),
customer.getTitle(), customer.isPublic()) customer.getTitle(), customer.isPublic())));
);
} }
List<EntityViewInfo> entityViewInfos = Futures.allAsList(viewFutures).get(TIMEOUT, SECONDS);
List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), urlTemplate); List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), urlTemplate);
Collections.sort(views, idComparator); assertThat(entityViewInfos).containsExactlyInAnyOrderElementsOf(loadedViews);
Collections.sort(loadedViews, idComparator);
assertEquals(views, loadedViews);
} }
@Test @Test
@ -263,35 +276,37 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?"; String urlTemplate = "/api/customer/" + customerId.getId().toString() + "/entityViews?";
String name1 = "Entity view name1"; String name1 = "Entity view name1";
List<EntityView> namesOfView1 = fillListOf(125, name1, "/api/customer/" + customerId.getId().toString() List<EntityView> namesOfView1 = Futures.allAsList(fillListByTemplate(125, name1, "/api/customer/" + customerId.getId().toString()
+ "/entityView/"); + "/entityView/")).get(TIMEOUT, SECONDS);
List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(15, 0, name1), urlTemplate); List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(15, 0, name1), urlTemplate);
Collections.sort(namesOfView1, idComparator); assertThat(namesOfView1).as(name1).containsExactlyInAnyOrderElementsOf(loadedNamesOfView1);
Collections.sort(loadedNamesOfView1, idComparator);
assertEquals(namesOfView1, loadedNamesOfView1);
String name2 = "Entity view name2"; String name2 = "Entity view name2";
List<EntityView> NamesOfView2 = fillListOf(143, name2, "/api/customer/" + customerId.getId().toString() List<EntityView> namesOfView2 = Futures.allAsList(fillListByTemplate(143, name2, "/api/customer/" + customerId.getId().toString()
+ "/entityView/"); + "/entityView/")).get(TIMEOUT, SECONDS);
List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), urlTemplate); List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), urlTemplate);
Collections.sort(NamesOfView2, idComparator); assertThat(namesOfView2).as(name2).containsExactlyInAnyOrderElementsOf(loadedNamesOfView2);
Collections.sort(loadedNamesOfView2, idComparator);
assertEquals(NamesOfView2, loadedNamesOfView2);
deleteFutures.clear();
for (EntityView view : loadedNamesOfView1) { for (EntityView view : loadedNamesOfView1) {
doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); deleteFutures.add(executor.submit(() ->
doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk())));
} }
PageData<EntityView> pageData = doGetTypedWithPageLink(urlTemplate, Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS);
new TypeReference<PageData<EntityView>>() {
}, new PageLink(4, 0, name1)); PageData<EntityView> pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name1));
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
assertEquals(0, pageData.getData().size()); assertEquals(0, pageData.getData().size());
deleteFutures.clear();
for (EntityView view : loadedNamesOfView2) { for (EntityView view : loadedNamesOfView2) {
doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); deleteFutures.add(executor.submit(() ->
doDelete("/api/customer/entityView/" + view.getId().getId().toString()).andExpect(status().isOk())));
} }
pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityView>>() { Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS);
},
pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name2)); new PageLink(4, 0, name2));
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
assertEquals(0, pageData.getData().size()); assertEquals(0, pageData.getData().size());
@ -299,49 +314,51 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test @Test
public void testGetTenantEntityViews() throws Exception { public void testGetTenantEntityViews() throws Exception {
List<ListenableFuture<EntityViewInfo>> entityViewInfoFutures = new ArrayList<>(178);
List<EntityViewInfo> views = new ArrayList<>();
for (int i = 0; i < 178; i++) { for (int i = 0; i < 178; i++) {
views.add(new EntityViewInfo(getNewSavedEntityView("Test entity view" + i), null, false)); ListenableFuture<EntityView> entityViewFuture = getNewSavedEntityViewAsync("Test entity view" + i);
entityViewInfoFutures.add(Futures.transform(entityViewFuture,
view -> new EntityViewInfo(view, null, false),
MoreExecutors.directExecutor()));
} }
List<EntityViewInfo> entityViewInfos = Futures.allAsList(entityViewInfoFutures).get(TIMEOUT, SECONDS);
List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), "/api/tenant/entityViewInfos?"); List<EntityViewInfo> loadedViews = loadListOfInfo(new PageLink(23), "/api/tenant/entityViewInfos?");
assertThat(entityViewInfos).containsExactlyInAnyOrderElementsOf(loadedViews);
Collections.sort(views, idComparator);
Collections.sort(loadedViews, idComparator);
assertEquals(views, loadedViews);
} }
@Test @Test
public void testGetTenantEntityViewsByName() throws Exception { public void testGetTenantEntityViewsByName() throws Exception {
String name1 = "Entity view name1"; String name1 = "Entity view name1";
List<EntityView> namesOfView1 = fillListOf(143, name1); List<EntityView> namesOfView1 = Futures.allAsList(fillListOf(17, name1)).get(TIMEOUT, SECONDS);
List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(15, 0, name1), "/api/tenant/entityViews?"); List<EntityView> loadedNamesOfView1 = loadListOf(new PageLink(5, 0, name1), "/api/tenant/entityViews?");
Collections.sort(namesOfView1, idComparator); assertThat(namesOfView1).as(name1).containsExactlyInAnyOrderElementsOf(loadedNamesOfView1);
Collections.sort(loadedNamesOfView1, idComparator);
assertEquals(namesOfView1, loadedNamesOfView1);
String name2 = "Entity view name2"; String name2 = "Entity view name2";
List<EntityView> NamesOfView2 = fillListOf(75, name2); List<EntityView> namesOfView2 = Futures.allAsList(fillListOf(15, name2)).get(TIMEOUT, SECONDS);
;
List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), "/api/tenant/entityViews?"); List<EntityView> loadedNamesOfView2 = loadListOf(new PageLink(4, 0, name2), "/api/tenant/entityViews?");
Collections.sort(NamesOfView2, idComparator); assertThat(namesOfView2).as(name2).containsExactlyInAnyOrderElementsOf(loadedNamesOfView2);
Collections.sort(loadedNamesOfView2, idComparator);
assertEquals(NamesOfView2, loadedNamesOfView2);
deleteFutures.clear();
for (EntityView view : loadedNamesOfView1) { for (EntityView view : loadedNamesOfView1) {
doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); deleteFutures.add(executor.submit(() ->
doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk())));
} }
PageData<EntityView> pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS);
new TypeReference<PageData<EntityView>>() {
}, new PageLink(4, 0, name1)); PageData<EntityView> pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name1));
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
assertEquals(0, pageData.getData().size()); assertEquals(0, pageData.getData().size());
deleteFutures.clear();
for (EntityView view : loadedNamesOfView2) { for (EntityView view : loadedNamesOfView2) {
doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk()); deleteFutures.add(executor.submit(() ->
doDelete("/api/entityView/" + view.getId().getId().toString()).andExpect(status().isOk())));
} }
pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", new TypeReference<PageData<EntityView>>() { Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS);
},
pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", PAGE_DATA_ENTITY_VIEW_TYPE_REF,
new PageLink(4, 0, name2)); new PageLink(4, 0, name2));
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
assertEquals(0, pageData.getData().size()); assertEquals(0, pageData.getData().size());
@ -349,20 +366,21 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test @Test
public void testTheCopyOfAttrsIntoTSForTheView() throws Exception { public void testTheCopyOfAttrsIntoTSForTheView() throws Exception {
Set<String> expectedActualAttributesSet = Set.of("caKey1", "caKey2", "caKey3", "caKey4");
Set<String> actualAttributesSet = Set<String> actualAttributesSet =
getAttributesByKeys("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}"); getAttributesByKeys("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}", expectedActualAttributesSet);
log.debug("got correct actualAttributesSet, saving new entity view...");
Set<String> expectedActualAttributesSet =
new HashSet<>(Arrays.asList("caKey1", "caKey2", "caKey3", "caKey4"));
assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet));
EntityView savedView = getNewSavedEntityView("Test entity view"); EntityView savedView = getNewSavedEntityView("Test entity view");
Thread.sleep(1000); log.debug("fetching entity view telemetry...");
List<Map<String, Object>> values = await("telemetry/ENTITY_VIEW")
List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + .atMost(TIMEOUT, SECONDS)
"/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); .until(() -> doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() +
"/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {
}),
x -> x.size() >= expectedActualAttributesSet.size());
log.debug("asserting...");
assertEquals("value1", getValue(values, "caKey1")); assertEquals("value1", getValue(values, "caKey1"));
assertEquals(true, getValue(values, "caKey2")); assertEquals(true, getValue(values, "caKey2"));
assertEquals(42.0, getValue(values, "caKey3")); assertEquals(42.0, getValue(values, "caKey3"));
@ -371,18 +389,17 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
@Test @Test
public void testTheCopyOfAttrsOutOfTSForTheView() throws Exception { public void testTheCopyOfAttrsOutOfTSForTheView() throws Exception {
Set<String> expectedActualAttributesSet = Set.of("caKey1", "caKey2", "caKey3", "caKey4");
Set<String> actualAttributesSet = Set<String> actualAttributesSet =
getAttributesByKeys("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}"); getAttributesByKeys("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}", expectedActualAttributesSet);
Set<String> expectedActualAttributesSet = new HashSet<>(Arrays.asList("caKey1", "caKey2", "caKey3", "caKey4"));
assertTrue(actualAttributesSet.containsAll(expectedActualAttributesSet));
List<Map<String, Object>> valueTelemetryOfDevices = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() + List<Map<String, Object>> valueTelemetryOfDevices = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + testDevice.getId().getId().toString() +
"/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {
});
EntityView view = new EntityView(); EntityView view = new EntityView();
view.setEntityId(testDevice.getId()); view.setEntityId(testDevice.getId());
view.setTenantId(savedTenant.getId()); view.setTenantId(tenantId);
view.setName("Test entity view"); view.setName("Test entity view");
view.setType("default"); view.setType("default");
view.setKeys(telemetry); view.setKeys(telemetry);
@ -390,28 +407,49 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
view.setEndTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") / 10); view.setEndTimeMs((long) getValue(valueTelemetryOfDevices, "lastActivityTime") / 10);
EntityView savedView = doPost("/api/entityView", view, EntityView.class); EntityView savedView = doPost("/api/entityView", view, EntityView.class);
Thread.sleep(1000);
List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + List<Map<String, Object>> values = doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() +
"/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {}); "/values/attributes?keys=" + String.join(",", actualAttributesSet), new TypeReference<>() {
});
assertEquals(0, values.size()); assertEquals(0, values.size());
} }
@Test @Test
public void testGetTelemetryWhenEntityViewTimeRangeInsideTimestampRange() throws Exception { public void testGetTelemetryWhenEntityViewTimeRangeInsideTimestampRange() throws Exception {
uploadTelemetry("{\"tsKey1\":\"value1\", \"tsKey2\":true, \"tsKey3\":40.0}"); DeviceTypeFilter dtf = new DeviceTypeFilter(testDevice.getType(), testDevice.getName());
Thread.sleep(1000); List<String> tsKeys = List.of("tsKey1", "tsKey2", "tsKey3");
DeviceCredentials deviceCredentials = doGet("/api/device/" + testDevice.getId().getId() + "/credentials", DeviceCredentials.class);
assertEquals(testDevice.getId(), deviceCredentials.getDeviceId());
String accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken);
long now = System.currentTimeMillis();
getWsClient().subscribeTsUpdate(tsKeys, now, TimeUnit.HOURS.toMillis(1), dtf);
getWsClient().registerWaitForUpdate();
uploadTelemetry("{\"tsKey1\":\"value1\", \"tsKey2\":true, \"tsKey3\":40.0}", accessToken);
getWsClient().waitForUpdate();
long startTimeMs = System.currentTimeMillis(); long startTimeMs = System.currentTimeMillis();
uploadTelemetry("{\"tsKey1\":\"value2\", \"tsKey2\":false, \"tsKey3\":80.0}");
Thread.sleep(1000); getWsClient().registerWaitForUpdate();
uploadTelemetry("{\"tsKey1\":\"value3\", \"tsKey2\":false, \"tsKey3\":120.0}"); uploadTelemetry("{\"tsKey1\":\"value2\", \"tsKey2\":false, \"tsKey3\":80.0}", accessToken);
getWsClient().waitForUpdate();
Thread.sleep(3);
getWsClient().registerWaitForUpdate();
uploadTelemetry("{\"tsKey1\":\"value3\", \"tsKey2\":false, \"tsKey3\":120.0}", accessToken);
getWsClient().waitForUpdate();
long endTimeMs = System.currentTimeMillis(); long endTimeMs = System.currentTimeMillis();
uploadTelemetry("{\"tsKey1\":\"value4\", \"tsKey2\":true, \"tsKey3\":160.0}"); getWsClient().registerWaitForUpdate();
uploadTelemetry("{\"tsKey1\":\"value4\", \"tsKey2\":true, \"tsKey3\":160.0}", accessToken);
getWsClient().waitForUpdate();
String deviceId = testDevice.getId().getId().toString(); String deviceId = testDevice.getId().getId().toString();
Set<String> keys = getTelemetryKeys("DEVICE", deviceId); Set<String> keys = getTelemetryKeys("DEVICE", deviceId);
Thread.sleep(1000);
EntityView view = createEntityView("Test entity view", startTimeMs, endTimeMs); EntityView view = createEntityView("Test entity view", startTimeMs, endTimeMs);
EntityView savedView = doPost("/api/entityView", view, EntityView.class); EntityView savedView = doPost("/api/entityView", view, EntityView.class);
@ -428,14 +466,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
Assert.assertEquals(1, actualValues.get("tsKey3").size()); Assert.assertEquals(1, actualValues.get("tsKey3").size());
} }
private void uploadTelemetry(String strKvs) throws Exception { private void uploadTelemetry(String strKvs, String accessToken) throws Exception {
String viewDeviceId = testDevice.getId().getId().toString(); String viewDeviceId = testDevice.getId().getId().toString();
DeviceCredentials deviceCredentials =
doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class);
assertEquals(testDevice.getId(), deviceCredentials.getDeviceId());
String accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken);
String clientId = MqttAsyncClient.generateClientId(); String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence()); MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence());
@ -443,35 +475,45 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
MqttConnectOptions options = new MqttConnectOptions(); MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(accessToken); options.setUserName(accessToken);
client.connect(options); client.connect(options);
awaitConnected(client, TimeUnit.SECONDS.toMillis(30)); awaitConnected(client, SECONDS.toMillis(30));
MqttMessage message = new MqttMessage(); MqttMessage message = new MqttMessage();
message.setPayload(strKvs.getBytes()); message.setPayload(strKvs.getBytes());
client.publish("v1/devices/me/telemetry", message); IMqttDeliveryToken token = client.publish("v1/devices/me/telemetry", message);
Thread.sleep(1000); await("mqtt ack").pollInterval(5, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null);
client.disconnect(); client.disconnect();
} }
private void awaitConnected(MqttAsyncClient client, long ms) throws InterruptedException { private void awaitConnected(MqttAsyncClient client, long ms) throws InterruptedException {
long start = System.currentTimeMillis(); await("awaitConnected").pollInterval(5, MILLISECONDS).atMost(TIMEOUT, SECONDS)
while (!client.isConnected()) { .until(client::isConnected);
Thread.sleep(100);
if (start + ms < System.currentTimeMillis()) {
throw new RuntimeException("Client is not connected!");
}
}
} }
private Set<String> getTelemetryKeys(String type, String id) throws Exception { private Set<String> getTelemetryKeys(String type, String id) throws Exception {
return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", new TypeReference<>() {})); return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + "/keys/timeseries", new TypeReference<>() {
}));
}
private Set<String> getAttributeKeys(String type, String id) throws Exception {
return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + "/keys/attributes", new TypeReference<>() {
}));
} }
private Map<String, List<Map<String, String>>> getTelemetryValues(String type, String id, Set<String> keys, Long startTs, Long endTs) throws Exception { private Map<String, List<Map<String, String>>> getTelemetryValues(String type, String id, Set<String> keys, Long startTs, Long endTs) throws Exception {
return doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id + return doGetAsyncTyped("/api/plugins/telemetry/" + type + "/" + id +
"/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, new TypeReference<>() {}); "/values/timeseries?keys=" + String.join(",", keys) + "&startTs=" + startTs + "&endTs=" + endTs, new TypeReference<>() {
});
} }
private Set<String> getAttributesByKeys(String stringKV) throws Exception { private Set<String> getAttributesByKeys(String stringKV, Set<String> expectedKeySet) throws Exception {
DeviceTypeFilter dtf = new DeviceTypeFilter(testDevice.getType(), testDevice.getName());
List<EntityKey> keysToSubscribe = expectedKeySet.stream()
.map(key -> new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, key))
.collect(Collectors.toList());
getWsClient().subscribeLatestUpdate(keysToSubscribe, dtf);
String viewDeviceId = testDevice.getId().getId().toString(); String viewDeviceId = testDevice.getId().getId().toString();
log.debug("deviceid {}", viewDeviceId);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class);
assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); assertEquals(testDevice.getId(), deviceCredentials.getDeviceId());
@ -479,20 +521,24 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
String accessToken = deviceCredentials.getCredentialsId(); String accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken); assertNotNull(accessToken);
log.debug("creating mqtt client...");
String clientId = MqttAsyncClient.generateClientId(); String clientId = MqttAsyncClient.generateClientId();
MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence()); MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions(); MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(accessToken); options.setUserName(accessToken);
client.connect(options); client.connect(options);
awaitConnected(client, TimeUnit.SECONDS.toMillis(30)); awaitConnected(client, SECONDS.toMillis(30));
log.debug("mqtt connected...");
MqttMessage message = new MqttMessage(); MqttMessage message = new MqttMessage();
message.setPayload((stringKV).getBytes()); message.setPayload((stringKV).getBytes());
client.publish("v1/devices/me/attributes", message); getWsClient().registerWaitForUpdate();
Thread.sleep(1000); IMqttDeliveryToken token = client.publish("v1/devices/me/attributes", message);
client.disconnect(); log.debug("publish token.message {}", token.getMessage());
return new HashSet<>(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + viewDeviceId + "/keys/attributes", new TypeReference<>() {})); await("mqtt ack").pollInterval(5, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null);
log.debug("token.message delivered {}", token.getMessage());
assertThat(getWsClient().waitForUpdate()).as("ws update received").isNotBlank();
return getAttributeKeys("DEVICE", viewDeviceId);
} }
private Object getValue(List<Map<String, Object>> values, String stringValue) { private Object getValue(List<Map<String, Object>> values, String stringValue) {
@ -502,15 +548,19 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
.findFirst().get().get("value"); .findFirst().get().get("value");
} }
private EntityView getNewSavedEntityView(String name) throws Exception { private EntityView getNewSavedEntityView(String name) {
EntityView view = createEntityView(name, 0, 0); EntityView view = createEntityView(name, 0, 0);
return doPost("/api/entityView", view, EntityView.class); return doPost("/api/entityView", view, EntityView.class);
} }
private ListenableFuture<EntityView> getNewSavedEntityViewAsync(String name) {
return executor.submit(() -> getNewSavedEntityView(name));
}
private EntityView createEntityView(String name, long startTimeMs, long endTimeMs) { private EntityView createEntityView(String name, long startTimeMs, long endTimeMs) {
EntityView view = new EntityView(); EntityView view = new EntityView();
view.setEntityId(testDevice.getId()); view.setEntityId(testDevice.getId());
view.setTenantId(savedTenant.getId()); view.setTenantId(tenantId);
view.setName(name); view.setName(name);
view.setType("default"); view.setType("default");
view.setKeys(telemetry); view.setKeys(telemetry);
@ -531,33 +581,41 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
return tenant; return tenant;
} }
private List<EntityView> fillListOf(int limit, String partOfName, String urlTemplate) throws Exception { private List<ListenableFuture<EntityView>> fillListByTemplate(int limit, String partOfName, String urlTemplate) {
List<EntityView> views = new ArrayList<>(); List<ListenableFuture<EntityView>> futures = new ArrayList<>(limit);
for (EntityView view : fillListOf(limit, partOfName)) { for (ListenableFuture<EntityView> viewFuture : fillListOf(limit, partOfName)) {
views.add(doPost(urlTemplate + view.getId().getId().toString(), EntityView.class)); futures.add(Futures.transform(viewFuture, view ->
doPost(urlTemplate + view.getId().getId().toString(), EntityView.class),
MoreExecutors.directExecutor()));
} }
return views; return futures;
} }
private List<EntityView> fillListOf(int limit, String partOfName) throws Exception { private List<ListenableFuture<EntityView>> fillListOf(int limit, String partOfName) {
List<EntityView> viewNames = new ArrayList<>(); List<ListenableFuture<EntityView>> viewNameFutures = new ArrayList<>(limit);
for (int i = 0; i < limit; i++) { for (int i = 0; i < limit; i++) {
String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15); boolean even = i % 2 == 0;
fullName = i % 2 == 0 ? fullName.toLowerCase() : fullName.toUpperCase(); ListenableFuture<CustomerId> customerFuture = executor.submit(() -> {
EntityView view = getNewSavedEntityView(fullName); Customer customer = getNewCustomer("Test customer " + Math.random());
Customer customer = getNewCustomer("Test customer " + String.valueOf(Math.random())); return doPost("/api/customer", customer, Customer.class).getId();
view.setCustomerId(doPost("/api/customer", customer, Customer.class).getId()); });
viewNames.add(doPost("/api/entityView", view, EntityView.class));
viewNameFutures.add(Futures.transform(customerFuture, customerId -> {
String fullName = partOfName + ' ' + RandomStringUtils.randomAlphanumeric(15);
fullName = even ? fullName.toLowerCase() : fullName.toUpperCase();
EntityView view = getNewSavedEntityView(fullName);
view.setCustomerId(customerId);
return doPost("/api/entityView", view, EntityView.class);
}, MoreExecutors.directExecutor()));
} }
return viewNames; return viewNameFutures;
} }
private List<EntityView> loadListOf(PageLink pageLink, String urlTemplate) throws Exception { private List<EntityView> loadListOf(PageLink pageLink, String urlTemplate) throws Exception {
List<EntityView> loadedItems = new ArrayList<>(); List<EntityView> loadedItems = new ArrayList<>();
PageData<EntityView> pageData; PageData<EntityView> pageData;
do { do {
pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityView>>() { pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF, pageLink);
}, pageLink);
loadedItems.addAll(pageData.getData()); loadedItems.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -571,8 +629,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
List<EntityViewInfo> loadedItems = new ArrayList<>(); List<EntityViewInfo> loadedItems = new ArrayList<>();
PageData<EntityViewInfo> pageData; PageData<EntityViewInfo> pageData;
do { do {
pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference<PageData<EntityViewInfo>>() { pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_INFO_TYPE_REF, pageLink);
}, pageLink);
loadedItems.addAll(pageData.getData()); loadedItems.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -596,7 +653,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
+ "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class); + "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
PageData<EntityView> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?", PageData<EntityView> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?",
new TypeReference<PageData<EntityView>>() {}, new PageLink(100)); PAGE_DATA_ENTITY_VIEW_TYPE_REF, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
@ -604,7 +661,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
+ "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class); + "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/entityViews?",
new TypeReference<PageData<EntityView>>() {}, new PageLink(100)); PAGE_DATA_ENTITY_VIEW_TYPE_REF, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }

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

@ -79,7 +79,7 @@ public abstract class BaseOtaPackageControllerTest extends AbstractControllerTes
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile", null); DeviceProfile deviceProfile = this.createDeviceProfile("Device Profile");
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(savedDeviceProfile); Assert.assertNotNull(savedDeviceProfile);
deviceProfileId = savedDeviceProfile.getId(); deviceProfileId = savedDeviceProfile.getId();

244
application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java

@ -16,24 +16,55 @@
package org.thingsboard.server.controller; package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultActions;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantInfo;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; 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.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@TestPropertySource(properties = {
"js.evaluator=mock",
})
@Slf4j
public abstract class BaseTenantControllerTest extends AbstractControllerTest { public abstract class BaseTenantControllerTest extends AbstractControllerTest {
private IdComparator<Tenant> idComparator = new IdComparator<>(); static final TypeReference<PageData<Tenant>> PAGE_DATA_TENANT_TYPE_REF = new TypeReference<>() {
};
static final TypeReference<PageData<TenantInfo>> PAGE_DATA_TENANT_INFO_TYPE_REF = new TypeReference<>() {
};
ListeningExecutorService executor;
@Before
public void setUp() throws Exception {
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
}
@After
public void tearDown() throws Exception {
executor.shutdownNow();
}
@Test @Test
public void testSaveTenant() throws Exception { public void testSaveTenant() throws Exception {
@ -47,10 +78,10 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
Assert.assertEquals(tenant.getTitle(), savedTenant.getTitle()); Assert.assertEquals(tenant.getTitle(), savedTenant.getTitle());
savedTenant.setTitle("My new tenant"); savedTenant.setTitle("My new tenant");
doPost("/api/tenant", savedTenant, Tenant.class); doPost("/api/tenant", savedTenant, Tenant.class);
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class); Tenant foundTenant = doGet("/api/tenant/" + savedTenant.getId().getId().toString(), Tenant.class);
Assert.assertEquals(foundTenant.getTitle(), savedTenant.getTitle()); Assert.assertEquals(foundTenant.getTitle(), savedTenant.getTitle());
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
@ -60,18 +91,18 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
tenant.setTitle(RandomStringUtils.randomAlphanumeric(300)); tenant.setTitle(RandomStringUtils.randomAlphanumeric(300));
doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255")));
} }
@Test @Test
public void testFindTenantById() throws Exception { public void testFindTenantById() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class); Tenant foundTenant = doGet("/api/tenant/" + savedTenant.getId().getId().toString(), Tenant.class);
Assert.assertNotNull(foundTenant); Assert.assertNotNull(foundTenant);
Assert.assertEquals(savedTenant, foundTenant); Assert.assertEquals(savedTenant, foundTenant);
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
@ -80,22 +111,22 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
TenantInfo foundTenant = doGet("/api/tenant/info/"+savedTenant.getId().getId().toString(), TenantInfo.class); TenantInfo foundTenant = doGet("/api/tenant/info/" + savedTenant.getId().getId().toString(), TenantInfo.class);
Assert.assertNotNull(foundTenant); Assert.assertNotNull(foundTenant);
Assert.assertEquals(new TenantInfo(savedTenant, "Default"), foundTenant); Assert.assertEquals(new TenantInfo(savedTenant, "Default"), foundTenant);
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testSaveTenantWithEmptyTitle() throws Exception { public void testSaveTenantWithEmptyTitle() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
doPost("/api/tenant", tenant) doPost("/api/tenant", tenant)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Tenant title should be specified"))); .andExpect(statusReason(containsString("Tenant title should be specified")));
} }
@Test @Test
public void testSaveTenantWithInvalidEmail() throws Exception { public void testSaveTenantWithInvalidEmail() throws Exception {
loginSysAdmin(); loginSysAdmin();
@ -103,140 +134,147 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
tenant.setEmail("invalid@mail"); tenant.setEmail("invalid@mail");
doPost("/api/tenant", tenant) doPost("/api/tenant", tenant)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Invalid email address format"))); .andExpect(statusReason(containsString("Invalid email address format")));
} }
@Test @Test
public void testDeleteTenant() throws Exception { public void testDeleteTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
doGet("/api/tenant/"+savedTenant.getId().getId().toString()) doGet("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
} }
@Test @Test
public void testFindTenants() throws Exception { public void testFindTenants() throws Exception {
loginSysAdmin(); loginSysAdmin();
List<Tenant> tenants = new ArrayList<>(); List<Tenant> tenants = new ArrayList<>();
PageLink pageLink = new PageLink(17); PageLink pageLink = new PageLink(17);
PageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); PageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
tenants.addAll(pageData.getData()); tenants.addAll(pageData.getData());
for (int i=0;i<56;i++) { List<ListenableFuture<Tenant>> createFutures = new ArrayList<>(56);
for (int i = 0; i < 56; i++) {
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("Tenant"+i); tenant.setTitle("Tenant" + i);
tenants.add(doPost("/api/tenant", tenant, Tenant.class)); createFutures.add(executor.submit(() ->
doPost("/api/tenant", tenant, Tenant.class)));
} }
tenants.addAll(Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS));
List<Tenant> loadedTenants = new ArrayList<>(); List<Tenant> loadedTenants = new ArrayList<>();
pageLink = new PageLink(17); pageLink = new PageLink(17);
do { do {
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
loadedTenants.addAll(pageData.getData()); loadedTenants.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(tenants, idComparator); assertThat(tenants).containsExactlyInAnyOrderElementsOf(loadedTenants);
Collections.sort(loadedTenants, idComparator);
deleteEntitiesAsync("/api/tenant/", loadedTenants.stream()
Assert.assertEquals(tenants, loadedTenants); .filter((t) -> !TEST_TENANT_NAME.equals(t.getTitle()))
.collect(Collectors.toList()), executor).get(TIMEOUT, TimeUnit.SECONDS);
for (Tenant tenant : loadedTenants) {
if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
doDelete("/api/tenant/"+tenant.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17); pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
} }
@Test @Test
public void testFindTenantsByTitle() throws Exception { public void testFindTenantsByTitle() throws Exception {
log.debug("login sys admin");
loginSysAdmin(); loginSysAdmin();
log.debug("test started");
String title1 = "Tenant title 1"; String title1 = "Tenant title 1";
List<Tenant> tenantsTitle1 = new ArrayList<>(); List<ListenableFuture<Tenant>> createFutures = new ArrayList<>(134);
for (int i=0;i<134;i++) { for (int i = 0; i < 134; i++) {
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
String title = title1+suffix; String title = title1 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
tenant.setTitle(title); tenant.setTitle(title);
tenantsTitle1.add(doPost("/api/tenant", tenant, Tenant.class)); createFutures.add(executor.submit(() ->
doPost("/api/tenant", tenant, Tenant.class)));
} }
List<Tenant> tenantsTitle1 = Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("saved '{}', qty {}", title1, tenantsTitle1.size());
String title2 = "Tenant title 2"; String title2 = "Tenant title 2";
List<Tenant> tenantsTitle2 = new ArrayList<>(); createFutures = new ArrayList<>(127);
for (int i=0;i<127;i++) { for (int i = 0; i < 127; i++) {
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10));
String title = title2+suffix; String title = title2 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
tenant.setTitle(title); tenant.setTitle(title);
tenantsTitle2.add(doPost("/api/tenant", tenant, Tenant.class)); createFutures.add(executor.submit(() ->
doPost("/api/tenant", tenant, Tenant.class)));
} }
List<Tenant> loadedTenantsTitle1 = new ArrayList<>(); List<Tenant> tenantsTitle2 = Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("saved '{}', qty {}", title2, tenantsTitle2.size());
List<Tenant> loadedTenantsTitle1 = new ArrayList<>(134);
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<Tenant> pageData = null; PageData<Tenant> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
loadedTenantsTitle1.addAll(pageData.getData()); loadedTenantsTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(tenantsTitle1, idComparator); log.debug("found by name '{}', step 15 {}", title1, loadedTenantsTitle1.size());
Collections.sort(loadedTenantsTitle1, idComparator);
assertThat(tenantsTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedTenantsTitle1);
Assert.assertEquals(tenantsTitle1, loadedTenantsTitle1); log.debug("asserted");
List<Tenant> loadedTenantsTitle2 = new ArrayList<>(); List<Tenant> loadedTenantsTitle2 = new ArrayList<>(127);
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
loadedTenantsTitle2.addAll(pageData.getData()); loadedTenantsTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(tenantsTitle2, idComparator); log.debug("found by name '{}', step 4 {}", title1, loadedTenantsTitle2.size());
Collections.sort(loadedTenantsTitle2, idComparator); assertThat(tenantsTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedTenantsTitle2);
log.debug("asserted");
Assert.assertEquals(tenantsTitle2, loadedTenantsTitle2);
deleteEntitiesAsync("/api/tenant/", loadedTenantsTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("deleted '{}', size {}", title1, loadedTenantsTitle1.size());
for (Tenant tenant : loadedTenantsTitle1) {
doDelete("/api/tenant/"+tenant.getId().getId().toString())
.andExpect(status().isOk());
}
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (Tenant tenant : loadedTenantsTitle2) { log.debug("tried to search another '{}', step 4", title1);
doDelete("/api/tenant/"+tenant.getId().getId().toString())
.andExpect(status().isOk()); deleteEntitiesAsync("/api/tenant/", loadedTenantsTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
} log.debug("deleted '{}', size {}", title2, loadedTenantsTitle2.size());
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
log.debug("tried to search another '{}', step 4", title2);
} }
@Test @Test
@ -244,42 +282,50 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
loginSysAdmin(); loginSysAdmin();
List<TenantInfo> tenants = new ArrayList<>(); List<TenantInfo> tenants = new ArrayList<>();
PageLink pageLink = new PageLink(17); PageLink pageLink = new PageLink(17);
PageData<TenantInfo> pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink); PageData<TenantInfo> pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
tenants.addAll(pageData.getData()); tenants.addAll(pageData.getData());
for (int i=0;i<56;i++) { List<ListenableFuture<TenantInfo>> createFutures = new ArrayList<>(56);
for (int i = 0; i < 56; i++) {
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("Tenant"+i); tenant.setTitle("Tenant" + i);
tenants.add(new TenantInfo(doPost("/api/tenant", tenant, Tenant.class), "Default")); createFutures.add(executor.submit(() ->
new TenantInfo(doPost("/api/tenant", tenant, Tenant.class), "Default")));
} }
tenants.addAll(Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS));
List<TenantInfo> loadedTenants = new ArrayList<>(); List<TenantInfo> loadedTenants = new ArrayList<>();
pageLink = new PageLink(17); pageLink = new PageLink(17);
do { do {
pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
loadedTenants.addAll(pageData.getData()); loadedTenants.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(tenants, idComparator); assertThat(tenants).containsExactlyInAnyOrderElementsOf(loadedTenants);
Collections.sort(loadedTenants, idComparator);
Assert.assertEquals(tenants, loadedTenants); deleteEntitiesAsync("/api/tenant/", loadedTenants.stream()
.filter((t) -> !TEST_TENANT_NAME.equals(t.getTitle()))
for (TenantInfo tenant : loadedTenants) { .collect(Collectors.toList()), executor).get(TIMEOUT, TimeUnit.SECONDS);
if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
doDelete("/api/tenant/"+tenant.getId().getId().toString())
.andExpect(status().isOk());
}
}
pageLink = new PageLink(17); pageLink = new PageLink(17);
pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink); pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
} }
ListenableFuture<List<ResultActions>> deleteTenantsAsync(String urlTemplate, List<Tenant> tenants) {
List<ListenableFuture<ResultActions>> futures = new ArrayList<>(tenants.size());
for (Tenant device : tenants) {
futures.add(executor.submit(() ->
doDelete(urlTemplate + device.getId().getId())
.andExpect(status().isOk())));
}
return Futures.allAsList(futures);
}
} }

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

@ -24,10 +24,6 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.kv.Aggregation;
import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
@ -46,19 +42,12 @@ import org.thingsboard.server.common.data.query.FilterPredicateValue;
import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.data.query.KeyFilter;
import org.thingsboard.server.common.data.query.NumericFilterPredicate; import org.thingsboard.server.common.data.query.NumericFilterPredicate;
import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.common.data.query.TsValue;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope; import org.thingsboard.server.service.subscription.TbAttributeSubscriptionScope;
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
import org.thingsboard.server.service.telemetry.cmd.TelemetryPluginCmdsWrapper;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountCmd; 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.EntityCountUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityHistoryCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.TimeSeriesCmd;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -68,77 +57,38 @@ import java.util.concurrent.TimeUnit;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest { public abstract class BaseWebsocketApiTest extends AbstractControllerTest {
private Tenant savedTenant;
private User tenantAdmin;
private TbTestWebSocketClient wsClient;
@Autowired @Autowired
private TelemetrySubscriptionService tsService; private TelemetrySubscriptionService tsService;
@Before Device device;
public void beforeTest() throws Exception { DeviceTypeFilter dtf;
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); @Before
public void setUp() throws Exception {
loginTenantAdmin();
wsClient = buildAndConnectWebSocketClient(); device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
dtf = new DeviceTypeFilter(device.getType(), device.getName());
} }
@After @After
public void afterTest() throws Exception { public void tearDown() throws Exception {
wsClient.close(); doDelete("/api/device/" + device.getId().getId())
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testEntityDataHistoryWsCmd() throws Exception { public void testEntityDataHistoryWsCmd() throws Exception {
Device device = new Device(); List<String> keys = List.of("temperature");
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
DeviceTypeFilter dtf = new DeviceTypeFilter(); EntityDataUpdate update = getWsClient().sendHistoryCmd(keys, now, TimeUnit.HOURS.toMillis(1), dtf);
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf,
new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
EntityHistoryCmd historyCmd = new EntityHistoryCmd();
historyCmd.setKeys(Arrays.asList("temperature"));
historyCmd.setAgg(Aggregation.NONE);
historyCmd.setLimit(1000);
historyCmd.setStartTs(now - TimeUnit.HOURS.toMillis(1));
historyCmd.setEndTs(now);
EntityDataCmd cmd = new EntityDataCmd(1, edq, historyCmd, null, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
String msg = wsClient.waitForReply();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
@ -154,9 +104,8 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
sendTelemetry(device, tsData); sendTelemetry(device, tsData);
Thread.sleep(100); Thread.sleep(100);
wsClient.send(mapper.writeValueAsString(wrapper)); update = getWsClient().sendHistoryCmd(keys, now, TimeUnit.HOURS.toMillis(1), dtf);
msg = wsClient.waitForReply();
update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
List<EntityData> dataList = update.getUpdate(); List<EntityData> dataList = update.getUpdate();
Assert.assertNotNull(dataList); Assert.assertNotNull(dataList);
@ -171,41 +120,16 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
@Test @Test
public void testEntityDataTimeSeriesWsCmd() throws Exception { public void testEntityDataTimeSeriesWsCmd() throws Exception {
Device device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
DeviceTypeFilter dtf = new DeviceTypeFilter(); EntityDataUpdate update = getWsClient().sendEntityDataQuery(dtf);
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, null, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
String msg = wsClient.waitForReply();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
Assert.assertEquals(device.getId(), pageData.getData().get(0).getEntityId()); Assert.assertEquals(device.getId(), pageData.getData().get(0).getEntityId());
TimeSeriesCmd tsCmd = new TimeSeriesCmd();
tsCmd.setKeys(Arrays.asList("temperature"));
tsCmd.setAgg(Aggregation.NONE);
tsCmd.setLimit(1000);
tsCmd.setStartTs(now - TimeUnit.HOURS.toMillis(1));
tsCmd.setTimeWindow(TimeUnit.HOURS.toMillis(1));
TsKvEntry dataPoint1 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("temperature", 42L)); TsKvEntry dataPoint1 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("temperature", 42L));
TsKvEntry dataPoint2 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(2), new LongDataEntry("temperature", 43L)); TsKvEntry dataPoint2 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(2), new LongDataEntry("temperature", 43L));
TsKvEntry dataPoint3 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(3), new LongDataEntry("temperature", 44L)); TsKvEntry dataPoint3 = new BasicTsKvEntry(now - TimeUnit.MINUTES.toMillis(3), new LongDataEntry("temperature", 44L));
@ -214,12 +138,7 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
sendTelemetry(device, tsData); sendTelemetry(device, tsData);
Thread.sleep(100); Thread.sleep(100);
cmd = new EntityDataCmd(1, null, null, null, tsCmd); update = getWsClient().subscribeTsUpdate(List.of("temperature"), now, TimeUnit.HOURS.toMillis(1));
wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
msg = wsClient.waitForReply();
update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
List<EntityData> listData = update.getUpdate(); List<EntityData> listData = update.getUpdate();
Assert.assertNotNull(listData); Assert.assertNotNull(listData);
@ -233,10 +152,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
now = System.currentTimeMillis(); now = System.currentTimeMillis();
TsKvEntry dataPoint4 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 45L)); TsKvEntry dataPoint4 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 45L));
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
Thread.sleep(100); Thread.sleep(100);
sendTelemetry(device, Arrays.asList(dataPoint4)); sendTelemetry(device, Arrays.asList(dataPoint4));
msg = wsClient.waitForUpdate(); String msg = getWsClient().waitForUpdate();
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
@ -252,44 +171,26 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
@Test @Test
public void testEntityCountWsCmd() throws Exception { public void testEntityCountWsCmd() throws Exception {
Device device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(System.currentTimeMillis(), new LongDataEntry("temperature", 42L)); AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(System.currentTimeMillis(), new LongDataEntry("temperature", 42L));
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Collections.singletonList(dataPoint1)); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Collections.singletonList(dataPoint1));
DeviceTypeFilter dtf1 = new DeviceTypeFilter(); EntityCountQuery edq1 = new EntityCountQuery(dtf, Collections.emptyList());
dtf1.setDeviceNameFilter("D");
dtf1.setDeviceType("default");
EntityCountQuery edq1 = new EntityCountQuery(dtf1, Collections.emptyList());
EntityCountCmd cmd1 = new EntityCountCmd(1, edq1); EntityCountCmd cmd1 = new EntityCountCmd(1, edq1);
TelemetryPluginCmdsWrapper wrapper1 = new TelemetryPluginCmdsWrapper(); getWsClient().send(cmd1);
wrapper1.setEntityCountCmds(Collections.singletonList(cmd1));
wsClient.send(mapper.writeValueAsString(wrapper1)); EntityCountUpdate update1 = getWsClient().parseCountReply(getWsClient().waitForReply());
String msg1 = wsClient.waitForReply();
EntityCountUpdate update1 = mapper.readValue(msg1, EntityCountUpdate.class);
Assert.assertEquals(1, update1.getCmdId()); Assert.assertEquals(1, update1.getCmdId());
Assert.assertEquals(1, update1.getCount()); Assert.assertEquals(1, update1.getCount());
DeviceTypeFilter dtf2 = new DeviceTypeFilter(); DeviceTypeFilter dtf2 = new DeviceTypeFilter("non-existing-device-type", "D");
dtf2.setDeviceNameFilter("D");
dtf2.setDeviceType("non-existing-device-type");
EntityCountQuery edq2 = new EntityCountQuery(dtf2, Collections.emptyList()); EntityCountQuery edq2 = new EntityCountQuery(dtf2, Collections.emptyList());
EntityCountCmd cmd2 = new EntityCountCmd(2, edq2); EntityCountCmd cmd2 = new EntityCountCmd(2, edq2);
TelemetryPluginCmdsWrapper wrapper2 = new TelemetryPluginCmdsWrapper(); getWsClient().send(cmd2);
wrapper2.setEntityCountCmds(Collections.singletonList(cmd2));
wsClient.send(mapper.writeValueAsString(wrapper2));
String msg2 = wsClient.waitForReply(); String msg2 = getWsClient().waitForReply();
EntityCountUpdate update2 = mapper.readValue(msg2, EntityCountUpdate.class); EntityCountUpdate update2 = getWsClient().parseCountReply(getWsClient().waitForReply());
Assert.assertEquals(2, update2.getCmdId()); Assert.assertEquals(2, update2.getCmdId());
Assert.assertEquals(0, update2.getCount()); Assert.assertEquals(0, update2.getCount());
@ -301,19 +202,12 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
highTemperatureFilter.setPredicate(predicate); highTemperatureFilter.setPredicate(predicate);
highTemperatureFilter.setValueType(EntityKeyValueType.NUMERIC); highTemperatureFilter.setValueType(EntityKeyValueType.NUMERIC);
DeviceTypeFilter dtf3 = new DeviceTypeFilter(); DeviceTypeFilter dtf3 = new DeviceTypeFilter("default", "D");
dtf3.setDeviceNameFilter("D");
dtf3.setDeviceType("default");
EntityCountQuery edq3 = new EntityCountQuery(dtf3, Collections.singletonList(highTemperatureFilter)); EntityCountQuery edq3 = new EntityCountQuery(dtf3, Collections.singletonList(highTemperatureFilter));
EntityCountCmd cmd3 = new EntityCountCmd(3, edq3); EntityCountCmd cmd3 = new EntityCountCmd(3, edq3);
getWsClient().send(cmd3);
TelemetryPluginCmdsWrapper wrapper3 = new TelemetryPluginCmdsWrapper(); EntityCountUpdate update3 = getWsClient().parseCountReply(getWsClient().waitForReply());
wrapper3.setEntityCountCmds(Collections.singletonList(cmd3));
wsClient.send(mapper.writeValueAsString(wrapper3));
String msg3 = wsClient.waitForReply();
EntityCountUpdate update3 = mapper.readValue(msg3, EntityCountUpdate.class);
Assert.assertEquals(3, update3.getCmdId()); Assert.assertEquals(3, update3.getCmdId());
Assert.assertEquals(1, update3.getCount()); Assert.assertEquals(1, update3.getCount());
@ -325,47 +219,26 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
highTemperatureFilter2.setPredicate(predicate2); highTemperatureFilter2.setPredicate(predicate2);
highTemperatureFilter2.setValueType(EntityKeyValueType.NUMERIC); highTemperatureFilter2.setValueType(EntityKeyValueType.NUMERIC);
DeviceTypeFilter dtf4 = new DeviceTypeFilter(); DeviceTypeFilter dtf4 = new DeviceTypeFilter("default", "D");
dtf4.setDeviceNameFilter("D");
dtf4.setDeviceType("default");
EntityCountQuery edq4 = new EntityCountQuery(dtf4, Collections.singletonList(highTemperatureFilter2)); EntityCountQuery edq4 = new EntityCountQuery(dtf4, Collections.singletonList(highTemperatureFilter2));
EntityCountCmd cmd4 = new EntityCountCmd(4, edq4); EntityCountCmd cmd4 = new EntityCountCmd(4, edq4);
TelemetryPluginCmdsWrapper wrapper4 = new TelemetryPluginCmdsWrapper(); getWsClient().send(cmd4);
wrapper4.setEntityCountCmds(Collections.singletonList(cmd4));
wsClient.send(mapper.writeValueAsString(wrapper4));
String msg4 = wsClient.waitForReply(); EntityCountUpdate update4 = getWsClient().parseCountReply(getWsClient().waitForReply());
EntityCountUpdate update4 = mapper.readValue(msg4, EntityCountUpdate.class);
Assert.assertEquals(4, update4.getCmdId()); Assert.assertEquals(4, update4.getCmdId());
Assert.assertEquals(0, update4.getCount()); Assert.assertEquals(0, update4.getCount());
} }
@Test @Test
public void testEntityDataLatestWidgetFlow() throws Exception { public void testEntityDataLatestWidgetFlow() throws Exception {
Device device = new Device(); List<EntityKey> keys = List.of(new EntityKey(EntityKeyType.TIME_SERIES, "temperature"));
device.setName("Device"); long now = System.currentTimeMillis() - 100;
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis();
DeviceTypeFilter dtf = new DeviceTypeFilter();
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null), Collections.emptyList(),
Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")), Collections.emptyList());
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, null, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper(); EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null),
wrapper.setEntityDataCmds(Collections.singletonList(cmd)); Collections.emptyList(), keys, Collections.emptyList());
wsClient.send(mapper.writeValueAsString(wrapper)); EntityDataUpdate update = getWsClient().sendEntityDataQuery(edq);
String msg = wsClient.waitForReply();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
@ -379,17 +252,7 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
List<TsKvEntry> tsData = Arrays.asList(dataPoint1); List<TsKvEntry> tsData = Arrays.asList(dataPoint1);
sendTelemetry(device, tsData); sendTelemetry(device, tsData);
Thread.sleep(100); update = getWsClient().subscribeLatestUpdate(keys);
LatestValueCmd latestCmd = new LatestValueCmd();
latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")));
cmd = new EntityDataCmd(1, null, null, latestCmd, null);
wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
msg = wsClient.waitForReply();
update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
@ -404,11 +267,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
now = System.currentTimeMillis(); now = System.currentTimeMillis();
TsKvEntry dataPoint2 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 52L)); TsKvEntry dataPoint2 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 52L));
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint2)); sendTelemetry(device, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate();
update = mapper.readValue(msg, EntityDataUpdate.class); update = getWsClient().parseDataReply(getWsClient().waitForUpdate());
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
List<EntityData> eData = update.getUpdate(); List<EntityData> eData = update.getUpdate();
Assert.assertNotNull(eData); Assert.assertNotNull(eData);
@ -419,43 +281,25 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(new TsValue(dataPoint2.getTs(), dataPoint2.getValueAsString()), tsValue); Assert.assertEquals(new TsValue(dataPoint2.getTs(), dataPoint2.getValueAsString()), tsValue);
//Sending update from the past, while latest value has new timestamp; //Sending update from the past, while latest value has new timestamp;
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint1)); sendTelemetry(device, Arrays.asList(dataPoint1));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); String msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
//Sending duplicate update again //Sending duplicate update again
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint2)); sendTelemetry(device, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
} }
@Test @Test
public void testEntityDataLatestTsWsCmd() throws Exception { public void testEntityDataLatestTsWsCmd() throws Exception {
Device device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
List<EntityKey> keys = List.of(new EntityKey(EntityKeyType.TIME_SERIES, "temperature"));
DeviceTypeFilter dtf = new DeviceTypeFilter(); EntityDataUpdate update = getWsClient().subscribeLatestUpdate(keys, dtf);
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null), Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
LatestValueCmd latestCmd = new LatestValueCmd();
latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.TIME_SERIES, "temperature")));
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
String msg = wsClient.waitForReply();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
@ -471,13 +315,7 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Thread.sleep(100); Thread.sleep(100);
cmd = new EntityDataCmd(1, edq, null, latestCmd, null); update = getWsClient().subscribeLatestUpdate(keys, dtf);
wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
msg = wsClient.waitForReply();
update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
@ -492,11 +330,9 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
now = System.currentTimeMillis(); now = System.currentTimeMillis();
TsKvEntry dataPoint2 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 52L)); TsKvEntry dataPoint2 = new BasicTsKvEntry(now, new LongDataEntry("temperature", 52L));
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint2)); sendTelemetry(device, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(); update = getWsClient().parseDataReply(getWsClient().waitForUpdate());
update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
List<EntityData> eData = update.getUpdate(); List<EntityData> eData = update.getUpdate();
Assert.assertNotNull(eData); Assert.assertNotNull(eData);
@ -507,45 +343,24 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(new TsValue(dataPoint2.getTs(), dataPoint2.getValueAsString()), tsValue); Assert.assertEquals(new TsValue(dataPoint2.getTs(), dataPoint2.getValueAsString()), tsValue);
//Sending update from the past, while latest value has new timestamp; //Sending update from the past, while latest value has new timestamp;
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint1)); sendTelemetry(device, Arrays.asList(dataPoint1));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); String msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
//Sending duplicate update again //Sending duplicate update again
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendTelemetry(device, Arrays.asList(dataPoint2)); sendTelemetry(device, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
} }
@Test @Test
public void testEntityDataLatestAttrWsCmd() throws Exception { public void testEntityDataLatestAttrWsCmd() throws Exception {
Device device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
List<EntityKey> keys = List.of(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, "serverAttributeKey"));
DeviceTypeFilter dtf = new DeviceTypeFilter(); EntityDataUpdate update = getWsClient().subscribeLatestUpdate(keys, dtf);
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
LatestValueCmd latestCmd = new LatestValueCmd();
latestCmd.setKeys(Collections.singletonList(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, "serverAttributeKey")));
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
String msg = wsClient.waitForReply();
Assert.assertNotNull(msg);
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
@ -555,15 +370,14 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(0, pageData.getData().get(0).getLatest().get(EntityKeyType.SERVER_ATTRIBUTE).get("serverAttributeKey").getTs()); Assert.assertEquals(0, pageData.getData().get(0).getLatest().get(EntityKeyType.SERVER_ATTRIBUTE).get("serverAttributeKey").getTs());
Assert.assertEquals("", pageData.getData().get(0).getLatest().get(EntityKeyType.SERVER_ATTRIBUTE).get("serverAttributeKey").getValue()); Assert.assertEquals("", pageData.getData().get(0).getLatest().get(EntityKeyType.SERVER_ATTRIBUTE).get("serverAttributeKey").getValue());
getWsClient().registerWaitForUpdate();
wsClient.registerWaitForUpdate();
Thread.sleep(500); Thread.sleep(500);
AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("serverAttributeKey", 42L)); AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("serverAttributeKey", 42L));
List<AttributeKvEntry> tsData = Arrays.asList(dataPoint1); List<AttributeKvEntry> tsData = Arrays.asList(dataPoint1);
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, tsData); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, tsData);
msg = wsClient.waitForUpdate(); String msg = getWsClient().waitForUpdate();
Assert.assertNotNull(msg); Assert.assertNotNull(msg);
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
@ -579,10 +393,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
now = System.currentTimeMillis(); now = System.currentTimeMillis();
AttributeKvEntry dataPoint2 = new BaseAttributeKvEntry(now, new LongDataEntry("serverAttributeKey", 52L)); AttributeKvEntry dataPoint2 = new BaseAttributeKvEntry(now, new LongDataEntry("serverAttributeKey", 52L));
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
Thread.sleep(500); Thread.sleep(500);
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint2)); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(); msg = getWsClient().waitForUpdate();
Assert.assertNotNull(msg); Assert.assertNotNull(msg);
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
@ -596,51 +410,31 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(new TsValue(dataPoint2.getLastUpdateTs(), dataPoint2.getValueAsString()), tsValue); Assert.assertEquals(new TsValue(dataPoint2.getLastUpdateTs(), dataPoint2.getValueAsString()), tsValue);
//Sending update from the past, while latest value has new timestamp; //Sending update from the past, while latest value has new timestamp;
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
Thread.sleep(500); Thread.sleep(500);
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint1)); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint1));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
//Sending duplicate update again //Sending duplicate update again
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
Thread.sleep(500); Thread.sleep(500);
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint2)); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
} }
@Test @Test
public void testEntityDataLatestAttrTypesWsCmd() throws Exception { public void testEntityDataLatestAttrTypesWsCmd() throws Exception {
Device device = new Device();
device.setName("Device");
device.setType("default");
device.setLabel("testLabel" + (int) (Math.random() * 1000));
device = doPost("/api/device", device, Device.class);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
List<EntityKey> keys = List.of(
new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, "serverAttributeKey"),
new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, "clientAttributeKey"),
new EntityKey(EntityKeyType.SHARED_ATTRIBUTE, "sharedAttributeKey"),
new EntityKey(EntityKeyType.ATTRIBUTE, "anyAttributeKey"));
EntityDataUpdate update = getWsClient().subscribeLatestUpdate(keys, dtf);
DeviceTypeFilter dtf = new DeviceTypeFilter();
dtf.setDeviceNameFilter("D");
dtf.setDeviceType("default");
EntityDataQuery edq = new EntityDataQuery(dtf, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
LatestValueCmd latestCmd = new LatestValueCmd();
List<EntityKey> keys = new ArrayList<>();
keys.add(new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, "serverAttributeKey"));
keys.add(new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, "clientAttributeKey"));
keys.add(new EntityKey(EntityKeyType.SHARED_ATTRIBUTE, "sharedAttributeKey"));
keys.add(new EntityKey(EntityKeyType.ATTRIBUTE, "anyAttributeKey"));
latestCmd.setKeys(keys);
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
wsClient.send(mapper.writeValueAsString(wrapper));
String msg = wsClient.waitForReply();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
PageData<EntityData> pageData = update.getData(); PageData<EntityData> pageData = update.getData();
Assert.assertNotNull(pageData); Assert.assertNotNull(pageData);
@ -659,14 +453,14 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(0, pageData.getData().get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey").getTs()); Assert.assertEquals(0, pageData.getData().get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey").getTs());
Assert.assertEquals("", pageData.getData().get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey").getValue()); Assert.assertEquals("", pageData.getData().get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey").getValue());
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("serverAttributeKey", 42L)); AttributeKvEntry dataPoint1 = new BaseAttributeKvEntry(now - TimeUnit.MINUTES.toMillis(1), new LongDataEntry("serverAttributeKey", 42L));
List<AttributeKvEntry> tsData = Arrays.asList(dataPoint1); List<AttributeKvEntry> tsData = Arrays.asList(dataPoint1);
Thread.sleep(100); Thread.sleep(100);
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, tsData); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, tsData);
msg = wsClient.waitForUpdate(); String msg = getWsClient().waitForUpdate();
Assert.assertNotNull(msg); Assert.assertNotNull(msg);
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
@ -679,22 +473,22 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
Assert.assertEquals(new TsValue(dataPoint1.getLastUpdateTs(), dataPoint1.getValueAsString()), attrValue); Assert.assertEquals(new TsValue(dataPoint1.getLastUpdateTs(), dataPoint1.getValueAsString()), attrValue);
//Sending update from the past, while latest value has new timestamp; //Sending update from the past, while latest value has new timestamp;
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendAttributes(device, TbAttributeSubscriptionScope.SHARED_SCOPE, Arrays.asList(dataPoint1)); sendAttributes(device, TbAttributeSubscriptionScope.SHARED_SCOPE, Arrays.asList(dataPoint1));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
//Sending duplicate update again //Sending duplicate update again
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint1)); sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint1));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
Assert.assertNull(msg); Assert.assertNull(msg);
//Sending update from the past, while latest value has new timestamp; //Sending update from the past, while latest value has new timestamp;
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
AttributeKvEntry dataPoint2 = new BaseAttributeKvEntry(now, new LongDataEntry("sharedAttributeKey", 42L)); AttributeKvEntry dataPoint2 = new BaseAttributeKvEntry(now, new LongDataEntry("sharedAttributeKey", 42L));
sendAttributes(device, TbAttributeSubscriptionScope.SHARED_SCOPE, Arrays.asList(dataPoint2)); sendAttributes(device, TbAttributeSubscriptionScope.SHARED_SCOPE, Arrays.asList(dataPoint2));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
eData = update.getUpdate(); eData = update.getUpdate();
@ -705,10 +499,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
attrValue = eData.get(0).getLatest().get(EntityKeyType.SHARED_ATTRIBUTE).get("sharedAttributeKey"); attrValue = eData.get(0).getLatest().get(EntityKeyType.SHARED_ATTRIBUTE).get("sharedAttributeKey");
Assert.assertEquals(new TsValue(dataPoint2.getLastUpdateTs(), dataPoint2.getValueAsString()), attrValue); Assert.assertEquals(new TsValue(dataPoint2.getLastUpdateTs(), dataPoint2.getValueAsString()), attrValue);
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
AttributeKvEntry dataPoint3 = new BaseAttributeKvEntry(now, new LongDataEntry("clientAttributeKey", 42L)); AttributeKvEntry dataPoint3 = new BaseAttributeKvEntry(now, new LongDataEntry("clientAttributeKey", 42L));
sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint3)); sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint3));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
eData = update.getUpdate(); eData = update.getUpdate();
@ -719,10 +513,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
attrValue = eData.get(0).getLatest().get(EntityKeyType.CLIENT_ATTRIBUTE).get("clientAttributeKey"); attrValue = eData.get(0).getLatest().get(EntityKeyType.CLIENT_ATTRIBUTE).get("clientAttributeKey");
Assert.assertEquals(new TsValue(dataPoint3.getLastUpdateTs(), dataPoint3.getValueAsString()), attrValue); Assert.assertEquals(new TsValue(dataPoint3.getLastUpdateTs(), dataPoint3.getValueAsString()), attrValue);
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
AttributeKvEntry dataPoint4 = new BaseAttributeKvEntry(now, new LongDataEntry("anyAttributeKey", 42L)); AttributeKvEntry dataPoint4 = new BaseAttributeKvEntry(now, new LongDataEntry("anyAttributeKey", 42L));
sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint4)); sendAttributes(device, TbAttributeSubscriptionScope.CLIENT_SCOPE, Arrays.asList(dataPoint4));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
eData = update.getUpdate(); eData = update.getUpdate();
@ -733,10 +527,10 @@ public abstract class BaseWebsocketApiTest extends AbstractWebsocketTest {
attrValue = eData.get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey"); attrValue = eData.get(0).getLatest().get(EntityKeyType.ATTRIBUTE).get("anyAttributeKey");
Assert.assertEquals(new TsValue(dataPoint4.getLastUpdateTs(), dataPoint4.getValueAsString()), attrValue); Assert.assertEquals(new TsValue(dataPoint4.getLastUpdateTs(), dataPoint4.getValueAsString()), attrValue);
wsClient.registerWaitForUpdate(); getWsClient().registerWaitForUpdate();
AttributeKvEntry dataPoint5 = new BaseAttributeKvEntry(now, new LongDataEntry("anyAttributeKey", 43L)); AttributeKvEntry dataPoint5 = new BaseAttributeKvEntry(now, new LongDataEntry("anyAttributeKey", 43L));
sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint5)); sendAttributes(device, TbAttributeSubscriptionScope.SERVER_SCOPE, Arrays.asList(dataPoint5));
msg = wsClient.waitForUpdate(TimeUnit.SECONDS.toMillis(1)); msg = getWsClient().waitForUpdate(TimeUnit.SECONDS.toMillis(1));
update = mapper.readValue(msg, EntityDataUpdate.class); update = mapper.readValue(msg, EntityDataUpdate.class);
Assert.assertEquals(1, update.getCmdId()); Assert.assertEquals(1, update.getCmdId());
eData = update.getUpdate(); eData = update.getUpdate();

5
application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java

@ -30,9 +30,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
}) })
public class ControllerSqlTestSuite { public class ControllerSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

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

@ -18,9 +18,25 @@ package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient; import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake; import org.java_websocket.handshake.ServerHandshake;
import org.thingsboard.common.util.JacksonUtil;
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.v2.EntityCountCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityCountUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
import org.thingsboard.server.service.telemetry.cmd.v2.EntityHistoryCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd;
import org.thingsboard.server.service.telemetry.cmd.v2.TimeSeriesCmd;
import java.net.URI; import java.net.URI;
import java.nio.channels.NotYetConnectedException; import java.nio.channels.NotYetConnectedException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -73,6 +89,18 @@ public class TbTestWebSocketClient extends WebSocketClient {
super.send(text); super.send(text);
} }
public void send(EntityDataCmd cmd) throws NotYetConnectedException {
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityDataCmds(Collections.singletonList(cmd));
this.send(JacksonUtil.toString(wrapper));
}
public void send(EntityCountCmd cmd) throws NotYetConnectedException {
TelemetryPluginCmdsWrapper wrapper = new TelemetryPluginCmdsWrapper();
wrapper.setEntityCountCmds(Collections.singletonList(cmd));
this.send(JacksonUtil.toString(wrapper));
}
public String waitForUpdate() { public String waitForUpdate() {
return waitForUpdate(TimeUnit.SECONDS.toMillis(3)); return waitForUpdate(TimeUnit.SECONDS.toMillis(3));
} }
@ -94,4 +122,95 @@ public class TbTestWebSocketClient extends WebSocketClient {
} }
return lastMsg; return lastMsg;
} }
public EntityDataUpdate parseDataReply(String msg) {
return JacksonUtil.fromString(msg, EntityDataUpdate.class);
}
public EntityCountUpdate parseCountReply(String msg) {
return JacksonUtil.fromString(msg, EntityCountUpdate.class);
}
public EntityDataUpdate subscribeLatestUpdate(List<EntityKey> keys, EntityFilter entityFilter) {
EntityDataQuery edq = new EntityDataQuery(entityFilter, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return subscribeLatestUpdate(keys, edq);
}
public EntityDataUpdate subscribeLatestUpdate(List<EntityKey> keys) {
return subscribeLatestUpdate(keys, (EntityDataQuery) null);
}
public EntityDataUpdate subscribeLatestUpdate(List<EntityKey> keys, EntityDataQuery edq) {
LatestValueCmd latestCmd = new LatestValueCmd();
latestCmd.setKeys(keys);
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, latestCmd, null);
send(cmd);
return parseDataReply(waitForReply());
}
public EntityDataUpdate subscribeTsUpdate(List<String> keys, long startTs, long timeWindow) {
return subscribeTsUpdate(keys, startTs, timeWindow, (EntityDataQuery) null);
}
public EntityDataUpdate subscribeTsUpdate(List<String> keys, long startTs, long timeWindow, EntityFilter entityFilter) {
EntityDataQuery edq = new EntityDataQuery(entityFilter, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return subscribeTsUpdate(keys, startTs, timeWindow, edq);
}
public EntityDataUpdate subscribeTsUpdate(List<String> keys, long startTs, long timeWindow, EntityDataQuery edq) {
TimeSeriesCmd tsCmd = new TimeSeriesCmd();
tsCmd.setKeys(keys);
tsCmd.setAgg(Aggregation.NONE);
tsCmd.setLimit(1000);
tsCmd.setStartTs(startTs - timeWindow);
tsCmd.setTimeWindow(timeWindow);
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, null, tsCmd);
send(cmd);
return parseDataReply(waitForReply());
}
public EntityDataUpdate sendHistoryCmd(List<String> keys, long startTs, long timeWindow) {
return sendHistoryCmd(keys, startTs, timeWindow, (EntityDataQuery) null);
}
public EntityDataUpdate sendHistoryCmd(List<String> keys, long startTs, long timeWindow, EntityFilter entityFilter) {
EntityDataQuery edq = new EntityDataQuery(entityFilter,
new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return sendHistoryCmd(keys, startTs, timeWindow, edq);
}
public EntityDataUpdate sendHistoryCmd(List<String> keys, long startTs, long timeWindow, EntityDataQuery edq) {
EntityHistoryCmd historyCmd = new EntityHistoryCmd();
historyCmd.setKeys(keys);
historyCmd.setAgg(Aggregation.NONE);
historyCmd.setLimit(1000);
historyCmd.setStartTs(startTs - timeWindow);
historyCmd.setEndTs(startTs);
EntityDataCmd cmd = new EntityDataCmd(1, edq, historyCmd, null, null);
send(cmd);
return parseDataReply(this.waitForReply());
}
public EntityDataUpdate sendEntityDataQuery(EntityDataQuery edq) {
log.warn("sendEntityDataQuery {}", edq);
EntityDataCmd cmd = new EntityDataCmd(1, edq, null, null, null);
send(cmd);
String msg = this.waitForReply();
return parseDataReply(msg);
}
public EntityDataUpdate sendEntityDataQuery(EntityFilter entityFilter) {
log.warn("sendEntityDataQuery {}", entityFilter);
EntityDataQuery edq = new EntityDataQuery(entityFilter, new EntityDataPageLink(1, 0, null, null),
Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
return sendEntityDataQuery(edq);
}
} }

24
application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java

@ -32,6 +32,7 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
@ -131,6 +132,9 @@ import java.util.concurrent.TimeUnit;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@TestPropertySource(properties = {
"edges.enabled=true",
})
abstract public class BaseEdgeTest extends AbstractControllerTest { abstract public class BaseEdgeTest extends AbstractControllerTest {
private static final String CUSTOM_DEVICE_PROFILE_NAME = "Thermostat"; private static final String CUSTOM_DEVICE_PROFILE_NAME = "Thermostat";
@ -195,7 +199,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
private void installation() throws Exception { private void installation() throws Exception {
edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class);
DeviceProfile deviceProfile = this.createDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME, null); DeviceProfile deviceProfile = this.createDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME);
extendDeviceProfileData(deviceProfile); extendDeviceProfileData(deviceProfile);
doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
@ -972,7 +976,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
String timeseriesData = "{\"data\":{\"temperature\":25},\"ts\":" + System.currentTimeMillis() + "}"; String timeseriesData = "{\"data\":{\"temperature\":25},\"ts\":" + System.currentTimeMillis() + "}";
JsonNode timeseriesEntityData = mapper.readTree(timeseriesData); JsonNode timeseriesEntityData = mapper.readTree(timeseriesData);
EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData); EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
edgeEventService.save(edgeEvent); edgeEventService.saveAsync(edgeEvent).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertTrue(edgeImitator.waitForMessages());
@ -1003,12 +1007,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
testAttributesDeleteMsg(device); testAttributesDeleteMsg(device);
} }
private void testAttributesUpdatedMsg(Device device) throws JsonProcessingException, InterruptedException { private void testAttributesUpdatedMsg(Device device) throws Exception {
String attributesData = "{\"scope\":\"SERVER_SCOPE\",\"kv\":{\"key1\":\"value1\"}}"; String attributesData = "{\"scope\":\"SERVER_SCOPE\",\"kv\":{\"key1\":\"value1\"}}";
JsonNode attributesEntityData = mapper.readTree(attributesData); JsonNode attributesEntityData = mapper.readTree(attributesData);
EdgeEvent edgeEvent1 = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, attributesEntityData); EdgeEvent edgeEvent1 = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, attributesEntityData);
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);
edgeEventService.save(edgeEvent1); edgeEventService.saveAsync(edgeEvent1).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertTrue(edgeImitator.waitForMessages());
@ -1028,12 +1032,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
Assert.assertEquals("value1", keyValueProto.getStringV()); Assert.assertEquals("value1", keyValueProto.getStringV());
} }
private void testPostAttributesMsg(Device device) throws JsonProcessingException, InterruptedException { private void testPostAttributesMsg(Device device) throws Exception {
String postAttributesData = "{\"scope\":\"SERVER_SCOPE\",\"kv\":{\"key2\":\"value2\"}}"; String postAttributesData = "{\"scope\":\"SERVER_SCOPE\",\"kv\":{\"key2\":\"value2\"}}";
JsonNode postAttributesEntityData = mapper.readTree(postAttributesData); JsonNode postAttributesEntityData = mapper.readTree(postAttributesData);
EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.POST_ATTRIBUTES, device.getId().getId(), EdgeEventType.DEVICE, postAttributesEntityData); EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.POST_ATTRIBUTES, device.getId().getId(), EdgeEventType.DEVICE, postAttributesEntityData);
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);
edgeEventService.save(edgeEvent); edgeEventService.saveAsync(edgeEvent).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertTrue(edgeImitator.waitForMessages());
@ -1053,12 +1057,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
Assert.assertEquals("value2", keyValueProto.getStringV()); Assert.assertEquals("value2", keyValueProto.getStringV());
} }
private void testAttributesDeleteMsg(Device device) throws JsonProcessingException, InterruptedException { private void testAttributesDeleteMsg(Device device) throws Exception {
String deleteAttributesData = "{\"scope\":\"SERVER_SCOPE\",\"keys\":[\"key1\",\"key2\"]}"; String deleteAttributesData = "{\"scope\":\"SERVER_SCOPE\",\"keys\":[\"key1\",\"key2\"]}";
JsonNode deleteAttributesEntityData = mapper.readTree(deleteAttributesData); JsonNode deleteAttributesEntityData = mapper.readTree(deleteAttributesData);
EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_DELETED, device.getId().getId(), EdgeEventType.DEVICE, deleteAttributesEntityData); EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.ATTRIBUTES_DELETED, device.getId().getId(), EdgeEventType.DEVICE, deleteAttributesEntityData);
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);
edgeEventService.save(edgeEvent); edgeEventService.saveAsync(edgeEvent).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertTrue(edgeImitator.waitForMessages());
@ -1093,7 +1097,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.RPC_CALL, device.getId().getId(), EdgeEventType.DEVICE, body); EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.RPC_CALL, device.getId().getId(), EdgeEventType.DEVICE, body);
edgeImitator.expectMessageAmount(1); edgeImitator.expectMessageAmount(1);
edgeEventService.save(edgeEvent); edgeEventService.saveAsync(edgeEvent).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
Assert.assertTrue(edgeImitator.waitForMessages()); Assert.assertTrue(edgeImitator.waitForMessages());
@ -1118,7 +1122,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
JsonNode timeseriesEntityData = mapper.readTree(timeseriesData); JsonNode timeseriesEntityData = mapper.readTree(timeseriesData);
EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED,
device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData); device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
edgeEventService.save(edgeEvent); edgeEventService.saveAsync(edgeEvent).get();
clusterService.onEdgeEventUpdate(tenantId, edge.getId()); clusterService.onEdgeEventUpdate(tenantId, edge.getId());
} }

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

@ -26,8 +26,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
}) })
public class EdgeSqlTestSuite { public class EdgeSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

5
application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java

@ -27,9 +27,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
}) })
public class RuleEngineSqlTestSuite { public class RuleEngineSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

5
application/src/test/java/org/thingsboard/server/rules/lifecycle/AbstractRuleEngineLifecycleIntegrationTest.java

@ -75,6 +75,9 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
@Autowired @Autowired
protected EventService eventService; protected EventService eventService;
@Autowired
protected InMemoryStorage storage;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
@ -159,7 +162,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis()))); Collections.singletonList(new BaseAttributeKvEntry(new StringDataEntry("serverAttributeKey", "serverAttributeValue"), System.currentTimeMillis())));
await("total inMemory queue lag is empty").atMost(30, TimeUnit.SECONDS) await("total inMemory queue lag is empty").atMost(30, TimeUnit.SECONDS)
.until(() -> InMemoryStorage.getInstance().getLagTotal() == 0); .until(() -> storage.getLagTotal() == 0);
Thread.sleep(1000); Thread.sleep(1000);
TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class); TbMsgCallback tbMsgCallback = Mockito.mock(TbMsgCallback.class);

5
application/src/test/java/org/thingsboard/server/service/ServiceSqlTestSuite.java

@ -27,9 +27,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
}) })
public class ServiceSqlTestSuite { public class ServiceSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

50
application/src/test/java/org/thingsboard/server/service/script/MockJsInvokeService.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.service.script;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.UUID;
@Slf4j
@Service
@ConditionalOnProperty(prefix = "js", value = "evaluator", havingValue = "mock")
public class MockJsInvokeService implements JsInvokeService {
@Override
public ListenableFuture<UUID> eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames) {
log.warn("eval {} {} {} {}", tenantId, scriptType, scriptBody, argNames);
return Futures.immediateFuture(UUID.randomUUID());
}
@Override
public ListenableFuture<Object> invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) {
log.warn("invokeFunction {} {} {} {}", tenantId, customerId, scriptId, args);
return Futures.immediateFuture("{}");
}
@Override
public ListenableFuture<Void> release(UUID scriptId) {
log.warn("release {}", scriptId);
return Futures.immediateFuture(null);
}
}

121
application/src/test/java/org/thingsboard/server/service/sms/smpp/SmppSmsSenderTest.java

@ -0,0 +1,121 @@
/**
* 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.service.sms.smpp;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.api.Assertions;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.smpp.Session;
import org.smpp.pdu.SubmitSMResp;
import org.thingsboard.server.common.data.sms.config.SmppSmsProviderConfiguration;
import java.lang.reflect.Constructor;
import java.net.UnknownHostException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class SmppSmsSenderTest {
SmppSmsSender smppSmsSender;
SmppSmsProviderConfiguration smppConfig;
Session smppSession;
@Before
public void beforeEach() throws Exception {
Constructor<SmppSmsSender> constructor = SmppSmsSender.class.getDeclaredConstructor();
constructor.setAccessible(true);
smppSmsSender = spy(constructor.newInstance());
smppSession = mock(Session.class);
smppSmsSender.smppSession = smppSession;
smppConfig = new SmppSmsProviderConfiguration();
smppSmsSender.config = smppConfig;
}
@Test
public void testSendSms() throws Exception {
when(smppSession.isOpened()).thenReturn(true);
when(smppSession.submit(any())).thenReturn(new SubmitSMResp());
setDefaultSmppConfig();
String number = "123545";
String message = "message";
smppSmsSender.sendSms(number, message);
verify(smppSmsSender, never()).initSmppSession();
verify(smppSession).submit(argThat(submitRequest -> {
try {
return submitRequest.getShortMessage().equals(message) &&
submitRequest.getDestAddr().getAddress().equals(number) &&
submitRequest.getServiceType().equals(smppConfig.getServiceType()) &&
(StringUtils.isEmpty(smppConfig.getSourceAddress()) ? submitRequest.getSourceAddr().getAddress().equals("")
: submitRequest.getSourceAddr().getAddress().equals(smppConfig.getSourceAddress()) &&
submitRequest.getSourceAddr().getTon() == smppConfig.getSourceTon() &&
submitRequest.getSourceAddr().getNpi() == smppConfig.getSourceNpi()) &&
submitRequest.getDestAddr().getTon() == smppConfig.getDestinationTon() &&
submitRequest.getDestAddr().getNpi() == smppConfig.getDestinationNpi() &&
submitRequest.getDataCoding() == smppConfig.getCodingScheme() &&
submitRequest.getReplaceIfPresentFlag() == 0 &&
submitRequest.getEsmClass() == 0 &&
submitRequest.getProtocolId() == 0 &&
submitRequest.getPriorityFlag() == 0 &&
submitRequest.getRegisteredDelivery() == 0 &&
submitRequest.getSmDefaultMsgId() == 0;
} catch (Exception e) {
fail(e.getMessage());
return false;
}
}));
}
private void setDefaultSmppConfig() {
smppConfig.setProtocolVersion("3.3");
smppConfig.setHost("smpphost");
smppConfig.setPort(5687);
smppConfig.setSystemId("213131");
smppConfig.setPassword("35125q");
smppConfig.setSystemType("");
smppConfig.setBindType(SmppSmsProviderConfiguration.SmppBindType.TX);
smppConfig.setServiceType("");
smppConfig.setSourceAddress("");
smppConfig.setSourceTon((byte) 5);
smppConfig.setSourceNpi((byte) 0);
smppConfig.setDestinationTon((byte) 5);
smppConfig.setDestinationNpi((byte) 0);
smppConfig.setAddressRange("");
smppConfig.setCodingScheme((byte) 0);
}
}

2
application/src/test/java/org/thingsboard/server/service/sql/SequentialTimeseriesPersistenceTest.java

@ -56,8 +56,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@DaoSqlTest @DaoSqlTest
public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest { public class SequentialTimeseriesPersistenceTest extends AbstractControllerTest {
static final int TIMEOUT = 30;
final String TOTALIZER = "Totalizer"; final String TOTALIZER = "Totalizer";
final int TTL = 99999; final int TTL = 99999;
final String GENERIC_CUMULATIVE_OBJ = "genericCumulativeObj"; final String GENERIC_CUMULATIVE_OBJ = "genericCumulativeObj";

4
application/src/test/java/org/thingsboard/server/system/BaseHttpDeviceApiTest.java

@ -17,6 +17,7 @@ package org.thingsboard.server.system;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -35,6 +36,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
/** /**
* @author Andrew Shvayka * @author Andrew Shvayka
*/ */
@TestPropertySource(properties = {
"transport.http.enabled=true",
})
public abstract class BaseHttpDeviceApiTest extends AbstractControllerTest { public abstract class BaseHttpDeviceApiTest extends AbstractControllerTest {
private static final AtomicInteger idSeq = new AtomicInteger(new Random(System.currentTimeMillis()).nextInt()); private static final AtomicInteger idSeq = new AtomicInteger(new Random(System.currentTimeMillis()).nextInt());

5
application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java

@ -29,9 +29,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
}) })
public class SystemSqlTestSuite { public class SystemSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

14
application/src/test/java/org/thingsboard/server/transport/AbstractTransportIntegrationTest.java

@ -18,8 +18,6 @@ package org.thingsboard.server.transport;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
@ -27,8 +25,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractTransportIntegrationTest extends AbstractControllerTest { public abstract class AbstractTransportIntegrationTest extends AbstractControllerTest {
@ -95,21 +91,11 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle
" optional string params = 3;\n" + " optional string params = 3;\n" +
"}"; "}";
protected Tenant savedTenant;
protected User tenantAdmin;
protected Device savedDevice; protected Device savedDevice;
protected String accessToken; protected String accessToken;
protected DeviceProfile deviceProfile; protected DeviceProfile deviceProfile;
protected void processAfterTest() throws Exception {
loginSysAdmin();
if (savedTenant != null) {
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk());
}
}
protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) { protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) {
List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>(); List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>();
TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V); TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V);

5
application/src/test/java/org/thingsboard/server/transport/TransportNoSqlTestSuite.java

@ -40,9 +40,4 @@ public class TransportNoSqlTestSuite {
), ),
"cassandra-test.yaml", 30000l); "cassandra-test.yaml", 30000l);
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

21
application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java

@ -15,28 +15,21 @@
*/ */
package org.thingsboard.server.transport; package org.thingsboard.server.transport;
import org.junit.BeforeClass;
import org.junit.extensions.cpsuite.ClasspathSuite; import org.junit.extensions.cpsuite.ClasspathSuite;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.thingsboard.server.queue.memory.InMemoryStorage;
@RunWith(ClasspathSuite.class) @RunWith(ClasspathSuite.class)
@ClasspathSuite.ClassnameFilters({ @ClasspathSuite.ClassnameFilters({
"org.thingsboard.server.transport.*.rpc.sql.*Test", "org.thingsboard.server.transport.*.rpc.*Test",
"org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test", "org.thingsboard.server.transport.*.telemetry.timeseries.sql.*Test",
"org.thingsboard.server.transport.*.telemetry.attributes.sql.*Test", "org.thingsboard.server.transport.*.telemetry.attributes.*Test",
"org.thingsboard.server.transport.*.attributes.updates.sql.*Test", "org.thingsboard.server.transport.*.attributes.updates.*Test",
"org.thingsboard.server.transport.*.attributes.request.sql.*Test", "org.thingsboard.server.transport.*.attributes.request.*Test",
"org.thingsboard.server.transport.*.claim.sql.*Test", "org.thingsboard.server.transport.*.claim.*Test",
"org.thingsboard.server.transport.*.provision.sql.*Test", "org.thingsboard.server.transport.*.provision.*Test",
"org.thingsboard.server.transport.*.credentials.sql.*Test", "org.thingsboard.server.transport.*.credentials.*Test",
"org.thingsboard.server.transport.lwm2m.*.sql.*Test" "org.thingsboard.server.transport.lwm2m.*.sql.*Test"
}) })
public class TransportSqlTestSuite { public class TransportSqlTestSuite {
@BeforeClass
public static void cleanupInMemStorage() {
InMemoryStorage.getInstance().cleanup();
}
} }

202
application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java

@ -17,17 +17,16 @@ package org.thingsboard.server.transport.coap;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.CoapClient;
import org.junit.Assert; import org.junit.After;
import org.springframework.util.StringUtils; import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
@ -41,7 +40,6 @@ import org.thingsboard.server.common.data.device.profile.EfentoCoapDeviceTypeCon
import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.AbstractTransportIntegrationTest; import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
@ -49,6 +47,9 @@ import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@TestPropertySource(properties = {
"transport.coap.enabled=true",
})
@Slf4j @Slf4j
public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest { public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
@ -56,133 +57,104 @@ public abstract class AbstractCoapIntegrationTest extends AbstractTransportInteg
protected CoapClient client; protected CoapClient client;
@Override
protected void processAfterTest() throws Exception { protected void processAfterTest() throws Exception {
if (client != null) { if (client != null) {
client.shutdown(); client.shutdown();
} }
super.processAfterTest();
} }
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception { protected void processBeforeTest(CoapTestConfigProperties config) throws Exception {
this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); loginTenantAdmin();
} deviceProfile = createCoapDeviceProfile(config);
assertNotNull(deviceProfile);
protected void processBeforeTest(String deviceName, savedDevice = createDevice(config.getDeviceName(), deviceProfile.getName());
CoapDeviceType coapDeviceType,
TransportPayloadType payloadType,
String telemetryProtoSchema,
String attributesProtoSchema,
String rpcResponseProtoSchema,
String rpcRequestProtoSchema,
String provisionKey,
String provisionSecret,
DeviceProfileProvisionType provisionType
) throws Exception {
loginSysAdmin();
Tenant tenant = new Tenant();
tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant);
tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org");
tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
Device device = new Device();
device.setName(deviceName);
device.setType("default");
if (coapDeviceType != null) {
DeviceProfile coapDeviceProfile = createCoapDeviceProfile(payloadType, coapDeviceType, provisionSecret, provisionType, provisionKey, attributesProtoSchema, telemetryProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema);
deviceProfile = doPost("/api/deviceProfile", coapDeviceProfile, DeviceProfile.class);
device.setType(deviceProfile.getName());
device.setDeviceProfileId(deviceProfile.getId());
}
savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
assertNotNull(deviceCredentials);
assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
accessToken = deviceCredentials.getCredentialsId(); accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken); assertNotNull(accessToken);
} }
protected DeviceProfile createCoapDeviceProfile(TransportPayloadType transportPayloadType, CoapDeviceType coapDeviceType, protected DeviceProfile createCoapDeviceProfile(CoapTestConfigProperties config) throws Exception {
String provisionSecret, DeviceProfileProvisionType provisionType, CoapDeviceType coapDeviceType = config.getCoapDeviceType();
String provisionKey, String attributesProtoSchema, if (coapDeviceType == null) {
String telemetryProtoSchema, String rpcResponseProtoSchema, String rpcRequestProtoSchema) { DeviceProfileInfo defaultDeviceProfileInfo = doGet("/api/deviceProfileInfo/default", DeviceProfileInfo.class);
DeviceProfile deviceProfile = new DeviceProfile(); return doGet("/api/deviceProfile/" + defaultDeviceProfileInfo.getId().getId(), DeviceProfile.class);
deviceProfile.setName(transportPayloadType.name()); } else {
deviceProfile.setType(DeviceProfileType.DEFAULT); TransportPayloadType transportPayloadType = config.getTransportPayloadType();
deviceProfile.setProvisionType(provisionType); DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setProvisionDeviceKey(provisionKey); deviceProfile.setName(transportPayloadType.name());
deviceProfile.setDescription(transportPayloadType.name() + " Test"); deviceProfile.setType(DeviceProfileType.DEFAULT);
DeviceProfileData deviceProfileData = new DeviceProfileData(); DeviceProfileProvisionType provisionType = config.getProvisionType() != null ?
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); config.getProvisionType() : DeviceProfileProvisionType.DISABLED;
deviceProfile.setTransportType(DeviceTransportType.COAP); deviceProfile.setProvisionType(provisionType);
CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = new CoapDeviceProfileTransportConfiguration(); deviceProfile.setProvisionDeviceKey(config.getProvisionKey());
CoapDeviceTypeConfiguration coapDeviceTypeConfiguration; deviceProfile.setDescription(transportPayloadType.name() + " Test");
if (CoapDeviceType.DEFAULT.equals(coapDeviceType)) { DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = new DefaultCoapDeviceTypeConfiguration(); DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
TransportPayloadTypeConfiguration transportPayloadTypeConfiguration; deviceProfile.setTransportType(DeviceTransportType.COAP);
if (TransportPayloadType.PROTOBUF.equals(transportPayloadType)) { CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = new CoapDeviceProfileTransportConfiguration();
ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration(); CoapDeviceTypeConfiguration coapDeviceTypeConfiguration;
if (StringUtils.isEmpty(telemetryProtoSchema)) { if (CoapDeviceType.DEFAULT.equals(coapDeviceType)) {
telemetryProtoSchema = DEVICE_TELEMETRY_PROTO_SCHEMA; DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = new DefaultCoapDeviceTypeConfiguration();
} TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
if (StringUtils.isEmpty(attributesProtoSchema)) { if (TransportPayloadType.PROTOBUF.equals(transportPayloadType)) {
attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA; ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = new ProtoTransportPayloadConfiguration();
} String telemetryProtoSchema = config.getTelemetryProtoSchema();
if (StringUtils.isEmpty(rpcResponseProtoSchema)) { String attributesProtoSchema = config.getAttributesProtoSchema();
rpcResponseProtoSchema = DEVICE_RPC_RESPONSE_PROTO_SCHEMA; String rpcResponseProtoSchema = config.getRpcResponseProtoSchema();
} String rpcRequestProtoSchema = config.getRpcRequestProtoSchema();
if (StringUtils.isEmpty(rpcRequestProtoSchema)) { protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(
rpcRequestProtoSchema = DEVICE_RPC_REQUEST_PROTO_SCHEMA; telemetryProtoSchema != null ? telemetryProtoSchema : DEVICE_TELEMETRY_PROTO_SCHEMA
);
protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(
attributesProtoSchema != null ? attributesProtoSchema : DEVICE_ATTRIBUTES_PROTO_SCHEMA
);
protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(
rpcResponseProtoSchema != null ? rpcResponseProtoSchema : DEVICE_RPC_RESPONSE_PROTO_SCHEMA
);
protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(
rpcRequestProtoSchema != null ? rpcRequestProtoSchema : DEVICE_RPC_REQUEST_PROTO_SCHEMA
);
transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
} else {
transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
} }
protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema); defaultCoapDeviceTypeConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema); coapDeviceTypeConfiguration = defaultCoapDeviceTypeConfiguration;
protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(rpcResponseProtoSchema);
protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(rpcRequestProtoSchema);
transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
} else { } else {
transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration(); coapDeviceTypeConfiguration = new EfentoCoapDeviceTypeConfiguration();
} }
defaultCoapDeviceTypeConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration); coapDeviceProfileTransportConfiguration.setCoapDeviceTypeConfiguration(coapDeviceTypeConfiguration);
coapDeviceTypeConfiguration = defaultCoapDeviceTypeConfiguration; deviceProfileData.setTransportConfiguration(coapDeviceProfileTransportConfiguration);
} else { DeviceProfileProvisionConfiguration provisionConfiguration;
coapDeviceTypeConfiguration = new EfentoCoapDeviceTypeConfiguration(); switch (provisionType) {
} case ALLOW_CREATE_NEW_DEVICES:
coapDeviceProfileTransportConfiguration.setCoapDeviceTypeConfiguration(coapDeviceTypeConfiguration); provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(config.getProvisionSecret());
deviceProfileData.setTransportConfiguration(coapDeviceProfileTransportConfiguration); break;
DeviceProfileProvisionConfiguration provisionConfiguration; case CHECK_PRE_PROVISIONED_DEVICES:
switch (provisionType) { provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(config.getProvisionSecret());
case ALLOW_CREATE_NEW_DEVICES: break;
provisionConfiguration = new AllowCreateNewDevicesDeviceProfileProvisionConfiguration(provisionSecret); case DISABLED:
break; default:
case CHECK_PRE_PROVISIONED_DEVICES: provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(config.getProvisionSecret());
provisionConfiguration = new CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration(provisionSecret); break;
break; }
case DISABLED: deviceProfileData.setProvisionConfiguration(provisionConfiguration);
default: deviceProfileData.setConfiguration(configuration);
provisionConfiguration = new DisabledDeviceProfileProvisionConfiguration(provisionSecret); deviceProfile.setProfileData(deviceProfileData);
break; deviceProfile.setDefault(false);
deviceProfile.setDefaultRuleChainId(null);
return doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
} }
deviceProfileData.setProvisionConfiguration(provisionConfiguration); }
deviceProfileData.setConfiguration(configuration);
deviceProfile.setProfileData(deviceProfileData); protected Device createDevice(String name, String type) throws Exception {
deviceProfile.setDefault(false); Device device = new Device();
deviceProfile.setDefaultRuleChainId(null); device.setName(name);
return deviceProfile; device.setType(type);
return doPost("/api/device", device, Device.class);
} }
protected CoapClient getCoapClient(FeatureType featureType) { protected CoapClient getCoapClient(FeatureType featureType) {

46
application/src/test/java/org/thingsboard/server/transport/coap/CoapTestConfigProperties.java

@ -0,0 +1,46 @@
/**
* 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.coap;
import lombok.Builder;
import lombok.Data;
import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.TransportPayloadType;
@Data
@Builder
public class CoapTestConfigProperties {
String deviceName;
CoapDeviceType coapDeviceType;
TransportPayloadType transportPayloadType;
String telemetryTopicFilter;
String attributesTopicFilter;
String telemetryProtoSchema;
String attributesProtoSchema;
String rpcResponseProtoSchema;
String rpcRequestProtoSchema;
DeviceProfileProvisionType provisionType;
String provisionKey;
String provisionSecret;
}

12
application/src/test/java/org/thingsboard/server/transport/coap/attributes/AbstractCoapAttributesIntegrationTest.java

@ -16,10 +16,8 @@
package org.thingsboard.server.transport.coap.attributes; package org.thingsboard.server.transport.coap.attributes;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -30,14 +28,6 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap
protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," + protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," +
"\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}"; "\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}";
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
super.processBeforeTest(deviceName, coapDeviceType, payloadType);
}
protected void processAfterTest() throws Exception {
super.processAfterTest();
}
protected List<TransportProtos.TsKvProto> getTsKvProtoList() { protected List<TransportProtos.TsKvProto> getTsKvProtoList() {
TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("attribute1", "value1", TransportProtos.KeyValueType.STRING_V); TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("attribute1", "value1", TransportProtos.KeyValueType.STRING_V);
TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("attribute2", "true", TransportProtos.KeyValueType.BOOLEAN_V); TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("attribute2", "true", TransportProtos.KeyValueType.BOOLEAN_V);

11
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestIntegrationTest.java

@ -18,7 +18,6 @@ package org.thingsboard.server.transport.coap.attributes.request;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapResponse; import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry; import org.eclipse.californium.core.coap.MediaTypeRegistry;
@ -26,6 +25,8 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest; import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
@ -37,13 +38,17 @@ import static org.junit.Assert.assertNotNull;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesRequestIntegrationTest extends AbstractCoapAttributesIntegrationTest { @DaoSqlTest
public class CoapAttributesRequestIntegrationTest extends AbstractCoapAttributesIntegrationTest {
protected static final long CLIENT_REQUEST_TIMEOUT = 60000L; protected static final long CLIENT_REQUEST_TIMEOUT = 60000L;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Request attribute values from the server", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Request attribute values from the server")
.build();
processBeforeTest(configProperties);
} }
@After @After

12
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestJsonIntegrationTest.java

@ -21,13 +21,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesRequestJsonIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest { @DaoSqlTest
public class CoapAttributesRequestJsonIntegrationTest extends CoapAttributesRequestIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Request attribute values from the server json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Request attribute values from the server json")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
} }
@After @After

14
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/AbstractCoapAttributesRequestProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/CoapAttributesRequestProtoIntegrationTest.java

@ -36,7 +36,9 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -47,7 +49,8 @@ import static org.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends AbstractCoapAttributesRequestIntegrationTest { @DaoSqlTest
public class CoapAttributesRequestProtoIntegrationTest extends CoapAttributesRequestIntegrationTest {
public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" + public static final String ATTRIBUTES_SCHEMA_STR = "syntax =\"proto3\";\n" +
"\n" + "\n" +
@ -73,8 +76,13 @@ public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends
@Before @Before
@Override @Override
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT, CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED); .deviceName("Test Request attribute values from the server proto")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.attributesProtoSchema(ATTRIBUTES_SCHEMA_STR)
.build();
processBeforeTest(configProperties);
} }
@Test @Test

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestJsonSqlIntegrationTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestProtoSqlIntegrationTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/request/sql/CoapAttributesRequestSqlIntegrationTest.java

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

13
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesIntegrationTest.java

@ -30,10 +30,13 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.coapserver.DefaultCoapServerService; import org.thingsboard.server.coapserver.DefaultCoapServerService;
import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.common.transport.service.DefaultTransportService; import org.thingsboard.server.common.transport.service.DefaultTransportService;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import org.thingsboard.server.transport.coap.CoapTransportResource; import org.thingsboard.server.transport.coap.CoapTransportResource;
import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest; import org.thingsboard.server.transport.coap.attributes.AbstractCoapAttributesIntegrationTest;
import org.thingsboard.server.common.msg.session.FeatureType;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -45,7 +48,8 @@ import static org.mockito.Mockito.spy;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesUpdatesIntegrationTest extends AbstractCoapAttributesIntegrationTest { @DaoSqlTest
public class CoapAttributesUpdatesIntegrationTest extends AbstractCoapAttributesIntegrationTest {
private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}"; private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}";
@ -66,7 +70,10 @@ public abstract class AbstractCoapAttributesUpdatesIntegrationTest extends Abstr
coapTransportResource = spy( (CoapTransportResource) api.getChild("v1") ); coapTransportResource = spy( (CoapTransportResource) api.getChild("v1") );
api.delete(api.getChild("v1") ); api.delete(api.getChild("v1") );
api.add(coapTransportResource); api.add(coapTransportResource);
processBeforeTest("Test Subscribe to attribute updates", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Subscribe to attribute updates")
.build();
processBeforeTest(configProperties);
} }
@After @After

12
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesJsonIntegrationTest.java

@ -21,13 +21,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesUpdatesJsonIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest { @DaoSqlTest
public class CoapAttributesUpdatesJsonIntegrationTest extends CoapAttributesUpdatesIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Subscribe to attribute updates")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
} }
@After @After

12
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/CoapAttributesUpdatesProtoIntegrationTest.java

@ -23,7 +23,9 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -35,11 +37,17 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends AbstractCoapAttributesUpdatesIntegrationTest { @DaoSqlTest
public class CoapAttributesUpdatesProtoIntegrationTest extends CoapAttributesUpdatesIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Subscribe to attribute updates", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Subscribe to attribute updates")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.build();
processBeforeTest(configProperties);
} }
@After @After

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlIntegrationTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlJsonIntegrationTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/sql/CoapAttributesUpdatesSqlProtoIntegrationTest.java

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

20
application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimDeviceTest.java

@ -24,7 +24,6 @@ import org.eclipse.californium.elements.exception.ConnectorException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.data.ClaimRequest; import org.thingsboard.server.common.data.ClaimRequest;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -33,6 +32,9 @@ import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.dao.device.claim.ClaimResponse; import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.io.IOException; import java.io.IOException;
@ -41,7 +43,8 @@ import static org.junit.Assert.assertNotNull;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegrationTest { @DaoSqlTest
public class CoapClaimDeviceTest extends AbstractCoapIntegrationTest {
protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!"; protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!";
@ -50,21 +53,24 @@ public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegratio
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
super.processBeforeTest("Test Claim device", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Claim device")
.build();
processBeforeTest(configProperties);
createCustomerAndUser(); createCustomerAndUser();
} }
protected void createCustomerAndUser() throws Exception { protected void createCustomerAndUser() throws Exception {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTenantId(savedTenant.getId()); customer.setTenantId(tenantId);
customer.setTitle("Test Claiming Customer"); customer.setTitle("Test Claiming Customer");
savedCustomer = doPost("/api/customer", customer, Customer.class); savedCustomer = doPost("/api/customer", customer, Customer.class);
assertNotNull(savedCustomer); assertNotNull(savedCustomer);
assertEquals(savedTenant.getId(), savedCustomer.getTenantId()); assertEquals(tenantId, savedCustomer.getTenantId());
User user = new User(); User user = new User();
user.setAuthority(Authority.CUSTOMER_USER); user.setAuthority(Authority.CUSTOMER_USER);
user.setTenantId(savedTenant.getId()); user.setTenantId(tenantId);
user.setCustomerId(savedCustomer.getId()); user.setCustomerId(savedCustomer.getId());
user.setEmail("customer@thingsboard.org"); user.setEmail("customer@thingsboard.org");
@ -75,7 +81,7 @@ public abstract class AbstractCoapClaimDeviceTest extends AbstractCoapIntegratio
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test

12
application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimJsonDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimJsonDeviceTest.java

@ -21,13 +21,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapClaimJsonDeviceTest extends AbstractCoapClaimDeviceTest { @DaoSqlTest
public class CoapClaimJsonDeviceTest extends CoapClaimDeviceTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
super.processBeforeTest("Test Claim device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Claim device Json")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
createCustomerAndUser(); createCustomerAndUser();
} }

13
application/src/test/java/org/thingsboard/server/transport/coap/claim/AbstractCoapClaimProtoDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/coap/claim/CoapClaimProtoDeviceTest.java

@ -16,21 +16,28 @@
package org.thingsboard.server.transport.coap.claim; package org.thingsboard.server.transport.coap.claim;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapClient;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportApiProtos;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapClaimProtoDeviceTest extends AbstractCoapClaimDeviceTest { @DaoSqlTest
public class CoapClaimProtoDeviceTest extends CoapClaimDeviceTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Claim device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Claim device Proto")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.build();
processBeforeTest(configProperties);
createCustomerAndUser(); createCustomerAndUser();
} }

23
application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceJsonSqlTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceProtoSqlTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/claim/sql/CoapClaimDeviceSqlTest.java

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

80
application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionJsonDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java

@ -25,6 +25,7 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -37,13 +38,13 @@ import org.thingsboard.server.common.transport.util.JsonUtils;
import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.io.IOException; import java.io.IOException;
import static org.junit.Assert.assertEquals;
@Slf4j @Slf4j
public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest { @DaoSqlTest
public class CoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest {
@Autowired @Autowired
DeviceCredentialsService deviceCredentialsService; DeviceCredentialsService deviceCredentialsService;
@ -53,7 +54,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test
@ -88,7 +89,12 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
private void processTestProvisioningDisabledDevice() throws Exception { private void processTestProvisioningDisabledDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
byte[] result = createCoapClientAndPublish().getPayload(); byte[] result = createCoapClientAndPublish().getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
@ -97,15 +103,23 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
byte[] result = createCoapClientAndPublish().getPayload(); byte[] result = createCoapClientAndPublish().getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString()); Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
@ -113,16 +127,24 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\""; String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
byte[] result = createCoapClientAndPublish(requestCredentials).getPayload(); byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN"); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "ACCESS_TOKEN");
@ -132,16 +154,24 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
private void processTestProvisioningCreateNewDeviceWithCert() throws Exception { private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\""; String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
byte[] result = createCoapClientAndPublish(requestCredentials).getPayload(); byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE"); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), "X509_CERTIFICATE");
@ -156,18 +186,34 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
} }
private void processTestProvisioningCheckPreProvisionedDevice() throws Exception { private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
byte[] result = createCoapClientAndPublish().getPayload(); byte[] result = createCoapClientAndPublish().getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, savedDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").getAsString());
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString()); Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").getAsString());
} }
private void processTestProvisioningWithBadKeyDevice() throws Exception { private void processTestProvisioningWithBadKeyDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.provisionType(DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES)
.provisionKey("testProvisionKeyOrig")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
byte[] result = createCoapClientAndPublish().getPayload(); byte[] result = createCoapClientAndPublish().getPayload();
JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject(); JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString()); Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());

78
application/src/test/java/org/thingsboard/server/transport/coap/provision/AbstractCoapProvisionProtoDeviceTest.java → application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java

@ -24,6 +24,7 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -43,11 +44,13 @@ import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceReque
import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.io.IOException; import java.io.IOException;
@Slf4j @Slf4j
public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest { @DaoSqlTest
public class CoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest {
@Autowired @Autowired
DeviceCredentialsService deviceCredentialsService; DeviceCredentialsService deviceCredentialsService;
@ -57,7 +60,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test
@ -92,37 +95,58 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
private void processTestProvisioningDisabledDevice() throws Exception { private void processTestProvisioningDisabledDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.build();
processBeforeTest(configProperties);
ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload()); ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
Assert.assertNotNull(result); Assert.assertNotNull(result);
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString()); Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
} }
private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload()); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString()); Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
} }
private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build(); CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayload()); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayload());
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN); Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.ACCESS_TOKEN);
@ -131,16 +155,24 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
} }
private void processTestProvisioningCreateNewDeviceWithCert() throws Exception { private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device3")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build(); CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayload()); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayload());
Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device"); Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device");
Assert.assertNotNull(createdDevice); Assert.assertNotNull(createdDevice);
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), createdDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE); Assert.assertEquals(deviceCredentials.getCredentialsType(), DeviceCredentialsType.X509_CERTIFICATE);
@ -155,17 +187,33 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
} }
private void processTestProvisioningCheckPreProvisionedDevice() throws Exception { private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.provisionType(DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES)
.provisionKey("testProvisionKey")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload()); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, savedDevice.getId());
Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString()); Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().toString());
Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString()); Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().toString());
} }
private void processTestProvisioningWithBadKeyDevice() throws Exception { private void processTestProvisioningWithBadKeyDevice() throws Exception {
super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Provision device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.provisionType(DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES)
.provisionKey("testProvisionKeyOrig")
.provisionSecret("testProvisionSecret")
.build();
processBeforeTest(configProperties);
ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload()); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString()); Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
} }

23
application/src/test/java/org/thingsboard/server/transport/coap/provision/sql/CoapProvisionDeviceJsonSqlTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/provision/sql/CoapProvisionDeviceProtoSqlTest.java

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

9
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java

@ -26,8 +26,6 @@ import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry; import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request; import org.eclipse.californium.core.coap.Request;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
@ -45,12 +43,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}"; protected static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}";
protected Long asyncContextTimeoutToUseRpcPlugin; protected static final Long asyncContextTimeoutToUseRpcPlugin = 10000L;
protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
super.processBeforeTest(deviceName, coapDeviceType, payloadType);
asyncContextTimeoutToUseRpcPlugin = 10000L;
}
protected void processOneWayRpcTest() throws Exception { protected void processOneWayRpcTest() throws Exception {
client = getCoapClient(FeatureType.RPC); client = getCoapClient(FeatureType.RPC);

15
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcDefaultIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcDefaultIntegrationTest.java

@ -21,21 +21,30 @@ import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.service.security.AccessValidator; import org.thingsboard.server.service.security.AccessValidator;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapServerSideRpcDefaultIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest { @DaoSqlTest
public class CoapServerSideRpcDefaultIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("RPC test device", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("RPC test device")
.build();
processBeforeTest(configProperties);
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test

14
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcJsonIntegrationTest.java

@ -21,18 +21,26 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapServerSideRpcJsonIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest { @DaoSqlTest
public class CoapServerSideRpcJsonIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("RPC test device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test

25
application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/rpc/CoapServerSideRpcProtoIntegrationTest.java

@ -23,16 +23,12 @@ import com.squareup.wire.schema.internal.parser.ProtoFileElement;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapHandler; import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapObserveRelation;
import org.eclipse.californium.core.CoapResponse; import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.MediaTypeRegistry; import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration; import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
@ -40,19 +36,16 @@ import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeCo
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
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.junit.Assert.assertTrue;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Slf4j @Slf4j
public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest { @DaoSqlTest
public class CoapServerSideRpcProtoIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" + private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
"package rpc;\n" + "package rpc;\n" +
@ -70,12 +63,18 @@ public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends Abst
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("RPC test device")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.rpcRequestProtoSchema(RPC_REQUEST_PROTO_SCHEMA)
.build();
processBeforeTest(configProperties);
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
super.processAfterTest(); processAfterTest();
} }
@Test @Test

23
application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcJsonSqlIntegrationTest.java

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

23
application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcSqlIntegrationTest.java

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

11
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesIntegrationTest.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.transport.coap.telemetry.attributes; package org.thingsboard.server.transport.coap.telemetry.attributes;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.CoapClient; import org.eclipse.californium.core.CoapClient;
@ -26,9 +25,11 @@ import org.eclipse.californium.elements.exception.ConnectorException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -43,14 +44,18 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoapIntegrationTest { @DaoSqlTest
public class CoapAttributesIntegrationTest extends AbstractCoapIntegrationTest {
private static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + private 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\"}}}"; " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}";
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Post Attributes device", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Post Attributes device")
.build();
processBeforeTest(configProperties);
} }
@After @After

12
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesJsonIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesJsonIntegrationTest.java

@ -21,13 +21,21 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesJsonIntegrationTest extends AbstractCoapAttributesIntegrationTest { @DaoSqlTest
public class CoapAttributesJsonIntegrationTest extends CoapAttributesIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Post Attributes device Json", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Post Attributes device Json")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
} }
@After @After

12
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/AbstractCoapAttributesProtoIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/CoapAttributesProtoIntegrationTest.java

@ -30,6 +30,8 @@ import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeCo
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.util.Arrays; import java.util.Arrays;
@ -37,12 +39,18 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@Slf4j @Slf4j
public abstract class AbstractCoapAttributesProtoIntegrationTest extends AbstractCoapAttributesIntegrationTest { @DaoSqlTest
public class CoapAttributesProtoIntegrationTest extends CoapAttributesIntegrationTest {
@Before @Before
@Override @Override
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Post Attributes device Proto")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.PROTOBUF)
.build();
processBeforeTest(configProperties);
} }
@Test @Test

26
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlIntegrationTest.java

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

26
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlJsonIntegrationTest.java

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

26
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/attributes/sql/CoapAttributesSqlProtoIntegrationTest.java

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

8
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesIntegrationTest.java

@ -25,8 +25,9 @@ import org.eclipse.californium.elements.exception.ConnectorException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.common.msg.session.FeatureType;
import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -46,7 +47,10 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Post Telemetry device", null, null); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Post Telemetry device")
.build();
processBeforeTest(configProperties);
} }
@After @After

8
application/src/test/java/org/thingsboard/server/transport/coap/telemetry/timeseries/AbstractCoapTimeseriesJsonIntegrationTest.java

@ -21,13 +21,19 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.CoapDeviceType;
import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.TransportPayloadType;
import org.thingsboard.server.transport.coap.CoapTestConfigProperties;
@Slf4j @Slf4j
public abstract class AbstractCoapTimeseriesJsonIntegrationTest extends AbstractCoapTimeseriesIntegrationTest { public abstract class AbstractCoapTimeseriesJsonIntegrationTest extends AbstractCoapTimeseriesIntegrationTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
processBeforeTest("Test Post Telemetry device json payload", CoapDeviceType.DEFAULT, TransportPayloadType.JSON); CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder()
.deviceName("Test Post Telemetry device json payload")
.coapDeviceType(CoapDeviceType.DEFAULT)
.transportPayloadType(TransportPayloadType.JSON)
.build();
processBeforeTest(configProperties);
} }
@After @After

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

Loading…
Cancel
Save