Browse Source

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

pull/6859/head
Andrii Shvaika 4 years ago
parent
commit
240e1ffc3b
  1. 4
      application/src/main/java/org/thingsboard/server/controller/AssetController.java
  2. 4
      application/src/main/java/org/thingsboard/server/controller/DeviceController.java
  3. 4
      application/src/main/java/org/thingsboard/server/controller/EdgeController.java
  4. 22
      application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java
  5. 2
      application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
  7. 2
      application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
  8. 3
      application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java
  9. 10
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java
  10. 119
      application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java
  11. 6
      application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java
  12. 4
      application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java
  13. 254
      application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java
  14. 36
      application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java
  15. 123
      application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
  16. 47
      application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java
  17. 294
      application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java
  18. 313
      application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
  19. 6
      common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java
  20. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportColumnType.java
  21. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportRequest.java
  22. 2
      common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportResult.java
  23. 3
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/BranchInfo.java
  24. 1
      common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequest.java
  25. 6
      common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java
  26. 24
      dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java
  27. 10
      dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java
  28. 9
      dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java
  29. 28
      dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java
  30. 74
      docker/compose-utils.sh
  31. 21
      docker/docker-check-log-folders.sh
  32. 39
      docker/docker-create-log-folders.sh
  33. 2
      docker/docker-install-tb.sh
  34. 2
      docker/docker-start-services.sh
  35. 2
      docker/docker-upgrade-tb.sh
  36. 266
      rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java
  37. 6
      ui-ngx/src/app/core/http/entities-version-control.service.ts
  38. 3
      ui-ngx/src/app/modules/home/components/queue/queue-form.component.html
  39. 4
      ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts
  40. 4
      ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts
  41. 6
      ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts
  42. 4
      ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts
  43. 3
      ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts
  44. 1
      ui-ngx/src/app/shared/models/vc.models.ts
  45. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

4
application/src/main/java/org/thingsboard/server/controller/AssetController.java

@ -51,8 +51,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService; import org.thingsboard.server.service.asset.AssetBulkImportService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.asset.TbAssetService; import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;

4
application/src/main/java/org/thingsboard/server/controller/DeviceController.java

@ -66,8 +66,8 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService; import org.thingsboard.server.service.device.DeviceBulkImportService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;

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

@ -53,8 +53,8 @@ import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService; import org.thingsboard.server.service.edge.EdgeBulkImportService;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportRequest; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportResult; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource; import org.thingsboard.server.service.security.permission.Resource;

22
application/src/main/java/org/thingsboard/server/controller/EntitiesVersionControlController.java

@ -310,15 +310,13 @@ public class EntitiesVersionControlController extends BaseController {
"Each entity item in the result has `externalId` property. " + "Each entity item in the result has `externalId` property. " +
"Entities order will be the same as in the repository." + "Entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{entityType}/{versionId}", params = {"branch"}) @GetMapping(value = "/entity/{entityType}/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) public DeferredResult<List<VersionedEntityInfo>> listEntitiesAtVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType, @PathVariable EntityType entityType,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) @ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId, @PathVariable String versionId) throws Exception {
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), branch, versionId, entityType)); return wrapFuture(versionControlService.listEntitiesAtVersion(getTenantId(), versionId, entityType));
} }
@ApiOperation(value = "List all entities at version (listAllEntitiesAtVersion)", notes = "" + @ApiOperation(value = "List all entities at version (listAllEntitiesAtVersion)", notes = "" +
@ -326,13 +324,11 @@ public class EntitiesVersionControlController extends BaseController {
"Response type is the same as for listAllEntitiesAtVersion API method. \n" + "Response type is the same as for listAllEntitiesAtVersion API method. \n" +
"Returned entities order will be the same as in the repository." + "Returned entities order will be the same as in the repository." +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/entity/{versionId}", params = {"branch"}) @GetMapping(value = "/entity/{versionId}")
public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) public DeferredResult<List<VersionedEntityInfo>> listAllEntitiesAtVersion(@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@PathVariable String versionId, @PathVariable String versionId) throws Exception {
@ApiParam(value = BRANCH_PARAM_DESCRIPTION, required = true)
@RequestParam String branch) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), branch, versionId)); return wrapFuture(versionControlService.listAllEntitiesAtVersion(getTenantId(), versionId));
} }
@ApiOperation(value = "Get entity data info (getEntityDataInfo)", notes = "" + @ApiOperation(value = "Get entity data info (getEntityDataInfo)", notes = "" +
@ -357,18 +353,16 @@ public class EntitiesVersionControlController extends BaseController {
"Returns an object with current entity data and the one at a specific version. " + "Returns an object with current entity data and the one at a specific version. " +
"Entity data structure is the same as stored in a repository. " + "Entity data structure is the same as stored in a repository. " +
TENANT_AUTHORITY_PARAGRAPH) TENANT_AUTHORITY_PARAGRAPH)
@GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"branch", "versionId"}) @GetMapping(value = "/diff/{entityType}/{internalEntityUuid}", params = {"versionId"})
public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true) public DeferredResult<EntityDataDiff> compareEntityDataToVersion(@ApiParam(value = ENTITY_TYPE_PARAM_DESCRIPTION, required = true)
@PathVariable EntityType entityType, @PathVariable EntityType entityType,
@ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true) @ApiParam(value = ENTITY_ID_PARAM_DESCRIPTION, required = true)
@PathVariable UUID internalEntityUuid, @PathVariable UUID internalEntityUuid,
@ApiParam(value = BRANCH_PARAM_DESCRIPTION)
@RequestParam String branch,
@ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true) @ApiParam(value = VERSION_ID_PARAM_DESCRIPTION, required = true)
@RequestParam String versionId) throws Exception { @RequestParam String versionId) throws Exception {
accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ); accessControlService.checkPermission(getCurrentUser(), Resource.VERSION_CONTROL, Operation.READ);
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid); EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, internalEntityUuid);
return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), branch, entityId, versionId)); return wrapFuture(versionControlService.compareEntityDataToVersion(getCurrentUser(), entityId, versionId));
} }
@ApiOperation(value = "Load entities version (loadEntitiesVersion)", notes = "" + @ApiOperation(value = "Load entities version (loadEntitiesVersion)", notes = "" +

2
application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java

@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.asset.TbAssetService; import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

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

@ -50,7 +50,7 @@ import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException; import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.device.TbDeviceService; import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

2
application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java

@ -29,7 +29,7 @@ import org.thingsboard.server.dao.edge.EdgeService;
import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService; import org.thingsboard.server.service.sync.ie.importing.csv.AbstractBulkImportService;
import org.thingsboard.server.service.sync.ie.importing.csv.BulkImportColumnType; import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.service.entitiy.edge.TbEdgeService; import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.SecurityUser;

3
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/AbstractBulkImportService.java

@ -39,6 +39,9 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.DataType;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportColumnType;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.adaptor.JsonConverter;
import org.thingsboard.server.controller.BaseController; import org.thingsboard.server.controller.BaseController;

10
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java

@ -241,13 +241,13 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception { public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId, EntityType entityType) throws Exception {
return gitServiceQueue.listEntitiesAtVersion(tenantId, branch, versionId, entityType); return gitServiceQueue.listEntitiesAtVersion(tenantId, versionId, entityType);
} }
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception { public ListenableFuture<List<VersionedEntityInfo>> listAllEntitiesAtVersion(TenantId tenantId, String versionId) throws Exception {
return gitServiceQueue.listEntitiesAtVersion(tenantId, branch, versionId); return gitServiceQueue.listEntitiesAtVersion(tenantId, versionId);
} }
@SuppressWarnings({"UnstableApiUsage", "rawtypes"}) @SuppressWarnings({"UnstableApiUsage", "rawtypes"})
@ -451,7 +451,7 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont
} }
@Override @Override
public ListenableFuture<EntityDataDiff> compareEntityDataToVersion(User user, String branch, EntityId entityId, String versionId) throws Exception { public ListenableFuture<EntityDataDiff> compareEntityDataToVersion(User user, EntityId entityId, String versionId) throws Exception {
HasId<EntityId> entity = exportableEntitiesService.findEntityByTenantIdAndId(user.getTenantId(), entityId); HasId<EntityId> entity = exportableEntitiesService.findEntityByTenantIdAndId(user.getTenantId(), entityId);
if (!(entity instanceof ExportableEntity)) throw new IllegalArgumentException("Unsupported entity type"); if (!(entity instanceof ExportableEntity)) throw new IllegalArgumentException("Unsupported entity type");

119
application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultGitVersionControlQueueService.java

@ -245,7 +245,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
} }
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) { public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId, EntityType entityType) {
return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder()
.setVersionId(versionId) .setVersionId(versionId)
.setEntityType(entityType.name()) .setEntityType(entityType.name())
@ -253,7 +253,7 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
} }
@Override @Override
public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId) { public ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId) {
return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder() return listEntitiesAtVersion(tenantId, ListEntitiesRequestMsg.newBuilder()
.setVersionId(versionId) .setVersionId(versionId)
.build()); .build());
@ -385,66 +385,71 @@ public class DefaultGitVersionControlQueueService implements GitVersionControlQu
if (!StringUtils.isEmpty(vcResponseMsg.getError())) { if (!StringUtils.isEmpty(vcResponseMsg.getError())) {
future.setException(new RuntimeException(vcResponseMsg.getError())); future.setException(new RuntimeException(vcResponseMsg.getError()));
} else { } else {
if (vcResponseMsg.hasGenericResponse()) { try {
future.set(null); if (vcResponseMsg.hasGenericResponse()) {
} else if (vcResponseMsg.hasCommitResponse()) { future.set(null);
var commitResponse = vcResponseMsg.getCommitResponse(); } else if (vcResponseMsg.hasCommitResponse()) {
var commitResult = new VersionCreationResult(); var commitResponse = vcResponseMsg.getCommitResponse();
if (commitResponse.getTs() > 0) { var commitResult = new VersionCreationResult();
commitResult.setVersion(new EntityVersion(commitResponse.getTs(), commitResponse.getCommitId(), commitResponse.getName(), commitResponse.getAuthor())); if (commitResponse.getTs() > 0) {
} commitResult.setVersion(new EntityVersion(commitResponse.getTs(), commitResponse.getCommitId(), commitResponse.getName(), commitResponse.getAuthor()));
commitResult.setAdded(commitResponse.getAdded()); }
commitResult.setRemoved(commitResponse.getRemoved()); commitResult.setAdded(commitResponse.getAdded());
commitResult.setModified(commitResponse.getModified()); commitResult.setRemoved(commitResponse.getRemoved());
commitResult.setDone(true); commitResult.setModified(commitResponse.getModified());
((CommitGitRequest) request).getFuture().set(commitResult); commitResult.setDone(true);
} else if (vcResponseMsg.hasListBranchesResponse()) { ((CommitGitRequest) request).getFuture().set(commitResult);
var listBranchesResponse = vcResponseMsg.getListBranchesResponse(); } else if (vcResponseMsg.hasListBranchesResponse()) {
((ListBranchesGitRequest) request).getFuture().set(listBranchesResponse.getBranchesList().stream().map(this::getBranchInfo).collect(Collectors.toList())); var listBranchesResponse = vcResponseMsg.getListBranchesResponse();
} else if (vcResponseMsg.hasListEntitiesResponse()) { ((ListBranchesGitRequest) request).getFuture().set(listBranchesResponse.getBranchesList().stream().map(this::getBranchInfo).collect(Collectors.toList()));
var listEntitiesResponse = vcResponseMsg.getListEntitiesResponse(); } else if (vcResponseMsg.hasListEntitiesResponse()) {
((ListEntitiesGitRequest) request).getFuture().set( var listEntitiesResponse = vcResponseMsg.getListEntitiesResponse();
listEntitiesResponse.getEntitiesList().stream().map(this::getVersionedEntityInfo).collect(Collectors.toList())); ((ListEntitiesGitRequest) request).getFuture().set(
} else if (vcResponseMsg.hasListVersionsResponse()) { listEntitiesResponse.getEntitiesList().stream().map(this::getVersionedEntityInfo).collect(Collectors.toList()));
var listVersionsResponse = vcResponseMsg.getListVersionsResponse(); } else if (vcResponseMsg.hasListVersionsResponse()) {
((ListVersionsGitRequest) request).getFuture().set(toPageData(listVersionsResponse)); var listVersionsResponse = vcResponseMsg.getListVersionsResponse();
} else if (vcResponseMsg.hasEntityContentResponse()) { ((ListVersionsGitRequest) request).getFuture().set(toPageData(listVersionsResponse));
TransportProtos.EntityContentResponseMsg responseMsg = vcResponseMsg.getEntityContentResponse(); } else if (vcResponseMsg.hasEntityContentResponse()) {
log.trace("[{}] received chunk {} for 'getEntity'", responseMsg.getChunkedMsgId(), responseMsg.getChunkIndex()); TransportProtos.EntityContentResponseMsg responseMsg = vcResponseMsg.getEntityContentResponse();
var joined = joinChunks(requestId, responseMsg, 1); log.trace("[{}] received chunk {} for 'getEntity'", responseMsg.getChunkedMsgId(), responseMsg.getChunkIndex());
if (joined.isPresent()) { var joined = joinChunks(requestId, responseMsg, 1);
log.trace("[{}] collected all chunks for 'getEntity'", responseMsg.getChunkedMsgId());
((EntityContentGitRequest) request).getFuture().set(joined.get().get(0));
} else {
completed = false;
}
} else if (vcResponseMsg.hasEntitiesContentResponse()) {
TransportProtos.EntitiesContentResponseMsg responseMsg = vcResponseMsg.getEntitiesContentResponse();
TransportProtos.EntityContentResponseMsg item = responseMsg.getItem();
if (responseMsg.getItemsCount() > 0) {
var joined = joinChunks(requestId, item, responseMsg.getItemsCount());
if (joined.isPresent()) { if (joined.isPresent()) {
((EntitiesContentGitRequest) request).getFuture().set(joined.get()); log.trace("[{}] collected all chunks for 'getEntity'", responseMsg.getChunkedMsgId());
((EntityContentGitRequest) request).getFuture().set(joined.get().get(0));
} else { } else {
completed = false; completed = false;
} }
} else { } else if (vcResponseMsg.hasEntitiesContentResponse()) {
((EntitiesContentGitRequest) request).getFuture().set(Collections.emptyList()); TransportProtos.EntitiesContentResponseMsg responseMsg = vcResponseMsg.getEntitiesContentResponse();
TransportProtos.EntityContentResponseMsg item = responseMsg.getItem();
if (responseMsg.getItemsCount() > 0) {
var joined = joinChunks(requestId, item, responseMsg.getItemsCount());
if (joined.isPresent()) {
((EntitiesContentGitRequest) request).getFuture().set(joined.get());
} else {
completed = false;
}
} else {
((EntitiesContentGitRequest) request).getFuture().set(Collections.emptyList());
}
} else if (vcResponseMsg.hasVersionsDiffResponse()) {
TransportProtos.VersionsDiffResponseMsg diffResponse = vcResponseMsg.getVersionsDiffResponse();
List<EntityVersionsDiff> entityVersionsDiffList = diffResponse.getDiffList().stream()
.map(diff -> EntityVersionsDiff.builder()
.externalId(EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(diff.getEntityType()),
new UUID(diff.getEntityIdMSB(), diff.getEntityIdLSB())))
.entityDataAtVersion1(StringUtils.isNotEmpty(diff.getEntityDataAtVersion1()) ?
toData(diff.getEntityDataAtVersion1()) : null)
.entityDataAtVersion2(StringUtils.isNotEmpty(diff.getEntityDataAtVersion2()) ?
toData(diff.getEntityDataAtVersion2()) : null)
.rawDiff(diff.getRawDiff())
.build())
.collect(Collectors.toList());
((VersionsDiffGitRequest) request).getFuture().set(entityVersionsDiffList);
} }
} else if (vcResponseMsg.hasVersionsDiffResponse()) { } catch (Exception e) {
TransportProtos.VersionsDiffResponseMsg diffResponse = vcResponseMsg.getVersionsDiffResponse(); future.setException(e);
List<EntityVersionsDiff> entityVersionsDiffList = diffResponse.getDiffList().stream() throw e;
.map(diff -> EntityVersionsDiff.builder()
.externalId(EntityIdFactory.getByTypeAndUuid(EntityType.valueOf(diff.getEntityType()),
new UUID(diff.getEntityIdMSB(), diff.getEntityIdLSB())))
.entityDataAtVersion1(StringUtils.isNotEmpty(diff.getEntityDataAtVersion1()) ?
toData(diff.getEntityDataAtVersion1()) : null)
.entityDataAtVersion2(StringUtils.isNotEmpty(diff.getEntityDataAtVersion2()) ?
toData(diff.getEntityDataAtVersion2()) : null)
.rawDiff(diff.getRawDiff())
.build())
.collect(Collectors.toList());
((VersionsDiffGitRequest) request).getFuture().set(entityVersionsDiffList);
} }
} }
if (completed) { if (completed) {

6
application/src/main/java/org/thingsboard/server/service/sync/vc/EntitiesVersionControlService.java

@ -49,15 +49,15 @@ public interface EntitiesVersionControlService {
ListenableFuture<PageData<EntityVersion>> listVersions(TenantId tenantId, String branch, PageLink pageLink) throws Exception; ListenableFuture<PageData<EntityVersion>> listVersions(TenantId tenantId, String branch, PageLink pageLink) throws Exception;
ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType) throws Exception; ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId, EntityType entityType) throws Exception;
ListenableFuture<List<VersionedEntityInfo>> listAllEntitiesAtVersion(TenantId tenantId, String branch, String versionId) throws Exception; ListenableFuture<List<VersionedEntityInfo>> listAllEntitiesAtVersion(TenantId tenantId, String versionId) throws Exception;
UUID loadEntitiesVersion(User user, VersionLoadRequest request) throws Exception; UUID loadEntitiesVersion(User user, VersionLoadRequest request) throws Exception;
VersionLoadResult getVersionLoadStatus(User user, UUID requestId) throws ThingsboardException; VersionLoadResult getVersionLoadStatus(User user, UUID requestId) throws ThingsboardException;
ListenableFuture<EntityDataDiff> compareEntityDataToVersion(User user, String branch, EntityId entityId, String versionId) throws Exception; ListenableFuture<EntityDataDiff> compareEntityDataToVersion(User user, EntityId entityId, String versionId) throws Exception;
ListenableFuture<List<BranchInfo>> listBranches(TenantId tenantId) throws Exception; ListenableFuture<List<BranchInfo>> listBranches(TenantId tenantId) throws Exception;

4
application/src/main/java/org/thingsboard/server/service/sync/vc/GitVersionControlQueueService.java

@ -52,9 +52,9 @@ public interface GitVersionControlQueueService {
ListenableFuture<PageData<EntityVersion>> listVersions(TenantId tenantId, String branch, EntityId entityId, PageLink pageLink); ListenableFuture<PageData<EntityVersion>> listVersions(TenantId tenantId, String branch, EntityId entityId, PageLink pageLink);
ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId, EntityType entityType); ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId, EntityType entityType);
ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String branch, String versionId); ListenableFuture<List<VersionedEntityInfo>> listEntitiesAtVersion(TenantId tenantId, String versionId);
ListenableFuture<List<BranchInfo>> listBranches(TenantId tenantId); ListenableFuture<List<BranchInfo>> listBranches(TenantId tenantId);

