Browse Source

Merge with develop/3.5.1

pull/8456/head
ViacheslavKlimov 3 years ago
parent
commit
3cdd293173
  1. 2
      application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
  2. 37
      application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java
  3. 9
      application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java
  4. 4
      application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java
  5. 2
      application/src/main/resources/thingsboard.yml
  6. 142
      application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java
  7. 148
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  8. 16
      dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java
  9. 9
      dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java
  10. 2
      dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java
  11. 12
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/TestRestClient.java
  12. 14
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java
  13. 1
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java
  14. 117
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DevicePageElements.java
  15. 61
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DevicePageHelper.java
  16. 45
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/AbstractDeviceTest.java
  17. 214
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/CreateDeviceTest.java
  18. 75
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/DeleteDeviceTest.java
  19. 84
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/DeleteSeveralDevicesTest.java
  20. 179
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/EditDeviceTest.java
  21. 2
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/rulechainssmoke/RuleChainEditMenuTest.java
  22. 5
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/Const.java
  23. 12
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/DataProviderCredential.java
  24. 35
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/EntityPrototypes.java
  25. 10
      msa/black-box-tests/src/test/resources/all.xml
  26. 35
      msa/black-box-tests/src/test/resources/smokeDevices.xml
  27. 10
      msa/black-box-tests/src/test/resources/uiTests.xml
  28. 2
      msa/tb/docker-cassandra/Dockerfile
  29. 17
      security.md
  30. 24
      ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js

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

@ -117,7 +117,7 @@ public class WidgetsBundleController extends BaseController {
checkParameter("widgetsBundleId", strWidgetsBundleId);
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
WidgetsBundle widgetsBundle = checkWidgetsBundleId(widgetsBundleId, Operation.DELETE);
tbWidgetsBundleService.delete(widgetsBundle);
tbWidgetsBundleService.delete(widgetsBundle, getCurrentUser());
}
@ApiOperation(value = "Get Widget Bundles (getWidgetsBundles)",

37
application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/DefaultWidgetsBundleService.java

@ -17,9 +17,10 @@ package org.thingsboard.server.service.entitiy.widgets.bundle;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
import org.thingsboard.server.queue.util.TbCoreComponent;
@ -34,17 +35,31 @@ public class DefaultWidgetsBundleService extends AbstractTbEntityService impleme
@Override
public WidgetsBundle save(WidgetsBundle widgetsBundle, User user) throws Exception {
WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
autoCommit(user, savedWidgetsBundle.getId());
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), savedWidgetsBundle.getId(),
widgetsBundle.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
return savedWidgetsBundle;
ActionType actionType = widgetsBundle.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
TenantId tenantId = widgetsBundle.getTenantId();
try {
WidgetsBundle savedWidgetsBundle = checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
autoCommit(user, savedWidgetsBundle.getId());
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, savedWidgetsBundle.getId(),
savedWidgetsBundle, user, actionType, true, null);
return savedWidgetsBundle;
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE), widgetsBundle, actionType, user, e);
throw e;
}
}
@Override
public void delete(WidgetsBundle widgetsBundle) throws ThingsboardException {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
notificationEntityService.notifySendMsgToEdgeService(widgetsBundle.getTenantId(), widgetsBundle.getId(),
EdgeEventActionType.DELETED);
public void delete(WidgetsBundle widgetsBundle, User user) {
TenantId tenantId = widgetsBundle.getTenantId();
try {
widgetsBundleService.deleteWidgetsBundle(widgetsBundle.getTenantId(), widgetsBundle.getId());
notificationEntityService.notifyCreateOrUpdateOrDelete(tenantId, null, widgetsBundle.getId(), widgetsBundle,
user, ActionType.DELETED, true, null);
} catch (Exception e) {
notificationEntityService.logEntityAction(tenantId, emptyId(EntityType.WIDGETS_BUNDLE),
ActionType.DELETED, user, e, widgetsBundle.getId());
throw e;
}
}
}

9
application/src/main/java/org/thingsboard/server/service/entitiy/widgets/bundle/TbWidgetsBundleService.java

