diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java index 21905a12c6..d89cc4c3c5 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseTenantControllerTest.java @@ -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 idComparator = new IdComparator<>(); + + static final TypeReference> PAGE_DATA_TENANT_TYPE_REF = new TypeReference<>(){}; + static final TypeReference> PAGE_DATA_TENANT_INFO_TYPE_REF = new TypeReference<>(){}; + static final int TIMEOUT = 30; + + List> createFutures = new ArrayList<>(); + List> 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 tenants = new ArrayList<>(); + Collection tenants = new ConcurrentLinkedQueue<>(); PageLink pageLink = new PageLink(17); - PageData pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference>(){}, pageLink); + PageData 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 loadedTenants = new ArrayList<>(); pageLink = new PageLink(17); do { - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference>(){}, 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>(){}, 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 tenantsTitle1 = new ArrayList<>(); + Collection 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 tenantsTitle2 = new ArrayList<>(); + Collection 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 loadedTenantsTitle1 = new ArrayList<>(); PageLink pageLink = new PageLink(15, 0, title1); PageData pageData = null; do { - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference>(){}, 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 loadedTenantsTitle2 = new ArrayList<>(); pageLink = new PageLink(4, 0, title2); do { - pageData = doGetTypedWithPageLink("/api/tenants?", new TypeReference>(){}, 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>(){}, 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>(){}, 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 tenants = new ArrayList<>(); + Collection tenants = new ConcurrentLinkedQueue<>(); PageLink pageLink = new PageLink(17); - PageData pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference>(){}, pageLink); + PageData 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 loadedTenants = new ArrayList<>(); pageLink = new PageLink(17); do { - pageData = doGetTypedWithPageLink("/api/tenantInfos?", new TypeReference>(){}, 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>(){}, pageLink); + pageData = doGetTypedWithPageLink("/api/tenantInfos?", PAGE_DATA_TENANT_INFO_TYPE_REF, pageLink); Assert.assertFalse(pageData.hasNext()); Assert.assertEquals(1, pageData.getData().size()); }