Browse Source

Edge mergeAndFilterDownlinkDuplicates - handle cases when no TS in attrbiutes body

pull/14665/head
Volodymyr Babak 9 months ago
parent
commit
dbbd97cbcc
  1. 35
      application/src/main/java/org/thingsboard/server/service/edge/EdgeMsgConstructorUtils.java
  2. 5
      application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java
  3. 25
      application/src/test/java/org/thingsboard/server/service/edge/EdgeMsgConstructorUtilsTest.java

35
application/src/main/java/org/thingsboard/server/service/edge/EdgeMsgConstructorUtils.java

@ -560,7 +560,7 @@ public class EdgeMsgConstructorUtils {
.setEntityIdMSB(entityId.getId().getMostSignificantBits()) .setEntityIdMSB(entityId.getId().getMostSignificantBits())
.setEntityIdLSB(entityId.getId().getLeastSignificantBits()) .setEntityIdLSB(entityId.getId().getLeastSignificantBits())
.setEntityType(entityId.getEntityType().name()); .setEntityType(entityId.getEntityType().name());
long ts = getTs(entityData.getAsJsonObject()); long ts = extractTs(entityData.getAsJsonObject());
switch (actionType) { switch (actionType) {
case TIMESERIES_UPDATED: case TIMESERIES_UPDATED:
try { try {
@ -613,8 +613,8 @@ public class EdgeMsgConstructorUtils {
return builder.build(); return builder.build();
} }
private static long getTs(JsonObject data) { private static long extractTs(JsonObject data) {
if (data.get("ts") != null && !data.get("ts").isJsonNull()) { if (data.has("ts") && data.get("ts").isJsonPrimitive()) {
return data.getAsJsonPrimitive("ts").getAsLong(); return data.getAsJsonPrimitive("ts").getAsLong();
} }
return System.currentTimeMillis(); return System.currentTimeMillis();
@ -740,7 +740,7 @@ public class EdgeMsgConstructorUtils {
result.sort(Comparator.comparingLong(EdgeEvent::getSeqId)); result.sort(Comparator.comparingLong(EdgeEvent::getSeqId));
return result; return result;
} catch (Exception e) { } catch (Exception e) {
log.warn("Can't merge downlink duplicates, edgeEvents [{}]", edgeEvents, e); log.info("Can't merge downlink duplicates. Sending downlinks without merge. Original edgeEvents [{}]", edgeEvents, e);
return edgeEvents; return edgeEvents;
} }
} }
@ -751,6 +751,9 @@ public class EdgeMsgConstructorUtils {
} }
String bodyStr = JacksonUtil.toString(body); String bodyStr = JacksonUtil.toString(body);
var jsonObject = JsonParser.parseString(bodyStr).getAsJsonObject(); var jsonObject = JsonParser.parseString(bodyStr).getAsJsonObject();
if (!jsonObject.has("ts")) {
return new AttrsTs(0L, List.of());
}
long ts = jsonObject.get("ts").getAsLong(); long ts = jsonObject.get("ts").getAsLong();
var kv = jsonObject.getAsJsonObject("kv"); var kv = jsonObject.getAsJsonObject("kv");
List<AttributeKvEntry> attrs = JsonConverter.convertToAttributes( List<AttributeKvEntry> attrs = JsonConverter.convertToAttributes(
@ -761,22 +764,24 @@ public class EdgeMsgConstructorUtils {
} }
private static JsonNode filterAttributesBody(JsonNode body, Map<String, Long> latestByKey) { private static JsonNode filterAttributesBody(JsonNode body, Map<String, Long> latestByKey) {
if (body == null || latestByKey == null || latestByKey.isEmpty()) { if (body == null) {
return null; return null;
} }
String bodyStr = JacksonUtil.toString(body); String bodyStr = JacksonUtil.toString(body);
JsonObject jsonObject = JsonParser.parseString(bodyStr).getAsJsonObject(); JsonObject jsonObject = JsonParser.parseString(bodyStr).getAsJsonObject();
long ts = jsonObject.get("ts").getAsLong(); if (jsonObject.has("ts") && latestByKey != null && !latestByKey.isEmpty()) {
JsonObject kv = jsonObject.getAsJsonObject("kv"); long ts = jsonObject.get("ts").getAsLong();
for (Iterator<Map.Entry<String, JsonElement>> it = kv.entrySet().iterator(); it.hasNext(); ) { JsonObject kv = jsonObject.getAsJsonObject("kv");
Map.Entry<String, JsonElement> e = it.next(); for (Iterator<Map.Entry<String, JsonElement>> it = kv.entrySet().iterator(); it.hasNext(); ) {
Long latestTs = latestByKey.get(e.getKey()); Map.Entry<String, JsonElement> e = it.next();
if (latestTs == null || !latestTs.equals(ts)) { Long latestTs = latestByKey.get(e.getKey());
it.remove(); if (latestTs == null || !latestTs.equals(ts)) {
it.remove();
}
}
if (kv.isEmpty()) {
return null;
} }
}
if (kv.isEmpty()) {
return null;
} }
return JacksonUtil.toJsonNode(jsonObject.toString()); return JacksonUtil.toJsonNode(jsonObject.toString());
} }

5
application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java

@ -49,8 +49,6 @@ import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
@ -671,8 +669,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest {
.atMost(10, TimeUnit.SECONDS) .atMost(10, TimeUnit.SECONDS)
.until(() -> { .until(() -> {
String urlTemplate = "/api/plugins/telemetry/DEVICE/" + device.getId() + "/keys/attributes/" + scope; String urlTemplate = "/api/plugins/telemetry/DEVICE/" + device.getId() + "/keys/attributes/" + scope;
List<String> actualKeys = doGetAsyncTyped(urlTemplate, new TypeReference<>() { List<String> actualKeys = doGetAsyncTyped(urlTemplate, new TypeReference<>() {});
});
return actualKeys != null && !actualKeys.isEmpty() && actualKeys.contains(expectedKey); return actualKeys != null && !actualKeys.isEmpty() && actualKeys.contains(expectedKey);
}); });

25
application/src/test/java/org/thingsboard/server/service/edge/EdgeMsgConstructorUtilsTest.java

@ -230,10 +230,35 @@ public class EdgeMsgConstructorUtilsTest {
Assertions.assertEquals(8, getIntValue(assetMergedAttrAD.getBody(), "d")); Assertions.assertEquals(8, getIntValue(assetMergedAttrAD.getBody(), "d"));
} }
@Test
public void testMergeDownlinkDuplicates_attrBodyHasNoTs_returnOriginalList() {
UUID deviceId = UUID.randomUUID();
TenantId tenantId = TenantId.fromUUID(UUID.randomUUID());
var deviceAttrUpdate1 = createEdgeEvent(tenantId, 1, EdgeEventActionType.ATTRIBUTES_UPDATED,
deviceId, EdgeEventType.DEVICE, createAttrBodyWithoutTs("{\"a\":1,\"b\":1,\"d\":1}"));
var deviceAttrUpdate2 = createEdgeEvent(tenantId, 2, EdgeEventActionType.ATTRIBUTES_UPDATED,
deviceId, EdgeEventType.DEVICE, createAttrBodyWithoutTs("{\"a\":2,\"b\":2,\"c\":2}"));
var deviceAttrUpdate3 = createEdgeEvent(tenantId, 3, EdgeEventActionType.ATTRIBUTES_UPDATED,
deviceId, EdgeEventType.DEVICE, createAttrBodyWithoutTs("{\"a\":3,\"d\":3}"));
List<EdgeEvent> input = List.of(deviceAttrUpdate1, deviceAttrUpdate2, deviceAttrUpdate3);
List<EdgeEvent> merged = EdgeMsgConstructorUtils.mergeAndFilterDownlinkDuplicates(input);
Assertions.assertEquals(3, merged.size());
Assertions.assertEquals(deviceAttrUpdate1, merged.get(0));
Assertions.assertEquals(deviceAttrUpdate2, merged.get(1));
Assertions.assertEquals(deviceAttrUpdate3, merged.get(2));
}
private Integer getIntValue(JsonNode body, String key) { private Integer getIntValue(JsonNode body, String key) {
return body.get("kv").get(key) != null ? body.get("kv").get(key).asInt() : null; return body.get("kv").get(key) != null ? body.get("kv").get(key).asInt() : null;
} }
private static JsonNode createAttrBodyWithoutTs(String kvJson) {
return JacksonUtil.toJsonNode("{\"kv\":" + kvJson + "}");
}
private static JsonNode createAttrBody(long ts, String kvJson) { private static JsonNode createAttrBody(long ts, String kvJson) {
return JacksonUtil.toJsonNode("{\"ts\":" + ts + ",\"kv\":" + kvJson + "}"); return JacksonUtil.toJsonNode("{\"ts\":" + ts + ",\"kv\":" + kvJson + "}");
} }

Loading…
Cancel
Save