@ -15,13 +15,8 @@
*/
package org.thingsboard.server.service.entitiy.widgets.bundle;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.service.entitiy.SimpleTbEntityService;
public interface TbWidgetsBundleService {
WidgetsBundle save(WidgetsBundle entity, User currentUser) throws Exception;
void delete(WidgetsBundle entity) throws ThingsboardException;
public interface TbWidgetsBundleService extends SimpleTbEntityService<WidgetsBundle> {
}

4
application/src/main/java/org/thingsboard/server/service/notification/rule/trigger/DeviceActivityTriggerProcessor.java

@ -20,6 +20,7 @@ import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.notification.info.DeviceActivityNotificationInfo;
@ -41,6 +42,9 @@ public class DeviceActivityTriggerProcessor implements RuleEngineMsgNotification
@Override
public boolean matchesFilter(RuleEngineMsgTrigger trigger, DeviceActivityNotificationRuleTriggerConfig triggerConfig) {
if (trigger.getMsg().getOriginator().getEntityType() != EntityType.DEVICE) {
return false;
}
DeviceEvent event = trigger.getMsg().getType().equals(DataConstants.ACTIVITY_EVENT) ? DeviceEvent.ACTIVE : DeviceEvent.INACTIVE;
if (!triggerConfig.getNotifyOn().contains(event)) {
return false;

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

@ -607,6 +607,7 @@ spring:
username: "${SPRING_DATASOURCE_USERNAME:postgres}"
password: "${SPRING_DATASOURCE_PASSWORD:postgres}"
hikari:
leakDetectionThreshold: "${SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD:0}"
maximumPoolSize: "${SPRING_DATASOURCE_MAXIMUM_POOL_SIZE:16}"
registerMbeans: "${SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS:false}" # true - enable MBean to diagnose pools state via JMX
@ -621,6 +622,7 @@ audit-log:
"device": "${AUDIT_LOG_MASK_DEVICE:W}"
"asset": "${AUDIT_LOG_MASK_ASSET:W}"
"dashboard": "${AUDIT_LOG_MASK_DASHBOARD:W}"
"widgets_bundle": "${AUDIT_LOG_MASK_WIDGETS_BUNDLE:W}"
"customer": "${AUDIT_LOG_MASK_CUSTOMER:W}"
"user": "${AUDIT_LOG_MASK_USER:W}"
"rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}"

142
application/src/test/java/org/thingsboard/server/controller/WidgetsBundleControllerTest.java

@ -21,16 +21,15 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.DaoSqlTest;
import java.util.ArrayList;
@ -39,7 +38,6 @@ import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.SYSTEM_TENANT;
@DaoSqlTest
public class WidgetsBundleControllerTest extends AbstractControllerTest {
@ -72,7 +70,7 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
public void afterTest() throws Exception {
loginSysAdmin();
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk());
}
@ -81,14 +79,14 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("My widgets bundle");
Mockito.reset(tbClusterService);
Mockito.reset(tbClusterService, auditLogService);
WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class);
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedWidgetsBundle, savedWidgetsBundle,
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ADDED, 0, 1, 0);
Mockito.reset(tbClusterService);
testNotifyEntityAllOneTime(savedWidgetsBundle, savedWidgetsBundle.getId(), savedWidgetsBundle.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
Mockito.reset(tbClusterService, auditLogService);
Assert.assertNotNull(savedWidgetsBundle);
Assert.assertNotNull(savedWidgetsBundle.getId());
@ -103,25 +101,26 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
WidgetsBundle foundWidgetsBundle = doGet("/api/widgetsBundle/" + savedWidgetsBundle.getId().getId().toString(), WidgetsBundle.class);
Assert.assertEquals(foundWidgetsBundle.getTitle(), savedWidgetsBundle.getTitle());
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedWidgetsBundle, savedWidgetsBundle,
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.UPDATED, ActionType.UPDATED, 0, 1, 0);
testNotifyEntityAllOneTime(savedWidgetsBundle, savedWidgetsBundle.getId(), savedWidgetsBundle.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED);
}
@Test
public void testSaveWidgetBundleWithViolationOfLengthValidation() throws Exception {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle(StringUtils.randomAlphabetic(300));
@Test
public void testSaveWidgetBundleWithViolationOfLengthValidation() throws Exception {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle(StringUtils.randomAlphabetic(300));
Mockito.reset(tbClusterService);
Mockito.reset(tbClusterService, auditLogService);
String msgError = msgErrorFieldLength("title");
doPost("/api/widgetsBundle", widgetsBundle)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
String msgError = msgErrorFieldLength("title");
doPost("/api/widgetsBundle", widgetsBundle)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError)));
testNotifyEntityNever(widgetsBundle.getId(), widgetsBundle);
}
testNotifyEntityEqualsOneTimeServiceNeverError(widgetsBundle, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED,
new DataValidationException("Validation error: title length must be equal or less than 255"));
}
@Test
public void testUpdateWidgetsBundleFromDifferentTenant() throws Exception {
@ -131,7 +130,7 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
loginDifferentTenant();
Mockito.reset(tbClusterService);
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/widgetsBundle", savedWidgetsBundle)
.andExpect(status().isForbidden())
@ -157,26 +156,25 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("My widgets bundle");
Mockito.reset(tbClusterService, auditLogService);
WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class);
doDelete("/api/widgetsBundle/"+savedWidgetsBundle.getId().getId().toString())
Mockito.reset(tbClusterService, auditLogService);
doDelete("/api/widgetsBundle/" + savedWidgetsBundle.getId().getId().toString())
.andExpect(status().isOk());
String savedWidgetsBundleIdStr = savedWidgetsBundle.getId().getId().toString();
testNotifyEntityAllOneTime(savedWidgetsBundle, savedWidgetsBundle.getId(), savedWidgetsBundle.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.DELETED);
doGet("/api/widgetsBundle/" + savedWidgetsBundleIdStr)
.andExpect(status().isNotFound())
.andExpect(statusReason(containsString(msgErrorNoFound("Widgets bundle", savedWidgetsBundleIdStr))));
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(savedWidgetsBundle, savedWidgetsBundle,
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.DELETED, ActionType.DELETED, 0, 1, 0);
}
@Test
public void testSaveWidgetsBundleWithEmptyTitle() throws Exception {
Mockito.reset(tbClusterService, auditLogService);
WidgetsBundle widgetsBundle = new WidgetsBundle();
@ -184,7 +182,9 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Widgets bundle title " + msgErrorShouldBeSpecified)));
testNotifyEntityNever(widgetsBundle.getId(), widgetsBundle);
testNotifyEntityEqualsOneTimeServiceNeverError(widgetsBundle, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED,
new DataValidationException("Widgets bundle title should be specified!"));
}
@Test
@ -194,13 +194,14 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class);
savedWidgetsBundle.setAlias("new_alias");
Mockito.clearInvocations(tbClusterService);
Mockito.reset(tbClusterService, auditLogService);
doPost("/api/widgetsBundle", savedWidgetsBundle)
.andExpect(status().isBadRequest())
.andExpect(statusReason(containsString("Update of widgets bundle alias is prohibited")));
testNotifyEntityNever(savedWidgetsBundle.getId(), savedWidgetsBundle);
testNotifyEntityEqualsOneTimeServiceNeverError(savedWidgetsBundle, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.UPDATED,
new DataValidationException("Update of widgets bundle alias is prohibited!"));
}
@Test
@ -209,22 +210,17 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
login(tenantAdmin.getEmail(), "testPassword1");
List<WidgetsBundle> sysWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<>(){});
Mockito.reset(tbClusterService);
new TypeReference<>() {
});
int cntEntity = 73;
List<WidgetsBundle> widgetsBundles = new ArrayList<>();
for (int i=0;i<cntEntity;i++) {
for (int i = 0; i < cntEntity; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("Widgets bundle"+i);
widgetsBundle.setTitle("Widgets bundle" + i);
widgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new WidgetsBundle(), new WidgetsBundle(),
savedTenant.getId(), tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(),
ActionType.ADDED, ActionType.ADDED, 0, cntEntity, 0);
widgetsBundles.addAll(sysWidgetsBundles);
List<WidgetsBundle> loadedWidgetsBundles = new ArrayList<>();
@ -232,7 +228,8 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
PageData<WidgetsBundle> pageData;
do {
pageData = doGetTypedWithPageLink("/api/widgetsBundles?",
new TypeReference<>(){}, pageLink);
new TypeReference<>() {
}, pageLink);
loadedWidgetsBundles.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
@ -251,13 +248,14 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
loginSysAdmin();
List<WidgetsBundle> sysWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<>(){});
new TypeReference<>() {
});
int cntEntity = 120;
List<WidgetsBundle> createdWidgetsBundles = new ArrayList<>();
for (int i=0;i<cntEntity;i++) {
for (int i = 0; i < cntEntity; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("Widgets bundle"+i);
widgetsBundle.setTitle("Widgets bundle" + i);
createdWidgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
@ -269,7 +267,8 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
PageData<WidgetsBundle> pageData;
do {
pageData = doGetTypedWithPageLink("/api/widgetsBundles?",
new TypeReference<>(){}, pageLink);
new TypeReference<>() {
}, pageLink);
loadedWidgetsBundles.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
@ -281,22 +280,17 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
Assert.assertEquals(widgetsBundles, loadedWidgetsBundles);
Mockito.reset(tbClusterService);
for (WidgetsBundle widgetsBundle : createdWidgetsBundles) {
doDelete("/api/widgetsBundle/"+widgetsBundle.getId().getId().toString())
doDelete("/api/widgetsBundle/" + widgetsBundle.getId().getId().toString())
.andExpect(status().isOk());
}
testNotifyManyEntityManyTimeMsgToEdgeServiceEntityEqAny(new WidgetsBundle(), new WidgetsBundle(),
SYSTEM_TENANT, (CustomerId) createEntityId_NULL_UUID(new Customer()), null, SYS_ADMIN_EMAIL,
ActionType.DELETED, ActionType.DELETED, 0, cntEntity, 0);
pageLink = new PageLink(17);
loadedWidgetsBundles.clear();
do {
pageData = doGetTypedWithPageLink("/api/widgetsBundles?",
new TypeReference<PageData<WidgetsBundle>>(){}, pageLink);
new TypeReference<PageData<WidgetsBundle>>() {
}, pageLink);
loadedWidgetsBundles.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
@ -316,19 +310,21 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
login(tenantAdmin.getEmail(), "testPassword1");
List<WidgetsBundle> sysWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<List<WidgetsBundle>>(){});
new TypeReference<List<WidgetsBundle>>() {
});
List<WidgetsBundle> widgetsBundles = new ArrayList<>();
for (int i=0;i<73;i++) {
for (int i = 0; i < 73; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("Widgets bundle"+i);
widgetsBundle.setTitle("Widgets bundle" + i);
widgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
widgetsBundles.addAll(sysWidgetsBundles);
List<WidgetsBundle> loadedWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<>(){});
new TypeReference<>() {
});
Collections.sort(widgetsBundles, idComparator);
Collections.sort(loadedWidgetsBundles, idComparator);
@ -343,12 +339,13 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
List<WidgetsBundle> sysWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<>(){});
new TypeReference<>() {
});
List<WidgetsBundle> createdSystemWidgetsBundles = new ArrayList<>();
for (int i=0;i<82;i++) {
for (int i = 0; i < 82; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("Sys widgets bundle"+i);
widgetsBundle.setTitle("Sys widgets bundle" + i);
createdSystemWidgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
@ -360,14 +357,15 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
login(tenantAdmin.getEmail(), "testPassword1");
for (int i=0;i<127;i++) {
for (int i = 0; i < 127; i++) {
WidgetsBundle widgetsBundle = new WidgetsBundle();
widgetsBundle.setTitle("Tenant widgets bundle"+i);
widgetsBundle.setTitle("Tenant widgets bundle" + i);
widgetsBundles.add(doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class));
}
List<WidgetsBundle> loadedWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<List<WidgetsBundle>>(){});
new TypeReference<List<WidgetsBundle>>() {
});
Collections.sort(widgetsBundles, idComparator);
Collections.sort(loadedWidgetsBundles, idComparator);
@ -377,7 +375,8 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
loginSysAdmin();
loadedWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<List<WidgetsBundle>>(){});
new TypeReference<>() {
});
Collections.sort(systemWidgetsBundles, idComparator);
Collections.sort(loadedWidgetsBundles, idComparator);
@ -385,12 +384,13 @@ public class WidgetsBundleControllerTest extends AbstractControllerTest {
Assert.assertEquals(systemWidgetsBundles, loadedWidgetsBundles);
for (WidgetsBundle widgetsBundle : createdSystemWidgetsBundles) {
doDelete("/api/widgetsBundle/"+widgetsBundle.getId().getId().toString())
doDelete("/api/widgetsBundle/" + widgetsBundle.getId().getId().toString())
.andExpect(status().isOk());
}
loadedWidgetsBundles = doGetTyped("/api/widgetsBundles?",
new TypeReference<>(){});
new TypeReference<>() {
});
Collections.sort(sysWidgetsBundles, idComparator);
Collections.sort(loadedWidgetsBundles, idComparator);

