From 74a78ddc612ee36d253edf052e3db4eb50a4edf8 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 21 Apr 2022 18:55:49 +0300 Subject: [PATCH] test entity view refactored from sleep to WSW --- .../BaseEntityViewControllerTest.java | 121 ++++++++++-------- .../controller/TbTestWebSocketClient.java | 8 +- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java index fb6ded866a..0887b58ce4 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseEntityViewControllerTest.java @@ -48,16 +48,22 @@ import org.thingsboard.server.common.data.objects.AttributesEntityView; import org.thingsboard.server.common.data.objects.TelemetryEntityView; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.query.DeviceTypeFilter; +import org.thingsboard.server.common.data.query.EntityKey; +import org.thingsboard.server.common.data.query.EntityKeyType; +import org.thingsboard.server.common.data.query.EntityViewTypeFilter; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.model.ModelConstants; -import org.thingsboard.server.queue.memory.InMemoryStorage; +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -71,12 +77,14 @@ import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; @TestPropertySource(properties = { "transport.mqtt.enabled=true", + "js.evaluator=mock", }) @Slf4j public abstract class BaseEntityViewControllerTest extends AbstractControllerTest { - static final int TIMEOUT = 30; static final TypeReference> PAGE_DATA_ENTITY_VIEW_TYPE_REF = new TypeReference<>() { }; + static final TypeReference> PAGE_DATA_ENTITY_VIEW_INFO_TYPE_REF = new TypeReference<>() { + }; private Tenant savedTenant; private User tenantAdmin; @@ -86,13 +94,10 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List> deleteFutures = new ArrayList<>(); ListeningExecutorService executor; - @Autowired - InMemoryStorage inMemoryStorage; - @Before public void beforeTest() throws Exception { - log.warn("beforeTest"); - executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(16, getClass())); + log.debug("beforeTest"); + executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass())); loginSysAdmin(); @@ -108,7 +113,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); Device device = new Device(); - device.setName("Test device"); + device.setName("Test device 4view"); device.setType("default"); testDevice = doPost("/api/device", device, Device.class); @@ -128,7 +133,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) .andExpect(status().isOk()); - log.warn("after test"); + log.debug("after test"); } @Test @@ -304,9 +309,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS); - PageData pageData = doGetTypedWithPageLink(urlTemplate, - new TypeReference>() { - }, new PageLink(4, 0, name1)); + PageData pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF, + new PageLink(4, 0, name1)); Assert.assertFalse(pageData.hasNext()); assertEquals(0, pageData.getData().size()); @@ -317,8 +321,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS); - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>() { - }, + pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_TYPE_REF, new PageLink(4, 0, name2)); Assert.assertFalse(pageData.hasNext()); assertEquals(0, pageData.getData().size()); @@ -358,9 +361,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } Futures.allAsList(deleteFutures).get(TIMEOUT, SECONDS); - PageData pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", - new TypeReference>() { - }, new PageLink(4, 0, name1)); + PageData pageData = doGetTypedWithPageLink("/api/tenant/entityViews?", PAGE_DATA_ENTITY_VIEW_TYPE_REF, + new PageLink(4, 0, name1)); Assert.assertFalse(pageData.hasNext()); assertEquals(0, pageData.getData().size()); @@ -382,11 +384,10 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Set expectedActualAttributesSet = Set.of("caKey1", "caKey2", "caKey3", "caKey4"); Set actualAttributesSet = getAttributesByKeys("{\"caKey1\":\"value1\", \"caKey2\":true, \"caKey3\":42.0, \"caKey4\":73}", expectedActualAttributesSet); - - log.warn("got correct actualAttributesSet, saving new entity view..."); + log.debug("got correct actualAttributesSet, saving new entity view..."); EntityView savedView = getNewSavedEntityView("Test entity view"); - log.warn("fetching entity view telemetry..."); + log.debug("fetching entity view telemetry..."); List> values = await("telemetry/ENTITY_VIEW") .atMost(TIMEOUT, SECONDS) .until(() -> doGetAsyncTyped("/api/plugins/telemetry/ENTITY_VIEW/" + savedView.getId().getId().toString() + @@ -394,7 +395,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes }), x -> x.size() >= expectedActualAttributesSet.size()); - log.warn("asserting..."); + log.debug("asserting..."); assertEquals("value1", getValue(values, "caKey1")); assertEquals(true, getValue(values, "caKey2")); assertEquals(42.0, getValue(values, "caKey3")); @@ -430,18 +431,40 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @Test public void testGetTelemetryWhenEntityViewTimeRangeInsideTimestampRange() throws Exception { - uploadTelemetry("{\"tsKey1\":\"value1\", \"tsKey2\":true, \"tsKey3\":40.0}"); - Thread.sleep(1000); + DeviceTypeFilter dtf = new DeviceTypeFilter(testDevice.getType(), testDevice.getName()); + List tsKeys = List.of("tsKey1", "tsKey2", "tsKey3"); + + DeviceCredentials deviceCredentials =doGet("/api/device/" + testDevice.getId().getId() + "/credentials", DeviceCredentials.class); + assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); + String accessToken = deviceCredentials.getCredentialsId(); + assertNotNull(accessToken); + + long now = System.currentTimeMillis(); + getWsClient().subscribeTsUpdate(tsKeys, now, TimeUnit.HOURS.toMillis(1), dtf); + + getWsClient().registerWaitForUpdate(); + uploadTelemetry("{\"tsKey1\":\"value1\", \"tsKey2\":true, \"tsKey3\":40.0}", accessToken); + getWsClient().waitForUpdate(); + long startTimeMs = System.currentTimeMillis(); - uploadTelemetry("{\"tsKey1\":\"value2\", \"tsKey2\":false, \"tsKey3\":80.0}"); - Thread.sleep(1000); - uploadTelemetry("{\"tsKey1\":\"value3\", \"tsKey2\":false, \"tsKey3\":120.0}"); + + getWsClient().registerWaitForUpdate(); + uploadTelemetry("{\"tsKey1\":\"value2\", \"tsKey2\":false, \"tsKey3\":80.0}", accessToken); + getWsClient().waitForUpdate(); + + Thread.sleep(3); + + getWsClient().registerWaitForUpdate(); + uploadTelemetry("{\"tsKey1\":\"value3\", \"tsKey2\":false, \"tsKey3\":120.0}", accessToken); + getWsClient().waitForUpdate(); + long endTimeMs = System.currentTimeMillis(); - uploadTelemetry("{\"tsKey1\":\"value4\", \"tsKey2\":true, \"tsKey3\":160.0}"); + getWsClient().registerWaitForUpdate(); + uploadTelemetry("{\"tsKey1\":\"value4\", \"tsKey2\":true, \"tsKey3\":160.0}", accessToken); + getWsClient().waitForUpdate(); String deviceId = testDevice.getId().getId().toString(); Set keys = getTelemetryKeys("DEVICE", deviceId); - Thread.sleep(1000); EntityView view = createEntityView("Test entity view", startTimeMs, endTimeMs); EntityView savedView = doPost("/api/entityView", view, EntityView.class); @@ -458,15 +481,8 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes Assert.assertEquals(1, actualValues.get("tsKey3").size()); } - private void uploadTelemetry(String strKvs) throws Exception { - + private void uploadTelemetry(String strKvs, String accessToken) throws Exception { String viewDeviceId = testDevice.getId().getId().toString(); - DeviceCredentials deviceCredentials = - doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); - assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); - - String accessToken = deviceCredentials.getCredentialsId(); - assertNotNull(accessToken); String clientId = MqttAsyncClient.generateClientId(); MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence()); @@ -478,7 +494,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes MqttMessage message = new MqttMessage(); message.setPayload(strKvs.getBytes()); IMqttDeliveryToken token = client.publish("v1/devices/me/telemetry", message); - await("mqtt ack").pollInterval(10, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null); + await("mqtt ack").pollInterval(5, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null); client.disconnect(); } @@ -504,7 +520,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes } private Set getAttributesByKeys(String stringKV, Set expectedKeySet) throws Exception { + DeviceTypeFilter dtf = new DeviceTypeFilter(testDevice.getType(), testDevice.getName()); + List keysToSubscribe = expectedKeySet.stream() + .map(key -> new EntityKey(EntityKeyType.CLIENT_ATTRIBUTE, key)) + .collect(Collectors.toList()); + + getWsClient().subscribeLatestUpdate(keysToSubscribe, dtf); + String viewDeviceId = testDevice.getId().getId().toString(); + log.debug("deviceid {}", viewDeviceId); DeviceCredentials deviceCredentials = doGet("/api/device/" + viewDeviceId + "/credentials", DeviceCredentials.class); assertEquals(testDevice.getId(), deviceCredentials.getDeviceId()); @@ -512,6 +536,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes String accessToken = deviceCredentials.getCredentialsId(); assertNotNull(accessToken); + log.debug("creating mqtt client..."); String clientId = MqttAsyncClient.generateClientId(); MqttAsyncClient client = new MqttAsyncClient("tcp://localhost:1883", clientId, new MemoryPersistence()); @@ -519,21 +544,16 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes options.setUserName(accessToken); client.connect(options); awaitConnected(client, SECONDS.toMillis(30)); - + log.debug("mqtt connected..."); MqttMessage message = new MqttMessage(); message.setPayload((stringKV).getBytes()); + getWsClient().registerWaitForUpdate(); IMqttDeliveryToken token = client.publish("v1/devices/me/attributes", message); - log.warn("token.message {}", token.getMessage()); - await("mqtt ack").pollInterval(10, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null); - log.warn("token.message delivered {}", token.getMessage()); - client.disconnect(); - - return await().pollInterval(20, MILLISECONDS).atMost(TIMEOUT, SECONDS) - .until(() -> { - inMemoryStorage.printStats(); - return getAttributeKeys("DEVICE", viewDeviceId); - }, - keys -> keys.containsAll(expectedKeySet)); + log.debug("publish token.message {}", token.getMessage()); + await("mqtt ack").pollInterval(5, MILLISECONDS).atMost(TIMEOUT, SECONDS).until(() -> token.getMessage() == null); + log.debug("token.message delivered {}", token.getMessage()); + assertThat(getWsClient().waitForUpdate()).as("ws update received").isNotBlank(); + return getAttributeKeys("DEVICE", viewDeviceId); } private Object getValue(List> values, String stringValue) { @@ -624,8 +644,7 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes List loadedItems = new ArrayList<>(); PageData pageData; do { - pageData = doGetTypedWithPageLink(urlTemplate, new TypeReference>() { - }, pageLink); + pageData = doGetTypedWithPageLink(urlTemplate, PAGE_DATA_ENTITY_VIEW_INFO_TYPE_REF, pageLink); loadedItems.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); diff --git a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java index 013547aa24..6af6176b06 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java +++ b/application/src/test/java/org/thingsboard/server/controller/TbTestWebSocketClient.java @@ -150,7 +150,13 @@ public class TbTestWebSocketClient extends WebSocketClient { } public EntityDataUpdate subscribeTsUpdate(List keys, long startTs, long timeWindow) { - return subscribeTsUpdate(keys, startTs, timeWindow, null); + return subscribeTsUpdate(keys, startTs, timeWindow, (EntityDataQuery) null); + } + + public EntityDataUpdate subscribeTsUpdate(List keys, long startTs, long timeWindow, EntityFilter entityFilter) { + EntityDataQuery edq = new EntityDataQuery(entityFilter, new EntityDataPageLink(1, 0, null, null), + Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); + return subscribeTsUpdate(keys, startTs, timeWindow, edq); } public EntityDataUpdate subscribeTsUpdate(List keys, long startTs, long timeWindow, EntityDataQuery edq) {