fix_bug: Entity delete with delete relations, Dashboard

This commit is contained in:
nickAS21 2022-08-24 13:18:51 +03:00
parent 34814e8d8a
commit c6535a128e
3 changed files with 105 additions and 43 deletions

View File

@ -27,6 +27,7 @@ import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hibernate.exception.ConstraintViolationException;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -34,6 +35,7 @@ import org.junit.Rule;
import org.junit.rules.TestRule; import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher; import org.junit.rules.TestWatcher;
import org.junit.runner.Description; import org.junit.runner.Description;
import org.mockito.BDDMockito;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -67,6 +69,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.id.UUIDBased;
@ -74,20 +77,25 @@ import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink; import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.config.ThingsboardSecurityConfiguration; import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
import org.thingsboard.server.dao.Dao;
import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantProfileService;
import org.thingsboard.server.service.mail.TestMailService; import org.thingsboard.server.service.mail.TestMailService;
import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest;
import org.thingsboard.server.service.security.auth.rest.LoginRequest; import org.thingsboard.server.service.security.auth.rest.LoginRequest;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
@ -656,7 +664,11 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
} }
protected <T> T readResponse(ResultActions result, TypeReference<T> type) throws Exception { protected <T> T readResponse(ResultActions result, TypeReference<T> type) throws Exception {
byte[] content = result.andReturn().getResponse().getContentAsByteArray(); return readResponse(result.andReturn(), type);
}
protected <T> T readResponse(MvcResult result, TypeReference<T> type) throws Exception {
byte[] content = result.getResponse().getContentAsByteArray();
return mapper.readerFor(type).readValue(content); return mapper.readerFor(type).readValue(content);
} }
@ -699,4 +711,49 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return Futures.allAsList(futures); return Futures.allAsList(futures);
} }
protected void tesEntityDaoWithRelationsOk(EntityId entityIdFrom, EntityId entityTo, String urlDelete) throws Exception {
createEntityRelation(entityIdFrom, entityTo, "TEST_TYPE");
assertThat(getRelationsTo(entityTo)).hasSize(1);
doDelete(urlDelete).andExpect(status().isOk());
assertThat(getRelationsTo(entityTo)).hasSize(0);
}
protected <T> void tesEntityDaoWithRelationsTransactionalException(Dao<T> dao, EntityId entityIdFrom, EntityId entityTo,
String urlDelete) throws Exception {
entityDaoRemoveByIdWithException (dao);
createEntityRelation(entityIdFrom, entityTo, "TEST_TRANSACTIONAL_TYPE");
assertThat(getRelationsTo(entityTo)).hasSize(1);
doDelete(urlDelete)
.andExpect(status().isInternalServerError());
assertThat(getRelationsTo(entityTo)).hasSize(1);
}
protected <T> void entityDaoRemoveByIdWithException (Dao<T> dao) {
BDDMockito.willThrow(new ConstraintViolationException("mock message", new SQLException(), "MOCK_CONSTRAINT"))
.given(dao).removeById(any(), any());
}
protected <T> void afterTestEntityDaoRemoveByIdWithException (Dao<T> dao) {
BDDMockito.willCallRealMethod().given(dao).removeById(any(), any());
}
protected void createEntityRelation(EntityId entityIdFrom, EntityId entityIdTo, String typeRelation) throws Exception {
EntityRelation relation = new EntityRelation(entityIdFrom, entityIdTo, typeRelation);
doPost("/api/relation", relation);
}
protected List<EntityRelation> getRelationsTo(EntityId entityId) throws Exception {
String url = String.format("/api/relations?toId=%s&toType=%s", entityId.getId(), entityId.getEntityType().name());
MvcResult mvcResult = doGet(url).andReturn();
switch (mvcResult.getResponse().getStatus()) {
case 200: return readResponse(mvcResult, new TypeReference<>() {});
case 404: return Collections.emptyList();
}
throw new AssertionError("Unexpected status " + mvcResult.getResponse().getStatus());
}
} }

View File

