|
|
|
@ -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()); |
|
|
|
} |
|
|
|
|