Tests: improved performance on tenant tests with concurrent creation and deletion
This commit is contained in:
parent
77b962e1bb
commit
668634f890
@ -16,24 +16,53 @@
|
||||
package org.thingsboard.server.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.thingsboard.common.util.ThingsBoardExecutors;
|
||||
import org.thingsboard.server.common.data.Tenant;
|
||||
import org.thingsboard.server.common.data.TenantInfo;
|
||||
import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.page.PageLink;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@Slf4j
|
||||
public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
|
||||
private IdComparator<Tenant> idComparator = new IdComparator<>();
|
||||
|
||||
static final TypeReference<PageData<Tenant>> PAGE_DATA_TENANT_TYPE_REF = new TypeReference<>(){};
|
||||
static final TypeReference<PageData<TenantInfo>> PAGE_DATA_TENANT_INFO_TYPE_REF = new TypeReference<>(){};
|
||||
static final int TIMEOUT = 30;
|
||||
|
||||
List<ListenableFuture<Boolean>> createFutures = new ArrayList<>();
|
||||
List<ListenableFuture<ResultActions>> deleteFutures = new ArrayList<>();
|
||||
ListeningExecutorService executor;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveTenant() throws Exception {
|
||||
@ -47,7 +76,7 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
Assert.assertEquals(tenant.getTitle(), savedTenant.getTitle());
|
||||
savedTenant.setTitle("My new tenant");
|
||||
doPost("/api/tenant", savedTenant, Tenant.class);
|
||||
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class);
|
||||
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class);
|
||||
Assert.assertEquals(foundTenant.getTitle(), savedTenant.getTitle());
|
||||
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
@ -60,14 +89,14 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
tenant.setTitle(RandomStringUtils.randomAlphanumeric(300));
|
||||
doPost("/api/tenant", tenant).andExpect(statusReason(containsString("length of title must be equal or less than 255")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindTenantById() throws Exception {
|
||||
loginSysAdmin();
|
||||
Tenant tenant = new Tenant();
|
||||
tenant.setTitle("My tenant");
|
||||
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
|
||||
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class);
|
||||
Tenant foundTenant = doGet("/api/tenant/"+savedTenant.getId().getId().toString(), Tenant.class);
|
||||
Assert.assertNotNull(foundTenant);
|
||||
Assert.assertEquals(savedTenant, foundTenant);
|
||||
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
|
||||
@ -86,7 +115,7 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSaveTenantWithEmptyTitle() throws Exception {
|
||||
loginSysAdmin();
|
||||
@ -95,7 +124,7 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("Tenant title should be specified")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSaveTenantWithInvalidEmail() throws Exception {
|
||||
loginSysAdmin();
|
||||
@ -106,7 +135,7 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(statusReason(containsString("Invalid email address format")));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteTenant() throws Exception {
|
||||
loginSysAdmin();
|
||||
@ -114,17 +143,17 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
tenant.setTitle("My tenant");
|
||||
Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
|
||||
doDelete("/api/tenant/"+savedTenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
.andExpect(status().isOk());
|
||||
doGet("/api/tenant/"+savedTenant.getId().getId().toString())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindTenants() throws Exception {
|
||||
loginSysAdmin();
|
||||
List<Tenant> tenants = new ArrayList<>();
|
||||
Collection<Tenant> tenants = new ConcurrentLinkedQueue<>();
|
||||
PageLink pageLink = new PageLink(17);
|
||||
PageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
PageData<Tenant> pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(1, pageData.getData().size());
|
||||
tenants.addAll(pageData.getData());
|
||||
@ -132,119 +161,146 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
for (int i=0;i<56;i++) {
|
||||
Tenant tenant = new Tenant();
|
||||
tenant.setTitle("Tenant"+i);
|
||||
tenants.add(doPost("/api/tenant", tenant, Tenant.class));
|
||||
createFutures.add(executor.submit(() ->
|
||||
tenants.add(doPost("/api/tenant", tenant, Tenant.class))));
|
||||
}
|
||||
|
||||
Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
List<Tenant> loadedTenants = new ArrayList<>();
|
||||
pageLink = new PageLink(17);
|
||||
do {
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
loadedTenants.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageLink.nextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Collections.sort(tenants, idComparator);
|
||||
Collections.sort(loadedTenants, idComparator);
|
||||
|
||||
Assert.assertEquals(tenants, loadedTenants);
|
||||
|
||||
|
||||
assertThat(tenants).containsExactlyInAnyOrderElementsOf(loadedTenants);
|
||||
|
||||
for (Tenant tenant : loadedTenants) {
|
||||
if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
deleteFutures.add(executor.submit(()->
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk())));
|
||||
}
|
||||
}
|
||||
|
||||
Futures.allAsList(deleteFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
pageLink = new PageLink(17);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(1, pageData.getData().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFindTenantsByTitle() throws Exception {
|
||||
log.debug("login sys admin");
|
||||
loginSysAdmin();
|
||||
log.debug("test started");
|
||||
String title1 = "Tenant title 1";
|
||||
List<Tenant> tenantsTitle1 = new ArrayList<>();
|
||||
Collection<Tenant> tenantsTitle1 = new ConcurrentLinkedQueue<>();
|
||||
createFutures.clear();
|
||||
for (int i=0;i<134;i++) {
|
||||
Tenant tenant = new Tenant();
|
||||
String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10));
|
||||
String title = title1+suffix;
|
||||
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
|
||||
tenant.setTitle(title);
|
||||
tenantsTitle1.add(doPost("/api/tenant", tenant, Tenant.class));
|
||||
|
||||
createFutures.add(executor.submit(() ->
|
||||
tenantsTitle1.add(doPost("/api/tenant", tenant, Tenant.class))));
|
||||
}
|
||||
|
||||
Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
log.debug("saved '{}', qty {}", title1, 134);
|
||||
|
||||
String title2 = "Tenant title 2";
|
||||
List<Tenant> tenantsTitle2 = new ArrayList<>();
|
||||
Collection<Tenant> tenantsTitle2 = new ConcurrentLinkedQueue<>();
|
||||
createFutures.clear();
|
||||
for (int i=0;i<127;i++) {
|
||||
Tenant tenant = new Tenant();
|
||||
String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10));
|
||||
String title = title2+suffix;
|
||||
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
|
||||
tenant.setTitle(title);
|
||||
tenantsTitle2.add(doPost("/api/tenant", tenant, Tenant.class));
|
||||
createFutures.add(executor.submit(() ->
|
||||
tenantsTitle2.add(doPost("/api/tenant", tenant, Tenant.class))));
|
||||
}
|
||||
|
||||
|
||||
Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
log.debug("saved '{}', qty {}", title2, 127);
|
||||
|
||||
List<Tenant> loadedTenantsTitle1 = new ArrayList<>();
|
||||
PageLink pageLink = new PageLink(15, 0, title1);
|
||||
PageData<Tenant> pageData = null;
|
||||
do {
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
loadedTenantsTitle1.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageLink.nextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Collections.sort(tenantsTitle1, idComparator);
|
||||
Collections.sort(loadedTenantsTitle1, idComparator);
|
||||
|
||||
Assert.assertEquals(tenantsTitle1, loadedTenantsTitle1);
|
||||
|
||||
|
||||
log.debug("found by name '{}', step 15 {}", title1, loadedTenantsTitle1.size());
|
||||
|
||||
assertThat(tenantsTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedTenantsTitle1);
|
||||
log.debug("asserted");
|
||||
|
||||
List<Tenant> loadedTenantsTitle2 = new ArrayList<>();
|
||||
pageLink = new PageLink(4, 0, title2);
|
||||
do {
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
loadedTenantsTitle2.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageLink.nextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Collections.sort(tenantsTitle2, idComparator);
|
||||
Collections.sort(loadedTenantsTitle2, idComparator);
|
||||
|
||||
Assert.assertEquals(tenantsTitle2, loadedTenantsTitle2);
|
||||
log.debug("found by name '{}', step 4 {}", title1, loadedTenantsTitle2.size());
|
||||
assertThat(tenantsTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedTenantsTitle2);
|
||||
log.debug("asserted");
|
||||
|
||||
deleteFutures.clear();
|
||||
for (Tenant tenant : loadedTenantsTitle1) {
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
deleteFutures.add(executor.submit(()->
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk())));
|
||||
}
|
||||
|
||||
|
||||
Futures.allAsList(deleteFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
log.debug("deleted '{}', size {}", title1, loadedTenantsTitle1.size());
|
||||
|
||||
pageLink = new PageLink(4, 0, title1);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(0, pageData.getData().size());
|
||||
|
||||
|
||||
log.debug("tried to search another '{}', step 4", title1);
|
||||
|
||||
deleteFutures.clear();
|
||||
for (Tenant tenant : loadedTenantsTitle2) {
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
deleteFutures.add(executor.submit(()->
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk())));
|
||||
}
|
||||
|
||||
|
||||
Futures.allAsList(deleteFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
log.debug("deleted '{}', size {}", title2, loadedTenantsTitle2.size());
|
||||
|
||||
pageLink = new PageLink(4, 0, title2);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference<PageData<Tenant>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenants?", PAGE_DATA_TENANT_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(0, pageData.getData().size());
|
||||
log.debug("tried to search another '{}', step 4", title2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindTenantInfos() throws Exception {
|
||||
loginSysAdmin();
|
||||
List<TenantInfo> tenants = new ArrayList<>();
|
||||
Collection<TenantInfo> tenants = new ConcurrentLinkedQueue<>();
|
||||
PageLink pageLink = new PageLink(17);
|
||||
PageData<TenantInfo> pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink);
|
||||
PageData<TenantInfo> pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(1, pageData.getData().size());
|
||||
tenants.addAll(pageData.getData());
|
||||
@ -252,33 +308,34 @@ public abstract class BaseTenantControllerTest extends AbstractControllerTest {
|
||||
for (int i=0;i<56;i++) {
|
||||
Tenant tenant = new Tenant();
|
||||
tenant.setTitle("Tenant"+i);
|
||||
tenants.add(new TenantInfo(doPost("/api/tenant", tenant, Tenant.class), "Default"));
|
||||
createFutures.add(executor.submit(() ->
|
||||
tenants.add(new TenantInfo(doPost("/api/tenant", tenant, Tenant.class), "Default"))));
|
||||
}
|
||||
Futures.allAsList(createFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
List<TenantInfo> loadedTenants = new ArrayList<>();
|
||||
pageLink = new PageLink(17);
|
||||
do {
|
||||
pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
|
||||
loadedTenants.addAll(pageData.getData());
|
||||
if (pageData.hasNext()) {
|
||||
pageLink = pageLink.nextPageLink();
|
||||
}
|
||||
} while (pageData.hasNext());
|
||||
|
||||
Collections.sort(tenants, idComparator);
|
||||
Collections.sort(loadedTenants, idComparator);
|
||||
|
||||
Assert.assertEquals(tenants, loadedTenants);
|
||||
|
||||
assertThat(tenants).containsExactlyInAnyOrderElementsOf(loadedTenants);
|
||||
|
||||
for (TenantInfo tenant : loadedTenants) {
|
||||
if (!tenant.getTitle().equals(TEST_TENANT_NAME)) {
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk());
|
||||
deleteFutures.add(executor.submit(()->
|
||||
doDelete("/api/tenant/"+tenant.getId().getId().toString())
|
||||
.andExpect(status().isOk())));
|
||||
}
|
||||
}
|
||||
|
||||
Futures.allAsList(deleteFutures).get(TIMEOUT, TimeUnit.SECONDS);
|
||||
|
||||
pageLink = new PageLink(17);
|
||||
pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference<PageData<TenantInfo>>(){}, pageLink);
|
||||
pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink);
|
||||
Assert.assertFalse(pageData.hasNext());
|
||||
Assert.assertEquals(1, pageData.getData().size());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user