diff --git a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java index 8f05f26648..6882157000 100644 --- a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.SystemInfo; import org.thingsboard.server.common.data.SystemInfoData; import org.thingsboard.server.common.data.id.TenantId; @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; import org.thingsboard.server.queue.discovery.DiscoveryService; import org.thingsboard.server.queue.discovery.PartitionService; @@ -50,9 +52,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import static org.thingsboard.common.util.SystemUtil.getFreeMemory; import static org.thingsboard.common.util.SystemUtil.getCpuUsage; import static org.thingsboard.common.util.SystemUtil.getFreeDiscSpace; +import static org.thingsboard.common.util.SystemUtil.getFreeMemory; import static org.thingsboard.common.util.SystemUtil.getMemoryUsage; import static org.thingsboard.common.util.SystemUtil.getTotalCpuUsage; import static org.thingsboard.common.util.SystemUtil.getTotalDiscSpace; @@ -79,6 +81,7 @@ public class DefaultSystemInfoService extends TbApplicationEventListener telemetry) { - telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, TenantId.SYS_TENANT_ID, telemetry, CALLBACK); + ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); + telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, apiUsageState.getId(), telemetry, CALLBACK); } private List getSystemData(ServiceInfo serviceInfo) { diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseHomePageApiTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseHomePageApiTest.java new file mode 100644 index 0000000000..07fa2ddaad --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/BaseHomePageApiTest.java @@ -0,0 +1,241 @@ +/** + * 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.controller; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.ApiUsageState; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.Tenant; +import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.query.EntityCountQuery; +import org.thingsboard.server.common.data.query.EntityData; +import org.thingsboard.server.common.data.query.EntityTypeFilter; +import org.thingsboard.server.common.data.query.SingleEntityFilter; +import org.thingsboard.server.common.data.query.TsValue; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; +import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountCmd; +import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityCountUpdate; +import org.thingsboard.server.service.ws.telemetry.cmd.v2.EntityDataUpdate; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +@Slf4j +public abstract class BaseHomePageApiTest extends AbstractControllerTest { + + @Autowired + private TbApiUsageStateClient apiUsageStateClient; + + //For system administrator + @Test + public void testTenantsCountWsCmd() throws Exception { + loginSysAdmin(); + + List tenants = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + Tenant tenant = new Tenant(); + tenant.setTitle("tenant" + i); + tenants.add(doPost("/api/tenant", tenant, Tenant.class)); + } + + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.TENANT); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(101, update.getCount()); + + for (Tenant tenant : tenants) { + doDelete("/api/tenant/" + tenant.getId().toString()); + } + } + + @Test + public void testTenantProfilesCountWsCmd() throws Exception { + loginSysAdmin(); + + List tenantProfiles = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + TenantProfile tenantProfile = new TenantProfile(); + tenantProfile.setName("tenantProfile" + i); + tenantProfiles.add(doPost("/api/tenantProfile", tenantProfile, TenantProfile.class)); + } + + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.TENANT_PROFILE); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(101, update.getCount()); + + for (TenantProfile tenantProfile : tenantProfiles) { + doDelete("/api/tenantProfile/" + tenantProfile.getId().toString()); + } + } + + @Test + public void testUsersCountWsCmd() throws Exception { + loginSysAdmin(); + + List users = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + User user = new User(); + user.setEmail(i + "user@thingsboard.org"); + user.setTenantId(tenantId); + user.setAuthority(Authority.TENANT_ADMIN); + users.add(doPost("/api/user", user, User.class)); + } + + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.USER); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(103, update.getCount()); + + for (User user : users) { + doDelete("/api/user/" + user.getId().toString()); + } + } + + @Test + public void testCustomersCountWsCmd() throws Exception { + loginTenantAdmin(); + + List customers = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + Customer customer = new Customer(); + customer.setTitle("customer" + i); + customers.add(doPost("/api/customer", customer, Customer.class)); + } + + loginSysAdmin(); + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.CUSTOMER); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(101, update.getCount()); + + loginTenantAdmin(); + for (Customer customer : customers) { + doDelete("/api/customer/" + customer.getId().toString()); + } + } + + @Test + public void testDevicesCountWsCmd() throws Exception { + loginTenantAdmin(); + + List devices = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + Device device = new Device(); + device.setName("device" + i); + devices.add(doPost("/api/device", device, Device.class)); + } + + loginSysAdmin(); + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.DEVICE); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(100, update.getCount()); + + loginTenantAdmin(); + for (Device device : devices) { + doDelete("/api/device/" + device.getId().toString()); + } + } + + @Test + public void testAssetsCountWsCmd() throws Exception { + loginTenantAdmin(); + + List assets = new ArrayList<>(); + for (int i = 0; i < 100; i++) { + Asset asset = new Asset(); + asset.setName("asset" + i); + assets.add(doPost("/api/asset", asset, Asset.class)); + } + + loginSysAdmin(); + EntityTypeFilter ef = new EntityTypeFilter(); + ef.setEntityType(EntityType.ASSET); + EntityCountCmd cmd = new EntityCountCmd(1, new EntityCountQuery(ef, Collections.emptyList())); + getWsClient().send(cmd); + EntityCountUpdate update = getWsClient().parseCountReply(getWsClient().waitForReply()); + Assert.assertEquals(1, update.getCmdId()); + Assert.assertEquals(100, update.getCount()); + + loginTenantAdmin(); + for (Asset asset : assets) { + doDelete("/api/asset/" + asset.getId().toString()); + } + } + + @Test + public void testSystemInfoTimeSeriesWsCmd() throws Exception { + ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); + Assert.assertNotNull(apiUsageState); + + SingleEntityFilter entityFilter = new SingleEntityFilter(); + entityFilter.setSingleEntity(apiUsageState.getId()); + + loginSysAdmin(); + long now = System.currentTimeMillis(); + + EntityDataUpdate update = getWsClient().sendEntityDataQuery(entityFilter); + + Assert.assertEquals(1, update.getCmdId()); + PageData pageData = update.getData(); + Assert.assertNotNull(pageData); + Assert.assertEquals(1, pageData.getData().size()); + Assert.assertEquals(apiUsageState.getId(), pageData.getData().get(0).getEntityId()); + + update = getWsClient().subscribeTsUpdate( + List.of("memoryUsage", "totalMemory", "freeMemory", "cpuUsage", "totalCpuUsage", "freeDiscSpace", "totalDiscSpace"), + now, TimeUnit.HOURS.toMillis(1)); + Assert.assertEquals(1, update.getCmdId()); + List listData = update.getUpdate(); + Assert.assertNotNull(listData); + Assert.assertEquals(1, listData.size()); + Assert.assertEquals(apiUsageState.getId(), listData.get(0).getEntityId()); + Assert.assertEquals(7, listData.get(0).getTimeseries().size()); + + for (TsValue[] tsv : listData.get(0).getTimeseries().values()) { + Assert.assertEquals(1, tsv.length); + } + } + +} diff --git a/application/src/test/java/org/thingsboard/server/controller/sql/HomePageApiSqlTest.java b/application/src/test/java/org/thingsboard/server/controller/sql/HomePageApiSqlTest.java new file mode 100644 index 0000000000..5aa50c9336 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/controller/sql/HomePageApiSqlTest.java @@ -0,0 +1,23 @@ +/** + * 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.controller.sql; + +import org.thingsboard.server.controller.BaseHomePageApiTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class HomePageApiSqlTest extends BaseHomePageApiTest { +}