254
application/src/test/java/org/thingsboard/server/controller/AbstractNotifyEntityTest.java

@ -20,9 +20,11 @@ import org.mockito.ArgumentMatcher;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.boot.test.mock.mockito.SpyBean;
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.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityIdFactory;
@ -30,9 +32,13 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
@ -49,13 +55,32 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
@SpyBean @SpyBean
protected AuditLogService auditLogService; protected AuditLogService auditLogService;
@SpyBean
protected GatewayNotificationsService gatewayNotificationsService;
protected final String msgErrorPermission = "You don't have permission to perform this operation!";
protected final String msgErrorShouldBeSpecified = "should be specified";
protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId, protected void testNotifyEntityAllOneTime(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName, TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) { ActionType actionType, Object... additionalInfo) {
int cntTime = 1; int cntTime = 1;
testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime); testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityActionEntityEqClass(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
} }
@ -73,7 +98,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
int cntTime = 1; int cntTime = 1;
testNotificationMsgToEdgeServiceNever(entityId); testNotificationMsgToEdgeServiceNever(entityId);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
} }
@ -86,8 +112,49 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ArgumentMatcher<HasName> matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass()); ArgumentMatcher<HasName> matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass()); ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime, testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
additionalInfo); extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(HasName entity, HasName originator,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, ActionType actionTypeEdge,
int cntTime, int cntTimeEdge, int cntTimeRuleEngine, Object... additionalInfo) {
EntityId originatorId = createEntityId_NULL_UUID(originator);
testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge);
ArgumentMatcher<HasName> matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
testLogEntityActionAdditionalInfo(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTimeRuleEngine);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(HasName entity, HasName originator,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, ActionType actionTypeEdge, int cntTime, int cntTimeEdge, int cntAdditionalInfo) {
EntityId originatorId = createEntityId_NULL_UUID(originator);
testSendNotificationMsgToEdgeServiceTimeEntityEqAny(tenantId, actionTypeEdge, cntTimeEdge);
ArgumentMatcher<HasName> matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
cntAdditionalInfo);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTimeEdge);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(HasName entity, HasName originator,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, int cntAdditionalInfo) {
EntityId entityId = createEntityId_NULL_UUID(entity);
EntityId originatorId = createEntityId_NULL_UUID(originator);
testNotificationMsgToEdgeServiceNever(entityId);
ArgumentMatcher<HasName> matcherEntityClassEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.getClass().equals(originatorId.getClass());
testLogEntityActionAdditionalInfoAny(matcherEntityClassEquals, matcherOriginatorId, tenantId, customerId, userId, userName, actionType, cntTime,
cntAdditionalInfo);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
} }
@ -97,11 +164,24 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
int cntTime = 1; int cntTime = 1;
testNotificationMsgToEdgeServiceNever(entityId); testNotificationMsgToEdgeServiceNever(entityId);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo); testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
testPushMsgToRuleEngineTime(originatorId, tenantId, cntTime); ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testPushMsgToRuleEngineTime(matcherOriginatorId, tenantId, cntTime);
testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime); testBroadcastEntityStateChangeEventTime(entityId, tenantId, cntTime);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
} }
protected void testNotifyEntityMsgToEdgePushMsgToCoreOneTime(HasName entity, EntityId entityId, EntityId originatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, Object... additionalInfo) {
int cntTime = 1;
testSendNotificationMsgToEdgeServiceTime(entityId, tenantId, actionType, cntTime);
testLogEntityAction(entity, originatorId, tenantId, customerId, userId, userName, actionType, cntTime, additionalInfo);
tesPushMsgToCoreTime(cntTime);
Mockito.reset(tbClusterService, auditLogService);
}
protected void testNotifyEntityEqualsOneTimeError(HasName entity, TenantId tenantId, protected void testNotifyEntityEqualsOneTimeError(HasName entity, TenantId tenantId,
UserId userId, String userName, ActionType actionType, Exception exp, UserId userId, String userName, ActionType actionType, Exception exp,
Object... additionalInfo) { Object... additionalInfo) {
@ -112,7 +192,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ArgumentMatcher<Exception> matcherError = argument -> argument.getMessage().contains(exp.getMessage()) ArgumentMatcher<Exception> matcherError = argument -> argument.getMessage().contains(exp.getMessage())
& argument.getClass().equals(exp.getClass()); & argument.getClass().equals(exp.getClass());
testLogEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId, testLogEntityActionErrorAdditionalInfo(matcherEntityEquals, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, userId,
userName, actionType, 1, matcherError, additionalInfo); userName, actionType, 1, matcherError, extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID);
} }
@ -126,7 +206,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
ArgumentMatcher<Exception> matcherError = argument -> argument.getMessage().contains(exp.getMessage()) & ArgumentMatcher<Exception> matcherError = argument -> argument.getMessage().contains(exp.getMessage()) &
argument.getClass().equals(exp.getClass()); argument.getClass().equals(exp.getClass());
testLogEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID, testLogEntityActionErrorAdditionalInfo(matcherEntityIsNull, entity_originator_NULL_UUID, tenantId, customer_NULL_UUID,
userId, userName, actionType, 1, matcherError, additionalInfo); userId, userName, actionType, 1, matcherError, extractMatcherAdditionalInfo(additionalInfo));
testPushMsgToRuleEngineNever(entity_originator_NULL_UUID); testPushMsgToRuleEngineNever(entity_originator_NULL_UUID);
} }
@ -138,6 +218,26 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
} }
protected void testNotificationUpdateGatewayOneTime(Device device, Device oldDevice) {
Mockito.verify(gatewayNotificationsService, times(1)).onDeviceUpdated(Mockito.eq(device), Mockito.eq(oldDevice));
}
protected void testNotificationUpdateGatewayTime(int cntTimes) {
Mockito.verify(gatewayNotificationsService, times(cntTimes)).onDeviceUpdated(Mockito.any(Device.class), Mockito.isNull());
}
protected void testNotificationUpdateGatewayNever() {
Mockito.verify(gatewayNotificationsService, never()).onDeviceUpdated(Mockito.any(Device.class), Mockito.any(Device.class));
}
protected void testNotificationDeleteGatewayOneTime(Device device) {
Mockito.verify(gatewayNotificationsService, times(1)).onDeviceDeleted(device);
}
protected void testNotificationDeleteGatewayNever() {
Mockito.verify(gatewayNotificationsService, never()).onDeviceDeleted(Mockito.any(Device.class));
}
private void testNotificationMsgToEdgeServiceNever(EntityId entityId) { private void testNotificationMsgToEdgeServiceNever(EntityId entityId) {
Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdge(Mockito.any(), Mockito.verify(tbClusterService, never()).sendNotificationMsgToEdge(Mockito.any(),
Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any(), Mockito.any()); Mockito.any(), Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any(), Mockito.any());
@ -154,16 +254,22 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any()); Mockito.any(entityId.getClass()), Mockito.any(), Mockito.any());
} }
private void testPushMsgToRuleEngineTime(EntityId originatorId, TenantId tenantId, int cntTime) { private void testPushMsgToRuleEngineTime(ArgumentMatcher<EntityId> matcherOriginatorId, TenantId tenantId, int cntTime) {
ArgumentMatcher<EntityId> matcherOriginatorId = cntTime == 1 ? argument -> argument.equals(originatorId) :
argument -> argument.getClass().equals(originatorId.getClass());
Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId), Mockito.verify(tbClusterService, times(cntTime)).pushMsgToRuleEngine(Mockito.eq(tenantId),
Mockito.argThat(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull()); Mockito.argThat(matcherOriginatorId), Mockito.any(TbMsg.class), Mockito.isNull());
} }
private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) { private void testSendNotificationMsgToEdgeServiceTime(EntityId entityId, TenantId tenantId, ActionType actionType, int cntTime) {
EdgeEventActionType edgeEventActionType = ActionType.CREDENTIALS_UPDATED.equals(actionType) ?
EdgeEventActionType.CREDENTIALS_UPDATED : edgeTypeByActionType(actionType);
Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId), Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId),
Mockito.any(), Mockito.eq(entityId), Mockito.any(), Mockito.isNull(), Mockito.any(), Mockito.eq(entityId), Mockito.any(), Mockito.isNull(),
Mockito.eq(edgeEventActionType));
}
private void testSendNotificationMsgToEdgeServiceTimeEntityEqAny(TenantId tenantId, ActionType actionType, int cntTime) {
Mockito.verify(tbClusterService, times(cntTime)).sendNotificationMsgToEdge(Mockito.eq(tenantId),
Mockito.any(), Mockito.any(EntityId.class), Mockito.any(), Mockito.isNull(),
Mockito.eq(edgeTypeByActionType(actionType))); Mockito.eq(edgeTypeByActionType(actionType)));
} }
@ -172,19 +278,88 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class)); Mockito.any(entityId.getClass()), Mockito.any(ComponentLifecycleEvent.class));
} }
private void tesPushMsgToCoreTime(int cntTime) {
Mockito.verify(tbClusterService, times(cntTime)).pushMsgToCore(Mockito.any(ToDeviceActorNotificationMsg.class), Mockito.isNull());
}
private void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId, private void testLogEntityAction(HasName entity, EntityId originatorId, TenantId tenantId,
CustomerId customerId, UserId userId, String userName, CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, Object... additionalInfo) { ActionType actionType, int cntTime, Object... additionalInfo) {
ArgumentMatcher<HasName> matcherEntityEquals = argument -> argument.equals(entity); ArgumentMatcher<HasName> matcherEntityEquals = argument -> argument.equals(entity);
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId); ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName, testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName,
actionType, cntTime, additionalInfo); actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo));
}
private void testLogEntityActionEntityEqClass(HasName entity, EntityId originatorId, TenantId tenantId,
CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, Object... additionalInfo) {
ArgumentMatcher<HasName> matcherEntityEquals = argument -> argument.getClass().equals(entity.getClass());
ArgumentMatcher<EntityId> matcherOriginatorId = argument -> argument.equals(originatorId);
testLogEntityActionAdditionalInfo(matcherEntityEquals, matcherOriginatorId, tenantId, customerId, userId, userName,
actionType, cntTime, extractMatcherAdditionalInfo(additionalInfo));
} }
private void testLogEntityActionAdditionalInfo(ArgumentMatcher<HasName> matcherEntity, ArgumentMatcher<EntityId> matcherOriginatorId, private void testLogEntityActionAdditionalInfo(ArgumentMatcher<HasName> matcherEntity, ArgumentMatcher<EntityId> matcherOriginatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName, TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, Object... additionalInfo) { ActionType actionType, int cntTime, List<ArgumentMatcher<Object>> matcherAdditionalInfos) {
switch (additionalInfo.length) { switch (matcherAdditionalInfos.size()) {
case 1:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
Mockito.eq(userId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
Mockito.eq(actionType),
Mockito.isNull(),
Mockito.argThat(matcherAdditionalInfos.get(0)));
break;
case 2:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
Mockito.eq(userId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
Mockito.eq(actionType),
Mockito.isNull(),
Mockito.argThat(matcherAdditionalInfos.get(0)),
Mockito.argThat(matcherAdditionalInfos.get(1)));
break;
case 3:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
Mockito.eq(userId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
Mockito.eq(actionType),
Mockito.isNull(),
Mockito.argThat(matcherAdditionalInfos.get(0)),
Mockito.argThat(matcherAdditionalInfos.get(1)),
Mockito.argThat(matcherAdditionalInfos.get(2)));
break;
default:
Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId),
Mockito.eq(userId),
Mockito.eq(userName),
Mockito.argThat(matcherOriginatorId),
Mockito.argThat(matcherEntity),
Mockito.eq(actionType),
Mockito.isNull());
}
}
private void testLogEntityActionAdditionalInfoAny(ArgumentMatcher<HasName> matcherEntity, ArgumentMatcher<EntityId> matcherOriginatorId,
TenantId tenantId, CustomerId customerId, UserId userId, String userName,
ActionType actionType, int cntTime, int cntAdditionalInfo) {
switch (cntAdditionalInfo) {
case 1: case 1:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId), .logEntityAction(Mockito.eq(tenantId),
@ -195,7 +370,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.isNull(), Mockito.isNull(),
Mockito.eq(extractParameter(String.class, 0, additionalInfo))); Mockito.anyString());
break; break;
case 2: case 2:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
@ -207,8 +382,8 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.isNull(), Mockito.isNull(),
Mockito.eq(extractParameter(String.class, 0, additionalInfo)), Mockito.anyString(),
Mockito.eq(extractParameter(String.class, 1, additionalInfo))); Mockito.anyString());
break; break;
case 3: case 3:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
@ -220,9 +395,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.isNull(), Mockito.isNull(),
Mockito.eq(extractParameter(String.class, 0, additionalInfo)), Mockito.anyString(),
Mockito.eq(extractParameter(String.class, 1, additionalInfo)), Mockito.anyString(),
Mockito.eq(extractParameter(String.class, 2, additionalInfo))); Mockito.anyString());
break; break;
default: default:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
@ -239,8 +414,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
private void testLogEntityActionErrorAdditionalInfo(ArgumentMatcher<HasName> matcherEntity, EntityId originatorId, TenantId tenantId, private void testLogEntityActionErrorAdditionalInfo(ArgumentMatcher<HasName> matcherEntity, EntityId originatorId, TenantId tenantId,
CustomerId customerId, UserId userId, String userName, ActionType actionType, CustomerId customerId, UserId userId, String userName, ActionType actionType,
int cntTime, ArgumentMatcher<Exception> matcherError, Object... additionalInfo) { int cntTime, ArgumentMatcher<Exception> matcherError,
switch (additionalInfo.length) { List<ArgumentMatcher<Object>> matcherAdditionalInfos) {
switch (matcherAdditionalInfos.size()) {
case 1: case 1:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId), .logEntityAction(Mockito.eq(tenantId),
@ -251,7 +427,7 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.argThat(matcherError), Mockito.argThat(matcherError),
Mockito.eq(extractParameter(String.class, 0, additionalInfo))); Mockito.argThat(matcherAdditionalInfos.get(0)));
break; break;
case 2: case 2:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
@ -263,9 +439,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.argThat(matcherError), Mockito.argThat(matcherError),
Mockito.eq(extractParameter(String.class, 0, additionalInfo)), Mockito.argThat(Mockito.eq(matcherAdditionalInfos.get(0))),
Mockito.eq(extractParameter(String.class, 1, additionalInfo))); Mockito.argThat(Mockito.eq(matcherAdditionalInfos.get(1))));
case 3: case 3:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
.logEntityAction(Mockito.eq(tenantId), .logEntityAction(Mockito.eq(tenantId),
Mockito.eq(customerId), Mockito.eq(customerId),
@ -275,9 +451,9 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
Mockito.argThat(matcherEntity), Mockito.argThat(matcherEntity),
Mockito.eq(actionType), Mockito.eq(actionType),
Mockito.argThat(matcherError), Mockito.argThat(matcherError),
Mockito.eq(extractParameter(String.class, 0, additionalInfo)), Mockito.argThat(Mockito.eq(matcherAdditionalInfos.get(0))),
Mockito.eq(extractParameter(String.class, 1, additionalInfo)), Mockito.argThat(Mockito.eq(matcherAdditionalInfos.get(1))),
Mockito.eq(extractParameter(String.class, 3, additionalInfo))); Mockito.argThat(Mockito.eq(matcherAdditionalInfos.get(2))));
break; break;
default: default:
Mockito.verify(auditLogService, times(cntTime)) Mockito.verify(auditLogService, times(cntTime))
@ -292,10 +468,18 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
} }
} }
private <T> T extractParameter(Class<T> clazz, int index, Object... additionalInfo) { private List<ArgumentMatcher<Object>> extractMatcherAdditionalInfo(Object... additionalInfos) {
List<ArgumentMatcher<Object>> matcherAdditionalInfos = new ArrayList<>(additionalInfos.length);
for (Object additionalInfo : additionalInfos) {
matcherAdditionalInfos.add(argument -> argument.equals(extractParameter(additionalInfo.getClass(), additionalInfo)));
}
return matcherAdditionalInfos;
}
private <T> T extractParameter(Class<T> clazz, Object additionalInfo) {
T result = null; T result = null;
if (additionalInfo != null && additionalInfo.length > index) { if (additionalInfo != null) {
Object paramObject = additionalInfo[index]; Object paramObject = additionalInfo;
if (clazz.isInstance(paramObject)) { if (clazz.isInstance(paramObject)) {
result = clazz.cast(paramObject); result = clazz.cast(paramObject);
} }
@ -308,4 +492,12 @@ public abstract class AbstractNotifyEntityTest extends AbstractWebTest {
.substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)), .substring(entity.getClass().toString().lastIndexOf(".") + 1).toUpperCase(Locale.ENGLISH)),
ModelConstants.NULL_UUID); ModelConstants.NULL_UUID);
} }
protected String msgErrorFieldLength(String fieldName){
return "length of " + fieldName + " must be equal or less than 255";
}
protected String msgErrorNoFound(String entityClassName, String assetIdStr){
return entityClassName + " with id [" + assetIdStr + "] is not found";
}
} }

