Browse Source

MSA tests

pull/14107/head
dshvaika 8 months ago
parent
commit
6146cdc622
  1. 45
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/TestRestClient.java
  2. 183
      msa/black-box-tests/src/test/java/org/thingsboard/server/msa/cf/CalculatedFieldTest.java

45
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/TestRestClient.java

@ -266,6 +266,33 @@ public class TestRestClient {
.as(ArrayNode.class);
}
public ValidatableResponse deleteEntityAttributes(EntityId entityId, AttributeScope scope, String keys) {
Map<String, String> pathParams = new HashMap<>();
pathParams.put("entityId", entityId.getId().toString());
pathParams.put("entityType", entityId.getEntityType().name());
pathParams.put("scope", scope.name());
return given().spec(requestSpec)
.pathParams(pathParams)
.queryParam("keys", keys)
.delete("/api/plugins/telemetry/{entityType}/{entityId}/{scope}")
.then()
.statusCode(HTTP_OK);
}
public ValidatableResponse deleteEntityTimeseries(EntityId entityId, String keys, boolean deleteAllDataForKeys) {
Map<String, String> pathParams = new HashMap<>();
pathParams.put("entityType", entityId.getEntityType().name());
pathParams.put("entityId", entityId.getId().toString());
return given().spec(requestSpec)
.pathParams(pathParams)
.queryParam("keys", keys)
.queryParam("deleteAllDataForKeys", Boolean.toString(deleteAllDataForKeys))
.delete("/api/plugins/telemetry/{entityType}/{entityId}/timeseries/delete")
.then()
.statusCode(HTTP_OK);
}
public JsonNode getLatestTelemetry(EntityId entityId) {
return given().spec(requestSpec)
.get("/api/plugins/telemetry/" + entityId.getEntityType().name() + "/" + entityId.getId() + "/values/timeseries")
@ -378,6 +405,24 @@ public class TestRestClient {
.as(EntityRelation.class);
}
public EntityRelation deleteEntityRelation(EntityId fromId, String relationType, EntityId toId) {
Map<String, String> queryParams = new HashMap<>();
queryParams.put("fromId", fromId.getId().toString());
queryParams.put("fromType", fromId.getEntityType().name());
queryParams.put("relationType", relationType);
queryParams.put("toId", toId.getId().toString());
queryParams.put("toType", toId.getEntityType().name());
return given().spec(requestSpec)
.queryParams(queryParams)
//.delete("/api/v2/relation?fromId={fromId}&fromType={fromType}&relationType={relationType}&toId={toId}&toType={toType}")
.delete("/api/v2/relation")
.then()
.statusCode(HTTP_OK)
.extract()
.as(EntityRelation.class);
}
public JsonNode postServerSideRpc(DeviceId deviceId, JsonNode serverRpcPayload) {
return given().spec(requestSpec)
.body(serverRpcPayload)

183
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/cf/CalculatedFieldTest.java

@ -23,6 +23,7 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.AttributeScope;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.asset.Asset;
@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.cf.configuration.Argument;
import org.thingsboard.server.common.data.cf.configuration.ArgumentType;
import org.thingsboard.server.common.data.cf.configuration.Output;
import org.thingsboard.server.common.data.cf.configuration.OutputType;
import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey;
import org.thingsboard.server.common.data.cf.configuration.RelationPathQueryDynamicSourceConfiguration;
import org.thingsboard.server.common.data.cf.configuration.ScriptCalculatedFieldConfiguration;
@ -419,6 +421,179 @@ public class CalculatedFieldTest extends AbstractContainerTest {
testRestClient.deleteCalculatedFieldIfExists(saved.getId());
}
@Test
public void testPropagationCalculatedField_withExpression() {
// login tenant admin
testRestClient.getAndSetUserToken(tenantAdminId);
// --- Arrange entities ---
String deviceToken = "propagationDeviceTokenA";
Device device = testRestClient.postDevice(deviceToken, createDevice("Propagation Device With Expression", deviceProfileId));
Asset asset1 = testRestClient.postAsset(createAsset("Propagated Asset 1", null));
Asset asset2 = testRestClient.postAsset(createAsset("Propagated Asset 2", null));
// Create relations FROM assets TO device
EntityRelation rel1 = new EntityRelation(asset1.getId(), device.getId(), EntityRelation.CONTAINS_TYPE);
EntityRelation rel2 = new EntityRelation(asset2.getId(), device.getId(), EntityRelation.CONTAINS_TYPE);
testRestClient.postEntityRelation(rel1);
testRestClient.postEntityRelation(rel2);
// Telemetry on device
testRestClient.postTelemetry(deviceToken, JacksonUtil.toJsonNode("{\"temperature\":12.5}"));
// --- Build CF: PROPAGATION with expression ---
CalculatedField cf = new CalculatedField();
cf.setEntityId(device.getId());
cf.setType(CalculatedFieldType.PROPAGATION);
cf.setName("Propagation CF (expr)");
cf.setConfigurationVersion(1);
PropagationCalculatedFieldConfiguration cfg = new PropagationCalculatedFieldConfiguration();
cfg.setDirection(EntitySearchDirection.TO);
cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
cfg.setApplyExpressionToResolvedArguments(true);
Argument arg = new Argument();
arg.setRefEntityKey(new ReferencedEntityKey("temperature", ArgumentType.TS_LATEST, null));
cfg.setArguments(Map.of("t", arg));
cfg.setExpression("{\"testResult\": t * 2}");
Output output = new Output();
output.setType(OutputType.ATTRIBUTES);
output.setScope(AttributeScope.SERVER_SCOPE);
cfg.setOutput(output);
cf.setConfiguration(cfg);
CalculatedField saved = testRestClient.postCalculatedField(cf);
// --- Assert propagated calculation (expression applied) ---
await().alias("propagation expr mode evaluation")
.atMost(TIMEOUT, TimeUnit.SECONDS)
.pollInterval(POLL_INTERVAL, TimeUnit.SECONDS)
.untilAsserted(() -> {
ArrayNode attrs1 = testRestClient.getAttributes(asset1.getId(), SERVER_SCOPE, "testResult");
assertThat(attrs1).isNotNull().hasSize(1);
Map<String, Integer> m1 = intKv(attrs1);
assertThat(m1).containsEntry("testResult", 25);
ArrayNode attrs2 = testRestClient.getAttributes(asset2.getId(), SERVER_SCOPE, "testResult");
assertThat(attrs2).isNotNull().hasSize(1);
Map<String, Integer> m2 = intKv(attrs2);
assertThat(m2).containsEntry("testResult", 25);
});
testRestClient.deleteEntityRelation(asset1.getId(), EntityRelation.CONTAINS_TYPE, device.getId());
testRestClient.deleteEntityAttributes(asset1.getId(), SERVER_SCOPE, "testResult");
testRestClient.postTelemetry(deviceToken, JacksonUtil.toJsonNode("{\"temperature\":25}"));
// --- Assert propagated calculation (expression applied with new temperature argument and one relation removed) ---
await().alias("propagation expr mode evaluation after temperature update")
.atMost(TIMEOUT, TimeUnit.SECONDS)
.pollInterval(POLL_INTERVAL, TimeUnit.SECONDS)
.untilAsserted(() -> {
ArrayNode attrs1 = testRestClient.getAttributes(asset1.getId(), SERVER_SCOPE, "testResult");
assertThat(attrs1).isNullOrEmpty();
ArrayNode attrs2 = testRestClient.getAttributes(asset2.getId(), SERVER_SCOPE, "testResult");
assertThat(attrs2).isNotNull().hasSize(1);
Map<String, Integer> m2 = intKv(attrs2);
assertThat(m2).containsEntry("testResult", 50);
});
testRestClient.deleteCalculatedFieldIfExists(saved.getId());
}
@Test
public void testPropagationCalculatedField_withoutExpression() {
// login tenant admin
testRestClient.getAndSetUserToken(tenantAdminId);
// --- Arrange entities ---
String deviceToken = "propagationDeviceTokenB";
Device device = testRestClient.postDevice(deviceToken, createDevice("Propagation Device Without Expression", deviceProfileId));
Asset asset1 = testRestClient.postAsset(createAsset("Propagated Asset 3", null));
Asset asset2 = testRestClient.postAsset(createAsset("Propagated Asset 4", null));
// Create relations FROM assets TO device
EntityRelation rel1 = new EntityRelation(asset1.getId(), device.getId(), EntityRelation.CONTAINS_TYPE);
EntityRelation rel2 = new EntityRelation(asset2.getId(), device.getId(), EntityRelation.CONTAINS_TYPE);
testRestClient.postEntityRelation(rel1);
testRestClient.postEntityRelation(rel2);
// Telemetry on device
long ts = System.currentTimeMillis() - 300000L;
testRestClient.postTelemetry(deviceToken, JacksonUtil.toJsonNode(String.format("{\"ts\": %s, \"values\": {\"temperature\":12.5}}", ts)));
// --- Build CF: PROPAGATION without expression ---
CalculatedField cf = new CalculatedField();
cf.setEntityId(device.getId());
cf.setType(CalculatedFieldType.PROPAGATION);
cf.setName("Propagation CF (args-only)");
cf.setConfigurationVersion(1);
PropagationCalculatedFieldConfiguration cfg = new PropagationCalculatedFieldConfiguration();
cfg.setDirection(EntitySearchDirection.TO);
cfg.setRelationType(EntityRelation.CONTAINS_TYPE);
cfg.setApplyExpressionToResolvedArguments(false); // arguments-only mode
Argument arg = new Argument();
arg.setRefEntityKey(new ReferencedEntityKey("temperature", ArgumentType.TS_LATEST, null));
cfg.setArguments(Map.of("t", arg));
Output output = new Output();
output.setType(OutputType.TIME_SERIES);
cfg.setOutput(output);
cf.setConfiguration(cfg);
CalculatedField saved = testRestClient.postCalculatedField(cf);
// --- Assert propagated calculation (arguments-only mode) ---
await().alias("propagation args-only evaluation")
.atMost(TIMEOUT, TimeUnit.SECONDS)
.pollInterval(POLL_INTERVAL, TimeUnit.SECONDS)
.untilAsserted(() -> {
JsonNode temperature1 = testRestClient.getLatestTelemetry(asset1.getId());
assertThat(temperature1).isNotNull();
assertThat(temperature1.get("temperature")).isNotNull();
assertThat(temperature1.get("temperature").get(0).get("ts").asText()).isEqualTo(Long.toString(ts));
assertThat(temperature1.get("temperature").get(0).get("value").asText()).isEqualTo("12.5");
JsonNode temperature2 = testRestClient.getLatestTelemetry(asset2.getId());
assertThat(temperature2).isNotNull();
assertThat(temperature2.get("temperature")).isNotNull();
assertThat(temperature2.get("temperature").get(0).get("ts").asText()).isEqualTo(Long.toString(ts));
assertThat(temperature2.get("temperature").get(0).get("value").asText()).isEqualTo("12.5");
});
testRestClient.deleteEntityRelation(asset1.getId(), EntityRelation.CONTAINS_TYPE, device.getId());
testRestClient.deleteEntityTimeseries(asset1.getId(), "temperature", true);
// Update telemetry on device
long newTs = System.currentTimeMillis() - 300000L;
testRestClient.postTelemetry(deviceToken, JacksonUtil.toJsonNode(String.format("{\"ts\": %s, \"values\": {\"temperature\":25}}", newTs)));
// --- Assert propagated calculation (arguments-only mode after update) ---
await().alias("propagation args-only evaluation after temperature update")
.atMost(TIMEOUT, TimeUnit.SECONDS)
.pollInterval(POLL_INTERVAL, TimeUnit.SECONDS)
.untilAsserted(() -> {
JsonNode temperature1 = testRestClient.getLatestTelemetry(asset1.getId());
assertThat(temperature1).isNullOrEmpty();
JsonNode temperature2 = testRestClient.getLatestTelemetry(asset2.getId());
assertThat(temperature2).isNotNull();
assertThat(temperature2.get("temperature")).isNotNull();
assertThat(temperature2.get("temperature").get(0).get("ts").asText()).isEqualTo(Long.toString(newTs));
assertThat(temperature2.get("temperature").get(0).get("value").asInt()).isEqualTo(25);
});
testRestClient.deleteCalculatedFieldIfExists(saved.getId());
}
private CalculatedField createSimpleCalculatedField() {
return createSimpleCalculatedField(device.getId());
}
@ -514,4 +689,12 @@ public class CalculatedFieldTest extends AbstractContainerTest {
return m;
}
private static Map<String, Integer> intKv(ArrayNode attrs) {
Map<String, Integer> m = new HashMap<>();
for (JsonNode n : attrs) {
m.put(n.get("key").asText(), n.get("value").asInt());
}
return m;
}
}

Loading…
Cancel
Save