148
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -58,9 +58,8 @@ public class ModelConstants {
public static final String LAST_UPDATE_TS_COLUMN = "last_update_ts";
/**
* Cassandra user constants.
* User constants.
*/
public static final String USER_COLUMN_FAMILY_NAME = "user";
public static final String USER_PG_HIBERNATE_COLUMN_FAMILY_NAME = "tb_user";
public static final String USER_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String USER_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
@ -70,12 +69,8 @@ public class ModelConstants {
public static final String USER_LAST_NAME_PROPERTY = "last_name";
public static final String USER_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String USER_BY_EMAIL_COLUMN_FAMILY_NAME = "user_by_email";
public static final String USER_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "user_by_tenant_and_search_text";
public static final String USER_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "user_by_customer_and_search_text";
/**
* Cassandra user_credentials constants.
* User_credentials constants.
*/
public static final String USER_CREDENTIALS_COLUMN_FAMILY_NAME = "user_credentials";
public static final String USER_CREDENTIALS_USER_ID_PROPERTY = USER_ID_PROPERTY;
@ -85,10 +80,6 @@ public class ModelConstants {
public static final String USER_CREDENTIALS_RESET_TOKEN_PROPERTY = "reset_token";
public static final String USER_CREDENTIALS_ADDITIONAL_PROPERTY = "additional_info";
public static final String USER_CREDENTIALS_BY_USER_COLUMN_FAMILY_NAME = "user_credentials_by_user";
public static final String USER_CREDENTIALS_BY_ACTIVATE_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_activate_token";
public static final String USER_CREDENTIALS_BY_RESET_TOKEN_COLUMN_FAMILY_NAME = "user_credentials_by_reset_token";
/**
* User settings constants.
*/
@ -98,7 +89,7 @@ public class ModelConstants {
public static final String USER_SETTINGS_SETTINGS = "settings";
/**
* Cassandra admin_settings constants.
* Admin_settings constants.
*/
public static final String ADMIN_SETTINGS_COLUMN_FAMILY_NAME = "admin_settings";
@ -106,10 +97,8 @@ public class ModelConstants {
public static final String ADMIN_SETTINGS_KEY_PROPERTY = "key";
public static final String ADMIN_SETTINGS_JSON_VALUE_PROPERTY = "json_value";
public static final String ADMIN_SETTINGS_BY_KEY_COLUMN_FAMILY_NAME = "admin_settings_by_key";
/**
* Cassandra contact constants.
* Contact constants.
*/
public static final String COUNTRY_PROPERTY = "country";
public static final String STATE_PROPERTY = "state";
@ -121,7 +110,7 @@ public class ModelConstants {
public static final String EMAIL_PROPERTY = "email";
/**
* Cassandra tenant constants.
* Tenant constants.
*/
public static final String TENANT_COLUMN_FAMILY_NAME = "tenant";
public static final String TENANT_TITLE_PROPERTY = TITLE_PROPERTY;
@ -129,8 +118,6 @@ public class ModelConstants {
public static final String TENANT_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String TENANT_TENANT_PROFILE_ID_PROPERTY = "tenant_profile_id";
public static final String TENANT_BY_REGION_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "tenant_by_region_and_search_text";
/**
* Tenant profile constants.
*/
@ -139,25 +126,20 @@ public class ModelConstants {
public static final String TENANT_PROFILE_PROFILE_DATA_PROPERTY = "profile_data";
public static final String TENANT_PROFILE_DESCRIPTION_PROPERTY = "description";
public static final String TENANT_PROFILE_IS_DEFAULT_PROPERTY = "is_default";
public static final String TENANT_PROFILE_ISOLATED_TB_CORE = "isolated_tb_core";
public static final String TENANT_PROFILE_ISOLATED_TB_RULE_ENGINE = "isolated_tb_rule_engine";
/**
* Cassandra customer constants.
* Customer constants.
*/
public static final String CUSTOMER_COLUMN_FAMILY_NAME = "customer";
public static final String CUSTOMER_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String CUSTOMER_TITLE_PROPERTY = TITLE_PROPERTY;
public static final String CUSTOMER_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String CUSTOMER_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "customer_by_tenant_and_search_text";
public static final String CUSTOMER_BY_TENANT_AND_TITLE_VIEW_NAME = "customer_by_tenant_and_title";
/**
* Cassandra device constants.
* Device constants.
*/
public static final String DEVICE_COLUMN_FAMILY_NAME = "device";
public static final String DEVICE_FAMILY_NAME = "device";
public static final String DEVICE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String DEVICE_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String DEVICE_NAME_PROPERTY = "name";
@ -174,13 +156,6 @@ public class ModelConstants {
public static final String DEVICE_DEVICE_PROFILE_NAME_PROPERTY = "device_profile_name";
public static final String DEVICE_ACTIVE_PROPERTY = "active";
public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
public static final String DEVICE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_and_search_text";
public static final String DEVICE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_customer_by_type_and_search_text";
public static final String DEVICE_BY_TENANT_AND_NAME_VIEW_NAME = "device_by_tenant_and_name";
public static final String DEVICE_TYPES_BY_TENANT_VIEW_NAME = "device_types_by_tenant";
public static final String DEVICE_INFO_VIEW_COLUMN_FAMILY_NAME = "device_info_view";
/**
@ -198,7 +173,6 @@ public class ModelConstants {
public static final String DEVICE_PROFILE_IS_DEFAULT_PROPERTY = "is_default";
public static final String DEVICE_PROFILE_DEFAULT_RULE_CHAIN_ID_PROPERTY = "default_rule_chain_id";
public static final String DEVICE_PROFILE_DEFAULT_DASHBOARD_ID_PROPERTY = "default_dashboard_id";
public static final String DEVICE_PROFILE_DEFAULT_QUEUE_ID_PROPERTY = "default_queue_id";
public static final String DEVICE_PROFILE_DEFAULT_QUEUE_NAME_PROPERTY = "default_queue_name";
public static final String DEVICE_PROFILE_PROVISION_DEVICE_KEY = "provision_device_key";
public static final String DEVICE_PROFILE_FIRMWARE_ID_PROPERTY = "firmware_id";
@ -220,44 +194,28 @@ public class ModelConstants {
public static final String ASSET_PROFILE_DEFAULT_EDGE_RULE_CHAIN_ID_PROPERTY = "default_edge_rule_chain_id";
/**
* Cassandra entityView constants.
* Entity view constants.
*/
public static final String ENTITY_VIEW_TABLE_FAMILY_NAME = "entity_view";
public static final String ENTITY_VIEW_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN;
public static final String ENTITY_VIEW_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ENTITY_VIEW_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String ENTITY_VIEW_NAME_PROPERTY = DEVICE_NAME_PROPERTY;
public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_CF = "entity_view_by_tenant_and_customer";
public static final String ENTITY_VIEW_BY_TENANT_AND_CUSTOMER_AND_TYPE_CF = "entity_view_by_tenant_and_customer_and_type";
public static final String ENTITY_VIEW_BY_TENANT_AND_ENTITY_ID_CF = "entity_view_by_tenant_and_entity_id";
public static final String ENTITY_VIEW_KEYS_PROPERTY = "keys";
public static final String ENTITY_VIEW_TYPE_PROPERTY = "type";
public static final String ENTITY_VIEW_START_TS_PROPERTY = "start_ts";
public static final String ENTITY_VIEW_END_TS_PROPERTY = "end_ts";
public static final String ENTITY_VIEW_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String ENTITY_VIEW_BY_TENANT_AND_SEARCH_TEXT_CF = "entity_view_by_tenant_and_search_text";
public static final String ENTITY_VIEW_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_CF = "entity_view_by_tenant_by_type_and_search_text";
public static final String ENTITY_VIEW_BY_TENANT_AND_NAME = "entity_view_by_tenant_and_name";
/**
* Cassandra audit log constants.
* Audit log constants.
*/
public static final String AUDIT_LOG_COLUMN_FAMILY_NAME = "audit_log";
public static final String AUDIT_LOG_BY_ENTITY_ID_CF = "audit_log_by_entity_id";
public static final String AUDIT_LOG_BY_CUSTOMER_ID_CF = "audit_log_by_customer_id";
public static final String AUDIT_LOG_BY_USER_ID_CF = "audit_log_by_user_id";
public static final String AUDIT_LOG_BY_TENANT_ID_CF = "audit_log_by_tenant_id";
public static final String AUDIT_LOG_BY_TENANT_ID_PARTITIONS_CF = "audit_log_by_tenant_id_partitions";
public static final String AUDIT_LOG_ID_PROPERTY = ID_PROPERTY;
public static final String AUDIT_LOG_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String AUDIT_LOG_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String AUDIT_LOG_ENTITY_TYPE_PROPERTY = ENTITY_TYPE_PROPERTY;
public static final String AUDIT_LOG_ENTITY_ID_PROPERTY = ENTITY_ID_COLUMN;
public static final String AUDIT_LOG_ENTITY_NAME_PROPERTY = "entity_name";
public static final String AUDIT_LOG_USER_ID_PROPERTY = USER_ID_PROPERTY;
public static final String AUDIT_LOG_PARTITION_PROPERTY = "partition";
public static final String AUDIT_LOG_USER_NAME_PROPERTY = "user_name";
public static final String AUDIT_LOG_ACTION_TYPE_PROPERTY = "action_type";
public static final String AUDIT_LOG_ACTION_DATA_PROPERTY = "action_data";
@ -265,7 +223,7 @@ public class ModelConstants {
public static final String AUDIT_LOG_ACTION_FAILURE_DETAILS_PROPERTY = "action_failure_details";
/**
* Cassandra asset constants.
* Asset constants.
*/
public static final String ASSET_COLUMN_FAMILY_NAME = "asset";
public static final String ASSET_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -277,23 +235,8 @@ public class ModelConstants {
public static final String ASSET_ASSET_PROFILE_ID_PROPERTY = "asset_profile_id";
public static final String ASSET_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_and_search_text";
public static final String ASSET_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_tenant_by_type_and_search_text";
public static final String ASSET_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_and_search_text";
public static final String ASSET_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "asset_by_customer_by_type_and_search_text";
public static final String ASSET_BY_TENANT_AND_NAME_VIEW_NAME = "asset_by_tenant_and_name";
public static final String ASSET_TYPES_BY_TENANT_VIEW_NAME = "asset_types_by_tenant";
/**
* Cassandra entity_subtype constants.
*/
public static final String ENTITY_SUBTYPE_COLUMN_FAMILY_NAME = "entity_subtype";
public static final String ENTITY_SUBTYPE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ENTITY_SUBTYPE_ENTITY_TYPE_PROPERTY = ENTITY_TYPE_PROPERTY;
public static final String ENTITY_SUBTYPE_TYPE_PROPERTY = "type";
/**
* Cassandra alarm constants.
* Alarm constants.
*/
public static final String ENTITY_ALARM_COLUMN_FAMILY_NAME = "entity_alarm";
public static final String ALARM_COLUMN_FAMILY_NAME = "alarm";
@ -324,12 +267,6 @@ public class ModelConstants {
public static final String ALARM_PROPAGATE_TO_TENANT_PROPERTY = "propagate_to_tenant";
public static final String ALARM_PROPAGATE_RELATION_TYPES = "propagate_relation_types";
public static final String ALARM_OPERATION_RESULT_PROPERTY = "operation_result";
public static final String ALARM_BY_ID_VIEW_NAME = "alarm_by_id";
public static final String ALARM_COMMENT_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String ALARM_COMMENT_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
public static final String ALARM_COMMENT_COLUMN_FAMILY_NAME = "alarm_comment";
public static final String ALARM_COMMENT_ALARM_ID = "alarm_id";
public static final String ALARM_COMMENT_USER_ID = USER_ID_PROPERTY;
@ -337,7 +274,7 @@ public class ModelConstants {
public static final String ALARM_COMMENT_COMMENT = "comment";
/**
* Cassandra entity relation constants.
* Entity relation constants.
*/
public static final String RELATION_COLUMN_FAMILY_NAME = "relation";
public static final String RELATION_FROM_ID_PROPERTY = "from_id";
@ -347,12 +284,8 @@ public class ModelConstants {
public static final String RELATION_TYPE_PROPERTY = "relation_type";
public static final String RELATION_TYPE_GROUP_PROPERTY = "relation_type_group";
public static final String RELATION_BY_TYPE_AND_CHILD_TYPE_VIEW_NAME = "relation_by_type_and_child_type";
public static final String RELATION_REVERSE_VIEW_NAME = "reverse_relation";
/**
* Cassandra device_credentials constants.
* Device_credentials constants.
*/
public static final String DEVICE_CREDENTIALS_COLUMN_FAMILY_NAME = "device_credentials";
public static final String DEVICE_CREDENTIALS_DEVICE_ID_PROPERTY = DEVICE_ID_PROPERTY;
@ -360,11 +293,8 @@ public class ModelConstants {
public static final String DEVICE_CREDENTIALS_CREDENTIALS_ID_PROPERTY = "credentials_id";
public static final String DEVICE_CREDENTIALS_CREDENTIALS_VALUE_PROPERTY = "credentials_value";
public static final String DEVICE_CREDENTIALS_BY_DEVICE_COLUMN_FAMILY_NAME = "device_credentials_by_device";
public static final String DEVICE_CREDENTIALS_BY_CREDENTIALS_ID_COLUMN_FAMILY_NAME = "device_credentials_by_credentials_id";
/**
* Cassandra widgets_bundle constants.
* Widgets_bundle constants.
*/
public static final String WIDGETS_BUNDLE_COLUMN_FAMILY_NAME = "widgets_bundle";
public static final String WIDGETS_BUNDLE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -373,11 +303,8 @@ public class ModelConstants {
public static final String WIDGETS_BUNDLE_IMAGE_PROPERTY = "image";
public static final String WIDGETS_BUNDLE_DESCRIPTION = "description";
public static final String WIDGETS_BUNDLE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "widgets_bundle_by_tenant_and_search_text";
public static final String WIDGETS_BUNDLE_BY_TENANT_AND_ALIAS_COLUMN_FAMILY_NAME = "widgets_bundle_by_tenant_and_alias";
/**
* Cassandra widget_type constants.
* Widget_type constants.
*/
public static final String WIDGET_TYPE_COLUMN_FAMILY_NAME = "widget_type";
public static final String WIDGET_TYPE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -388,10 +315,8 @@ public class ModelConstants {
public static final String WIDGET_TYPE_DESCRIPTION_PROPERTY = "description";
public static final String WIDGET_TYPE_DESCRIPTOR_PROPERTY = "descriptor";
public static final String WIDGET_TYPE_BY_TENANT_AND_ALIASES_COLUMN_FAMILY_NAME = "widget_type_by_tenant_and_aliases";
/**
* Cassandra dashboard constants.
* Dashboard constants.
*/
public static final String DASHBOARD_COLUMN_FAMILY_NAME = "dashboard";
public static final String DASHBOARD_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -402,10 +327,8 @@ public class ModelConstants {
public static final String DASHBOARD_MOBILE_HIDE_PROPERTY = "mobile_hide";
public static final String DASHBOARD_MOBILE_ORDER_PROPERTY = "mobile_order";
public static final String DASHBOARD_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "dashboard_by_tenant_and_search_text";
/**
* Cassandra plugin component metadata constants.
* Plugin component metadata constants.
*/
public static final String COMPONENT_DESCRIPTOR_COLUMN_FAMILY_NAME = "component_descriptor";
public static final String COMPONENT_DESCRIPTOR_TYPE_PROPERTY = "type";
@ -416,12 +339,8 @@ public class ModelConstants {
public static final String COMPONENT_DESCRIPTOR_CONFIGURATION_DESCRIPTOR_PROPERTY = "configuration_descriptor";
public static final String COMPONENT_DESCRIPTOR_ACTIONS_PROPERTY = "actions";
public static final String COMPONENT_DESCRIPTOR_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "component_desc_by_type_search_text";
public static final String COMPONENT_DESCRIPTOR_BY_SCOPE_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "component_desc_by_scope_type_search_text";
public static final String COMPONENT_DESCRIPTOR_BY_ID = "component_desc_by_id";
/**
* Cassandra event constants.
* Event constants.
*/
public static final String ERROR_EVENT_TABLE_NAME = "error_event";
public static final String LC_EVENT_TABLE_NAME = "lc_event";
@ -432,7 +351,6 @@ public class ModelConstants {
public static final String EVENT_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String EVENT_SERVICE_ID_PROPERTY = "service_id";
public static final String EVENT_ENTITY_ID_PROPERTY = "entity_id";
public static final String EVENT_BODY_PROPERTY = "body";
public static final String EVENT_MESSAGES_PROCESSED_COLUMN_NAME = "e_messages_processed";
public static final String EVENT_ERRORS_OCCURRED_COLUMN_NAME = "e_errors_occurred";
@ -457,7 +375,7 @@ public class ModelConstants {
public static final String SINGLETON_MODE = "singleton_mode";
/**
* Cassandra rule chain constants.
* Rule chain constants.
*/
public static final String RULE_CHAIN_COLUMN_FAMILY_NAME = "rule_chain";
public static final String RULE_CHAIN_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -467,11 +385,8 @@ public class ModelConstants {
public static final String RULE_CHAIN_ROOT_PROPERTY = "root";
public static final String RULE_CHAIN_CONFIGURATION_PROPERTY = "configuration";
public static final String RULE_CHAIN_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "rule_chain_by_tenant_and_search_text";
public static final String RULE_CHAIN_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "rule_chain_by_tenant_by_type_and_search_text";
/**
* Cassandra rule node constants.
* Rule node constants.
*/
public static final String RULE_NODE_COLUMN_FAMILY_NAME = "rule_node";
public static final String RULE_NODE_CHAIN_ID_PROPERTY = "rule_chain_id";
@ -480,7 +395,7 @@ public class ModelConstants {
public static final String RULE_NODE_CONFIGURATION_PROPERTY = "configuration";
/**
* Rule node state constants.
* Node state constants.
*/
public static final String RULE_NODE_STATE_TABLE_NAME = "rule_node_state";
public static final String RULE_NODE_STATE_NODE_ID_PROPERTY = "rule_node_id";
@ -491,7 +406,6 @@ public class ModelConstants {
/**
* OAuth2 client registration constants.
*/
public static final String OAUTH2_PARAMS_COLUMN_FAMILY_NAME = "oauth2_params";
public static final String OAUTH2_PARAMS_ENABLED_PROPERTY = "enabled";
public static final String OAUTH2_PARAMS_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
@ -503,12 +417,8 @@ public class ModelConstants {
public static final String OAUTH2_PKG_NAME_PROPERTY = "pkg_name";
public static final String OAUTH2_APP_SECRET_PROPERTY = "app_secret";
public static final String OAUTH2_CLIENT_REGISTRATION_INFO_COLUMN_FAMILY_NAME = "oauth2_client_registration_info";
public static final String OAUTH2_CLIENT_REGISTRATION_COLUMN_FAMILY_NAME = "oauth2_client_registration";
public static final String OAUTH2_CLIENT_REGISTRATION_TEMPLATE_COLUMN_FAMILY_NAME = "oauth2_client_registration_template";
public static final String OAUTH2_ENABLED_PROPERTY = "enabled";
public static final String OAUTH2_TEMPLATE_PROVIDER_ID_PROPERTY = "provider_id";
public static final String OAUTH2_CLIENT_REGISTRATION_INFO_ID_PROPERTY = "client_registration_info_id";
public static final String OAUTH2_DOMAIN_NAME_PROPERTY = "domain_name";
public static final String OAUTH2_DOMAIN_SCHEME_PROPERTY = "domain_scheme";
public static final String OAUTH2_CLIENT_ID_PROPERTY = "client_id";
@ -613,12 +523,6 @@ public class ModelConstants {
public static final String EDGE_LABEL_PROPERTY = "label";
public static final String EDGE_TYPE_PROPERTY = "type";
public static final String EDGE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
public static final String EDGE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "edge_by_tenant_and_search_text";
public static final String EDGE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "edge_by_tenant_by_type_and_search_text";
public static final String EDGE_BY_CUSTOMER_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "edge_by_customer_and_search_text";
public static final String EDGE_BY_CUSTOMER_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "edge_by_customer_by_type_and_search_text";
public static final String EDGE_BY_TENANT_AND_NAME_VIEW_NAME = "edge_by_tenant_and_name";
public static final String EDGE_BY_ROUTING_KEY_VIEW_NAME = "edge_by_routing_key";
public static final String EDGE_ROUTING_KEY_PROPERTY = "routing_key";
public static final String EDGE_SECRET_PROPERTY = "secret";
@ -635,13 +539,11 @@ public class ModelConstants {
public static final String EDGE_EVENT_ENTITY_ID_PROPERTY = "entity_id";
public static final String EDGE_EVENT_BODY_PROPERTY = "body";
public static final String EDGE_EVENT_BY_ID_VIEW_NAME = "edge_event_by_id";
public static final String EXTERNAL_ID_PROPERTY = "external_id";
/**
* User auth settings constants.
* */
*/
public static final String USER_AUTH_SETTINGS_COLUMN_FAMILY_NAME = "user_auth_settings";
public static final String USER_AUTH_SETTINGS_USER_ID_PROPERTY = USER_ID_PROPERTY;
public static final String USER_AUTH_SETTINGS_TWO_FA_SETTINGS = "two_fa_settings";
@ -649,7 +551,6 @@ public class ModelConstants {
/**
* Cassandra attributes and timeseries constants.
*/
public static final String ATTRIBUTES_KV_CF = "attributes_kv_cf";
public static final String TS_KV_CF = "ts_kv_cf";
public static final String TS_KV_PARTITIONS_CF = "ts_kv_partitions_cf";
public static final String TS_KV_LATEST_CF = "ts_kv_latest_cf";
@ -671,7 +572,6 @@ public class ModelConstants {
/**
* Queue constants.
*/
public static final String QUEUE_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
public static final String QUEUE_NAME_PROPERTY = "name";
public static final String QUEUE_TOPIC_PROPERTY = "topic";
@ -684,11 +584,9 @@ public class ModelConstants {
public static final String QUEUE_COLUMN_FAMILY_NAME = "queue";
public static final String QUEUE_ADDITIONAL_INFO_PROPERTY = ADDITIONAL_INFO_PROPERTY;
/**
* Notification constants
* */
*/
public static final String NOTIFICATION_TARGET_TABLE_NAME = "notification_target";
public static final String NOTIFICATION_TARGET_CONFIGURATION_PROPERTY = "configuration";

16
dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java

@ -19,7 +19,6 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.query.Param;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.dao.model.sql.AlarmEntity;
@ -316,7 +315,9 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
@Query(value = "SELECT a FROM AlarmInfoEntity a WHERE a.tenantId = :tenantId AND a.id = :alarmId")
AlarmInfoEntity findAlarmInfoById(@Param("tenantId") UUID tenantId, @Param("alarmId") UUID alarmId);
@Procedure(procedureName = "create_or_update_active_alarm")
@Query(value = "SELECT create_or_update_active_alarm(:t_id, :c_id, :a_id, :a_created_ts, :a_o_id, :a_o_type, :a_type, :a_severity, " +
":a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " +
":a_propagate_to_tenant, :a_propagation_types, :a_creation_enabled)", nativeQuery = true)
String createOrUpdateActiveAlarm(@Param("t_id") UUID tenantId, @Param("c_id") UUID customerId,
@Param("a_id") UUID alarmId, @Param("a_created_ts") long createdTime,
@Param("a_o_id") UUID originatorId, @Param("a_o_type") int originatorType,
@ -326,21 +327,22 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
@Param("a_propagate_to_tenant") boolean propagateToTenant, @Param("a_propagation_types") String propagationTypes,
@Param("a_creation_enabled") boolean alarmCreationEnabled);
@Procedure(procedureName = "update_alarm")
@Query(value = "SELECT update_alarm(:t_id, :a_id, :a_severity, :a_start_ts, :a_end_ts, :a_details, :a_propagate, :a_propagate_to_owner, " +
":a_propagate_to_tenant, :a_propagation_types)", nativeQuery = true)
String updateAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("a_severity") String severity,
@Param("a_start_ts") long startTs, @Param("a_end_ts") long endTs, @Param("a_details") String detailsAsString,
@Param("a_propagate") boolean propagate, @Param("a_propagate_to_owner") boolean propagateToOwner,
@Param("a_propagate_to_tenant") boolean propagateToTenant, @Param("a_propagation_types") String propagationTypes);
@Procedure(procedureName = "acknowledge_alarm")
@Query(value = "SELECT acknowledge_alarm(:t_id, :a_id, :a_ts)", nativeQuery = true)
String acknowledgeAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("a_ts") long ts);
@Procedure(procedureName = "clear_alarm")
@Query(value = "SELECT clear_alarm(:t_id, :a_id, :a_ts, :a_details)", nativeQuery = true)
String clearAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("a_ts") long ts, @Param("a_details") String details);
@Procedure(procedureName = "assign_alarm")
@Query(value = "SELECT assign_alarm(:t_id, :a_id, :u_id, :a_ts)", nativeQuery = true)
String assignAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("u_id") UUID userId, @Param("a_ts") long assignTime);
@Procedure(procedureName = "unassign_alarm")
@Query(value = "SELECT unassign_alarm(:t_id, :a_id, :a_ts)", nativeQuery = true)
String unassignAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("a_ts") long unassignTime);
}

9
dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java

@ -110,9 +110,12 @@ public class SqlPartitioningRepository {
String tablePartition = table + "_" + partitionTs;
String detachPsqlStmtStr = "ALTER TABLE " + table + " DETACH PARTITION " + tablePartition;
if (getCurrentServerVersion() >= PSQL_VERSION_14) {
detachPsqlStmtStr += " CONCURRENTLY";
}
// hotfix of ERROR: partition "integration_debug_event_1678323600000" already pending detach in partitioned table "public.integration_debug_event"
// https://github.com/thingsboard/thingsboard/issues/8271
// if (getCurrentServerVersion() >= PSQL_VERSION_14) {
// detachPsqlStmtStr += " CONCURRENTLY";
// }
String dropStmtStr = "DROP TABLE " + tablePartition;
try {

2
dao/src/main/java/org/thingsboard/server/dao/util/limits/DefaultRateLimitService.java

@ -43,7 +43,7 @@ public class DefaultRateLimitService implements RateLimitService {
this.rateLimits = Caffeine.newBuilder()
.expireAfterAccess(rateLimitsTtl, TimeUnit.MINUTES)
.maximumSize(rateLimitsCacheMaxSize)
.build();
.build();
}
private final Cache<RateLimitKey, TbRateLimits> rateLimits;

12
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/TestRestClient.java

@ -132,6 +132,18 @@ public class TestRestClient {
.as(Device.class);
}
public PageData<Device> getDevices(PageLink pageLink) {
Map<String, String> params = new HashMap<>();
addPageLinkToParam(params, pageLink);
return given().spec(requestSpec).queryParams(params)
.get("/api/tenant/devices")
.then()
.statusCode(HTTP_OK)
.extract()
.as(new TypeRef<PageData<Device>>() {
});
}
public DeviceCredentials getDeviceCredentialsByDeviceId(DeviceId deviceId) {
return given().spec(requestSpec).get("/api/device/{deviceId}/credentials", deviceId.getId())
.then()

14
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/base/AbstractDriverBaseTest.java

@ -37,6 +37,7 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.id.AlarmId;
@ -150,6 +151,12 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest {
.findFirst().orElse(null);
}
public Device getDeviceByName(String name) {
return testRestClient.getDevices(pageLink).getData().stream()
.filter(s -> s.getName().equals(name))
.findFirst().orElse(null);
}
public List<RuleChain> getRuleChainsByName(String name) {
return testRestClient.getRuleChains(pageLink).getData().stream()
.filter(s -> s.getName().equals(name))
@ -269,4 +276,11 @@ abstract public class AbstractDriverBaseTest extends AbstractContainerTest {
testRestClient.deleteDashboard(dashboardId);
}
}
public void deleteDeviceByName(String deviceName) {
Device device = getDeviceByName(deviceName);
if (device != null) {
testRestClient.deleteDevice(device.getId());
}
}
}

1
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/CustomerPageHelper.java

@ -119,6 +119,7 @@ public class CustomerPageHelper extends CustomerPageElements {
public void createCustomersUser() {
plusBtn().click();
addUserEmailField().click();
addUserEmailField().sendKeys(getRandomNumber() + "@gmail.com");
addBtnC().click();
activateWindowOkBtn().click();

117
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DevicePageElements.java

@ -18,7 +18,7 @@ package org.thingsboard.server.msa.ui.pages;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
public class DevicePageElements extends OtherPageElements {
public class DevicePageElements extends OtherPageElementsHelper {
public DevicePageElements(WebDriver driver) {
super(driver);
}
@ -29,9 +29,30 @@ public class DevicePageElements extends OtherPageElements {
private static final String ASSIGN_TO_CUSTOMER_BTN = "//mat-cell[contains(@class,'name')]/span[text()='%s']" +
"/ancestor::mat-row//mat-icon[contains(text(),'assignment_ind')]/parent::button";
private static final String CHOOSE_CUSTOMER_FOR_ASSIGN_FIELD = "//input[@formcontrolname='entity']";
private static final String CUSTOMER_FROM_ASSIGN_DROPDOWN = "//div[@role = 'listbox']//span[text() = '%s']";
private static final String ENTITY_FROM_DROPDOWN = "//div[@role = 'listbox']//span[text() = '%s']";
private static final String CLOSE_DEVICE_DETAILS_VIEW = "//header//mat-icon[contains(text(),'close')]/parent::button";
private static final String SUBMIT_ASSIGN_TO_CUSTOMER_BTN = "//button[@type='submit']";
private static final String ADD_DEVICE_BTN = "//mat-icon[text() = 'insert_drive_file']/parent::button";
private static final String CREATE_DEVICE_NAME_FIELD = "//tb-device-wizard//input[@formcontrolname='name']";
private static final String HEADER_NAME_VIEW = "//header//div[@class='tb-details-title']/span";
private static final String DESCRIPTION_FIELD_CREATE_VIEW = "//tb-device-wizard//textarea[@formcontrolname='description']";
private static final String ADD_DEVICE_VIEW = "//tb-device-wizard";
private static final String DELETE_BTN_DETAILS_TAB = "//span[contains(text(),'Delete device')]/parent::button";
private static final String CHECKBOX_GATEWAY_EDIT = "//mat-checkbox[@formcontrolname='gateway']//label";
private static final String CHECKBOX_GATEWAY_CREATE = "//tb-device-wizard//mat-checkbox[@formcontrolname='gateway']//label";
private static final String CHECKBOX_OVERWRITE_ACTIVITY_TIME_EDIT = "//mat-checkbox[@formcontrolname='overwriteActivityTime']//label";
private static final String CHECKBOX_OVERWRITE_ACTIVITY_TIME_CREATE = "//tb-device-wizard//mat-checkbox[@formcontrolname='overwriteActivityTime']//label";
private static final String CHECKBOX_GATEWAY_DETAILS = "//mat-checkbox[@formcontrolname='gateway']//input";
private static final String CHECKBOX_GATEWAY_PAGE = DEVICE + "/ancestor::mat-row//mat-cell[contains(@class,'cdk-column-gateway')]//mat-icon[text() = 'check_box']";
private static final String CHECKBOX_OVERWRITE_ACTIVITY_TIME_DETAILS = "//mat-checkbox[@formcontrolname='overwriteActivityTime']//input";
private static final String CLEAR_PROFILE_FIELD_BTN = "//button[@aria-label='Clear']";
private static final String DEVICE_PROFILE_REDIRECTED_BTN = "//a[@aria-label='Open device profile']";
private static final String DEVICE_LABEL_FIELD_CREATE = "//tb-device-wizard//input[@formcontrolname='label']";
private static final String DEVICE_LABEL_PAGE = DEVICE + "/ancestor::mat-row//mat-cell[contains(@class,'cdk-column-label')]/span";
private static final String DEVICE_CUSTOMER_PAGE = DEVICE + "/ancestor::mat-row//mat-cell[contains(@class,'cdk-column-customerTitle')]/span";
private static final String CUSTOMER_OPTION_BNT = "//div[text() = 'Customer']/ancestor::mat-step-header";
private static final String ASSIGN_ON_CUSTOMER_FIELD = "//input[@formcontrolname='entity']";
private static final String DEVICE_LABEL_EDIT = "//input[@formcontrolname='label']";
public WebElement device(String deviceName) {
return waitUntilElementToBeClickable(String.format(DEVICE, deviceName));
@ -53,8 +74,8 @@ public class DevicePageElements extends OtherPageElements {
return waitUntilElementToBeClickable(CHOOSE_CUSTOMER_FOR_ASSIGN_FIELD);
}
public WebElement customerFromAssignDropdown(String customerTitle) {
return waitUntilElementToBeClickable(String.format(CUSTOMER_FROM_ASSIGN_DROPDOWN, customerTitle));
public WebElement entityFromDropdown(String customerTitle) {
return waitUntilElementToBeClickable(String.format(ENTITY_FROM_DROPDOWN, customerTitle));
}
public WebElement closeDeviceDetailsViewBtn() {
@ -64,4 +85,92 @@ public class DevicePageElements extends OtherPageElements {
public WebElement submitAssignToCustomerBtn() {
return waitUntilElementToBeClickable(SUBMIT_ASSIGN_TO_CUSTOMER_BTN);
}
public WebElement addDeviceBtn() {
return waitUntilElementToBeClickable(ADD_DEVICE_BTN);
}
public WebElement nameField() {
return waitUntilElementToBeClickable(CREATE_DEVICE_NAME_FIELD);
}
public WebElement headerNameView() {
return waitUntilVisibilityOfElementLocated(HEADER_NAME_VIEW);
}
public WebElement descriptionFieldCreateField() {
return waitUntilElementToBeClickable(DESCRIPTION_FIELD_CREATE_VIEW);
}
public WebElement addDeviceView() {
return waitUntilPresenceOfElementLocated(ADD_DEVICE_VIEW);
}
public WebElement deleteBtnDetailsTab() {
return waitUntilElementToBeClickable(DELETE_BTN_DETAILS_TAB);
}
public WebElement checkboxGatewayEdit() {
return waitUntilElementToBeClickable(CHECKBOX_GATEWAY_EDIT);
}
public WebElement checkboxGatewayCreate() {
return waitUntilElementToBeClickable(CHECKBOX_GATEWAY_CREATE);
}
public WebElement checkboxOverwriteActivityTimeEdit() {
return waitUntilElementToBeClickable(CHECKBOX_OVERWRITE_ACTIVITY_TIME_EDIT);
}
public WebElement checkboxOverwriteActivityTimeCreate() {
return waitUntilElementToBeClickable(CHECKBOX_OVERWRITE_ACTIVITY_TIME_CREATE);
}
public WebElement checkboxGatewayDetailsTab() {
return waitUntilPresenceOfElementLocated(CHECKBOX_GATEWAY_DETAILS);
}
public WebElement checkboxGatewayPage(String deviceName) {
return waitUntilPresenceOfElementLocated(String.format(CHECKBOX_GATEWAY_PAGE, deviceName));
}
public WebElement checkboxOverwriteActivityTimeDetails() {
return waitUntilPresenceOfElementLocated(CHECKBOX_OVERWRITE_ACTIVITY_TIME_DETAILS);
}
public WebElement clearProfileFieldBtn() {
return waitUntilElementToBeClickable(CLEAR_PROFILE_FIELD_BTN);
}
public WebElement deviceProfileRedirectedBtn() {
return waitUntilElementToBeClickable(DEVICE_PROFILE_REDIRECTED_BTN);
}
public WebElement deviceLabelFieldCreate() {
return waitUntilElementToBeClickable(DEVICE_LABEL_FIELD_CREATE);
}
public WebElement deviceLabelOnPage(String deviceName) {
return waitUntilVisibilityOfElementLocated(String.format(DEVICE_LABEL_PAGE, deviceName));
}
public WebElement customerOptionBtn() {
return waitUntilElementToBeClickable(CUSTOMER_OPTION_BNT);
}
public WebElement assignOnCustomerField() {
return waitUntilElementToBeClickable(ASSIGN_ON_CUSTOMER_FIELD);
}
public WebElement deviceCustomerOnPage(String deviceName) {
return waitUntilVisibilityOfElementLocated(String.format(DEVICE_CUSTOMER_PAGE, deviceName));
}
public WebElement deviceLabelEditField() {
return waitUntilElementToBeClickable(DEVICE_LABEL_EDIT);
}
public WebElement deviceLabelDetailsField() {
return waitUntilVisibilityOfElementLocated(DEVICE_LABEL_EDIT);
}
}

61
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/pages/DevicePageHelper.java

@ -22,6 +22,9 @@ public class DevicePageHelper extends DevicePageElements {
super(driver);
}
private String description;
private String label;
public void openDeviceAlarms(String deviceName) {
if (!deviceDetailsView().isDisplayed()) {
device(deviceName).click();
@ -31,7 +34,63 @@ public class DevicePageHelper extends DevicePageElements {
public void assignToCustomer(String customerTitle) {
chooseCustomerForAssignField().click();
customerFromAssignDropdown(customerTitle).click();
entityFromDropdown(customerTitle).click();
submitAssignToCustomerBtn().click();
}
public void openCreateDeviceView() {
plusBtn().click();
addDeviceBtn().click();
}
public void enterName(String deviceName) {
enterText(nameField(), deviceName);
}
public void enterDescription(String description) {
enterText(descriptionFieldCreateField(), description);
}
public void enterLabel(String label) {
enterText(deviceLabelFieldCreate(), label);
}
public void deleteDeviceByRightSideBtn(String deviceName) {
deleteBtn(deviceName).click();
warningPopUpYesBtn().click();
}
public void deleteDeviceFromDetailsTab() {
deleteBtnDetailsTab().click();
warningPopUpYesBtn().click();
}
public void setDescription() {
scrollToElement(descriptionEntityView());
description = descriptionEntityView().getAttribute("value");
}
public void setLabel() {
label = deviceLabelDetailsField().getAttribute("value");
}
public String getDescription() {
return description;
}
public String getLabel() {
return label;
}
public void changeDeviceProfile(String deviceProfileName) {
clearProfileFieldBtn().click();
entityFromDropdown(deviceProfileName).click();
}
public void assignOnCustomer(String customerTitle) {
customerOptionBtn().click();
assignOnCustomerField().click();
entityFromList(customerTitle).click();
sleep(2); //waiting for the action to count
}
}

45
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/AbstractDeviceTest.java

@ -0,0 +1,45 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.msa.ui.tests.devicessmoke;
import io.qameta.allure.Epic;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.thingsboard.server.msa.ui.base.AbstractDriverBaseTest;
import org.thingsboard.server.msa.ui.pages.DevicePageHelper;
import org.thingsboard.server.msa.ui.pages.LoginPageHelper;
import org.thingsboard.server.msa.ui.pages.SideBarMenuViewHelper;
@Epic("Device smoke tests")
abstract public class AbstractDeviceTest extends AbstractDriverBaseTest {
protected SideBarMenuViewHelper sideBarMenuView;
protected DevicePageHelper devicePage;
protected String deviceName;
@BeforeClass
public void login() {
new LoginPageHelper(driver).authorizationTenant();
sideBarMenuView = new SideBarMenuViewHelper(driver);
devicePage = new DevicePageHelper(driver);
}
@AfterMethod
public void delete() {
deleteDeviceByName(deviceName);
deviceName = null;
}
}

214
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/CreateDeviceTest.java

@ -0,0 +1,214 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.msa.ui.tests.devicessmoke;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import org.testng.annotations.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.msa.ui.utils.EntityPrototypes;
import static org.assertj.core.api.Assertions.assertThat;
import static org.thingsboard.server.msa.ui.base.AbstractBasePage.random;
import static org.thingsboard.server.msa.ui.utils.Const.DEVICE_PROFILE_IS_REQUIRED_MESSAGE;
import static org.thingsboard.server.msa.ui.utils.Const.EMPTY_DEVICE_MESSAGE;
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME;
import static org.thingsboard.server.msa.ui.utils.Const.NAME_IS_REQUIRED_MESSAGE;
import static org.thingsboard.server.msa.ui.utils.Const.SAME_NAME_WARNING_DEVICE_MESSAGE;
@Feature("Create device")
public class CreateDeviceTest extends AbstractDeviceTest {
@Test(groups = "smoke")
@Description("Add device after specifying the name (text/numbers /special characters)")
public void createDevice() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.addBtnC().click();
devicePage.refreshBtn().click();
assertIsDisplayed(devicePage.entity(deviceName));
}
@Test(groups = "smoke")
@Description("Add device after specifying the name and description (text/numbers /special characters)")
public void createDeviceWithDescription() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.enterDescription(deviceName);
devicePage.addBtnC().click();
devicePage.refreshBtn().click();
devicePage.entity(deviceName).click();
devicePage.setHeaderName();
assertThat(devicePage.getHeaderName()).as("Header of device details tab").isEqualTo(deviceName);
assertThat(devicePage.descriptionEntityView().getAttribute("value"))
.as("Description in device details tab").isEqualTo(deviceName);
}
@Test(groups = "smoke")
@Description("Add device without the name")
public void createDeviceWithoutName() {
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.nameField().click();
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.addDeviceView());
assertThat(devicePage.errorMessage().getText()).as("Text of warning message").isEqualTo(NAME_IS_REQUIRED_MESSAGE);
}
@Test(groups = "smoke")
@Description("Create device only with spase in name")
public void createDeviceWithOnlySpace() {
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(" ");
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.warningMessage());
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(EMPTY_DEVICE_MESSAGE);
assertIsDisplayed(devicePage.addDeviceView());
}
@Test(groups = "smoke")
@Description("Create a device with the same name")
public void createDeviceWithSameName() {
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME));
deviceName = device.getName();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.warningMessage());
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(SAME_NAME_WARNING_DEVICE_MESSAGE);
assertIsDisplayed(devicePage.addDeviceView());
}
@Test(groups = "smoke")
@Description("Add device after specifying the name (text/numbers /special characters) without refresh")
public void createDeviceWithoutRefresh() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.entity(deviceName));
}
@Test(groups = "smoke")
@Description("Add device without device profile")
public void createDeviceWithoutDeviceProfile() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.clearProfileFieldBtn().click();
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.errorMessage());
assertThat(devicePage.errorMessage().getText()).as("Text of warning message").isEqualTo(DEVICE_PROFILE_IS_REQUIRED_MESSAGE);
assertIsDisplayed(devicePage.addDeviceView());
}
@Test(groups = "smoke")
@Description("Add device with enabled gateway")
public void createDeviceWithEnableGateway() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.checkboxGatewayCreate().click();
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.device(deviceName));
assertIsDisplayed(devicePage.checkboxGatewayPage(deviceName));
}
@Test(groups = "smoke")
@Description("Add device with enabled overwrite activity time for connected")
public void createDeviceWithEnableOverwriteActivityTimeForConnected() {
deviceName = ENTITY_NAME + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.checkboxGatewayCreate().click();
devicePage.checkboxOverwriteActivityTimeCreate().click();
devicePage.addBtnC().click();
devicePage.device(deviceName).click();
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected"))
.as("Overwrite activity time for connected is enable").isTrue();
}
@Test(groups = "smoke")
@Description("Add device with label")
public void createDeviceWithLabel() {
deviceName = ENTITY_NAME + random();
String deviceLabel = "device label " + random();
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.enterLabel(deviceLabel);
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.deviceLabelOnPage(deviceName));
assertThat(devicePage.deviceLabelOnPage(deviceName).getText()).as("Label added correctly").isEqualTo(deviceLabel);
}
@Test(groups = "smoke")
@Description("Add device with assignee on customer")
public void createDeviceWithAssignee() {
deviceName = ENTITY_NAME + random();
String customer = "Customer A";
sideBarMenuView.goToDevicesPage();
devicePage.openCreateDeviceView();
devicePage.enterName(deviceName);
devicePage.assignOnCustomer(customer);
devicePage.addBtnC().click();
assertIsDisplayed(devicePage.deviceCustomerOnPage(deviceName));
assertThat(devicePage.deviceCustomerOnPage(deviceName).getText())
.as("Customer added correctly").isEqualTo(customer);
}
@Test(groups = "smoke")
@Description("Go to devices documentation page")
public void documentation() {
String urlPath = "docs/user-guide/ui/devices/";
sideBarMenuView.goToDevicesPage();
devicePage.entity("Thermostat T1").click();
devicePage.goToHelpPage();
assertThat(urlContains(urlPath)).as("Redirected URL contains " + urlPath).isTrue();
}
}

75
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/DeleteDeviceTest.java

@ -0,0 +1,75 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.msa.ui.tests.devicessmoke;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.msa.ui.utils.EntityPrototypes;
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME;
@Feature("Delete device")
public class DeleteDeviceTest extends AbstractDeviceTest {
@BeforeMethod
public void createDevice() {
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME));
deviceName = device.getName();
}
@Test(groups = "smoke")
@Description("Remove the device by clicking on the trash icon in the right side of device")
public void deleteDeviceByRightSideBtn() {
sideBarMenuView.goToDevicesPage();
devicePage.deleteDeviceByRightSideBtn(deviceName);
devicePage.refreshBtn().click();
devicePage.assertEntityIsNotPresent(deviceName);
}
@Test(groups = "smoke")
@Description("Remove device by mark in the checkbox and then click on the trash can icon in the menu that appears at the top")
public void deleteSelectedDevice() {
sideBarMenuView.goToDevicesPage();
devicePage.deleteSelected(deviceName);
devicePage.refreshBtn().click();
devicePage.assertEntityIsNotPresent(deviceName);
}
@Test(groups = "smoke")
@Description("Remove the device by clicking on the 'Delete device' btn in the entity view")
public void deleteDeviceFromDetailsTab() {
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.deleteDeviceFromDetailsTab();
devicePage.refreshBtn();
devicePage.assertEntityIsNotPresent(deviceName);
}
@Test(groups = "smoke")
@Description("Remove the device by clicking on the trash icon in the right side of device without refresh")
public void deleteDeviceWithoutRefresh() {
sideBarMenuView.goToDevicesPage();
devicePage.deleteDeviceByRightSideBtn(deviceName);
devicePage.assertEntityIsNotPresent(deviceName);
}
}

84
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/DeleteSeveralDevicesTest.java

@ -0,0 +1,84 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.msa.ui.tests.devicessmoke;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.msa.ui.utils.EntityPrototypes;
import static org.assertj.core.api.Assertions.assertThat;
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME;
@Feature("Delete several devices")
public class DeleteSeveralDevicesTest extends AbstractDeviceTest {
private String deviceName1;
private String deviceName2;
@BeforeMethod
public void createDevices() {
Device device = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME));
Device device1 = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME));
deviceName1 = device.getName();
deviceName2 = device1.getName();
}
@AfterMethod
public void deleteDevices() {
deleteDeviceByName(deviceName1);
deleteDeviceByName(deviceName2);
}
@Test(groups = "smoke")
@Description("Remove several devices by mark in the checkbox and then click on the trash can icon in the menu " +
"that appears at the top")
public void deleteSeveralDevicesByTopBtn() {
sideBarMenuView.goToDevicesPage();
devicePage.deleteSelected(2);
devicePage.refreshBtn().click();
devicePage.assertEntityIsNotPresent(deviceName1);
devicePage.assertEntityIsNotPresent(deviceName2);
}
@Test(groups = "smoke")
@Description("Remove several devices by mark all the devices on the page by clicking in the topmost checkbox" +
" and then clicking on the trash icon in the menu that appears")
public void selectAllDevices() {
sideBarMenuView.goToDevicesPage();
devicePage.selectAllCheckBox().click();
devicePage.deleteSelectedBtn().click();
assertIsDisplayed(devicePage.warningPopUpTitle());
assertThat(devicePage.warningPopUpTitle().getText()).as("Warning title contains true correct of selected devices")
.contains(String.valueOf(devicePage.markCheckbox().size()));
}
@Test(groups = "smoke")
@Description("Remove several devices by mark in the checkbox and then click on the trash can icon in the menu " +
"that appears at the top without refresh")
public void deleteSeveralWithoutRefresh() {
sideBarMenuView.goToDevicesPage();
devicePage.deleteSelected(2);
devicePage.assertEntityIsNotPresent(deviceName1);
devicePage.assertEntityIsNotPresent(deviceName2);
}
}

179
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/devicessmoke/EditDeviceTest.java

@ -0,0 +1,179 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.msa.ui.tests.devicessmoke;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import org.testng.annotations.Test;
import org.thingsboard.server.msa.ui.utils.DataProviderCredential;
import org.thingsboard.server.msa.ui.utils.EntityPrototypes;
import static org.assertj.core.api.Assertions.assertThat;
import static org.thingsboard.server.msa.ui.base.AbstractBasePage.getRandomNumber;
import static org.thingsboard.server.msa.ui.utils.Const.EMPTY_DEVICE_MESSAGE;
import static org.thingsboard.server.msa.ui.utils.Const.ENTITY_NAME;
@Feature("Edit device")
public class EditDeviceTest extends AbstractDeviceTest {
@Test(groups = "smoke")
@Description("Change name by edit menu")
public void changeName() {
String newDeviceName = "Changed" + getRandomNumber();
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.setHeaderName();
String nameBefore = devicePage.getHeaderName();
devicePage.editPencilBtn().click();
devicePage.changeNameEditMenu(newDeviceName);
devicePage.doneBtnEditView().click();
deviceName = newDeviceName;
devicePage.setHeaderName();
String nameAfter = devicePage.getHeaderName();
assertThat(nameAfter).as("The name has changed").isNotEqualTo(nameBefore);
assertThat(nameAfter).as("The name has changed correctly").isEqualTo(newDeviceName);
}
@Test(groups = "smoke")
@Description("Delete name and save")
public void deleteName() {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.changeNameEditMenu("");
assertIsDisable(devicePage.doneBtnEditViewVisible());
}
@Test(groups = "smoke")
@Description("Save only with space")
public void saveOnlyWithSpace() {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.changeNameEditMenu(" ");
devicePage.doneBtnEditView().click();
assertIsDisplayed(devicePage.warningMessage());
assertThat(devicePage.warningMessage().getText()).as("Text of warning message").isEqualTo(EMPTY_DEVICE_MESSAGE);
}
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "editMenuDescription")
@Description("Write the description and save the changes/Change the description and save the changes/Delete the description and save the changes")
public void editDescription(String description, String newDescription, String finalDescription) {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, description)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.descriptionEntityView().sendKeys(newDescription);
devicePage.doneBtnEditView().click();
devicePage.setDescription();
assertThat(devicePage.getDescription()).as("The description changed correctly").isEqualTo(finalDescription);
}
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "enable")
@Description("Enable gateway mode/Disable gateway")
public void isGateway(boolean isGateway) {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, isGateway)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.checkboxGatewayEdit().click();
devicePage.doneBtnEditView().click();
if (isGateway) {
assertThat(devicePage.checkboxGatewayDetailsTab().getAttribute("class").contains("selected"))
.as("Gateway is disable").isFalse();
} else {
assertThat(devicePage.checkboxGatewayDetailsTab().getAttribute("class").contains("selected"))
.as("Gateway is enable").isTrue();
}
}
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "enable")
@Description("Enable overwrite activity time for connected/Disable overwrite activity time for connected")
public void isOverwriteActivityTimeForConnectedDevice(boolean isOverwriteActivityTimeForConnected) {
deviceName = testRestClient.postDevice("",
EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, true, isOverwriteActivityTimeForConnected)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.checkboxOverwriteActivityTimeEdit().click();
devicePage.doneBtnEditView().click();
if (isOverwriteActivityTimeForConnected) {
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected"))
.as("Overwrite activity time for connected is disable").isFalse();
} else {
assertThat(devicePage.checkboxOverwriteActivityTimeDetails().getAttribute("class").contains("selected"))
.as("Overwrite activity time for connected is enable").isTrue();
}
}
@Test(groups = "smoke")
@Description("Change device profile")
public void changeDeviceProfile() {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.changeDeviceProfile("DEFAULT");
devicePage.doneBtnEditView().click();
assertIsDisplayed(devicePage.deviceProfileRedirectedBtn());
assertThat(devicePage.deviceProfileRedirectedBtn().getText()).as("Profile changed correctly").isEqualTo("DEFAULT");
}
@Test(groups = "smoke")
@Description("Save without device profile")
public void saveWithoutDeviceProfile() {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.clearProfileFieldBtn().click();
assertIsDisable(devicePage.doneBtnEditViewVisible());
}
@Test(groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "editDeviceLabel")
@Description("Write the label and save the changes/Change the label and save the changes/Delete the label and save the changes")
public void editLabel(String label, String newLabel, String finalLabel) {
deviceName = testRestClient.postDevice("", EntityPrototypes.defaultDevicePrototype(ENTITY_NAME, "", label)).getName();
sideBarMenuView.goToDevicesPage();
devicePage.entity(deviceName).click();
devicePage.editPencilBtn().click();
devicePage.deviceLabelEditField().sendKeys(newLabel);
devicePage.doneBtnEditView().click();
devicePage.setLabel();
assertThat(devicePage.getLabel()).as("The label changed correctly").isEqualTo(finalLabel);
}
}

2
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/tests/rulechainssmoke/RuleChainEditMenuTest.java

@ -99,7 +99,7 @@ public class RuleChainEditMenuTest extends AbstractRuleChainTest {
assertThat(ruleChainsPage.getDescription()).as("The description changed correctly").isEqualTo(finalDescription);
}
@Test(priority = 20, groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "debugMode")
@Test(priority = 20, groups = "smoke", dataProviderClass = DataProviderCredential.class, dataProvider = "enable")
@Description("Enable debug mode/Disable debug mode")
public void debugMode(boolean debugMode) {
ruleChainName = ENTITY_NAME + random();

5
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/Const.java

@ -36,10 +36,13 @@ public class Const {
public static final String EMPTY_CUSTOMER_MESSAGE = "Customer title should be specified!";
public static final String EMPTY_DEVICE_PROFILE_MESSAGE = "Device profile name should be specified!";
public static final String EMPTY_ASSET_PROFILE_MESSAGE = "Asset profile name should be specified!";
public static final String EMPTY_DEVICE_MESSAGE = "Device name should be specified!";
public static final String DELETE_RULE_CHAIN_WITH_PROFILE_MESSAGE = "The rule chain referenced by the device profiles cannot be deleted!";
public static final String SAME_NAME_WARNING_CUSTOMER_MESSAGE = "Customer with such title already exists!";
public static final String SAME_NAME_WARNING_DEVICE_PROFILE_MESSAGE = "Device profile with such name already exists!";
public static final String SAME_NAME_WARNING_ASSET_PROFILE_MESSAGE = "Asset profile with such name already exists!";
public static final String SAME_NAME_WARNING_DEVICE_MESSAGE = "Device with such name already exists!";
public static final String PHONE_NUMBER_ERROR_MESSAGE = "Phone number is invalid or not possible";
public static final String NAME_IS_REQUIRED_MESSAGE = "Name is required.";
}
public static final String DEVICE_PROFILE_IS_REQUIRED_MESSAGE = "Device profile is required";
}

12
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/DataProviderCredential.java

@ -151,9 +151,19 @@ public class DataProviderCredential {
}
@DataProvider
public static Object[][] debugMode() {
public static Object[][] enable() {
return new Object[][]{
{false},
{true}};
}
@DataProvider
public static Object[][] editDeviceLabel() {
String newLabel = "Label" + getRandomNumber();
String label = "Label";
return new Object[][]{
{"", newLabel, newLabel},
{label, newLabel, label + newLabel},
{label, Keys.CONTROL + "A" + Keys.BACK_SPACE, ""}};
}
}

35
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/ui/utils/EntityPrototypes.java

@ -192,6 +192,41 @@ public class EntityPrototypes {
return device;
}
public static Device defaultDevicePrototype(String name, String description) {
Device device = new Device();
device.setName(name + RandomStringUtils.randomAlphanumeric(7));
device.setType("DEFAULT");
device.setAdditionalInfo(JacksonUtil.newObjectNode().put("description", description));
return device;
}
public static Device defaultDevicePrototype(String name, String description, String label) {
Device device = new Device();
device.setName(name + RandomStringUtils.randomAlphanumeric(7));
device.setType("DEFAULT");
device.setAdditionalInfo(JacksonUtil.newObjectNode().put("description", description));
device.setLabel(label);
return device;
}
public static Device defaultDevicePrototype(String name, boolean gateway) {
Device device = new Device();
device.setName(name + RandomStringUtils.randomAlphanumeric(7));
device.setType("DEFAULT");
device.setAdditionalInfo(JacksonUtil.newObjectNode().put("gateway", gateway));
return device;
}
public static Device defaultDevicePrototype(String name, boolean gateway, boolean overwriteActivityTime) {
Device device = new Device();
device.setName(name + RandomStringUtils.randomAlphanumeric(7));
device.setType("DEFAULT");
device.setAdditionalInfo(JacksonUtil.newObjectNode()
.put("gateway", gateway)
.put("overwriteActivityTime", overwriteActivityTime));
return device;
}
public static Asset defaultAssetPrototype(String name, CustomerId id) {
Asset asset = new Asset();
asset.setName(name + RandomStringUtils.randomAlphanumeric(7));

10
msa/black-box-tests/src/test/resources/all.xml

@ -67,4 +67,14 @@
<package name="org.thingsboard.server.msa.ui.tests.assetProfileSmoke"/>
</packages>
</test>
<test name="Smoke devices tests">
<groups>
<run>
<exclude name="broken"/>
</run>
</groups>
<packages>
<package name="org.thingsboard.server.msa.ui.tests.devicessmoke"/>
</packages>
</test>
</suite>

35
msa/black-box-tests/src/test/resources/smokeDevices.xml

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Copyright © 2016-2023 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.
-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Devices Smoke Tests">
<listeners>
<listener class-name="org.thingsboard.server.msa.ui.listeners.RetryTestListener"/>
</listeners>
<test name="Devices ui smoke tests">
<groups>
<run>
<exclude name="broken"/>
</run>
</groups>
<packages>
<package name="org.thingsboard.server.msa.ui.tests.devicessmoke"/>
</packages>
</test>
</suite>

10
msa/black-box-tests/src/test/resources/uiTests.xml

@ -62,4 +62,14 @@
<package name="org.thingsboard.server.msa.ui.tests.assetProfileSmoke"/>
</packages>
</test>
<test name="Smoke devices tests">
<groups>
<run>
<exclude name="broken"/>
</run>
</groups>
<packages>
<package name="org.thingsboard.server.msa.ui.tests.devicessmoke"/>
</packages>
</test>
</suite>

2
msa/tb/docker-cassandra/Dockerfile

@ -47,7 +47,7 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends wget nmap procps gnupg2 \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee --append /etc/apt/sources.list.d/pgdg.list > /dev/null \
&& wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - \
&& echo 'deb http://downloads.apache.org/cassandra/debian 40x main' | tee --append /etc/apt/sources.list.d/cassandra.list > /dev/null \
&& echo "deb https://debian.cassandra.apache.org 40x main" | tee -a /etc/apt/sources.list.d/cassandra.sources.list > /dev/null \
&& wget -q https://downloads.apache.org/cassandra/KEYS -O- | apt-key add - \
&& apt-get update \
&& apt-get install -y --no-install-recommends cassandra cassandra-tools postgresql-${PG_MAJOR} \

17
security.md

@ -0,0 +1,17 @@
# Security Policy
## Reporting a Vulnerability
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to Thingsboard privately,
to minimize attacks against current users of Thingsboard before they are fixed. Vulnerabilities will be investigated and release as soon as possible.
To report a vulnerability or a security-related issue, please email the private address security@thingsboard.io with the details of the vulnerability.
Emails will be addressed within 3 business days, including a detailed plan to investigate the issue and any potential workarounds to perform in the meantime.
Do not report non-security-impacting bugs through this channel. Use GitHub issues instead.
**Proposed Email Content**
Provide a descriptive subject line and in the body of the email include the following information:
- Basic identity information, such as your name and your affiliation or company.
- Detailed steps to reproduce the vulnerability (log errors, screenshots are all helpful to us).
- Description of the effects of the vulnerability on Thingsboard.

24
ui-ngx/src/app/shared/models/ace/tbel/worker-tbel.js

@ -5026,6 +5026,21 @@ var JSHINT = (function() {
return that;
}, 20);
}
function nullSafeProperty(s) {
console.log("test " + s);
symbol(s, 20).exps = true;
return infix(s, function(context, left, that) {
if (state.option.bitwise) {
warning("W016", that, that.id);
}
checkLeftSideAssign(context, left, that);
that.right = expression(context, 10);
return that;
}, 20);
}
function suffix(s) {
var x = symbol(s, 150);
@ -5539,6 +5554,9 @@ var JSHINT = (function() {
bitwiseassignop("<<=");
bitwiseassignop(">>=");
bitwiseassignop(">>>=");
nullSafeProperty(".?");
infix(",", function(context, left, that) {
if (state.option.nocomma) {
warning("W127", that);
@ -9450,6 +9468,12 @@ Lexer.prototype = {
switch (ch1) {
case ".":
if (ch1 === "." && this.peek(1) === "?") {
return {
type: Token.Punctuator,
value: ".?"
};
}
if ((/^[0-9]$/).test(this.peek(1))) {
return null;
}

Loading…
Cancel
Save