36
application/src/test/java/org/thingsboard/server/controller/BaseAlarmControllerTest.java

@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.page.PageData;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
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;
@Slf4j @Slf4j
@ -132,7 +133,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm", alarm).andExpect(status().isForbidden()); doPost("/api/alarm", alarm)
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -147,7 +150,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm", alarm).andExpect(status().isForbidden()); doPost("/api/alarm", alarm)
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -187,7 +192,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isForbidden()); doDelete("/api/alarm/" + alarm.getId())
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -201,7 +208,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doDelete("/api/alarm/" + alarm.getId()).andExpect(status().isForbidden()); doDelete("/api/alarm/" + alarm.getId())
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -265,7 +274,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isForbidden()); doPost("/api/alarm/" + alarm.getId() + "/clear")
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -279,7 +290,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm/" + alarm.getId() + "/clear").andExpect(status().isForbidden()); doPost("/api/alarm/" + alarm.getId() + "/clear")
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -293,7 +306,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm/" + alarm.getId() + "/ack").andExpect(status().isForbidden()); doPost("/api/alarm/" + alarm.getId() + "/ack")
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(alarm.getId(), alarm); testNotifyEntityNever(alarm.getId(), alarm);
} }
@ -307,7 +322,9 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/alarm/" + alarm.getId() + "/ack").andExpect(status().isForbidden()); doPost("/api/alarm/" + alarm.getId() + "/ack")
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
} }
@Test @Test
@ -355,7 +372,8 @@ public abstract class BaseAlarmControllerTest extends AbstractControllerTest {
loginDifferentCustomer(); loginDifferentCustomer();
doGet("/api/alarm/" + EntityType.DEVICE + "/" doGet("/api/alarm/" + EntityType.DEVICE + "/"
+ customerDevice.getUuidId() + "?page=0&pageSize=" + size) + customerDevice.getUuidId() + "?page=0&pageSize=" + size)
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
} }
@Test @Test

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

@ -122,9 +122,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "length of name must be equal or less than 255"; String msgError = msgErrorFieldLength("name");
doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); doPost("/api/asset", asset)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -132,8 +133,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
asset.setName("Normal name"); asset.setName("Normal name");
asset.setType(RandomStringUtils.randomAlphabetic(300)); asset.setType(RandomStringUtils.randomAlphabetic(300));
msgError = "length of type must be equal or less than 255"; msgError = msgErrorFieldLength("type");
doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); doPost("/api/asset", asset)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -141,8 +144,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
asset.setType("default"); asset.setType("default");
asset.setLabel(RandomStringUtils.randomAlphabetic(300)); asset.setLabel(RandomStringUtils.randomAlphabetic(300));
msgError = "length of label must be equal or less than 255"; msgError = msgErrorFieldLength("label");
doPost("/api/asset", asset).andExpect(statusReason(containsString(msgError))); doPost("/api/asset", asset)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(), testNotifyEntityEqualsOneTimeError(asset, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -159,12 +164,15 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doPost("/api/asset", savedAsset, Asset.class, status().isForbidden()); doPost("/api/asset", savedAsset)
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(savedAsset.getId(), savedAsset); testNotifyEntityNever(savedAsset.getId(), savedAsset);
doDelete("/api/asset" + savedAsset.getId().getId().toString()) doDelete("/api/asset/" + savedAsset.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(savedAsset.getId(), savedAsset); testNotifyEntityNever(savedAsset.getId(), savedAsset);
@ -239,8 +247,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, savedAsset.getId().getId().toString()); ActionType.DELETED, savedAsset.getId().getId().toString());
doGet("/api/asset/" + savedAsset.getId().getId().toString()) String assetIdStr = savedAsset.getId().getId().toString();
.andExpect(status().isNotFound()); doGet("/api/asset/" + assetIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Asset", assetIdStr))));
} }
@Test @Test
@ -264,12 +274,12 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isBadRequest());
String msgError = "Can't delete asset that has entity views"; String msgError = "Can't delete asset that has entity views";
doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityIsNullOneTimeError(savedAsset1, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), testNotifyEntityIsNullOneTimeError(savedAsset1, savedTenant.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, new DataValidationException(msgError), savedAsset1.getId().getId().toString()); ActionType.DELETED, new DataValidationException(msgError), savedAsset1.getId().getId().toString());
savedView.setEntityId(savedAsset2.getId()); savedView.setEntityId(savedAsset2.getId());
@ -279,8 +289,10 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
doDelete("/api/asset/" + savedAsset1.getId().getId().toString()) doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
doGet("/api/asset/" + savedAsset1.getId().getId().toString()) String assetIdStr = savedAsset1.getId().getId().toString();
.andExpect(status().isNotFound()); doGet("/api/asset/" + assetIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Asset", assetIdStr))));
} }
@Test @Test
@ -290,7 +302,7 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "Asset type should be specified"; String msgError = "Asset type " + msgErrorShouldBeSpecified;
doPost("/api/asset", asset) doPost("/api/asset", asset)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError))); .andExpect(statusReason(containsString(msgError)));
@ -306,7 +318,7 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "Asset name should be specified"; String msgError = "Asset name " + msgErrorShouldBeSpecified;
doPost("/api/asset", asset) doPost("/api/asset", asset)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError))); .andExpect(statusReason(containsString(msgError)));
@ -362,10 +374,11 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "Asset name should be specified"; String customerIdStr = Uuids.timeBased().toString();
doPost("/api/customer/" + Uuids.timeBased().toString() doPost("/api/customer/" + customerIdStr
+ "/asset/" + savedAsset.getId().getId().toString()) + "/asset/" + savedAsset.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr))));
testNotifyEntityNever(asset.getId(), asset); testNotifyEntityNever(asset.getId(), asset);
} }
@ -401,9 +414,11 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "You don't have permission to perform this operation!";
doPost("/api/customer/" + savedCustomer.getId().getId().toString() doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/asset/" + savedAsset.getId().getId().toString()) + "/asset/" + savedAsset.getId().getId().toString())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityNever(savedAsset.getId(), savedAsset); testNotifyEntityNever(savedAsset.getId(), savedAsset);
@ -431,7 +446,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?", pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssets.addAll(pageData.getData()); loadedAssets.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -480,7 +496,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?", pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssetsTitle1.addAll(pageData.getData()); loadedAssetsTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -496,7 +513,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?", pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssetsTitle2.addAll(pageData.getData()); loadedAssetsTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -515,7 +533,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/assets?", pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -526,7 +545,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/assets?", pageData = doGetTypedWithPageLink("/api/tenant/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -563,7 +583,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type1); new TypeReference<PageData<Asset>>() {
}, pageLink, type1);
loadedAssetsType1.addAll(pageData.getData()); loadedAssetsType1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -579,7 +600,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type2); new TypeReference<PageData<Asset>>() {
}, pageLink, type2);
loadedAssetsType2.addAll(pageData.getData()); loadedAssetsType2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -598,7 +620,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type1); new TypeReference<PageData<Asset>>() {
}, pageLink, type1);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -609,7 +632,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/tenant/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type2); new TypeReference<PageData<Asset>>() {
}, pageLink, type2);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -636,7 +660,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssets.addAll(pageData.getData()); loadedAssets.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -688,7 +713,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssetsTitle1.addAll(pageData.getData()); loadedAssetsTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -704,7 +730,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
loadedAssetsTitle2.addAll(pageData.getData()); loadedAssetsTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -723,7 +750,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -734,7 +762,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>(){}, pageLink); new TypeReference<PageData<Asset>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -780,7 +809,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = null; PageData<Asset> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type1); new TypeReference<PageData<Asset>>() {
}, pageLink, type1);
loadedAssetsType1.addAll(pageData.getData()); loadedAssetsType1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -796,7 +826,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type2); new TypeReference<PageData<Asset>>() {
}, pageLink, type2);
loadedAssetsType2.addAll(pageData.getData()); loadedAssetsType2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -815,7 +846,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type1); new TypeReference<PageData<Asset>>() {
}, pageLink, type1);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
@ -826,7 +858,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
pageLink = new PageLink(4); pageLink = new PageLink(4);
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/assets?type={type}&",
new TypeReference<PageData<Asset>>(){}, pageLink, type2); new TypeReference<PageData<Asset>>() {
}, pageLink, type2);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@ -852,7 +885,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
PageData<Asset> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?", PageData<Asset> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>() {}, new PageLink(100)); new TypeReference<PageData<Asset>>() {
}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
@ -867,7 +901,8 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
ActionType.UNASSIGNED_FROM_EDGE, savedAsset.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName()); ActionType.UNASSIGNED_FROM_EDGE, savedAsset.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName());
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/assets?",
new TypeReference<PageData<Asset>>() {}, new PageLink(100)); new TypeReference<PageData<Asset>>() {
}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }

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