@ -22,6 +22,7 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.DashboardInfo; import org.thingsboard.server.common.data.DashboardInfo;
@ -31,9 +32,11 @@ import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.Authority;
import org.thingsboard.server.dao.dashboard.DashboardDao;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.ArrayList; import java.util.ArrayList;
@ -50,6 +53,9 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
private Tenant savedTenant; private Tenant savedTenant;
private User tenantAdmin; private User tenantAdmin;
@SpyBean
private DashboardDao dashboardDao;
@Before @Before
public void beforeTest() throws Exception { public void beforeTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
@ -73,18 +79,18 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
public void afterTest() throws Exception { public void afterTest() throws Exception {
loginSysAdmin(); loginSysAdmin();
afterTestEntityDaoRemoveByIdWithException (dashboardDao);
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@Test @Test
public void testSaveDashboard() throws Exception { public void testSaveDashboard() throws Exception {
Dashboard dashboard = new Dashboard();
dashboard.setTitle("My dashboard");
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); String title = "My dashboard";
Dashboard savedDashboard = createDashboard(title);
testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedTenant.getId(), testNotifyEntityOneTimeMsgToEdgeServiceNever(savedDashboard, savedDashboard.getId(), savedDashboard.getId(), savedTenant.getId(),
tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED); tenantAdmin.getCustomerId(), tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED);
@ -93,7 +99,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Assert.assertNotNull(savedDashboard.getId()); Assert.assertNotNull(savedDashboard.getId());
Assert.assertTrue(savedDashboard.getCreatedTime() > 0); Assert.assertTrue(savedDashboard.getCreatedTime() > 0);
Assert.assertEquals(savedTenant.getId(), savedDashboard.getTenantId()); Assert.assertEquals(savedTenant.getId(), savedDashboard.getTenantId());
Assert.assertEquals(dashboard.getTitle(), savedDashboard.getTitle()); Assert.assertEquals(title, savedDashboard.getTitle());
savedDashboard.setTitle("My new dashboard"); savedDashboard.setTitle("My new dashboard");
@ -120,7 +126,6 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(statusReason(containsString(msgError))); .andExpect(statusReason(containsString(msgError)));
dashboard.setTenantId(savedTenant.getId());
testNotifyEntityEqualsOneTimeServiceNeverError(dashboard, savedTenant.getId(), testNotifyEntityEqualsOneTimeServiceNeverError(dashboard, savedTenant.getId(),
tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError)); tenantAdmin.getId(), tenantAdmin.getEmail(), ActionType.ADDED, new DataValidationException(msgError));
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -128,9 +133,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
@Test @Test
public void testUpdateDashboardFromDifferentTenant() throws Exception { public void testUpdateDashboardFromDifferentTenant() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
loginDifferentTenant(); loginDifferentTenant();
@ -145,9 +148,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
@Test @Test
public void testFindDashboardById() throws Exception { public void testFindDashboardById() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
Assert.assertNotNull(foundDashboard); Assert.assertNotNull(foundDashboard);
Assert.assertEquals(savedDashboard, foundDashboard); Assert.assertEquals(savedDashboard, foundDashboard);
@ -155,9 +156,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
@Test @Test
public void testDeleteDashboard() throws Exception { public void testDeleteDashboard() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -190,9 +189,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
@Test @Test
public void testAssignUnassignDashboardToCustomer() throws Exception { public void testAssignUnassignDashboardToCustomer() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Customer customer = new Customer(); Customer customer = new Customer();
customer.setTitle("My customer"); customer.setTitle("My customer");
@ -230,9 +227,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
@Test @Test
public void testAssignDashboardToNonExistentCustomer() throws Exception { public void testAssignDashboardToNonExistentCustomer() throws Exception {
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
String customerIdStr = Uuids.timeBased().toString(); String customerIdStr = Uuids.timeBased().toString();
doPost("/api/customer/" + customerIdStr doPost("/api/customer/" + customerIdStr
@ -268,9 +263,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
login(tenantAdmin.getEmail(), "testPassword1"); login(tenantAdmin.getEmail(), "testPassword1");
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
doPost("/api/customer/" + savedCustomer.getId().getId().toString() doPost("/api/customer/" + savedCustomer.getId().getId().toString()
+ "/dashboard/" + savedDashboard.getId().getId().toString()) + "/dashboard/" + savedDashboard.getId().getId().toString())
@ -300,9 +293,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
int cntEntity = 173; int cntEntity = 173;
for (int i = 0; i < cntEntity; i++) { for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard(); dashboards.add(new DashboardInfo(createDashboard("Dashboard" + i)));
dashboard.setTitle("Dashboard" + i);
dashboards.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
} }
testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Dashboard(), new Dashboard(), testNotifyManyEntityManyTimeMsgToEdgeServiceNever(new Dashboard(), new Dashboard(),
@ -334,24 +325,19 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
List<DashboardInfo> dashboardsTitle1 = new ArrayList<>(); List<DashboardInfo> dashboardsTitle1 = new ArrayList<>();
int cntEntity = 134; int cntEntity = 134;
for (int i = 0; i < cntEntity; i++) { for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard();
String suffix = StringUtils.randomAlphanumeric((int) (Math.random() * 15)); String suffix = StringUtils.randomAlphanumeric((int) (Math.random() * 15));
String title = title1 + suffix; String title = title1 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
dashboard.setTitle(title); dashboardsTitle1.add(new DashboardInfo(createDashboard(title)));
dashboardsTitle1.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class))); }
}
String title2 = "Dashboard title 2"; String title2 = "Dashboard title 2";
List<DashboardInfo> dashboardsTitle2 = new ArrayList<>(); List<DashboardInfo> dashboardsTitle2 = new ArrayList<>();
for (int i = 0; i < 112; i++) { for (int i = 0; i < 112; i++) {
Dashboard dashboard = new Dashboard();
String suffix = StringUtils.randomAlphanumeric((int) (Math.random() * 15)); String suffix = StringUtils.randomAlphanumeric((int) (Math.random() * 15));
String title = title2 + suffix; String title = title2 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
dashboard.setTitle(title); dashboardsTitle2.add(new DashboardInfo(createDashboard(title))); }
dashboardsTitle2.add(new DashboardInfo(doPost("/api/dashboard", dashboard, Dashboard.class)));
}
List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>(); List<DashboardInfo> loadedDashboardsTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1); PageLink pageLink = new PageLink(15, 0, title1);
@ -431,9 +417,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
int cntEntity = 173; int cntEntity = 173;
List<DashboardInfo> dashboards = new ArrayList<>(); List<DashboardInfo> dashboards = new ArrayList<>();
for (int i = 0; i < cntEntity; i++) { for (int i = 0; i < cntEntity; i++) {
Dashboard dashboard = new Dashboard(); Dashboard dashboard = createDashboard("Dashboard" + i);
dashboard.setTitle("Dashboard" + i);
dashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
dashboards.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString() dashboards.add(new DashboardInfo(doPost("/api/customer/" + customerId.getId().toString()
+ "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class))); + "/dashboard/" + dashboard.getId().getId().toString(), Dashboard.class)));
} }
@ -466,9 +450,7 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Edge edge = constructEdge("My edge", "default"); Edge edge = constructEdge("My edge", "default");
Edge savedEdge = doPost("/api/edge", edge, Edge.class); Edge savedEdge = doPost("/api/edge", edge, Edge.class);
Dashboard dashboard = new Dashboard(); Dashboard savedDashboard = createDashboard();
dashboard.setTitle("My dashboard");
Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
Mockito.reset(tbClusterService, auditLogService); Mockito.reset(tbClusterService, auditLogService);
@ -495,4 +477,28 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
Assert.assertEquals(0, pageData.getData().size()); Assert.assertEquals(0, pageData.getData().size());
} }
@Test
public void testDeleteDashboardWithRelationsOk() throws Exception {
DashboardId dashboardId = createDashboard().getId();
tesEntityDaoWithRelationsOk(savedTenant.getId(), dashboardId, "/api/dashboard/" + dashboardId);
}
@Test
public void testDeleteDashboardWithRelationsTransactionalException() throws Exception {
DashboardId dashboardId = createDashboard().getId();
tesEntityDaoWithRelationsTransactionalException(dashboardDao, savedTenant.getId(), dashboardId, "/api/dashboard/" + dashboardId);
}
private Dashboard createDashboard(String title) {
Dashboard dashboard = new Dashboard();
dashboard.setTitle(title);
return doPost("/api/dashboard", dashboard, Dashboard.class);
}
private Dashboard createDashboard() {
String title = "My dashboard";
Dashboard dashboard = new Dashboard();
dashboard.setTitle(title);
return doPost("/api/dashboard", dashboard, Dashboard.class);
}
} }

View File

@ -171,7 +171,6 @@ public class TenantServiceImpl extends AbstractCachedEntityService<TenantId, Ten
} }
@Override @Override
@Transactional
public void deleteTenant(TenantId tenantId) { public void deleteTenant(TenantId tenantId) {
log.trace("Executing deleteTenant [{}]", tenantId); log.trace("Executing deleteTenant [{}]", tenantId);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);