@ -126,8 +126,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
String msgError = "length of title must be equal or less than 255"; String msgError = msgErrorFieldLength("title");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
customer.setTenantId(savedTenant.getId()); customer.setTenantId(savedTenant.getId());
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
@ -136,8 +138,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
customer.setTitle("Normal title"); customer.setTitle("Normal title");
customer.setCity(RandomStringUtils.randomAlphabetic(300)); customer.setCity(RandomStringUtils.randomAlphabetic(300));
msgError = "length of city must be equal or less than 255"; msgError = msgErrorFieldLength("city");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -145,8 +149,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
customer.setCity("Normal city"); customer.setCity("Normal city");
customer.setCountry(RandomStringUtils.randomAlphabetic(300)); customer.setCountry(RandomStringUtils.randomAlphabetic(300));
msgError = "length of country must be equal or less than 255"; msgError = msgErrorFieldLength("country");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -154,8 +160,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
customer.setCountry("Ukraine"); customer.setCountry("Ukraine");
customer.setPhone(RandomStringUtils.randomAlphabetic(300)); customer.setPhone(RandomStringUtils.randomAlphabetic(300));
msgError = "length of phone must be equal or less than 255"; msgError = msgErrorFieldLength("phone");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -163,8 +171,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
customer.setPhone("+3892555554512"); customer.setPhone("+3892555554512");
customer.setState(RandomStringUtils.randomAlphabetic(300)); customer.setState(RandomStringUtils.randomAlphabetic(300));
msgError = "length of state must be equal or less than 255"; msgError = msgErrorFieldLength("state");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -172,8 +182,10 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
customer.setState("Normal state"); customer.setState("Normal state");
customer.setZip(RandomStringUtils.randomAlphabetic(300)); customer.setZip(RandomStringUtils.randomAlphabetic(300));
msgError = "length of zip or postal code must be equal or less than 255"; msgError = msgErrorFieldLength("zip or postal code");
doPost("/api/customer", customer).andExpect(statusReason(containsString(msgError))); doPost("/api/customer", customer)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(), testNotifyEntityEqualsOneTimeError(customer,savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
@ -195,7 +207,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
testNotifyEntityNever(savedCustomer.getId(), savedCustomer); testNotifyEntityNever(savedCustomer.getId(), savedCustomer);
doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(savedCustomer.getId(), savedCustomer); testNotifyEntityNever(savedCustomer.getId(), savedCustomer);
@ -241,14 +254,16 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(), savedCustomer.getId(), savedCustomer.getTenantId(), savedCustomer.getId(), tenantAdmin.getId(),
tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString()); tenantAdmin.getEmail(), ActionType.DELETED, savedCustomer.getId().getId().toString());
doGet("/api/customer/" + savedCustomer.getId().getId().toString()) String customerIdStr = savedCustomer.getId().getId().toString();
.andExpect(status().isNotFound()); doGet("/api/customer/" + customerIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr))));
} }
@Test @Test
public void testSaveCustomerWithEmptyTitle() throws Exception { public void testSaveCustomerWithEmptyTitle() throws Exception {
Customer customer = new Customer(); Customer customer = new Customer();
String msgError = "Customer title should be specified"; String msgError = "Customer title " + msgErrorShouldBeSpecified;
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);

294
application/src/test/java/org/thingsboard/server/controller/BaseDashboardControllerTest.java

@ -22,16 +22,19 @@ 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.mockito.Mockito;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.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.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -41,54 +44,66 @@ 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;
public abstract class BaseDashboardControllerTest extends AbstractControllerTest { public abstract class BaseDashboardControllerTest extends AbstractControllerTest {
private IdComparator<DashboardInfo> idComparator = new IdComparator<>(); private IdComparator<DashboardInfo> idComparator = new IdComparator<>();
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant = new Tenant(); Tenant tenant = new Tenant();
tenant.setTitle("My tenant"); tenant.setTitle("My tenant");
savedTenant = doPost("/api/tenant", tenant, Tenant.class); savedTenant = doPost("/api/tenant", tenant, Tenant.class);
Assert.assertNotNull(savedTenant); Assert.assertNotNull(savedTenant);
tenantAdmin = new User(); tenantAdmin = new User();
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
tenantAdmin.setTenantId(savedTenant.getId()); tenantAdmin.setTenantId(savedTenant.getId());
tenantAdmin.setEmail("tenant2@thingsboard.org"); tenantAdmin.setEmail("tenant2@thingsboard.org");
tenantAdmin.setFirstName("Joe"); tenantAdmin.setFirstName("Joe");
tenantAdmin.setLastName("Downs"); tenantAdmin.setLastName("Downs");
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
} }
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testSaveDashboard() throws Exception { public void testSaveDashboard() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Mockito.reset(tbClusterService, auditLogService);
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
Assert.assertNotNull(savedDashboard); Assert.assertNotNull(savedDashboard);
Assert.assertNotNull(savedDashboard.getId()); Assert.assertNotNull(savedDashboard.getId());
Assert.assertTrue(savedDashboard.getCreatedTime() > 0); Assert.assertTrue(savedDashboard.getCreatedTime() > 0);
Assert.assertEquals(savedTenant.getId(), savedDashboard.getTenantId()); Assert.assertEquals(savedTenant.getId(), savedDashboard.getTenantId());
Assert.assertEquals(dashboard.getTitle(), savedDashboard.getTitle()); Assert.assertEquals(dashboard.getTitle(), savedDashboard.getTitle());
savedDashboard.setTitle("My new dashboard"); savedDashboard.setTitle("My new dashboard");
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/dashboard", savedDashboard, Dashboard.class); doPost("/api/dashboard", savedDashboard, Dashboard.class);
testNotifyEntityAllOneTime(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertEquals(foundDashboard.getTitle(), savedDashboard.getTitle()); Assert.assertEquals(foundDashboard.getTitle(), savedDashboard.getTitle());
} }
@ -97,7 +112,18 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
public void testSaveDashboardInfoWithViolationOfValidation() throws Exception { public void testSaveDashboardInfoWithViolationOfValidation() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle(RandomStringUtils.randomAlphabetic(300)); dashboard.setTitle(RandomStringUtils.randomAlphabetic(300));
doPost("/api/dashboard", dashboard).andExpect(statusReason(containsString("length of title must be equal or less than 255"))); String msgError = msgErrorFieldLength("title");
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/dashboard", dashboard)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
dashboard.setTenantId(savedTenant.getId());
testNotifyEntityEqualsOneTimeError(dashboard, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
Mockito.reset(tbClusterService, auditLogService);
} }
@Test @Test
@ -107,10 +133,16 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
loginDifferentTenant(); loginDifferentTenant();
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/dashboard", savedDashboard, Dashboard.class, status().isForbidden()); doPost("/api/dashboard", savedDashboard, Dashboard.class, status().isForbidden());
testNotifyEntityNever(savedDashboard.getId(), savedDashboard);
deleteDifferentTenant(); deleteDifferentTenant();
} }
@Test @Test
public void testFindDashboardById() throws Exception { public void testFindDashboardById() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
@ -120,48 +152,74 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Assert.assertNotNull(foundDashboard); Assert.assertNotNull(foundDashboard);
Assert.assertEquals(savedDashboard, foundDashboard); Assert.assertEquals(savedDashboard, foundDashboard);
} }
@Test @Test
public void testDeleteDashboard() throws Exception { public void testDeleteDashboard() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
doDelete("/api/dashboard/"+savedDashboard.getId().getId().toString())
.andExpect(status().isOk());
doGet("/api/dashboard/"+savedDashboard.getId().getId().toString()) Mockito.reset(tbClusterService, auditLogService);
.andExpect(status().isNotFound());
doDelete("/api/dashboard/" + savedDashboard.getId().getId().toString()).andExpect(status().isOk());
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(),
savedDashboard.getTenantId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED,
savedDashboard.getId().getId().toString());
String dashboardIdStr = savedDashboard.getId().getId().toString();
doGet("/api/dashboard/" + savedDashboard.getId().getId().toString())
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Dashboard", dashboardIdStr))));
} }
@Test @Test
public void testSaveDashboardWithEmptyTitle() throws Exception { public void testSaveDashboardWithEmptyTitle() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
String msgError = "Dashboard title " + msgErrorShouldBeSpecified;;
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/dashboard", dashboard) doPost("/api/dashboard", dashboard)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Dashboard title should be specified"))); .andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(dashboard, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
} }
@Test @Test
public void testAssignUnassignDashboardToCustomer() throws Exception { public void testAssignUnassignDashboardToCustomer() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("My customer"); customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
Dashboard assignedDashboard = doPost("/api/customer/" + savedCustomer.getId().getId().toString() Mockito.reset(tbClusterService, auditLogService);
Dashboard assignedDashboard = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertTrue(assignedDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo())); Assert.assertTrue(assignedDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo()));
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
savedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo())); Assert.assertTrue(foundDashboard.getAssignedCustomers().contains(savedCustomer.toShortCustomerInfo()));
Dashboard unassignedDashboard = Mockito.reset(tbClusterService, auditLogService);
doDelete("/api/customer/"+savedCustomer.getId().getId().toString()+"/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Dashboard unassignedDashboard =
doDelete("/api/customer/" + savedCustomer.getId().getId().toString() + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
testNotifyEntityAllOneTimeLogEntityActionEntityEqClass(assignedDashboard, assignedDashboard.getId(), assignedDashboard.getId(),
savedTenant.getId(), savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
savedDashboard.getId().getId().toString(), savedCustomer.getId().getId().toString(), savedCustomer.getTitle());
Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty()); Assert.assertTrue(unassignedDashboard.getAssignedCustomers() == null || unassignedDashboard.getAssignedCustomers().isEmpty());
@ -169,22 +227,27 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Assert.assertTrue(foundDashboard.getAssignedCustomers() == null || foundDashboard.getAssignedCustomers().isEmpty()); Assert.assertTrue(foundDashboard.getAssignedCustomers() == null || foundDashboard.getAssignedCustomers().isEmpty());
} }
@Test @Test
public void testAssignDashboardToNonExistentCustomer() throws Exception { public void testAssignDashboardToNonExistentCustomer() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
doPost("/api/customer/" + Uuids.timeBased().toString() String customerIdStr = Uuids.timeBased().toString();
doPost("/api/customer/" + customerIdStr
+ "/dashboard/" + savedDashboard.getId().getId().toString()) + "/dashboard/" + savedDashboard.getId().getId().toString())
.andExpect(status().isNotFound()); .andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr))));
Mockito.reset(tbClusterService, auditLogService);
testNotifyEntityNever(savedDashboard.getId(), savedDashboard);
} }
@Test @Test
public void testAssignDashboardToCustomerFromDifferentTenant() throws Exception { public void testAssignDashboardToCustomerFromDifferentTenant() throws Exception {
loginSysAdmin(); loginSysAdmin();
Tenant tenant2 = new Tenant(); Tenant tenant2 = new Tenant();
tenant2.setTitle("Different tenant"); tenant2.setTitle("Different tenant");
Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class);
@ -196,100 +259,123 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
tenantAdmin2.setEmail("tenant3@thingsboard.org"); tenantAdmin2.setEmail("tenant3@thingsboard.org");
tenantAdmin2.setFirstName("Joe"); tenantAdmin2.setFirstName("Joe");
tenantAdmin2.setLastName("Downs"); tenantAdmin2.setLastName("Downs");
tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); createUserAndLogin(tenantAdmin2, "testPassword1");
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("Different customer"); customer.setTitle("Different customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class); Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
login(tenantAdmin.getEmail(), "testPassword1"); login(tenantAdmin.getEmail(), "testPassword1");
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
doPost("/api/customer/" + savedCustomer.getId().getId().toString() doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString()) + "/dashboard/" + savedDashboard.getId().getId().toString())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
Mockito.reset(tbClusterService, auditLogService);
testNotifyEntityNever(savedDashboard.getId(), savedDashboard);
doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
.andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(savedDashboard.getId(), savedDashboard);
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/"+savedTenant2.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testFindTenantDashboards() throws Exception { public void testFindTenantDashboards() throws Exception {
List<DashboardInfo> dashboards = new ArrayList<>(); List<DashboardInfo> dashboards = new ArrayList<>();
for (int i=0;i<173;i++) {
Mockito.reset(tbClusterService, auditLogService);
int cntEntity = 173;
for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("Dashboard"+i); dashboard.setTitle("Dashboard" + i);
dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, cntEntity);
List<DashboardInfo> loadedDashboards = new ArrayList<>(); List<DashboardInfo> loadedDashboards = new ArrayList<>();
PageLink pageLink = new PageLink(24); PageLink pageLink = new PageLink(24);
PageData<DashboardInfo> pageData = null; PageData<DashboardInfo> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
loadedDashboards.addAll(pageData.getData()); loadedDashboards.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(dashboards, idComparator); Collections.sort(dashboards, idComparator);
Collections.sort(loadedDashboards, idComparator); Collections.sort(loadedDashboards, idComparator);
Assert.assertEquals(dashboards, loadedDashboards); Assert.assertEquals(dashboards, loadedDashboards);
} }
@Test @Test
public void testFindTenantDashboardsByTitle() throws Exception { public void testFindTenantDashboardsByTitle() throws Exception {
String title1 = "Dashboard title 1"; String title1 = "Dashboard title 1";
List<DashboardInfo> dashboardsTitle1 = new ArrayList<>(); List<DashboardInfo> dashboardsTitle1 = new ArrayList<>();
for (int i=0;i<134;i++) { int cntEntity = 134;
for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); String suffix = RandomStringUtils.randomAlphanumeric((int) (Math.random() * 15));
String title = title1+suffix; String title = title1 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
dashboard.setTitle(title); dashboard.setTitle(title);
dashboardsTitle1.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); dashboardsTitle1.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
} }
String title2 = "Dashboard title 2"; String title2 = "Dashboard title 2";
List<DashboardInfo> dashboardsTitle2 = new ArrayList<>(); List<DashboardInfo> dashboardsTitle2 = new ArrayList<>();
for (int i=0;i<112;i++) {
for (int i = 0; i < 112; i++) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
String suffix = RandomStringUtils.randomAlphanumeric((int)(Math.random()*15)); String suffix = RandomStringUtils.randomAlphanumeric((int) (Math.random() * 15));
String title = title2+suffix; String title = title2 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
dashboard.setTitle(title); dashboard.setTitle(title);
dashboardsTitle2.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); dashboardsTitle2.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
} }
List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>(); List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
PageData<DashboardInfo> pageData = null; PageData<DashboardInfo> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
loadedDashboardsTitle1.addAll(pageData.getData()); loadedDashboardsTitle1.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(dashboardsTitle1, idComparator); Collections.sort(dashboardsTitle1, idComparator);
Collections.sort(loadedDashboardsTitle1, idComparator); Collections.sort(loadedDashboardsTitle1, idComparator);
Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1); Assert.assertEquals(dashboardsTitle1, loadedDashboardsTitle1);
List<DashboardInfo> loadedDashboardsTitle2 = new ArrayList<>(); List<DashboardInfo> loadedDashboardsTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
loadedDashboardsTitle2.addAll(pageData.getData()); loadedDashboardsTitle2.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
@ -298,63 +384,79 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Collections.sort(dashboardsTitle2, idComparator); Collections.sort(dashboardsTitle2, idComparator);
Collections.sort(loadedDashboardsTitle2, idComparator); Collections.sort(loadedDashboardsTitle2, idComparator);
Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2); Assert.assertEquals(dashboardsTitle2, loadedDashboardsTitle2);
Mockito.reset(tbClusterService, auditLogService);
for (DashboardInfo dashboard : loadedDashboardsTitle1) { for (DashboardInfo dashboard : loadedDashboardsTitle1) {
doDelete("/api/dashboard/"+dashboard.getId().getId().toString()) doDelete("/api/dashboard/" + dashboard.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, cntEntity, 1);
pageLink = new PageLink(4, 0, title1); pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
for (DashboardInfo dashboard : loadedDashboardsTitle2) { for (DashboardInfo dashboard : loadedDashboardsTitle2) {
doDelete("/api/dashboard/"+dashboard.getId().getId().toString()) doDelete("/api/dashboard/" + dashboard.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
pageLink = new PageLink(4, 0, title2); pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/dashboards?", pageData = doGetTypedWithPageLink("/api/tenant/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
Assert.assertFalse(pageData.hasNext()); Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@Test @Test
public void testFindCustomerDashboards() throws Exception { public void testFindCustomerDashboards() throws Exception {
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("Test customer"); customer.setTitle("Test customer");
customer = doPost("/api/customer", customer, Customer.class); customer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
Mockito.reset(tbClusterService, auditLogService);
int cntEntity = 173;
List<DashboardInfo> dashboards = new ArrayList<>(); List<DashboardInfo> dashboards = new ArrayList<>();
for (int i=0;i<173;i++) { for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = new Dashboard();
dashboard.setTitle("Dashboard"+i); dashboard.setTitle("Dashboard" + i);
dashboard = doPost("/api/dashboard", dashboard, Dashboard.class); dashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
dashboards.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString() dashboards.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString()
+ "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class))); + "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class)));
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Dashboard(), new Dashboard(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity*2);
List<DashboardInfo> loadedDashboards = new ArrayList<>(); List<DashboardInfo> loadedDashboards = new ArrayList<>();
PageLink pageLink = new PageLink(21); PageLink pageLink = new PageLink(21);
PageData<DashboardInfo> pageData = null; PageData<DashboardInfo> pageData = null;
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/dashboards?",
new TypeReference<PageData<DashboardInfo>>(){}, pageLink); new TypeReference<PageData<DashboardInfo>>() {
}, pageLink);
loadedDashboards.addAll(pageData.getData()); loadedDashboards.addAll(pageData.getData());
if (pageData.hasNext()) { if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink(); pageLink = pageLink.nextPageLink();
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
Collections.sort(dashboards, idComparator); Collections.sort(dashboards, idComparator);
Collections.sort(loadedDashboards, idComparator); Collections.sort(loadedDashboards, idComparator);
Assert.assertEquals(dashboards, loadedDashboards); Assert.assertEquals(dashboards, loadedDashboards);
} }
@ -367,11 +469,18 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
dashboard.setTitle("My dashboard"); dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/edge/" + savedEdge.getId().getId().toString() doPost("/api/edge/" + savedEdge.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
testNotifyEntityAllOneTime(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_EDGE,
savedDashboard.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName());
PageData<Dashboard> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?", PageData<Dashboard> pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?",
new TypeReference<PageData<Dashboard>>() {}, new PageLink(100)); new TypeReference<PageData<Dashboard>>() {
}, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
@ -379,7 +488,8 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
+ "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId().toString() + "/dashboards?",
new TypeReference<PageData<Dashboard>>() {}, new PageLink(100)); new TypeReference<PageData<Dashboard>>() {
}, new PageLink(100));
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }

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

@ -21,22 +21,24 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; 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.mockito.Mockito;
import org.thingsboard.common.util.ThingsBoardExecutors; 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;
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.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; 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.DeviceCredentialsId; import org.thingsboard.server.common.data.id.DeviceCredentialsId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
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.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
@ -44,6 +46,8 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup;
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.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList; import java.util.ArrayList;
@ -55,7 +59,6 @@ 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<>() { static final TypeReference<PageData<Device>> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {
}; };
@ -70,7 +73,6 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
log.debug("beforeTest");
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
loginSysAdmin(); loginSysAdmin();
@ -92,14 +94,12 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@After @After
public void afterTest() throws Exception { public void afterTest() throws Exception {
log.debug("afterTest...");
executor.shutdownNow(); executor.shutdownNow();
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId()) doDelete("/api/tenant/" + savedTenant.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
log.debug("afterTest done");
} }
@Test @Test
@ -107,8 +107,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
device.setType("default"); device.setType("default");
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
Device oldDevice = new Device(savedDevice);
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
testNotificationUpdateGatewayNever();
Assert.assertNotNull(savedDevice); Assert.assertNotNull(savedDevice);
Assert.assertNotNull(savedDevice.getId()); Assert.assertNotNull(savedDevice.getId());
Assert.assertTrue(savedDevice.getCreatedTime() > 0); Assert.assertTrue(savedDevice.getCreatedTime() > 0);
@ -127,9 +136,15 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertNotNull(deviceCredentials.getCredentialsId()); Assert.assertNotNull(deviceCredentials.getCredentialsId());
Assert.assertEquals(20, deviceCredentials.getCredentialsId().length()); Assert.assertEquals(20, deviceCredentials.getCredentialsId().length());
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
savedDevice.setName("My new device"); savedDevice.setName("My new device");
doPost("/api/device", savedDevice, Device.class); doPost("/api/device", savedDevice, Device.class);
testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
testNotificationUpdateGatewayOneTime(savedDevice, oldDevice);
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
} }
@ -139,13 +154,41 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Device device = new Device(); Device device = new Device();
device.setName(RandomStringUtils.randomAlphabetic(300)); device.setName(RandomStringUtils.randomAlphabetic(300));
device.setType("default"); device.setType("default");
doPost("/api/device", device).andExpect(statusReason(containsString("length of name must be equal or less than 255")));
device.setName("Normal Name"); Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String msgError = "length of name must be equal or less than 255";
doPost("/api/device", device)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
testNotificationUpdateGatewayNever();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
device.setTenantId(savedTenant.getId());
msgError = "length of type must be equal or less than 255";
device.setType(RandomStringUtils.randomAlphabetic(300)); device.setType(RandomStringUtils.randomAlphabetic(300));
doPost("/api/device", device).andExpect(statusReason(containsString("length of type must be equal or less than 255"))); doPost("/api/device", device)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
testNotificationUpdateGatewayNever();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
msgError = "length of label must be equal or less than 255";
device.setType("Normal type"); device.setType("Normal type");
device.setLabel(RandomStringUtils.randomAlphabetic(300)); device.setLabel(RandomStringUtils.randomAlphabetic(300));
doPost("/api/device", device).andExpect(statusReason(containsString("length of label must be equal or less than 255"))); doPost("/api/device", device)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -155,7 +198,24 @@ 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);
loginDifferentTenant(); loginDifferentTenant();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/device", savedDevice, Device.class, status().isNotFound()); doPost("/api/device", savedDevice, Device.class, status().isNotFound());
testNotifyEntityNever(savedDevice.getId(), savedDevice);
testNotificationUpdateGatewayNever();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String savedDeviceIdStr = savedDevice.getId().getId().toString();
doDelete("/api/device/" + savedDeviceIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", savedDeviceIdStr))));
testNotifyEntityNever(savedDevice.getId(), savedDevice);
testNotificationUpdateGatewayNever();
deleteDifferentTenant(); deleteDifferentTenant();
} }
@ -173,12 +233,24 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Test @Test
public void testFindDeviceTypesByTenantId() throws Exception { public void testFindDeviceTypesByTenantId() throws Exception {
List<Device> devices = new ArrayList<>(); List<Device> devices = new ArrayList<>();
for (int i = 0; i < 3; i++) {
int cntEntity = 3;
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
for (int i = 0; i < cntEntity; i++) {
Device device = new Device(); Device device = new Device();
device.setName("My device B" + i); device.setName("My device B" + i);
device.setType("typeB"); device.setType("typeB");
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(),
savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, cntEntity);
testNotificationUpdateGatewayNever();
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
Device device = new Device(); Device device = new Device();
device.setName("My device C" + i); device.setName("My device C" + i);
@ -192,7 +264,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
devices.add(doPost("/api/device", device, Device.class)); devices.add(doPost("/api/device", device, Device.class));
} }
List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types", List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types",
new TypeReference<List<EntitySubtype>>() { new TypeReference<>() {
}); });
Assert.assertNotNull(deviceTypes); Assert.assertNotNull(deviceTypes);
@ -211,28 +283,52 @@ 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);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doDelete("/api/device/" + savedDevice.getId().getId()) doDelete("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isOk()); .andExpect(status().isOk());
doGet("/api/device/" + savedDevice.getId().getId()) testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
.andExpect(status().isNotFound()); tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED, savedDevice.getId().getId().toString());
testNotificationDeleteGatewayOneTime(savedDevice);
EntityId savedDeviceId = savedDevice.getId();
doGet("/api/device/" + savedDeviceId)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", savedDeviceId.getId().toString()))));
} }
@Test @Test
public void testSaveDeviceWithEmptyType() throws Exception { public void testSaveDeviceWithEmptyType() throws Exception {
Device device = new Device(); Device device = new Device();
device.setName("My device"); device.setName("My device");
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device savedDevice = doPost("/api/device", device, Device.class); Device savedDevice = doPost("/api/device", device, Device.class);
Assert.assertEquals("default", savedDevice.getType()); Assert.assertEquals("default", savedDevice.getType());
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED);
testNotificationUpdateGatewayNever();
} }
@Test @Test
public void testSaveDeviceWithEmptyName() throws Exception { public void testSaveDeviceWithEmptyName() throws Exception {
Device device = new Device(); Device device = new Device();
device.setType("default"); device.setType("default");
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String msgError = "Device name " + msgErrorShouldBeSpecified;
doPost("/api/device", device) doPost("/api/device", device)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device name should be specified"))); .andExpect(statusReason(containsString(msgError)));
testNotifyEntityEqualsOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -246,17 +342,33 @@ 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);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId() Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId()
+ "/device/" + savedDevice.getId().getId(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId());
testNotifyEntityAllOneTime(assignedDevice, assignedDevice.getId(), assignedDevice.getId(), savedTenant.getId(),
savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ASSIGNED_TO_CUSTOMER,
assignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
savedCustomer.getTitle());
testNotificationUpdateGatewayNever();
Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class); Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId());
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device unassignedDevice = Device unassignedDevice =
doDelete("/api/customer/device/" + savedDevice.getId().getId(), 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());
testNotifyEntityAllOneTime(unassignedDevice, unassignedDevice.getId(), unassignedDevice.getId(), savedTenant.getId(),
savedCustomer.getId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UNASSIGNED_FROM_CUSTOMER,
unassignedDevice.getId().getId().toString(), savedCustomer.getId().getId().toString(),
savedCustomer.getTitle());
testNotificationDeleteGatewayNever();
foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), 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());
} }
@ -267,9 +379,17 @@ 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);
doPost("/api/customer/" + Uuids.timeBased().toString()
+ "/device/" + savedDevice.getId().getId()) Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
.andExpect(status().isNotFound());
String customerIdStr = savedDevice.getId().toString();
doPost("/api/customer/" + customerIdStr
+ "/device/" + savedDevice.getId().getId())
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Customer", customerIdStr))));
testNotifyEntityNever(savedDevice.getId(), savedDevice);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -288,7 +408,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
tenantAdmin2.setFirstName("Joe"); tenantAdmin2.setFirstName("Joe");
tenantAdmin2.setLastName("Downs"); tenantAdmin2.setLastName("Downs");
tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); createUserAndLogin(tenantAdmin2, "testPassword1");
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("Different customer"); customer.setTitle("Different customer");
@ -301,9 +421,15 @@ 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);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/customer/" + savedCustomer.getId().getId() doPost("/api/customer/" + savedCustomer.getId().getId()
+ "/device/" + savedDevice.getId().getId()) + "/device/" + savedDevice.getId().getId())
.andExpect(status().isForbidden()); .andExpect(status().isForbidden())
.andExpect(statusReason(containsString(msgErrorPermission)));
testNotifyEntityNever(savedDevice.getId(), savedDevice);
testNotificationUpdateGatewayNever();
loginSysAdmin(); loginSysAdmin();
@ -333,9 +459,16 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
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");
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isOk()); .andExpect(status().isOk());
testNotifyEntityMsgToEdgePushMsgToCoreOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.CREDENTIALS_UPDATED, deviceCredentials);
testNotificationUpdateGatewayNever();
DeviceCredentials foundDeviceCredentials = DeviceCredentials foundDeviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
@ -345,8 +478,15 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Test @Test
public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception { public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception {
DeviceCredentials deviceCredentials = new DeviceCredentials(); DeviceCredentials deviceCredentials = new DeviceCredentials();
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()); .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Incorrect deviceId null")));
testNotifyEntityNever(deviceCredentials.getDeviceId(), new Device());
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -358,9 +498,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsType(null); deviceCredentials.setCredentialsType(null);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String msgError = "Device credentials type " + msgErrorShouldBeSpecified;
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device credentials type should be specified"))); .andExpect(statusReason(containsString(msgError)));
testNotifyEntityIsNullOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.CREDENTIALS_UPDATED,
new DataValidationException(msgError), deviceCredentials);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -372,9 +521,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsId(null); deviceCredentials.setCredentialsId(null);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String msgError = "Device credentials id " + msgErrorShouldBeSpecified;
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Device credentials id should be specified"))); .andExpect(statusReason(containsString(msgError)));
testNotifyEntityIsNullOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.CREDENTIALS_UPDATED,
new DeviceCredentialsValidationException(msgError), deviceCredentials);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -390,9 +548,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId()); newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId());
newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType());
newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId());
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
String msgError = "Unable to update non-existent device credentials";
doPost("/api/device/credentials", newDeviceCredentials) doPost("/api/device/credentials", newDeviceCredentials)
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Unable to update non-existent device credentials"))); .andExpect(statusReason(containsString(msgError)));
testNotifyEntityIsNullOneTimeError(device, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.CREDENTIALS_UPDATED,
new DeviceCredentialsValidationException(msgError), newDeviceCredentials);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -401,29 +568,44 @@ 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);
DeviceId deviceTimeBasedId = new DeviceId(Uuids.timeBased());
DeviceCredentials deviceCredentials = DeviceCredentials deviceCredentials =
doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class); doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased())); deviceCredentials.setDeviceId(deviceTimeBasedId);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/device/credentials", deviceCredentials) doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isNotFound()); .andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", deviceTimeBasedId.toString()))));
testNotifyEntityNever(savedDevice.getId(), savedDevice);
testNotificationUpdateGatewayNever();
} }
@Test @Test
public void testFindTenantDevices() throws Exception { public void testFindTenantDevices() throws Exception {
log.debug("testFindTenantDevices"); int cntEntity = 178;
futures = new ArrayList<>(178);
for (int i = 0; i < 178; i++) { Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
futures = new ArrayList<>(cntEntity);
for (int i = 0; i < cntEntity; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device" + i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
futures.add(executor.submit(() -> futures.add(executor.submit(() ->
doPost("/api/device", device, Device.class))); doPost("/api/device", device, Device.class)));
} }
log.debug("await create devices");
List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("start reading"); testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Device(), new Device(),
List<Device> loadedDevices = new ArrayList<>(178); savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, cntEntity);
testNotificationUpdateGatewayNever();
List<Device> loadedDevices = new ArrayList<>(cntEntity);
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
do { do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?", pageData = doGetTypedWithPageLink("/api/tenant/devices?",
@ -435,11 +617,16 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
} }
} while (pageData.hasNext()); } while (pageData.hasNext());
log.debug("asserting");
assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices); assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
log.debug("delete devices async");
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS); deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("done");
testNotifyManyEntityManyTimeMsgToEdgeServiceNeverAdditionalInfoAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, cntEntity, 1);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -604,9 +791,12 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
customer.setTitle("Test customer"); customer.setTitle("Test customer");
customer = doPost("/api/customer", customer, Customer.class); customer = doPost("/api/customer", customer, Customer.class);
CustomerId customerId = customer.getId(); CustomerId customerId = customer.getId();
int cntEntity = 128;
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
futures = new ArrayList<>(128); futures = new ArrayList<>(cntEntity);
for (int i = 0; i < 128; i++) { for (int i = 0; i < cntEntity; i++) {
Device device = new Device(); Device device = new Device();
device.setName("Device" + i); device.setName("Device" + i);
device.setType("default"); device.setType("default");
@ -618,7 +808,12 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS); List<Device> devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
List<Device> loadedDevices = new ArrayList<>(128); testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new Device(), new Device(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ASSIGNED_TO_CUSTOMER, cntEntity, cntEntity, cntEntity * 2);
testNotificationUpdateGatewayNever();
List<Device> loadedDevices = new ArrayList<>(cntEntity);
PageLink pageLink = new PageLink(23); PageLink pageLink = new PageLink(23);
do { do {
pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?", pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId() + "/devices?",
@ -631,9 +826,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices); assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
log.debug("delete devices async"); Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
deleteEntitiesAsync("/api/customer/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS); deleteEntitiesAsync("/api/customer/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
log.debug("done");
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAnyAdditionalInfoAny(new Device(), new Device(),
savedTenant.getId(), customerId, tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.UNASSIGNED_FROM_CUSTOMER, ActionType.UNASSIGNED_FROM_CUSTOMER, cntEntity, cntEntity, 3);
testNotificationUpdateGatewayNever();
} }
@Test @Test
@ -843,16 +1043,30 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
createUserAndLogin(user, "testPassword1"); createUserAndLogin(user, "testPassword1");
login("tenant2@thingsboard.org", "testPassword1"); login("tenant2@thingsboard.org", "testPassword1");
Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class);
doGet("/api/device/" + assignedDevice.getId().getId(), Device.class, status().isNotFound()); Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/"
+ savedDevice.getId().getId(), Device.class);
doGet("/api/device/" + assignedDevice.getId().getId())
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", assignedDevice.getId().getId().toString()))));
testNotifyEntityOneTimeMsgToEdgeServiceNever(assignedDevice, assignedDevice.getId(), assignedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ASSIGNED_TO_TENANT, savedDifferentTenant.getId().getId().toString(), savedDifferentTenant.getTitle());
testNotificationUpdateGatewayNever();
login("tenant9@thingsboard.org", "testPassword1"); login("tenant9@thingsboard.org", "testPassword1");
Device foundDevice1 = doGet("/api/device/" + assignedDevice.getId().getId(), 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")
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Device", savedAnotherDevice.getId().getId().toString()))));
loginSysAdmin(); loginSysAdmin();
doDelete("/api/tenant/" + savedDifferentTenant.getId().getId()) doDelete("/api/tenant/" + savedDifferentTenant.getId().getId())
@ -869,17 +1083,32 @@ 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);
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doPost("/api/edge/" + savedEdge.getId().getId() doPost("/api/edge/" + savedEdge.getId().getId()
+ "/device/" + savedDevice.getId().getId(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ASSIGNED_TO_EDGE,
savedDevice.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName());
testNotificationUpdateGatewayNever();
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?",
PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100)); PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100));
Assert.assertEquals(1, pageData.getData().size()); Assert.assertEquals(1, pageData.getData().size());
Mockito.reset(tbClusterService, auditLogService, gatewayNotificationsService);
doDelete("/api/edge/" + savedEdge.getId().getId() doDelete("/api/edge/" + savedEdge.getId().getId()
+ "/device/" + savedDevice.getId().getId(), Device.class); + "/device/" + savedDevice.getId().getId(), Device.class);
testNotifyEntityAllOneTime(savedDevice, savedDevice.getId(), savedDevice.getId(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.UNASSIGNED_FROM_EDGE, savedDevice.getId().getId().toString(), savedEdge.getId().getId().toString(), savedEdge.getName());
testNotificationUpdateGatewayNever();
pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?", pageData = doGetTypedWithPageLink("/api/edge/" + savedEdge.getId().getId() + "/devices?",
PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100)); PAGE_DATA_DEVICE_TYPE_REF, new PageLink(100));

6
common/data/src/main/java/org/thingsboard/server/common/data/queue/Queue.java

@ -22,11 +22,17 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo;
import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.QueueId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@Data @Data
public class Queue extends SearchTextBasedWithAdditionalInfo<QueueId> implements HasName, HasTenantId { public class Queue extends SearchTextBasedWithAdditionalInfo<QueueId> implements HasName, HasTenantId {
private TenantId tenantId; private TenantId tenantId;
@NoXss
@Length(fieldName = "name")
private String name; private String name;
@NoXss
@Length(fieldName = "topic")
private String topic; private String topic;
private int pollInterval; private int pollInterval;
private int partitions; private int partitions;

2
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportColumnType.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportColumnType.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.ie.importing.csv; package org.thingsboard.server.common.data.sync.ie.importing.csv;
import lombok.Getter; import lombok.Getter;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;

2
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportRequest.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportRequest.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.ie.importing.csv; package org.thingsboard.server.common.data.sync.ie.importing.csv;
import lombok.Data; import lombok.Data;

2
application/src/main/java/org/thingsboard/server/service/sync/ie/importing/csv/BulkImportResult.java → common/data/src/main/java/org/thingsboard/server/common/data/sync/ie/importing/csv/BulkImportResult.java

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.thingsboard.server.service.sync.ie.importing.csv; package org.thingsboard.server.common.data.sync.ie.importing.csv;
import lombok.Data; import lombok.Data;

3
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/BranchInfo.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.data.sync.vc; package org.thingsboard.server.common.data.sync.vc;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data; import lombok.Data;
import java.util.Objects; import java.util.Objects;
@ -22,6 +23,8 @@ import java.util.Objects;
@Data @Data
public class BranchInfo { public class BranchInfo {
private final String name; private final String name;
@JsonProperty("default")
private final boolean isDefault; private final boolean isDefault;
@Override @Override

1
common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/request/load/VersionLoadRequest.java

@ -29,7 +29,6 @@ import static com.fasterxml.jackson.annotation.JsonSubTypes.Type;
@Data @Data
public abstract class VersionLoadRequest { public abstract class VersionLoadRequest {
private String branch;
private String versionId; private String versionId;
public abstract VersionLoadRequestType getType(); public abstract VersionLoadRequestType getType();

6
common/version-control/src/main/java/org/thingsboard/server/service/sync/vc/GitRepository.java

@ -354,7 +354,11 @@ public class GitRepository {
} }
private ObjectId resolve(String rev) throws IOException { private ObjectId resolve(String rev) throws IOException {
return git.getRepository().resolve(rev); ObjectId result = git.getRepository().resolve(rev);
if (result == null) {
throw new IllegalArgumentException("Failed to parse git revision string: \"" + rev + "\"");
}
return result;
} }
private <C extends GitCommand<T>, T> T execute(C command) throws GitAPIException { private <C extends GitCommand<T>, T> T execute(C command) throws GitAPIException {

24
dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -36,6 +37,11 @@ public abstract class DataValidator<D extends BaseData<?>> {
private static final Pattern EMAIL_PATTERN = private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE);
private static final Pattern QUEUE_PATTERN = Pattern.compile("^[a-zA-Z0-9_.\\-]+$");
private static final String NAME = "name";
private static final String TOPIC = "topic";
// Returns old instance of the same object that is fetched during validation. // Returns old instance of the same object that is fetched during validation.
public D validate(D data, Function<D, TenantId> tenantIdFunction) { public D validate(D data, Function<D, TenantId> tenantIdFunction) {
try { try {
@ -134,4 +140,22 @@ public abstract class DataValidator<D extends BaseData<?>> {
} }
} }
protected static void validateQueueName(String name) {
validateQueueNameOrTopic(name, NAME);
}
protected static void validateQueueTopic(String topic) {
validateQueueNameOrTopic(topic, TOPIC);
}
private static void validateQueueNameOrTopic(String value, String fieldName) {
if (StringUtils.isEmpty(value)) {
throw new DataValidationException(String.format("Queue %s should be specified!", fieldName));
}
if (!QUEUE_PATTERN.matcher(value).matches()) {
throw new DataValidationException(
String.format("Queue %s contains a character other than ASCII alphanumerics, '.', '_' and '-'!", fieldName));
}
}
} }

10
dao/src/main/java/org/thingsboard/server/dao/service/validator/QueueValidator.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.dao.service.validator; package org.thingsboard.server.dao.service.validator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
@ -73,12 +72,9 @@ public class QueueValidator extends DataValidator<Queue> {
} }
} }
if (StringUtils.isEmpty(queue.getName())) { validateQueueName(queue.getName());
throw new DataValidationException("Queue name should be specified!"); validateQueueTopic(queue.getTopic());
}
if (StringUtils.isBlank(queue.getTopic())) {
throw new DataValidationException("Queue topic should be non empty and without spaces!");
}
if (queue.getPollInterval() < 1) { if (queue.getPollInterval() < 1) {
throw new DataValidationException("Queue poll interval should be more then 0!"); throw new DataValidationException("Queue poll interval should be more then 0!");
} }

9
dao/src/main/java/org/thingsboard/server/dao/service/validator/TenantProfileDataValidator.java

@ -107,12 +107,9 @@ public class TenantProfileDataValidator extends DataValidator<TenantProfile> {
} }
private void validateQueueConfiguration(TenantProfileQueueConfiguration queue) { private void validateQueueConfiguration(TenantProfileQueueConfiguration queue) {
if (StringUtils.isEmpty(queue.getName())) { validateQueueName(queue.getName());
throw new DataValidationException("Queue name should be specified!"); validateQueueTopic(queue.getTopic());
}
if (StringUtils.isBlank(queue.getTopic())) {
throw new DataValidationException("Queue topic should be non empty and without spaces!");
}
if (queue.getPollInterval() < 1) { if (queue.getPollInterval() < 1) {
throw new DataValidationException("Queue poll interval should be more then 0!"); throw new DataValidationException("Queue poll interval should be more then 0!");
} }

28
dao/src/test/java/org/thingsboard/server/dao/service/BaseQueueServiceTest.java

@ -152,6 +152,20 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest {
queueService.saveQueue(queue); queueService.saveQueue(queue);
} }
@Test(expected = DataValidationException.class)
public void testSaveQueueWithInvalidName() {
Queue queue = new Queue();
queue.setTenantId(tenantId);
queue.setName("Test 1");
queue.setTopic("tb_rule_engine.test");
queue.setPollInterval(25);
queue.setPartitions(1);
queue.setPackProcessingTimeout(2000);
queue.setSubmitStrategy(createTestSubmitStrategy());
queue.setProcessingStrategy(createTestProcessingStrategy());
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class) @Test(expected = DataValidationException.class)
public void testSaveQueueWithEmptyTopic() { public void testSaveQueueWithEmptyTopic() {
Queue queue = new Queue(); Queue queue = new Queue();
@ -165,6 +179,20 @@ public abstract class BaseQueueServiceTest extends AbstractServiceTest {
queueService.saveQueue(queue); queueService.saveQueue(queue);
} }
@Test(expected = DataValidationException.class)
public void testSaveQueueWithInvalidTopic() {
Queue queue = new Queue();
queue.setTenantId(tenantId);
queue.setName("Test");
queue.setTopic("tb rule engine test");
queue.setPollInterval(25);
queue.setPartitions(1);
queue.setPackProcessingTimeout(2000);
queue.setSubmitStrategy(createTestSubmitStrategy());
queue.setProcessingStrategy(createTestProcessingStrategy());
queueService.saveQueue(queue);
}
@Test(expected = DataValidationException.class) @Test(expected = DataValidationException.class)
public void testSaveQueueWithEmptyPollInterval() { public void testSaveQueueWithEmptyPollInterval() {
Queue queue = new Queue(); Queue queue = new Queue();

74
docker/compose-utils.sh

@ -121,3 +121,77 @@ function additionalStartupServices() {
echo $ADDITIONAL_STARTUP_SERVICES echo $ADDITIONAL_STARTUP_SERVICES
} }
function permissionList() {
PERMISSION_LIST="
799 799 tb-node/log
799 799 tb-transports/coap/log
799 799 tb-transports/lwm2m/log
799 799 tb-transports/http/log
799 799 tb-transports/mqtt/log
799 799 tb-transports/snmp/log
799 799 tb-transports/coap/log
799 799 tb-vc-executor/log
999 999 tb-node/postgres
"
source .env
if [ "$DATABASE" = "hybrid" ]; then
PERMISSION_LIST="$PERMISSION_LIST
999 999 tb-node/cassandra
"
fi
CACHE="${CACHE:-redis}"
case $CACHE in
redis)
PERMISSION_LIST="$PERMISSION_LIST
1001 1001 tb-node/redis-data
"
;;
redis-cluster)
PERMISSION_LIST="$PERMISSION_LIST
1001 1001 tb-node/redis-cluster-data-0
1001 1001 tb-node/redis-cluster-data-1
1001 1001 tb-node/redis-cluster-data-2
1001 1001 tb-node/redis-cluster-data-3
1001 1001 tb-node/redis-cluster-data-4
1001 1001 tb-node/redis-cluster-data-5
"
;;
*)
echo "Unknown CACHE value specified in the .env file: '${CACHE}'. Should be either 'redis' or 'redis-cluster'." >&2
exit 1
esac
echo "$PERMISSION_LIST"
}
function checkFolders() {
EXIT_CODE=0
PERMISSION_LIST=$(permissionList) || exit $?
set -e
while read -r USR GRP DIR
do
if [ -z "$DIR" ]; then # skip empty lines
continue
fi
MESSAGE="Checking user ${USR} group ${GRP} dir ${DIR}"
if [[ -d "$DIR" ]] &&
[[ $(ls -ldn "$DIR" | awk '{print $3}') -eq "$USR" ]] &&
[[ $(ls -ldn "$DIR" | awk '{print $4}') -eq "$GRP" ]]
then
MESSAGE="$MESSAGE OK"
else
if [ "$1" = "--create" ]; then
echo "Create and chown: user ${USR} group ${GRP} dir ${DIR}"
mkdir -p "$DIR" && sudo chown -R "$USR":"$GRP" "$DIR"
else
echo "$MESSAGE FAILED"
EXIT_CODE=1
fi
fi
done < <(echo "$PERMISSION_LIST")
return $EXIT_CODE
}

21
docker/docker-check-log-folders.sh

@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.
#
set -e
source compose-utils.sh
checkFolders || exit $?
echo "OK"

39
docker/docker-create-log-folders.sh

@ -15,39 +15,6 @@
# limitations under the License. # limitations under the License.
# #
mkdir -p tb-node/log && sudo chown -R 799:799 tb-node/log set -e
source compose-utils.sh
mkdir -p tb-transports/coap/log && sudo chown -R 799:799 tb-transports/coap/log checkFolders --create
mkdir -p tb-transports/lwm2m/log && sudo chown -R 799:799 tb-transports/lwm2m/log
mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log
mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log
mkdir -p tb-transports/snmp/log && sudo chown -R 799:799 tb-transports/snmp/log
mkdir -p tb-vc-executor/log && sudo chown -R 799:799 tb-vc-executor/log
mkdir -p tb-node/postgres && sudo chown -R 999:999 tb-node/postgres
mkdir -p tb-node/cassandra && sudo chown -R 999:999 tb-node/cassandra
source .env
CACHE="${CACHE:-redis}"
case $CACHE in
redis)
mkdir -p tb-node/redis-data && sudo chown -R 1001:1001 tb-node/redis-data
;;
redis-cluster)
mkdir -p tb-node/redis-cluster-data-0 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-0
mkdir -p tb-node/redis-cluster-data-1 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-1
mkdir -p tb-node/redis-cluster-data-2 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-2
mkdir -p tb-node/redis-cluster-data-3 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-3
mkdir -p tb-node/redis-cluster-data-4 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-4
mkdir -p tb-node/redis-cluster-data-5 && sudo chown -R 1001:1001 tb-node/redis-cluster-data-5
;;
*)
echo "Unknown CACHE value specified in the .env file: '${CACHE}'. Should be either 'redis' or 'redis-cluster'." >&2
exit 1
esac

2
docker/docker-install-tb.sh

@ -49,6 +49,8 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $?
ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $?
checkFolders --create || exit $?
if [ ! -z "${ADDITIONAL_STARTUP_SERVICES// }" ]; then if [ ! -z "${ADDITIONAL_STARTUP_SERVICES// }" ]; then
docker-compose \ docker-compose \
-f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS \ -f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS \

2
docker/docker-start-services.sh

@ -27,6 +27,8 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $?
ADDITIONAL_COMPOSE_MONITORING_ARGS=$(additionalComposeMonitoringArgs) || exit $? ADDITIONAL_COMPOSE_MONITORING_ARGS=$(additionalComposeMonitoringArgs) || exit $?
checkFolders --create || exit $?
docker-compose \ docker-compose \
-f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS $ADDITIONAL_COMPOSE_MONITORING_ARGS \ -f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS $ADDITIONAL_COMPOSE_MONITORING_ARGS \
up -d up -d

2
docker/docker-upgrade-tb.sh

@ -48,6 +48,8 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $?
ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $?
checkFolders --create || exit $?
docker-compose \ docker-compose \
-f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS \ -f docker-compose.yml $ADDITIONAL_CACHE_ARGS $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS \
pull \ pull \

266
rest-client/src/main/java/org/thingsboard/rest/client/RestClient.java

@ -51,6 +51,7 @@ import org.thingsboard.server.common.data.DeviceProfileInfo;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.EntityView; import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.EntityViewInfo; import org.thingsboard.server.common.data.EntityViewInfo;
import org.thingsboard.server.common.data.Event; import org.thingsboard.server.common.data.Event;
@ -77,6 +78,7 @@ import org.thingsboard.server.common.data.audit.AuditLog;
import org.thingsboard.server.common.data.device.DeviceSearchQuery; import org.thingsboard.server.common.data.device.DeviceSearchQuery;
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.EdgeInfo;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery; import org.thingsboard.server.common.data.entityview.EntityViewSearchQuery;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
@ -134,6 +136,19 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.security.model.SecuritySettings; import org.thingsboard.server.common.data.security.model.SecuritySettings;
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
import org.thingsboard.server.common.data.sms.config.TestSmsRequest; import org.thingsboard.server.common.data.sms.config.TestSmsRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportRequest;
import org.thingsboard.server.common.data.sync.ie.importing.csv.BulkImportResult;
import org.thingsboard.server.common.data.sync.vc.AutoCommitSettings;
import org.thingsboard.server.common.data.sync.vc.BranchInfo;
import org.thingsboard.server.common.data.sync.vc.EntityDataDiff;
import org.thingsboard.server.common.data.sync.vc.EntityDataInfo;
import org.thingsboard.server.common.data.sync.vc.EntityVersion;
import org.thingsboard.server.common.data.sync.vc.RepositorySettings;
import org.thingsboard.server.common.data.sync.vc.VersionCreationResult;
import org.thingsboard.server.common.data.sync.vc.VersionLoadResult;
import org.thingsboard.server.common.data.sync.vc.VersionedEntityInfo;
import org.thingsboard.server.common.data.sync.vc.request.create.VersionCreateRequest;
import org.thingsboard.server.common.data.sync.vc.request.load.VersionLoadRequest;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetTypeInfo;
@ -147,11 +162,12 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.isEmpty; import static org.thingsboard.server.common.data.StringUtils.isEmpty;
/** /**
* @author Andrew Shvayka * @author Andrew Shvayka
@ -267,6 +283,60 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
return restTemplate.postForEntity(baseURL + "/api/admin/securitySettings", securitySettings, SecuritySettings.class).getBody(); return restTemplate.postForEntity(baseURL + "/api/admin/securitySettings", securitySettings, SecuritySettings.class).getBody();
} }
public Optional<RepositorySettings> getRepositorySettings() {
try {
ResponseEntity<RepositorySettings> repositorySettings = restTemplate.getForEntity(baseURL + "/api/admin/repositorySettings", RepositorySettings.class);
return Optional.ofNullable(repositorySettings.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Boolean repositorySettingsExists() {
return restTemplate.getForEntity(baseURL + "/api/admin/repositorySettings/exists", Boolean.class).getBody();
}
public RepositorySettings saveRepositorySettings(RepositorySettings repositorySettings) {
return restTemplate.postForEntity(baseURL + "/api/admin/repositorySettings", repositorySettings, RepositorySettings.class).getBody();
}
public void deleteRepositorySettings() {
restTemplate.delete(baseURL + "/api/admin/repositorySettings");
}
public void checkRepositoryAccess(RepositorySettings repositorySettings) {
restTemplate.postForLocation(baseURL + "/api/admin/repositorySettings/checkAccess", repositorySettings);
}
public Optional<AutoCommitSettings> getAutoCommitSettings() {
try {
ResponseEntity<AutoCommitSettings> autoCommitSettings = restTemplate.getForEntity(baseURL + "/api/admin/autoCommitSettings", AutoCommitSettings.class);
return Optional.ofNullable(autoCommitSettings.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Boolean autoCommitSettingsExists() {
return restTemplate.getForEntity(baseURL + "/api/admin/autoCommitSettings/exists", Boolean.class).getBody();
}
public AutoCommitSettings saveAutoCommitSettings(AutoCommitSettings autoCommitSettings) {
return restTemplate.postForEntity(baseURL + "/api/admin/autoCommitSettings", autoCommitSettings, AutoCommitSettings.class).getBody();
}
public void deleteAutoCommitSettings() {
restTemplate.delete(baseURL + "/api/admin/autoCommitSettings");
}
public Optional<UpdateMessage> checkUpdates() { public Optional<UpdateMessage> checkUpdates() {
try { try {
ResponseEntity<UpdateMessage> updateMsg = restTemplate.getForEntity(baseURL + "/api/admin/updates", UpdateMessage.class); ResponseEntity<UpdateMessage> updateMsg = restTemplate.getForEntity(baseURL + "/api/admin/updates", UpdateMessage.class);
@ -550,6 +620,15 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}).getBody(); }).getBody();
} }
public BulkImportResult<Asset> processAssetsBulkImport(BulkImportRequest request) {
return restTemplate.exchange(
baseURL + "/api/asset/bulk_import",
HttpMethod.POST,
new HttpEntity<>(request),
new ParameterizedTypeReference<BulkImportResult<Asset>>() {
}).getBody();
}
@Deprecated @Deprecated
public Optional<Asset> findAsset(String name) { public Optional<Asset> findAsset(String name) {
Map<String, String> params = new HashMap<String, String>(); Map<String, String> params = new HashMap<String, String>();
@ -1251,7 +1330,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
HttpEntity.EMPTY, Device.class, tenantId, deviceId).getBody(); HttpEntity.EMPTY, Device.class, tenantId, deviceId).getBody();
} }
public Long countDevicesByTenantIdAndDeviceProfileIdAndEmptyOtaPackage(OtaPackageType otaPackageType, DeviceProfileId deviceProfileId) { public Long countByDeviceProfileAndEmptyOtaPackage(OtaPackageType otaPackageType, DeviceProfileId deviceProfileId) {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("otaPackageType", otaPackageType.name()); params.put("otaPackageType", otaPackageType.name());
params.put("deviceProfileId", deviceProfileId.getId().toString()); params.put("deviceProfileId", deviceProfileId.getId().toString());
@ -1266,6 +1345,15 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
).getBody(); ).getBody();
} }
public BulkImportResult<Device> processDevicesBulkImport(BulkImportRequest request) {
return restTemplate.exchange(
baseURL + "/api/device/bulk_import",
HttpMethod.POST,
new HttpEntity<>(request),
new ParameterizedTypeReference<BulkImportResult<Device>>() {
}).getBody();
}
@Deprecated @Deprecated
public Device createDevice(String name, String type) { public Device createDevice(String name, String type) {
Device device = new Device(); Device device = new Device();
@ -2499,6 +2587,10 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
} }
} }
public Boolean isEdgesSupportEnabled() {
return restTemplate.getForEntity(baseURL + "/api/edges/enabled", Boolean.class).getBody();
}
public Edge saveEdge(Edge edge) { public Edge saveEdge(Edge edge) {
return restTemplate.postForEntity(baseURL + "/api/edge", edge, Edge.class).getBody(); return restTemplate.postForEntity(baseURL + "/api/edge", edge, Edge.class).getBody();
} }
@ -2520,6 +2612,19 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
} }
} }
public Optional<EdgeInfo> getEdgeInfoById(EdgeId edgeId) {
try {
ResponseEntity<EdgeInfo> edge = restTemplate.getForEntity(baseURL + "/api/edge/info/{edgeId}", EdgeInfo.class, edgeId.getId());
return Optional.ofNullable(edge.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public Optional<Edge> assignEdgeToCustomer(CustomerId customerId, EdgeId edgeId) { public Optional<Edge> assignEdgeToCustomer(CustomerId customerId, EdgeId edgeId) {
try { try {
ResponseEntity<Edge> edge = restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/edge/{edgeId}", null, Edge.class, customerId.getId(), edgeId.getId()); ResponseEntity<Edge> edge = restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/edge/{edgeId}", null, Edge.class, customerId.getId(), edgeId.getId());
@ -2546,7 +2651,7 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
} }
} }
public Optional<Edge> setRootRuleChain(EdgeId edgeId, RuleChainId ruleChainId) { public Optional<Edge> setEdgeRootRuleChain(EdgeId edgeId, RuleChainId ruleChainId) {
try { try {
ResponseEntity<Edge> ruleChain = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/{ruleChainId}/root", null, Edge.class, edgeId.getId(), ruleChainId.getId()); ResponseEntity<Edge> ruleChain = restTemplate.postForEntity(baseURL + "/api/edge/{edgeId}/{ruleChainId}/root", null, Edge.class, edgeId.getId(), ruleChainId.getId());
return Optional.ofNullable(ruleChain.getBody()); return Optional.ofNullable(ruleChain.getBody());
@ -2827,6 +2932,17 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}, params).getBody(); }, params).getBody();
} }
public PageData<EdgeInfo> getTenantEdgeInfos(String type, PageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("type", type);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/tenant/edgeInfos?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<EdgeInfo>>() {
}, params).getBody();
}
public Optional<Edge> getTenantEdge(String edgeName) { public Optional<Edge> getTenantEdge(String edgeName) {
try { try {
ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/tenant/edges?edgeName={edgeName}", Edge.class, edgeName); ResponseEntity<Edge> edge = restTemplate.getForEntity(baseURL + "/api/tenant/edges?edgeName={edgeName}", Edge.class, edgeName);
@ -2852,6 +2968,18 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
}, params).getBody(); }, params).getBody();
} }
public PageData<EdgeInfo> getCustomerEdgeInfos(CustomerId customerId, PageLink pageLink, String edgeType) {
Map<String, String> params = new HashMap<>();
params.put("customerId", customerId.getId().toString());
params.put("type", edgeType);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/customer/{customerId}/edgeInfos?type={type}&" + getUrlParams(pageLink),
HttpMethod.GET, HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<EdgeInfo>>() {
}, params).getBody();
}
public List<Edge> getEdgesByIds(List<EdgeId> edgeIds) { public List<Edge> getEdgesByIds(List<EdgeId> edgeIds) {
return restTemplate.exchange(baseURL + "/api/edges?edgeIds={edgeIds}", return restTemplate.exchange(baseURL + "/api/edges?edgeIds={edgeIds}",
HttpMethod.GET, HttpMethod.GET,
@ -2896,6 +3024,138 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
restTemplate.postForEntity(baseURL + "/api/edge/sync/{edgeId}", null, EdgeId.class, params); restTemplate.postForEntity(baseURL + "/api/edge/sync/{edgeId}", null, EdgeId.class, params);
} }
public String findMissingToRelatedRuleChains(EdgeId edgeId) {
return restTemplate.getForEntity(baseURL + "/api/edge/missingToRelatedRuleChains/{edgeId}", String.class, edgeId.getId()).getBody();
}
public BulkImportResult<Edge> processEdgesBulkImport(BulkImportRequest request) {
return restTemplate.exchange(
baseURL + "/api/edge/bulk_import",
HttpMethod.POST,
new HttpEntity<>(request),
new ParameterizedTypeReference<BulkImportResult<Edge>>() {
}).getBody();
}
public UUID saveEntitiesVersion(VersionCreateRequest request) {
return restTemplate.postForEntity(baseURL + "/api/entities/vc/version", request, UUID.class).getBody();
}
public Optional<VersionCreationResult> getVersionCreateRequestStatus(UUID requestId) {
try {
ResponseEntity<VersionCreationResult> versionCreateResult = restTemplate.getForEntity(baseURL + "/api/entities/vc/version/{requestId}/status", VersionCreationResult.class, requestId);
return Optional.ofNullable(versionCreateResult.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public PageData<EntityVersion> listEntityVersions(EntityId externalEntityId, String branch, PageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("entityType", externalEntityId.getEntityType().name());
params.put("externalEntityUuid", externalEntityId.getId().toString());
params.put("branch", branch);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/entities/vc/version/{entityType}/{externalEntityUuid}?branch={branch}&" + getUrlParams(pageLink),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<EntityVersion>>() {
},
params).getBody();
}
public PageData<EntityVersion> listEntityTypeVersions(EntityType entityType, String branch, PageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("entityType", entityType.name());
params.put("branch", branch);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/entities/vc/version/{entityType}?branch={branch}&" + getUrlParams(pageLink),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<EntityVersion>>() {
},
params).getBody();
}
public PageData<EntityVersion> listVersions(String branch, PageLink pageLink) {
Map<String, String> params = new HashMap<>();
params.put("branch", branch);
addPageLinkToParam(params, pageLink);
return restTemplate.exchange(
baseURL + "/api/entities/vc/version?branch={branch}&" + getUrlParams(pageLink),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<PageData<EntityVersion>>() {
},
params).getBody();
}
public List<VersionedEntityInfo> listEntitiesAtVersion(EntityType entityType, String versionId) {
Map<String, String> params = new HashMap<>();
params.put("entityType", entityType.name());
params.put("versionId", versionId);
return restTemplate.exchange(
baseURL + "/api/entities/vc/entity/{entityType}/{versionId}",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<VersionedEntityInfo>>() {
},
params).getBody();
}
public List<VersionedEntityInfo> listAllEntitiesAtVersion(String versionId) {
Map<String, String> params = new HashMap<>();
params.put("versionId", versionId);
return restTemplate.exchange(
baseURL + "/api/entities/vc/entity/{versionId}",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<VersionedEntityInfo>>() {
},
params).getBody();
}
public EntityDataInfo getEntityDataInfo(EntityId externalEntityId, String versionId) {
return restTemplate.getForEntity(baseURL + "/api/entities/vc/info/{versionId}/{entityType}/{externalEntityUuid}",
EntityDataInfo.class, versionId, externalEntityId.getEntityType(), externalEntityId.getId()).getBody();
}
public EntityDataDiff compareEntityDataToVersion(EntityId internalEntityId, String versionId) {
return restTemplate.getForEntity(baseURL + "/api/entities/vc/diff/{entityType}/{internalEntityUuid}?versionId={versionId}",
EntityDataDiff.class, internalEntityId.getEntityType(), internalEntityId.getId(), versionId).getBody();
}
public UUID loadEntitiesVersion(VersionLoadRequest request) {
return restTemplate.postForEntity(baseURL + "/api/entities/vc/entity", request, UUID.class).getBody();
}
public Optional<VersionLoadResult> getVersionLoadRequestStatus(UUID requestId) {
try {
ResponseEntity<VersionLoadResult> versionLoadResult = restTemplate.getForEntity(baseURL + "/api/entities/vc/entity/{requestId}/status", VersionLoadResult.class, requestId);
return Optional.ofNullable(versionLoadResult.getBody());
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
return Optional.empty();
} else {
throw exception;
}
}
}
public List<BranchInfo> listBranches() {
return restTemplate.exchange(
baseURL + "/api/entities/vc/branches",
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<BranchInfo>>() {
}).getBody();
}
public ResponseEntity<Resource> downloadResource(TbResourceId resourceId) { public ResponseEntity<Resource> downloadResource(TbResourceId resourceId) {
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("resourceId", resourceId.getId().toString()); params.put("resourceId", resourceId.getId().toString());

6
ui-ngx/src/app/core/http/entities-version-control.service.ts

@ -158,12 +158,10 @@ export class EntitiesVersionControlService {
defaultHttpOptionsFromConfig({...config, ...{ignoreLoading: true}})); defaultHttpOptionsFromConfig({...config, ...{ignoreLoading: true}}));
} }
public compareEntityDataToVersion(branch: string, public compareEntityDataToVersion(entityId: EntityId,
entityId: EntityId,
versionId: string, versionId: string,
config?: RequestConfig): Observable<EntityDataDiff> { config?: RequestConfig): Observable<EntityDataDiff> {
const encodedBranch = encodeURIComponent(branch); return this.http.get<EntityDataDiff>(`/api/entities/vc/diff/${entityId.entityType}/${entityId.id}?versionId=${versionId}`,
return this.http.get<EntityDataDiff>(`/api/entities/vc/diff/${entityId.entityType}/${entityId.id}?branch=${encodedBranch}&versionId=${versionId}`,
defaultHttpOptionsFromConfig(config)); defaultHttpOptionsFromConfig(config));
} }

3
ui-ngx/src/app/modules/home/components/queue/queue-form.component.html

@ -26,6 +26,9 @@
<mat-error *ngIf="queueFormGroup.get('name').hasError('unique')"> <mat-error *ngIf="queueFormGroup.get('name').hasError('unique')">
{{ 'queue.name-unique' | translate }} {{ 'queue.name-unique' | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="queueFormGroup.get('name').hasError('pattern')">
{{ 'queue.name-pattern' | translate }}
</mat-error>
</mat-form-field> </mat-form-field>
<mat-accordion class="queue-strategy" [multi]="true"> <mat-accordion class="queue-strategy" [multi]="true">
<mat-expansion-panel [expanded]="true"> <mat-expansion-panel [expanded]="true">

4
ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts

@ -99,7 +99,7 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr
ngOnInit() { ngOnInit() {
this.queueFormGroup = this.fb.group( this.queueFormGroup = this.fb.group(
{ {
name: ['', [Validators.required]], name: ['', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_.\-]+$/)]],
pollInterval: [25, [Validators.min(1), Validators.required]], pollInterval: [25, [Validators.min(1), Validators.required]],
partitions: [10, [Validators.min(1), Validators.required]], partitions: [10, [Validators.min(1), Validators.required]],
consumerPerPartition: [false, []], consumerPerPartition: [false, []],
@ -205,10 +205,12 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr
if (type === QueueSubmitStrategyTypes.BATCH) { if (type === QueueSubmitStrategyTypes.BATCH) {
batchSizeField.patchValue(1000, {emitEvent: false}); batchSizeField.patchValue(1000, {emitEvent: false});
batchSizeField.setValidators([Validators.min(1), Validators.required]); batchSizeField.setValidators([Validators.min(1), Validators.required]);
batchSizeField.updateValueAndValidity({emitEvent: false});
this.hideBatchSize = true; this.hideBatchSize = true;
} else { } else {
batchSizeField.patchValue(null, {emitEvent: false}); batchSizeField.patchValue(null, {emitEvent: false});
batchSizeField.clearValidators(); batchSizeField.clearValidators();
batchSizeField.updateValueAndValidity({emitEvent: false});
this.hideBatchSize = false; this.hideBatchSize = false;
} }
} }

4
ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts

@ -41,9 +41,6 @@ import { parseHttpErrorMessage } from '@core/utils';
}) })
export class ComplexVersionLoadComponent extends PageComponent implements OnInit, OnDestroy { export class ComplexVersionLoadComponent extends PageComponent implements OnInit, OnDestroy {
@Input()
branch: string;
@Input() @Input()
versionName: string; versionName: string;
@ -117,7 +114,6 @@ export class ComplexVersionLoadComponent extends PageComponent implements OnInit
restore(): void { restore(): void {
const request: EntityTypeVersionLoadRequest = { const request: EntityTypeVersionLoadRequest = {
branch: this.branch,
versionId: this.versionId, versionId: this.versionId,
entityTypes: this.loadVersionFormGroup.get('entityTypes').value, entityTypes: this.loadVersionFormGroup.get('entityTypes').value,
type: VersionLoadRequestType.ENTITY_TYPE type: VersionLoadRequestType.ENTITY_TYPE

6
ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.ts

@ -59,9 +59,6 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit,
@ViewChild('diffViewer', {static: true}) @ViewChild('diffViewer', {static: true})
diffViewerElmRef: ElementRef<HTMLElement>; diffViewerElmRef: ElementRef<HTMLElement>;
@Input()
branch: string;
@Input() @Input()
versionName: string; versionName: string;
@ -108,7 +105,7 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit,
ngOnInit(): void { ngOnInit(): void {
this.entitiesVersionControlService this.entitiesVersionControlService
.compareEntityDataToVersion(this.branch, this.entityId, this.versionId).subscribe((diffData) => { .compareEntityDataToVersion(this.entityId, this.versionId).subscribe((diffData) => {
const leftContent = entityExportDataToJsonString(diffData.currentVersion); const leftContent = entityExportDataToJsonString(diffData.currentVersion);
const rightContent = entityExportDataToJsonString(diffData.otherVersion); const rightContent = entityExportDataToJsonString(diffData.otherVersion);
const leftLines = leftContent.split('\n').length; const leftLines = leftContent.split('\n').length;
@ -310,7 +307,6 @@ export class EntityVersionDiffComponent extends PageComponent implements OnInit,
const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null, this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null,
{ {
branch: this.branch,
versionName: this.versionName, versionName: this.versionName,
versionId: this.versionId, versionId: this.versionId,
externalEntityId: this.externalEntityId, externalEntityId: this.externalEntityId,

4
ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts

@ -41,9 +41,6 @@ import { parseHttpErrorMessage } from '@core/utils';
}) })
export class EntityVersionRestoreComponent extends PageComponent implements OnInit, OnDestroy { export class EntityVersionRestoreComponent extends PageComponent implements OnInit, OnDestroy {
@Input()
branch: string;
@Input() @Input()
versionName: string; versionName: string;
@ -108,7 +105,6 @@ export class EntityVersionRestoreComponent extends PageComponent implements OnIn
restore(): void { restore(): void {
const request: SingleEntityVersionLoadRequest = { const request: SingleEntityVersionLoadRequest = {
branch: this.branch,
versionId: this.versionId, versionId: this.versionId,
externalEntityId: this.externalEntityId, externalEntityId: this.externalEntityId,
config: { config: {

3
ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.ts

@ -260,7 +260,6 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
const diffVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, const diffVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionDiffComponent, 'leftTop', true, null, this.viewContainerRef, EntityVersionDiffComponent, 'leftTop', true, null,
{ {
branch: this.branch,
versionName: entityVersion.name, versionName: entityVersion.name,
versionId: entityVersion.id, versionId: entityVersion.id,
entityId: this.entityId, entityId: this.entityId,
@ -284,7 +283,6 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, const restoreVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null, this.viewContainerRef, EntityVersionRestoreComponent, 'leftTop', true, null,
{ {
branch: this.branch,
versionName: entityVersion.name, versionName: entityVersion.name,
versionId: entityVersion.id, versionId: entityVersion.id,
externalEntityId: this.externalEntityIdValue, externalEntityId: this.externalEntityIdValue,
@ -310,7 +308,6 @@ export class EntityVersionsTableComponent extends PageComponent implements OnIni
const restoreEntitiesVersionPopover = this.popoverService.displayPopover(trigger, this.renderer, const restoreEntitiesVersionPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, ComplexVersionLoadComponent, 'leftTop', true, null, this.viewContainerRef, ComplexVersionLoadComponent, 'leftTop', true, null,
{ {
branch: this.branch,
versionName: entityVersion.name, versionName: entityVersion.name,
versionId: entityVersion.id, versionId: entityVersion.id,
onClose: (result: VersionLoadResult | null) => { onClose: (result: VersionLoadResult | null) => {

1
ui-ngx/src/app/shared/models/vc.models.ts

@ -113,7 +113,6 @@ export enum VersionLoadRequestType {
} }
export interface VersionLoadRequest { export interface VersionLoadRequest {
branch: string;
versionId: string; versionId: string;
type: VersionLoadRequestType; type: VersionLoadRequestType;
} }

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2928,6 +2928,7 @@
"name": "Name", "name": "Name",
"name-required": "Queue name is required!", "name-required": "Queue name is required!",
"name-unique": "Queue name is not unique!", "name-unique": "Queue name is not unique!",
"name-pattern": "Queue name contains a character other than ASCII alphanumerics, '.', '_' and '-'!",
"queue-required": "Queue is required!", "queue-required": "Queue is required!",
"topic-required": "Queue topic is required!", "topic-required": "Queue topic is required!",
"poll-interval-required": "Poll interval is required!", "poll-interval-required": "Poll interval is required!",

Loading…
Cancel
Save