Commit c4133fa41a3a6519ef6c56b07c7ec4a4820ea98b
Committed by
Andrew Shvayka
1 parent
a1336f38
added new dynamic-schema based tests for telemetry and attributes upload
Showing
16 changed files
with
678 additions
and
101 deletions
@@ -634,6 +634,72 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController | @@ -634,6 +634,72 @@ public abstract class BaseDeviceProfileControllerTest extends AbstractController | ||
634 | dynamicMsgToJson(sampleMsgDescriptor, sampleMsgWithOneOfSubMessage.toByteArray())); | 634 | dynamicMsgToJson(sampleMsgDescriptor, sampleMsgWithOneOfSubMessage.toByteArray())); |
635 | } | 635 | } |
636 | 636 | ||
637 | + @Test | ||
638 | + public void testSaveProtoDeviceProfileWithInvalidTelemetrySchemaTsField() throws Exception { | ||
639 | + testSaveDeviceProfileWithInvalidProtoSchema("syntax =\"proto3\";\n" + | ||
640 | + "\n" + | ||
641 | + "package schemavalidation;\n" + | ||
642 | + "\n" + | ||
643 | + "message PostTelemetry {\n" + | ||
644 | + " int64 ts = 1;\n" + | ||
645 | + " Values values = 2;\n" + | ||
646 | + " \n" + | ||
647 | + " message Values {\n" + | ||
648 | + " string key1 = 3;\n" + | ||
649 | + " bool key2 = 4;\n" + | ||
650 | + " double key3 = 5;\n" + | ||
651 | + " int32 key4 = 6;\n" + | ||
652 | + " JsonObject key5 = 7;\n" + | ||
653 | + " }\n" + | ||
654 | + " \n" + | ||
655 | + " message JsonObject {\n" + | ||
656 | + " optional int32 someNumber = 8;\n" + | ||
657 | + " repeated int32 someArray = 9;\n" + | ||
658 | + " NestedJsonObject someNestedObject = 10;\n" + | ||
659 | + " message NestedJsonObject {\n" + | ||
660 | + " optional string key = 11;\n" + | ||
661 | + " }\n" + | ||
662 | + " }\n" + | ||
663 | + "}", "[Transport Configuration] invalid telemetry proto schema provided! Field 'ts' has invalid label. Field 'ts' should have optional keyword!"); | ||
664 | + } | ||
665 | + | ||
666 | + @Test | ||
667 | + public void testSaveProtoDeviceProfileWithInvalidTelemetrySchemaTsDateType() throws Exception { | ||
668 | + testSaveDeviceProfileWithInvalidProtoSchema("syntax =\"proto3\";\n" + | ||
669 | + "\n" + | ||
670 | + "package schemavalidation;\n" + | ||
671 | + "\n" + | ||
672 | + "message PostTelemetry {\n" + | ||
673 | + " optional int32 ts = 1;\n" + | ||
674 | + " Values values = 2;\n" + | ||
675 | + " \n" + | ||
676 | + " message Values {\n" + | ||
677 | + " string key1 = 3;\n" + | ||
678 | + " bool key2 = 4;\n" + | ||
679 | + " double key3 = 5;\n" + | ||
680 | + " int32 key4 = 6;\n" + | ||
681 | + " JsonObject key5 = 7;\n" + | ||
682 | + " }\n" + | ||
683 | + " \n" + | ||
684 | + " message JsonObject {\n" + | ||
685 | + " optional int32 someNumber = 8;\n" + | ||
686 | + " }\n" + | ||
687 | + "}", "[Transport Configuration] invalid telemetry proto schema provided! Field 'ts' has invalid data type. Only int64 type is supported!"); | ||
688 | + } | ||
689 | + | ||
690 | + @Test | ||
691 | + public void testSaveProtoDeviceProfileWithInvalidTelemetrySchemaValuesDateType() throws Exception { | ||
692 | + testSaveDeviceProfileWithInvalidProtoSchema("syntax =\"proto3\";\n" + | ||
693 | + "\n" + | ||
694 | + "package schemavalidation;\n" + | ||
695 | + "\n" + | ||
696 | + "message PostTelemetry {\n" + | ||
697 | + " optional int64 ts = 1;\n" + | ||
698 | + " string values = 2;\n" + | ||
699 | + " \n" + | ||
700 | + "}", "[Transport Configuration] invalid telemetry proto schema provided! Field 'values' has invalid data type. Only message type is supported!"); | ||
701 | + } | ||
702 | + | ||
637 | private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception { | 703 | private DeviceProfile testSaveDeviceProfileWithProtoPayloadType(String schema) throws Exception { |
638 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema); | 704 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = this.createProtoTransportPayloadConfiguration(schema, schema); |
639 | MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration); | 705 | MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = this.createMqttDeviceProfileTransportConfiguration(protoTransportPayloadConfiguration); |
@@ -42,18 +42,18 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | @@ -42,18 +42,18 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | ||
42 | "package test;\n" + | 42 | "package test;\n" + |
43 | "\n" + | 43 | "\n" + |
44 | "message PostTelemetry {\n" + | 44 | "message PostTelemetry {\n" + |
45 | - " string key1 = 1;\n" + | ||
46 | - " bool key2 = 2;\n" + | ||
47 | - " double key3 = 3;\n" + | ||
48 | - " int32 key4 = 4;\n" + | 45 | + " optional string key1 = 1;\n" + |
46 | + " optional bool key2 = 2;\n" + | ||
47 | + " optional double key3 = 3;\n" + | ||
48 | + " optional int32 key4 = 4;\n" + | ||
49 | " JsonObject key5 = 5;\n" + | 49 | " JsonObject key5 = 5;\n" + |
50 | "\n" + | 50 | "\n" + |
51 | " message JsonObject {\n" + | 51 | " message JsonObject {\n" + |
52 | - " int32 someNumber = 6;\n" + | 52 | + " optional int32 someNumber = 6;\n" + |
53 | " repeated int32 someArray = 7;\n" + | 53 | " repeated int32 someArray = 7;\n" + |
54 | - " NestedJsonObject someNestedObject = 8;\n" + | 54 | + " optional NestedJsonObject someNestedObject = 8;\n" + |
55 | " message NestedJsonObject {\n" + | 55 | " message NestedJsonObject {\n" + |
56 | - " string key = 9;\n" + | 56 | + " optional string key = 9;\n" + |
57 | " }\n" + | 57 | " }\n" + |
58 | " }\n" + | 58 | " }\n" + |
59 | "}"; | 59 | "}"; |
@@ -63,18 +63,18 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | @@ -63,18 +63,18 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | ||
63 | "package test;\n" + | 63 | "package test;\n" + |
64 | "\n" + | 64 | "\n" + |
65 | "message PostAttributes {\n" + | 65 | "message PostAttributes {\n" + |
66 | - " string key1 = 1;\n" + | ||
67 | - " bool key2 = 2;\n" + | ||
68 | - " double key3 = 3;\n" + | ||
69 | - " int32 key4 = 4;\n" + | 66 | + " optional string key1 = 1;\n" + |
67 | + " optional bool key2 = 2;\n" + | ||
68 | + " optional double key3 = 3;\n" + | ||
69 | + " optional int32 key4 = 4;\n" + | ||
70 | " JsonObject key5 = 5;\n" + | 70 | " JsonObject key5 = 5;\n" + |
71 | "\n" + | 71 | "\n" + |
72 | " message JsonObject {\n" + | 72 | " message JsonObject {\n" + |
73 | - " int32 someNumber = 6;\n" + | 73 | + " optional int32 someNumber = 6;\n" + |
74 | " repeated int32 someArray = 7;\n" + | 74 | " repeated int32 someArray = 7;\n" + |
75 | " NestedJsonObject someNestedObject = 8;\n" + | 75 | " NestedJsonObject someNestedObject = 8;\n" + |
76 | " message NestedJsonObject {\n" + | 76 | " message NestedJsonObject {\n" + |
77 | - " string key = 9;\n" + | 77 | + " optional string key = 9;\n" + |
78 | " }\n" + | 78 | " }\n" + |
79 | " }\n" + | 79 | " }\n" + |
80 | "}"; | 80 | "}"; |
@@ -83,16 +83,16 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | @@ -83,16 +83,16 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle | ||
83 | "package rpc;\n" + | 83 | "package rpc;\n" + |
84 | "\n" + | 84 | "\n" + |
85 | "message RpcResponseMsg {\n" + | 85 | "message RpcResponseMsg {\n" + |
86 | - " string payload = 1;\n" + | 86 | + " optional string payload = 1;\n" + |
87 | "}"; | 87 | "}"; |
88 | 88 | ||
89 | protected static final String DEVICE_RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" + | 89 | protected static final String DEVICE_RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" + |
90 | "package rpc;\n" + | 90 | "package rpc;\n" + |
91 | "\n" + | 91 | "\n" + |
92 | "message RpcRequestMsg {\n" + | 92 | "message RpcRequestMsg {\n" + |
93 | - " string method = 1;\n" + | ||
94 | - " int32 requestId = 2;\n" + | ||
95 | - " string params = 3;\n" + | 93 | + " optional string method = 1;\n" + |
94 | + " optional int32 requestId = 2;\n" + | ||
95 | + " optional string params = 3;\n" + | ||
96 | "}"; | 96 | "}"; |
97 | 97 | ||
98 | protected Tenant savedTenant; | 98 | protected Tenant savedTenant; |
@@ -61,11 +61,14 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | @@ -61,11 +61,14 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | ||
61 | @Test | 61 | @Test |
62 | public void testPushAttributes() throws Exception { | 62 | public void testPushAttributes() throws Exception { |
63 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 63 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
64 | - processAttributesTest(expectedKeys, PAYLOAD_VALUES_STR.getBytes()); | 64 | + processJsonPayloadAttributesTest(expectedKeys, PAYLOAD_VALUES_STR.getBytes()); |
65 | } | 65 | } |
66 | 66 | ||
67 | - protected void processAttributesTest(List<String> expectedKeys, byte[] payload) throws Exception { | ||
68 | - log.warn("[testPushAttributes] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType()); | 67 | + protected void processJsonPayloadAttributesTest(List<String> expectedKeys, byte[] payload) throws Exception { |
68 | + processAttributesTest(expectedKeys, payload, false); | ||
69 | + } | ||
70 | + | ||
71 | + protected void processAttributesTest(List<String> expectedKeys, byte[] payload, boolean presenceFieldsTest) throws Exception { | ||
69 | CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); | 72 | CoapClient client = getCoapClient(FeatureType.ATTRIBUTES); |
70 | 73 | ||
71 | postAttributes(client, payload); | 74 | postAttributes(client, payload); |
@@ -94,7 +97,11 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | @@ -94,7 +97,11 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | ||
94 | 97 | ||
95 | String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); | 98 | String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); |
96 | List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); | 99 | List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); |
97 | - assertAttributesValues(values, expectedKeySet); | 100 | + if (presenceFieldsTest) { |
101 | + assertAttributesProtoValues(values, actualKeySet); | ||
102 | + } else { | ||
103 | + assertAttributesValues(values, actualKeySet); | ||
104 | + } | ||
98 | String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); | 105 | String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
99 | doDelete(deleteAttributesUrl); | 106 | doDelete(deleteAttributesUrl); |
100 | } | 107 | } |
@@ -108,11 +115,11 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | @@ -108,11 +115,11 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | ||
108 | } | 115 | } |
109 | 116 | ||
110 | @SuppressWarnings("unchecked") | 117 | @SuppressWarnings("unchecked") |
111 | - protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException { | 118 | + protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> keySet) throws JsonProcessingException { |
112 | for (Map<String, Object> map : deviceValues) { | 119 | for (Map<String, Object> map : deviceValues) { |
113 | String key = (String) map.get("key"); | 120 | String key = (String) map.get("key"); |
114 | Object value = map.get("value"); | 121 | Object value = map.get("value"); |
115 | - assertTrue(expectedKeySet.contains(key)); | 122 | + assertTrue(keySet.contains(key)); |
116 | switch (key) { | 123 | switch (key) { |
117 | case "key1": | 124 | case "key1": |
118 | assertEquals("value1", value); | 125 | assertEquals("value1", value); |
@@ -138,6 +145,35 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | @@ -138,6 +145,35 @@ public abstract class AbstractCoapAttributesIntegrationTest extends AbstractCoap | ||
138 | } | 145 | } |
139 | } | 146 | } |
140 | 147 | ||
148 | + private void assertAttributesProtoValues(List<Map<String, Object>> values, Set<String> keySet) { | ||
149 | + for (Map<String, Object> map : values) { | ||
150 | + String key = (String) map.get("key"); | ||
151 | + Object value = map.get("value"); | ||
152 | + assertTrue(keySet.contains(key)); | ||
153 | + switch (key) { | ||
154 | + case "key1": | ||
155 | + assertEquals("", value); | ||
156 | + break; | ||
157 | + case "key2": | ||
158 | + assertEquals(false, value); | ||
159 | + break; | ||
160 | + case "key3": | ||
161 | + assertEquals(0.0, value); | ||
162 | + break; | ||
163 | + case "key4": | ||
164 | + assertEquals(0, value); | ||
165 | + break; | ||
166 | + case "key5": | ||
167 | + assertNotNull(value); | ||
168 | + assertEquals(2, ((LinkedHashMap) value).size()); | ||
169 | + assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray")); | ||
170 | + LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject"); | ||
171 | + assertEquals("value", someNestedObject.get("key")); | ||
172 | + break; | ||
173 | + } | ||
174 | + } | ||
175 | + } | ||
176 | + | ||
141 | private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) { | 177 | private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) { |
142 | return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); | 178 | return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
143 | } | 179 | } |
@@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo | @@ -32,7 +32,6 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo | ||
32 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; | 32 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; |
33 | 33 | ||
34 | import java.util.Arrays; | 34 | import java.util.Arrays; |
35 | -import java.util.List; | ||
36 | 35 | ||
37 | import static org.junit.Assert.assertNotNull; | 36 | import static org.junit.Assert.assertNotNull; |
38 | import static org.junit.Assert.assertTrue; | 37 | import static org.junit.Assert.assertTrue; |
@@ -48,7 +47,6 @@ public abstract class AbstractCoapAttributesProtoIntegrationTest extends Abstrac | @@ -48,7 +47,6 @@ public abstract class AbstractCoapAttributesProtoIntegrationTest extends Abstrac | ||
48 | @Test | 47 | @Test |
49 | public void testPushAttributes() throws Exception { | 48 | public void testPushAttributes() throws Exception { |
50 | super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); | 49 | super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); |
51 | - List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | ||
52 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | 50 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
53 | assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); | 51 | assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); |
54 | CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; | 52 | CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; |
@@ -87,7 +85,50 @@ public abstract class AbstractCoapAttributesProtoIntegrationTest extends Abstrac | @@ -87,7 +85,50 @@ public abstract class AbstractCoapAttributesProtoIntegrationTest extends Abstrac | ||
87 | .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4) | 85 | .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4) |
88 | .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) | 86 | .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) |
89 | .build(); | 87 | .build(); |
90 | - processAttributesTest(expectedKeys, postAttributesMsg.toByteArray()); | 88 | + processAttributesTest(Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); |
89 | + } | ||
90 | + | ||
91 | + @Test | ||
92 | + public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception { | ||
93 | + super.processBeforeTest("Test Post Attributes device Proto", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); | ||
94 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
95 | + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); | ||
96 | + CoapDeviceProfileTransportConfiguration coapTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; | ||
97 | + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapTransportConfiguration.getCoapDeviceTypeConfiguration(); | ||
98 | + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration); | ||
99 | + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration; | ||
100 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration(); | ||
101 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
102 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
103 | + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA); | ||
104 | + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA); | ||
105 | + | ||
106 | + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject"); | ||
107 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
108 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
109 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
110 | + | ||
111 | + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject"); | ||
112 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
113 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
114 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
115 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
116 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
117 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
118 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
119 | + .build(); | ||
120 | + | ||
121 | + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes"); | ||
122 | + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType(); | ||
123 | + assertNotNull(postAttributesMsgDescriptor); | ||
124 | + DynamicMessage postAttributesMsg = postAttributesBuilder | ||
125 | + .setField(postAttributesMsgDescriptor.findFieldByName("key1"), "") | ||
126 | + .setField(postAttributesMsgDescriptor.findFieldByName("key2"), false) | ||
127 | + .setField(postAttributesMsgDescriptor.findFieldByName("key3"), 0.0) | ||
128 | + .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 0) | ||
129 | + .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) | ||
130 | + .build(); | ||
131 | + processAttributesTest(Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), true); | ||
91 | } | 132 | } |
92 | 133 | ||
93 | } | 134 | } |
@@ -56,18 +56,21 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | @@ -56,18 +56,21 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | ||
56 | 56 | ||
57 | @Test | 57 | @Test |
58 | public void testPushTelemetry() throws Exception { | 58 | public void testPushTelemetry() throws Exception { |
59 | - processTestPostTelemetry(null, false); | 59 | + processJsonPayloadTelemetryTest(PAYLOAD_VALUES_STR.getBytes(), false); |
60 | } | 60 | } |
61 | 61 | ||
62 | @Test | 62 | @Test |
63 | public void testPushTelemetryWithTs() throws Exception { | 63 | public void testPushTelemetryWithTs() throws Exception { |
64 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; | 64 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; |
65 | - processTestPostTelemetry(payloadStr.getBytes(), true); | 65 | + processJsonPayloadTelemetryTest(payloadStr.getBytes(), true); |
66 | } | 66 | } |
67 | 67 | ||
68 | - protected void processTestPostTelemetry(byte[] payloadBytes, boolean withTs) throws Exception { | ||
69 | - log.warn("[testPushTelemetry] Device: {}, Transport type: {}", savedDevice.getName(), savedDevice.getType()); | 68 | + protected void processJsonPayloadTelemetryTest(byte[] payloadBytes, boolean withTs) throws Exception { |
70 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 69 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
70 | + processTestPostTelemetry(payloadBytes, expectedKeys, withTs, false); | ||
71 | + } | ||
72 | + | ||
73 | + protected void processTestPostTelemetry(byte[] payloadBytes, List<String> expectedKeys, boolean withTs, boolean presenceFieldsTest) throws Exception { | ||
71 | CoapClient coapClient = getCoapClient(FeatureType.TELEMETRY); | 74 | CoapClient coapClient = getCoapClient(FeatureType.TELEMETRY); |
72 | postTelemetry(coapClient, payloadBytes); | 75 | postTelemetry(coapClient, payloadBytes); |
73 | 76 | ||
@@ -127,16 +130,22 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | @@ -127,16 +130,22 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | ||
127 | } | 130 | } |
128 | assertNotNull(values); | 131 | assertNotNull(values); |
129 | 132 | ||
130 | - if (withTs) { | ||
131 | - assertTs(values, expectedKeys, 10000, 0); | 133 | + if (presenceFieldsTest) { |
134 | + if (withTs) { | ||
135 | + assertTsForExplicitProtoFieldValues(values, expectedKeys, 10000, 0); | ||
136 | + assertExplicitProtoFieldValuesWithTs(values); | ||
137 | + } else { | ||
138 | + assertExplicitProtoFieldValues(values); | ||
139 | + } | ||
140 | + } else { | ||
141 | + if (withTs) { | ||
142 | + assertTs(values, expectedKeys, 10000, 0); | ||
143 | + } | ||
144 | + assertValues(values, 0); | ||
132 | } | 145 | } |
133 | - assertValues(values, 0); | ||
134 | } | 146 | } |
135 | 147 | ||
136 | private void postTelemetry(CoapClient client, byte[] payload) throws IOException, ConnectorException { | 148 | private void postTelemetry(CoapClient client, byte[] payload) throws IOException, ConnectorException { |
137 | - if (payload == null) { | ||
138 | - payload = PAYLOAD_VALUES_STR.getBytes(); | ||
139 | - } | ||
140 | CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON); | 149 | CoapResponse coapResponse = client.setTimeout((long) 60000).post(payload, MediaTypeRegistry.APPLICATION_JSON); |
141 | assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode()); | 150 | assertEquals(CoAP.ResponseCode.CREATED, coapResponse.getCode()); |
142 | } | 151 | } |
@@ -174,5 +183,39 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | @@ -174,5 +183,39 @@ public abstract class AbstractCoapTimeseriesIntegrationTest extends AbstractCoap | ||
174 | } | 183 | } |
175 | } | 184 | } |
176 | 185 | ||
186 | + private void assertExplicitProtoFieldValues(Map<String, List<Map<String, Object>>> deviceValues) { | ||
187 | + for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) { | ||
188 | + String key = entry.getKey(); | ||
189 | + List<Map<String, Object>> tsKv = entry.getValue(); | ||
190 | + String value = (String) tsKv.get(0).get("value"); | ||
191 | + switch (key) { | ||
192 | + case "key1": | ||
193 | + assertEquals("", value); | ||
194 | + break; | ||
195 | + case "key2": | ||
196 | + assertEquals("false", value); | ||
197 | + break; | ||
198 | + case "key3": | ||
199 | + assertEquals("0.0", value); | ||
200 | + break; | ||
201 | + case "key4": | ||
202 | + assertEquals("0", value); | ||
203 | + break; | ||
204 | + case "key5": | ||
205 | + assertEquals("{\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value); | ||
206 | + break; | ||
207 | + } | ||
208 | + } | ||
209 | + } | ||
210 | + | ||
211 | + private void assertExplicitProtoFieldValuesWithTs(Map<String, List<Map<String, Object>>> deviceValues) { | ||
212 | + assertEquals(1, deviceValues.size()); | ||
213 | + List<Map<String, Object>> tsKv = deviceValues.get("key5"); | ||
214 | + assertEquals("{\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", tsKv.get(0).get("value")); | ||
215 | + } | ||
216 | + | ||
217 | + private void assertTsForExplicitProtoFieldValues(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { | ||
218 | + assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); | ||
219 | + } | ||
177 | 220 | ||
178 | } | 221 | } |
@@ -32,6 +32,9 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC | @@ -32,6 +32,9 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC | ||
32 | import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; | 32 | import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration; |
33 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; | 33 | import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; |
34 | 34 | ||
35 | +import java.util.Arrays; | ||
36 | +import java.util.Collections; | ||
37 | + | ||
35 | import static org.junit.Assert.assertNotNull; | 38 | import static org.junit.Assert.assertNotNull; |
36 | import static org.junit.Assert.assertTrue; | 39 | import static org.junit.Assert.assertTrue; |
37 | 40 | ||
@@ -84,7 +87,7 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | @@ -84,7 +87,7 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | ||
84 | .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4) | 87 | .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4) |
85 | .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) | 88 | .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) |
86 | .build(); | 89 | .build(); |
87 | - processTestPostTelemetry(postTelemetryMsg.toByteArray(), false); | 90 | + processTestPostTelemetry(postTelemetryMsg.toByteArray(), Arrays.asList("key1", "key2", "key3", "key4", "key5"), false, false); |
88 | } | 91 | } |
89 | 92 | ||
90 | @Test | 93 | @Test |
@@ -94,23 +97,23 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | @@ -94,23 +97,23 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | ||
94 | "package test;\n" + | 97 | "package test;\n" + |
95 | "\n" + | 98 | "\n" + |
96 | "message PostTelemetry {\n" + | 99 | "message PostTelemetry {\n" + |
97 | - " int64 ts = 1;\n" + | 100 | + " optional int64 ts = 1;\n" + |
98 | " Values values = 2;\n" + | 101 | " Values values = 2;\n" + |
99 | " \n" + | 102 | " \n" + |
100 | " message Values {\n" + | 103 | " message Values {\n" + |
101 | - " string key1 = 3;\n" + | ||
102 | - " bool key2 = 4;\n" + | ||
103 | - " double key3 = 5;\n" + | ||
104 | - " int32 key4 = 6;\n" + | 104 | + " optional string key1 = 3;\n" + |
105 | + " optional bool key2 = 4;\n" + | ||
106 | + " optional double key3 = 5;\n" + | ||
107 | + " optional int32 key4 = 6;\n" + | ||
105 | " JsonObject key5 = 7;\n" + | 108 | " JsonObject key5 = 7;\n" + |
106 | " }\n" + | 109 | " }\n" + |
107 | " \n" + | 110 | " \n" + |
108 | " message JsonObject {\n" + | 111 | " message JsonObject {\n" + |
109 | - " int32 someNumber = 8;\n" + | 112 | + " optional int32 someNumber = 8;\n" + |
110 | " repeated int32 someArray = 9;\n" + | 113 | " repeated int32 someArray = 9;\n" + |
111 | " NestedJsonObject someNestedObject = 10;\n" + | 114 | " NestedJsonObject someNestedObject = 10;\n" + |
112 | " message NestedJsonObject {\n" + | 115 | " message NestedJsonObject {\n" + |
113 | - " string key = 11;\n" + | 116 | + " optional string key = 11;\n" + |
114 | " }\n" + | 117 | " }\n" + |
115 | " }\n" + | 118 | " }\n" + |
116 | "}"; | 119 | "}"; |
@@ -164,7 +167,126 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | @@ -164,7 +167,126 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac | ||
164 | .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) | 167 | .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) |
165 | .build(); | 168 | .build(); |
166 | 169 | ||
167 | - processTestPostTelemetry(postTelemetryMsg.toByteArray(), true); | 170 | + processTestPostTelemetry(postTelemetryMsg.toByteArray(), Arrays.asList("key1", "key2", "key3", "key4", "key5"), true, false); |
171 | + } | ||
172 | + | ||
173 | + @Test | ||
174 | + public void testPushTelemetryWithExplicitPresenceProtoKeys() throws Exception { | ||
175 | + super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF); | ||
176 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
177 | + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); | ||
178 | + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; | ||
179 | + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration(); | ||
180 | + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration); | ||
181 | + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration; | ||
182 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration(); | ||
183 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
184 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
185 | + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA); | ||
186 | + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema"); | ||
187 | + | ||
188 | + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); | ||
189 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
190 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
191 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
192 | + | ||
193 | + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject"); | ||
194 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
195 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
196 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
197 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
198 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
199 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
200 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
201 | + .build(); | ||
202 | + | ||
203 | + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry"); | ||
204 | + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType(); | ||
205 | + assertNotNull(postTelemetryMsgDescriptor); | ||
206 | + DynamicMessage postTelemetryMsg = postTelemetryBuilder | ||
207 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "") | ||
208 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key2"), false) | ||
209 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 0.0) | ||
210 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 0) | ||
211 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) | ||
212 | + .build(); | ||
213 | + processTestPostTelemetry(postTelemetryMsg.toByteArray(), Arrays.asList("key1", "key2", "key3", "key4", "key5"), false, true); | ||
214 | + } | ||
215 | + | ||
216 | + @Test | ||
217 | + public void testPushTelemetryWithTsAndNoPresenceFields() throws Exception { | ||
218 | + String schemaStr = "syntax =\"proto3\";\n" + | ||
219 | + "\n" + | ||
220 | + "package test;\n" + | ||
221 | + "\n" + | ||
222 | + "message PostTelemetry {\n" + | ||
223 | + " optional int64 ts = 1;\n" + | ||
224 | + " Values values = 2;\n" + | ||
225 | + " \n" + | ||
226 | + " message Values {\n" + | ||
227 | + " string key1 = 3;\n" + | ||
228 | + " bool key2 = 4;\n" + | ||
229 | + " double key3 = 5;\n" + | ||
230 | + " int32 key4 = 6;\n" + | ||
231 | + " JsonObject key5 = 7;\n" + | ||
232 | + " }\n" + | ||
233 | + " \n" + | ||
234 | + " message JsonObject {\n" + | ||
235 | + " optional int32 someNumber = 8;\n" + | ||
236 | + " repeated int32 someArray = 9;\n" + | ||
237 | + " NestedJsonObject someNestedObject = 10;\n" + | ||
238 | + " message NestedJsonObject {\n" + | ||
239 | + " optional string key = 11;\n" + | ||
240 | + " }\n" + | ||
241 | + " }\n" + | ||
242 | + "}"; | ||
243 | + super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); | ||
244 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
245 | + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration); | ||
246 | + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration; | ||
247 | + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration(); | ||
248 | + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration); | ||
249 | + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration; | ||
250 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration(); | ||
251 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
252 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
253 | + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr); | ||
254 | + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema"); | ||
255 | + | ||
256 | + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); | ||
257 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
258 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
259 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
260 | + | ||
261 | + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject"); | ||
262 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
263 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
264 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
265 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
266 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
267 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
268 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
269 | + .build(); | ||
270 | + | ||
271 | + | ||
272 | + DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values"); | ||
273 | + Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType(); | ||
274 | + assertNotNull(valuesDescriptor); | ||
275 | + | ||
276 | + DynamicMessage valuesMsg = valuesBuilder | ||
277 | + .setField(valuesDescriptor.findFieldByName("key4"), 0) | ||
278 | + .setField(valuesDescriptor.findFieldByName("key5"), jsonObject) | ||
279 | + .build(); | ||
280 | + | ||
281 | + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry"); | ||
282 | + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType(); | ||
283 | + assertNotNull(postTelemetryMsgDescriptor); | ||
284 | + DynamicMessage postTelemetryMsg = postTelemetryBuilder | ||
285 | + .setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L) | ||
286 | + .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) | ||
287 | + .build(); | ||
288 | + | ||
289 | + processTestPostTelemetry(postTelemetryMsg.toByteArray(), Collections.singletonList("key5"), true, true); | ||
168 | } | 290 | } |
169 | 291 | ||
170 | } | 292 | } |
@@ -55,13 +55,13 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | @@ -55,13 +55,13 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | ||
55 | } | 55 | } |
56 | 56 | ||
57 | @Test | 57 | @Test |
58 | - public void testPushMqttAttributes() throws Exception { | 58 | + public void testPushAttributes() throws Exception { |
59 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 59 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
60 | - processAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); | 60 | + processJsonPayloadAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); |
61 | } | 61 | } |
62 | 62 | ||
63 | @Test | 63 | @Test |
64 | - public void testPushMqttAttributesGateway() throws Exception { | 64 | + public void testPushAttributesGateway() throws Exception { |
65 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 65 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
66 | String deviceName1 = "Device A"; | 66 | String deviceName1 = "Device A"; |
67 | String deviceName2 = "Device B"; | 67 | String deviceName2 = "Device B"; |
@@ -69,7 +69,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | @@ -69,7 +69,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | ||
69 | processGatewayAttributesTest(expectedKeys, payload.getBytes(), deviceName1, deviceName2); | 69 | processGatewayAttributesTest(expectedKeys, payload.getBytes(), deviceName1, deviceName2); |
70 | } | 70 | } |
71 | 71 | ||
72 | - protected void processAttributesTest(String topic, List<String> expectedKeys, byte[] payload) throws Exception { | 72 | + protected void processJsonPayloadAttributesTest(String topic, List<String> expectedKeys, byte[] payload) throws Exception { |
73 | + processAttributesTest(topic, expectedKeys, payload, false); | ||
74 | + } | ||
75 | + | ||
76 | + protected void processAttributesTest(String topic, List<String> expectedKeys, byte[] payload, boolean presenceFieldsTest) throws Exception { | ||
73 | MqttAsyncClient client = getMqttAsyncClient(accessToken); | 77 | MqttAsyncClient client = getMqttAsyncClient(accessToken); |
74 | 78 | ||
75 | publishMqttMsg(client, payload, topic); | 79 | publishMqttMsg(client, payload, topic); |
@@ -98,7 +102,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | @@ -98,7 +102,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | ||
98 | 102 | ||
99 | String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); | 103 | String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); |
100 | List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); | 104 | List<Map<String, Object>> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() {}); |
101 | - assertAttributesValues(values, expectedKeySet); | 105 | + if (presenceFieldsTest) { |
106 | + assertAttributesProtoValues(values, actualKeySet); | ||
107 | + } else { | ||
108 | + assertAttributesValues(values, actualKeySet); | ||
109 | + } | ||
102 | String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); | 110 | String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
103 | doDelete(deleteAttributesUrl); | 111 | doDelete(deleteAttributesUrl); |
104 | } | 112 | } |
@@ -145,11 +153,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | @@ -145,11 +153,11 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | ||
145 | } | 153 | } |
146 | 154 | ||
147 | @SuppressWarnings("unchecked") | 155 | @SuppressWarnings("unchecked") |
148 | - protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) throws JsonProcessingException { | 156 | + protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> keySet) throws JsonProcessingException { |
149 | for (Map<String, Object> map : deviceValues) { | 157 | for (Map<String, Object> map : deviceValues) { |
150 | String key = (String) map.get("key"); | 158 | String key = (String) map.get("key"); |
151 | Object value = map.get("value"); | 159 | Object value = map.get("value"); |
152 | - assertTrue(expectedKeySet.contains(key)); | 160 | + assertTrue(keySet.contains(key)); |
153 | switch (key) { | 161 | switch (key) { |
154 | case "key1": | 162 | case "key1": |
155 | assertEquals("value1", value); | 163 | assertEquals("value1", value); |
@@ -175,6 +183,35 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | @@ -175,6 +183,35 @@ public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqtt | ||
175 | } | 183 | } |
176 | } | 184 | } |
177 | 185 | ||
186 | + private void assertAttributesProtoValues(List<Map<String, Object>> values, Set<String> keySet) { | ||
187 | + for (Map<String, Object> map : values) { | ||
188 | + String key = (String) map.get("key"); | ||
189 | + Object value = map.get("value"); | ||
190 | + assertTrue(keySet.contains(key)); | ||
191 | + switch (key) { | ||
192 | + case "key1": | ||
193 | + assertEquals("", value); | ||
194 | + break; | ||
195 | + case "key2": | ||
196 | + assertEquals(false, value); | ||
197 | + break; | ||
198 | + case "key3": | ||
199 | + assertEquals(0.0, value); | ||
200 | + break; | ||
201 | + case "key4": | ||
202 | + assertEquals(0, value); | ||
203 | + break; | ||
204 | + case "key5": | ||
205 | + assertNotNull(value); | ||
206 | + assertEquals(2, ((LinkedHashMap) value).size()); | ||
207 | + assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray")); | ||
208 | + LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject"); | ||
209 | + assertEquals("value", someNestedObject.get("key")); | ||
210 | + break; | ||
211 | + } | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
178 | protected String getGatewayAttributesJsonPayload(String deviceA, String deviceB) { | 215 | protected String getGatewayAttributesJsonPayload(String deviceA, String deviceB) { |
179 | return "{\"" + deviceA + "\": " + PAYLOAD_VALUES_STR + ", \"" + deviceB + "\": " + PAYLOAD_VALUES_STR + "}"; | 216 | return "{\"" + deviceA + "\": " + PAYLOAD_VALUES_STR + ", \"" + deviceB + "\": " + PAYLOAD_VALUES_STR + "}"; |
180 | } | 217 | } |
@@ -40,13 +40,13 @@ public abstract class AbstractMqttAttributesJsonIntegrationTest extends Abstract | @@ -40,13 +40,13 @@ public abstract class AbstractMqttAttributesJsonIntegrationTest extends Abstract | ||
40 | } | 40 | } |
41 | 41 | ||
42 | @Test | 42 | @Test |
43 | - public void testPushMqttAttributes() throws Exception { | 43 | + public void testPushAttributes() throws Exception { |
44 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 44 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
45 | - processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); | 45 | + processJsonPayloadAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); |
46 | } | 46 | } |
47 | 47 | ||
48 | @Test | 48 | @Test |
49 | - public void testPushMqttAttributesGateway() throws Exception { | 49 | + public void testPushAttributesGateway() throws Exception { |
50 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 50 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
51 | String deviceName1 = "Device A"; | 51 | String deviceName1 = "Device A"; |
52 | String deviceName2 = "Device B"; | 52 | String deviceName2 = "Device B"; |
@@ -47,9 +47,8 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac | @@ -47,9 +47,8 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac | ||
47 | } | 47 | } |
48 | 48 | ||
49 | @Test | 49 | @Test |
50 | - public void testPushMqttAttributes() throws Exception { | 50 | + public void testPushAttributes() throws Exception { |
51 | super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); | 51 | super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); |
52 | - List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | ||
53 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | 52 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
54 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | 53 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); |
55 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | 54 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; |
@@ -85,11 +84,51 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac | @@ -85,11 +84,51 @@ public abstract class AbstractMqttAttributesProtoIntegrationTest extends Abstrac | ||
85 | .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4) | 84 | .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 4) |
86 | .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) | 85 | .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) |
87 | .build(); | 86 | .build(); |
88 | - processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, postAttributesMsg.toByteArray()); | 87 | + processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), false); |
88 | + } | ||
89 | + | ||
90 | + @Test | ||
91 | + public void testPushAttributesWithExplicitPresenceProtoKeys() throws Exception { | ||
92 | + super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); | ||
93 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
94 | + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | ||
95 | + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | ||
96 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); | ||
97 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
98 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
99 | + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_ATTRIBUTES_PROTO_SCHEMA); | ||
100 | + DynamicSchema attributesSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.ATTRIBUTES_PROTO_SCHEMA); | ||
101 | + | ||
102 | + DynamicMessage.Builder nestedJsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject.NestedJsonObject"); | ||
103 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
104 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
105 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
106 | + | ||
107 | + DynamicMessage.Builder jsonObjectBuilder = attributesSchema.newMessageBuilder("PostAttributes.JsonObject"); | ||
108 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
109 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
110 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
111 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
112 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
113 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
114 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
115 | + .build(); | ||
116 | + | ||
117 | + DynamicMessage.Builder postAttributesBuilder = attributesSchema.newMessageBuilder("PostAttributes"); | ||
118 | + Descriptors.Descriptor postAttributesMsgDescriptor = postAttributesBuilder.getDescriptorForType(); | ||
119 | + assertNotNull(postAttributesMsgDescriptor); | ||
120 | + DynamicMessage postAttributesMsg = postAttributesBuilder | ||
121 | + .setField(postAttributesMsgDescriptor.findFieldByName("key1"), "") | ||
122 | + .setField(postAttributesMsgDescriptor.findFieldByName("key2"), false) | ||
123 | + .setField(postAttributesMsgDescriptor.findFieldByName("key3"), 0.0) | ||
124 | + .setField(postAttributesMsgDescriptor.findFieldByName("key4"), 0) | ||
125 | + .setField(postAttributesMsgDescriptor.findFieldByName("key5"), jsonObject) | ||
126 | + .build(); | ||
127 | + processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postAttributesMsg.toByteArray(), true); | ||
89 | } | 128 | } |
90 | 129 | ||
91 | @Test | 130 | @Test |
92 | - public void testPushMqttAttributesGateway() throws Exception { | 131 | + public void testPushAttributesGateway() throws Exception { |
93 | super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null); | 132 | super.processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, null); |
94 | TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); | 133 | TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); |
95 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 134 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
@@ -61,20 +61,20 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | @@ -61,20 +61,20 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | ||
61 | } | 61 | } |
62 | 62 | ||
63 | @Test | 63 | @Test |
64 | - public void testPushMqttTelemetry() throws Exception { | 64 | + public void testPushTelemetry() throws Exception { |
65 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 65 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
66 | - processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); | 66 | + processJsonPayloadTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); |
67 | } | 67 | } |
68 | 68 | ||
69 | @Test | 69 | @Test |
70 | - public void testPushMqttTelemetryWithTs() throws Exception { | 70 | + public void testPushTelemetryWithTs() throws Exception { |
71 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; | 71 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; |
72 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 72 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
73 | - processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); | 73 | + processJsonPayloadTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); |
74 | } | 74 | } |
75 | 75 | ||
76 | @Test | 76 | @Test |
77 | - public void testPushMqttTelemetryGateway() throws Exception { | 77 | + public void testPushTelemetryGateway() throws Exception { |
78 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 78 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
79 | String deviceName1 = "Device A"; | 79 | String deviceName1 = "Device A"; |
80 | String deviceName2 = "Device B"; | 80 | String deviceName2 = "Device B"; |
@@ -97,7 +97,11 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | @@ -97,7 +97,11 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | ||
97 | assertNotNull(device); | 97 | assertNotNull(device); |
98 | } | 98 | } |
99 | 99 | ||
100 | - protected void processTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, boolean withTs) throws Exception { | 100 | + protected void processJsonPayloadTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, boolean withTs) throws Exception { |
101 | + processTelemetryTest(topic, expectedKeys, payload, withTs, false); | ||
102 | + } | ||
103 | + | ||
104 | + protected void processTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, boolean withTs, boolean presenceFieldsTest) throws Exception { | ||
101 | MqttAsyncClient client = getMqttAsyncClient(accessToken); | 105 | MqttAsyncClient client = getMqttAsyncClient(accessToken); |
102 | publishMqttMsg(client, payload, topic); | 106 | publishMqttMsg(client, payload, topic); |
103 | 107 | ||
@@ -157,10 +161,19 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | @@ -157,10 +161,19 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | ||
157 | } | 161 | } |
158 | assertNotNull(values); | 162 | assertNotNull(values); |
159 | 163 | ||
160 | - if (withTs) { | ||
161 | - assertTs(values, expectedKeys, 10000, 0); | 164 | + if (presenceFieldsTest) { |
165 | + if (withTs) { | ||
166 | + assertTsForExplicitProtoFieldValues(values, expectedKeys, 10000, 0); | ||
167 | + assertExplicitProtoFieldValuesWithTs(values); | ||
168 | + } else { | ||
169 | + assertExplicitProtoFieldValues(values); | ||
170 | + } | ||
171 | + } else { | ||
172 | + if (withTs) { | ||
173 | + assertTs(values, expectedKeys, 10000, 0); | ||
174 | + } | ||
175 | + assertValues(values, 0); | ||
162 | } | 176 | } |
163 | - assertValues(values, 0); | ||
164 | } | 177 | } |
165 | 178 | ||
166 | protected void processGatewayTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, String firstDeviceName, String secondDeviceName) throws Exception { | 179 | protected void processGatewayTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, String firstDeviceName, String secondDeviceName) throws Exception { |
@@ -254,6 +267,41 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | @@ -254,6 +267,41 @@ public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqtt | ||
254 | } | 267 | } |
255 | } | 268 | } |
256 | 269 | ||
270 | + private void assertExplicitProtoFieldValues(Map<String, List<Map<String, Object>>> deviceValues) { | ||
271 | + for (Map.Entry<String, List<Map<String, Object>>> entry : deviceValues.entrySet()) { | ||
272 | + String key = entry.getKey(); | ||
273 | + List<Map<String, Object>> tsKv = entry.getValue(); | ||
274 | + String value = (String) tsKv.get(0).get("value"); | ||
275 | + switch (key) { | ||
276 | + case "key1": | ||
277 | + assertEquals("", value); | ||
278 | + break; | ||
279 | + case "key2": | ||
280 | + assertEquals("false", value); | ||
281 | + break; | ||
282 | + case "key3": | ||
283 | + assertEquals("0.0", value); | ||
284 | + break; | ||
285 | + case "key4": | ||
286 | + assertEquals("0", value); | ||
287 | + break; | ||
288 | + case "key5": | ||
289 | + assertEquals("{\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value); | ||
290 | + break; | ||
291 | + } | ||
292 | + } | ||
293 | + } | ||
294 | + | ||
295 | + private void assertExplicitProtoFieldValuesWithTs(Map<String, List<Map<String, Object>>> deviceValues) { | ||
296 | + assertEquals(1, deviceValues.size()); | ||
297 | + List<Map<String, Object>> tsKv = deviceValues.get("key5"); | ||
298 | + assertEquals("{\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", tsKv.get(0).get("value")); | ||
299 | + } | ||
300 | + | ||
301 | + private void assertTsForExplicitProtoFieldValues(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { | ||
302 | + assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); | ||
303 | + } | ||
304 | + | ||
257 | private void assertTs(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { | 305 | private void assertTs(Map<String, List<Map<String, Object>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { |
258 | assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); | 306 | assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); |
259 | assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts")); | 307 | assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts")); |
@@ -45,20 +45,20 @@ public abstract class AbstractMqttTimeseriesJsonIntegrationTest extends Abstract | @@ -45,20 +45,20 @@ public abstract class AbstractMqttTimeseriesJsonIntegrationTest extends Abstract | ||
45 | } | 45 | } |
46 | 46 | ||
47 | @Test | 47 | @Test |
48 | - public void testPushMqttTelemetry() throws Exception { | 48 | + public void testPushTelemetry() throws Exception { |
49 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 49 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
50 | - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); | 50 | + processJsonPayloadTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); |
51 | } | 51 | } |
52 | 52 | ||
53 | @Test | 53 | @Test |
54 | - public void testPushMqttTelemetryWithTs() throws Exception { | 54 | + public void testPushTelemetryWithTs() throws Exception { |
55 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; | 55 | String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; |
56 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 56 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
57 | - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); | 57 | + processJsonPayloadTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); |
58 | } | 58 | } |
59 | 59 | ||
60 | @Test | 60 | @Test |
61 | - public void testPushMqttTelemetryGateway() throws Exception { | 61 | + public void testPushTelemetryGateway() throws Exception { |
62 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 62 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
63 | String deviceName1 = "Device A"; | 63 | String deviceName1 = "Device A"; |
64 | String deviceName2 = "Device B"; | 64 | String deviceName2 = "Device B"; |
@@ -22,6 +22,7 @@ import com.squareup.wire.schema.internal.parser.ProtoFileElement; | @@ -22,6 +22,7 @@ import com.squareup.wire.schema.internal.parser.ProtoFileElement; | ||
22 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
23 | import org.eclipse.paho.client.mqttv3.MqttAsyncClient; | 23 | import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
24 | import org.junit.After; | 24 | import org.junit.After; |
25 | +import org.junit.Ignore; | ||
25 | import org.junit.Test; | 26 | import org.junit.Test; |
26 | import org.thingsboard.server.common.data.Device; | 27 | import org.thingsboard.server.common.data.Device; |
27 | import org.thingsboard.server.common.data.DeviceProfileProvisionType; | 28 | import org.thingsboard.server.common.data.DeviceProfileProvisionType; |
@@ -35,6 +36,7 @@ import org.thingsboard.server.gen.transport.TransportApiProtos; | @@ -35,6 +36,7 @@ import org.thingsboard.server.gen.transport.TransportApiProtos; | ||
35 | import org.thingsboard.server.gen.transport.TransportProtos; | 36 | import org.thingsboard.server.gen.transport.TransportProtos; |
36 | 37 | ||
37 | import java.util.Arrays; | 38 | import java.util.Arrays; |
39 | +import java.util.Collections; | ||
38 | import java.util.List; | 40 | import java.util.List; |
39 | 41 | ||
40 | import static org.junit.Assert.assertNotNull; | 42 | import static org.junit.Assert.assertNotNull; |
@@ -51,9 +53,8 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | @@ -51,9 +53,8 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | ||
51 | } | 53 | } |
52 | 54 | ||
53 | @Test | 55 | @Test |
54 | - public void testPushMqttTelemetry() throws Exception { | 56 | + public void testPushTelemetry() throws Exception { |
55 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); | 57 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); |
56 | - List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | ||
57 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | 58 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
58 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | 59 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); |
59 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | 60 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; |
@@ -89,38 +90,37 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | @@ -89,38 +90,37 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | ||
89 | .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4) | 90 | .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 4) |
90 | .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) | 91 | .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) |
91 | .build(); | 92 | .build(); |
92 | - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), false); | 93 | + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, false); |
93 | } | 94 | } |
94 | 95 | ||
95 | @Test | 96 | @Test |
96 | - public void testPushMqttTelemetryWithTs() throws Exception { | 97 | + public void testPushTelemetryWithTs() throws Exception { |
97 | String schemaStr = "syntax =\"proto3\";\n" + | 98 | String schemaStr = "syntax =\"proto3\";\n" + |
98 | "\n" + | 99 | "\n" + |
99 | "package test;\n" + | 100 | "package test;\n" + |
100 | "\n" + | 101 | "\n" + |
101 | "message PostTelemetry {\n" + | 102 | "message PostTelemetry {\n" + |
102 | - " int64 ts = 1;\n" + | 103 | + " optional int64 ts = 1;\n" + |
103 | " Values values = 2;\n" + | 104 | " Values values = 2;\n" + |
104 | " \n" + | 105 | " \n" + |
105 | " message Values {\n" + | 106 | " message Values {\n" + |
106 | - " string key1 = 3;\n" + | ||
107 | - " bool key2 = 4;\n" + | ||
108 | - " double key3 = 5;\n" + | ||
109 | - " int32 key4 = 6;\n" + | 107 | + " optional string key1 = 3;\n" + |
108 | + " optional bool key2 = 4;\n" + | ||
109 | + " optional double key3 = 5;\n" + | ||
110 | + " optional int32 key4 = 6;\n" + | ||
110 | " JsonObject key5 = 7;\n" + | 111 | " JsonObject key5 = 7;\n" + |
111 | " }\n" + | 112 | " }\n" + |
112 | " \n" + | 113 | " \n" + |
113 | " message JsonObject {\n" + | 114 | " message JsonObject {\n" + |
114 | - " int32 someNumber = 8;\n" + | 115 | + " optional int32 someNumber = 8;\n" + |
115 | " repeated int32 someArray = 9;\n" + | 116 | " repeated int32 someArray = 9;\n" + |
116 | " NestedJsonObject someNestedObject = 10;\n" + | 117 | " NestedJsonObject someNestedObject = 10;\n" + |
117 | " message NestedJsonObject {\n" + | 118 | " message NestedJsonObject {\n" + |
118 | - " string key = 11;\n" + | 119 | + " optional string key = 11;\n" + |
119 | " }\n" + | 120 | " }\n" + |
120 | " }\n" + | 121 | " }\n" + |
121 | "}"; | 122 | "}"; |
122 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); | 123 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); |
123 | - List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | ||
124 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | 124 | DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); |
125 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | 125 | assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); |
126 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | 126 | MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; |
@@ -167,11 +167,124 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | @@ -167,11 +167,124 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac | ||
167 | .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) | 167 | .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) |
168 | .build(); | 168 | .build(); |
169 | 169 | ||
170 | - processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, postTelemetryMsg.toByteArray(), true); | 170 | + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), true, false); |
171 | + } | ||
172 | + | ||
173 | + @Test | ||
174 | + public void testPushTelemetryWithExplicitPresenceProtoKeys() throws Exception { | ||
175 | + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); | ||
176 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
177 | + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | ||
178 | + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | ||
179 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); | ||
180 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
181 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
182 | + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_TELEMETRY_PROTO_SCHEMA); | ||
183 | + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema"); | ||
184 | + | ||
185 | + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); | ||
186 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
187 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
188 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
189 | + | ||
190 | + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject"); | ||
191 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
192 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
193 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
194 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
195 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
196 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
197 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
198 | + .build(); | ||
199 | + | ||
200 | + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry"); | ||
201 | + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType(); | ||
202 | + assertNotNull(postTelemetryMsgDescriptor); | ||
203 | + DynamicMessage postTelemetryMsg = postTelemetryBuilder | ||
204 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key1"), "") | ||
205 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key2"), false) | ||
206 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key3"), 0.0) | ||
207 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key4"), 0) | ||
208 | + .setField(postTelemetryMsgDescriptor.findFieldByName("key5"), jsonObject) | ||
209 | + .build(); | ||
210 | + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Arrays.asList("key1", "key2", "key3", "key4", "key5"), postTelemetryMsg.toByteArray(), false, true); | ||
211 | + } | ||
212 | + | ||
213 | + @Test | ||
214 | + public void testPushTelemetryWithTsAndNoPresenceFields() throws Exception { | ||
215 | + String schemaStr = "syntax =\"proto3\";\n" + | ||
216 | + "\n" + | ||
217 | + "package test;\n" + | ||
218 | + "\n" + | ||
219 | + "message PostTelemetry {\n" + | ||
220 | + " optional int64 ts = 1;\n" + | ||
221 | + " Values values = 2;\n" + | ||
222 | + " \n" + | ||
223 | + " message Values {\n" + | ||
224 | + " string key1 = 3;\n" + | ||
225 | + " bool key2 = 4;\n" + | ||
226 | + " double key3 = 5;\n" + | ||
227 | + " int32 key4 = 6;\n" + | ||
228 | + " JsonObject key5 = 7;\n" + | ||
229 | + " }\n" + | ||
230 | + " \n" + | ||
231 | + " message JsonObject {\n" + | ||
232 | + " optional int32 someNumber = 8;\n" + | ||
233 | + " repeated int32 someArray = 9;\n" + | ||
234 | + " NestedJsonObject someNestedObject = 10;\n" + | ||
235 | + " message NestedJsonObject {\n" + | ||
236 | + " optional string key = 11;\n" + | ||
237 | + " }\n" + | ||
238 | + " }\n" + | ||
239 | + "}"; | ||
240 | + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); | ||
241 | + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); | ||
242 | + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration); | ||
243 | + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; | ||
244 | + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); | ||
245 | + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration); | ||
246 | + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | ||
247 | + ProtoFileElement transportProtoSchema = protoTransportPayloadConfiguration.getTransportProtoSchema(schemaStr); | ||
248 | + DynamicSchema telemetrySchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchema, "telemetrySchema"); | ||
249 | + | ||
250 | + DynamicMessage.Builder nestedJsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject.NestedJsonObject"); | ||
251 | + Descriptors.Descriptor nestedJsonObjectBuilderDescriptor = nestedJsonObjectBuilder.getDescriptorForType(); | ||
252 | + assertNotNull(nestedJsonObjectBuilderDescriptor); | ||
253 | + DynamicMessage nestedJsonObject = nestedJsonObjectBuilder.setField(nestedJsonObjectBuilderDescriptor.findFieldByName("key"), "value").build(); | ||
254 | + | ||
255 | + DynamicMessage.Builder jsonObjectBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.JsonObject"); | ||
256 | + Descriptors.Descriptor jsonObjectBuilderDescriptor = jsonObjectBuilder.getDescriptorForType(); | ||
257 | + assertNotNull(jsonObjectBuilderDescriptor); | ||
258 | + DynamicMessage jsonObject = jsonObjectBuilder | ||
259 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 1) | ||
260 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 2) | ||
261 | + .addRepeatedField(jsonObjectBuilderDescriptor.findFieldByName("someArray"), 3) | ||
262 | + .setField(jsonObjectBuilderDescriptor.findFieldByName("someNestedObject"), nestedJsonObject) | ||
263 | + .build(); | ||
264 | + | ||
265 | + | ||
266 | + DynamicMessage.Builder valuesBuilder = telemetrySchema.newMessageBuilder("PostTelemetry.Values"); | ||
267 | + Descriptors.Descriptor valuesDescriptor = valuesBuilder.getDescriptorForType(); | ||
268 | + assertNotNull(valuesDescriptor); | ||
269 | + | ||
270 | + DynamicMessage valuesMsg = valuesBuilder | ||
271 | + .setField(valuesDescriptor.findFieldByName("key4"), 0) | ||
272 | + .setField(valuesDescriptor.findFieldByName("key5"), jsonObject) | ||
273 | + .build(); | ||
274 | + | ||
275 | + DynamicMessage.Builder postTelemetryBuilder = telemetrySchema.newMessageBuilder("PostTelemetry"); | ||
276 | + Descriptors.Descriptor postTelemetryMsgDescriptor = postTelemetryBuilder.getDescriptorForType(); | ||
277 | + assertNotNull(postTelemetryMsgDescriptor); | ||
278 | + DynamicMessage postTelemetryMsg = postTelemetryBuilder | ||
279 | + .setField(postTelemetryMsgDescriptor.findFieldByName("ts"), 10000L) | ||
280 | + .setField(postTelemetryMsgDescriptor.findFieldByName("values"), valuesMsg) | ||
281 | + .build(); | ||
282 | + | ||
283 | + processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, Collections.singletonList("key5"), postTelemetryMsg.toByteArray(), true, true); | ||
171 | } | 284 | } |
172 | 285 | ||
173 | @Test | 286 | @Test |
174 | - public void testPushMqttTelemetryGateway() throws Exception { | 287 | + public void testPushTelemetryGateway() throws Exception { |
175 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); | 288 | super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED); |
176 | TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); | 289 | TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); |
177 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); | 290 | List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
@@ -47,6 +47,7 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC | @@ -47,6 +47,7 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC | ||
47 | public static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema"; | 47 | public static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema"; |
48 | public static final String RPC_RESPONSE_PROTO_SCHEMA = "rpc response proto schema"; | 48 | public static final String RPC_RESPONSE_PROTO_SCHEMA = "rpc response proto schema"; |
49 | public static final String RPC_REQUEST_PROTO_SCHEMA = "rpc request proto schema"; | 49 | public static final String RPC_REQUEST_PROTO_SCHEMA = "rpc request proto schema"; |
50 | + private static final String PROTO_3_SYNTAX = "proto3"; | ||
50 | 51 | ||
51 | private String deviceTelemetryProtoSchema; | 52 | private String deviceTelemetryProtoSchema; |
52 | private String deviceAttributesProtoSchema; | 53 | private String deviceAttributesProtoSchema; |
@@ -123,6 +124,7 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC | @@ -123,6 +124,7 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC | ||
123 | public DynamicSchema getDynamicSchema(ProtoFileElement protoFileElement, String schemaName) { | 124 | public DynamicSchema getDynamicSchema(ProtoFileElement protoFileElement, String schemaName) { |
124 | DynamicSchema.Builder schemaBuilder = DynamicSchema.newBuilder(); | 125 | DynamicSchema.Builder schemaBuilder = DynamicSchema.newBuilder(); |
125 | schemaBuilder.setName(schemaName); | 126 | schemaBuilder.setName(schemaName); |
127 | + schemaBuilder.setSyntax(PROTO_3_SYNTAX); | ||
126 | schemaBuilder.setPackage(!isEmptyStr(protoFileElement.getPackageName()) ? | 128 | schemaBuilder.setPackage(!isEmptyStr(protoFileElement.getPackageName()) ? |
127 | protoFileElement.getPackageName() : schemaName.toLowerCase()); | 129 | protoFileElement.getPackageName() : schemaName.toLowerCase()); |
128 | List<TypeElement> types = protoFileElement.getTypes(); | 130 | List<TypeElement> types = protoFileElement.getTypes(); |
@@ -160,7 +160,7 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor { | @@ -160,7 +160,7 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor { | ||
160 | 160 | ||
161 | private String dynamicMsgToJson(byte[] bytes, Descriptors.Descriptor descriptor) throws InvalidProtocolBufferException { | 161 | private String dynamicMsgToJson(byte[] bytes, Descriptors.Descriptor descriptor) throws InvalidProtocolBufferException { |
162 | DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, bytes); | 162 | DynamicMessage dynamicMessage = DynamicMessage.parseFrom(descriptor, bytes); |
163 | - return JsonFormat.printer().includingDefaultValueFields().print(dynamicMessage); | 163 | + return JsonFormat.printer().print(dynamicMessage); |
164 | } | 164 | } |
165 | 165 | ||
166 | } | 166 | } |
@@ -82,6 +82,7 @@ import java.util.concurrent.locks.Lock; | @@ -82,6 +82,7 @@ import java.util.concurrent.locks.Lock; | ||
82 | import java.util.concurrent.locks.ReentrantLock; | 82 | import java.util.concurrent.locks.ReentrantLock; |
83 | import java.util.stream.Collectors; | 83 | import java.util.stream.Collectors; |
84 | 84 | ||
85 | +import static com.google.protobuf.FieldType.MESSAGE; | ||
85 | import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE; | 86 | import static org.thingsboard.server.common.data.CacheConstants.DEVICE_PROFILE_CACHE; |
86 | import static org.thingsboard.server.dao.service.Validator.validateId; | 87 | import static org.thingsboard.server.dao.service.Validator.validateId; |
87 | 88 | ||
@@ -381,6 +382,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -381,6 +382,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
381 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = | 382 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = |
382 | (ProtoTransportPayloadConfiguration) mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); | 383 | (ProtoTransportPayloadConfiguration) mqttTransportConfiguration.getTransportPayloadTypeConfiguration(); |
383 | validateProtoSchemas(protoTransportPayloadConfiguration); | 384 | validateProtoSchemas(protoTransportPayloadConfiguration); |
385 | + validateTelemetryDynamicMessageFields(protoTransportPayloadConfiguration); | ||
384 | validateRpcRequestDynamicMessageFields(protoTransportPayloadConfiguration); | 386 | validateRpcRequestDynamicMessageFields(protoTransportPayloadConfiguration); |
385 | } | 387 | } |
386 | } else if (transportConfiguration instanceof CoapDeviceProfileTransportConfiguration) { | 388 | } else if (transportConfiguration instanceof CoapDeviceProfileTransportConfiguration) { |
@@ -392,6 +394,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -392,6 +394,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
392 | if (transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration) { | 394 | if (transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration) { |
393 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; | 395 | ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration; |
394 | validateProtoSchemas(protoTransportPayloadConfiguration); | 396 | validateProtoSchemas(protoTransportPayloadConfiguration); |
397 | + validateTelemetryDynamicMessageFields(protoTransportPayloadConfiguration); | ||
395 | validateRpcRequestDynamicMessageFields(protoTransportPayloadConfiguration); | 398 | validateRpcRequestDynamicMessageFields(protoTransportPayloadConfiguration); |
396 | } | 399 | } |
397 | } | 400 | } |
@@ -609,6 +612,33 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | @@ -609,6 +612,33 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D | ||
609 | 612 | ||
610 | }; | 613 | }; |
611 | 614 | ||
615 | + private void validateTelemetryDynamicMessageFields(ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration) { | ||
616 | + String deviceTelemetryProtoSchema = protoTransportPayloadTypeConfiguration.getDeviceTelemetryProtoSchema(); | ||
617 | + Descriptors.Descriptor telemetryDynamicMessageDescriptor = protoTransportPayloadTypeConfiguration.getTelemetryDynamicMessageDescriptor(deviceTelemetryProtoSchema); | ||
618 | + if (telemetryDynamicMessageDescriptor == null) { | ||
619 | + throw new DataValidationException(invalidSchemaProvidedMessage(TELEMETRY_PROTO_SCHEMA) + " Failed to get telemetryDynamicMessageDescriptor!"); | ||
620 | + } else { | ||
621 | + List<Descriptors.FieldDescriptor> fields = telemetryDynamicMessageDescriptor.getFields(); | ||
622 | + if (CollectionUtils.isEmpty(fields)) { | ||
623 | + throw new DataValidationException(invalidSchemaProvidedMessage(TELEMETRY_PROTO_SCHEMA) + " " + telemetryDynamicMessageDescriptor.getName() + " fields is empty!"); | ||
624 | + } else if (fields.size() == 2) { | ||
625 | + Descriptors.FieldDescriptor tsFieldDescriptor = telemetryDynamicMessageDescriptor.findFieldByName("ts"); | ||
626 | + Descriptors.FieldDescriptor valuesFieldDescriptor = telemetryDynamicMessageDescriptor.findFieldByName("values"); | ||
627 | + if (tsFieldDescriptor != null && valuesFieldDescriptor != null) { | ||
628 | + if (!Descriptors.FieldDescriptor.Type.MESSAGE.equals(valuesFieldDescriptor.getType())) { | ||
629 | + throw new DataValidationException(invalidSchemaProvidedMessage(TELEMETRY_PROTO_SCHEMA) + " Field 'values' has invalid data type. Only message type is supported!"); | ||
630 | + } | ||
631 | + if (!Descriptors.FieldDescriptor.Type.INT64.equals(tsFieldDescriptor.getType())) { | ||
632 | + throw new DataValidationException(invalidSchemaProvidedMessage(TELEMETRY_PROTO_SCHEMA) + " Field 'ts' has invalid data type. Only int64 type is supported!"); | ||
633 | + } | ||
634 | + if (!tsFieldDescriptor.hasOptionalKeyword()) { | ||
635 | + throw new DataValidationException(invalidSchemaProvidedMessage(TELEMETRY_PROTO_SCHEMA) + " Field 'ts' has invalid label. Field 'ts' should have optional keyword!"); | ||
636 | + } | ||
637 | + } | ||
638 | + } | ||
639 | + } | ||
640 | + } | ||
641 | + | ||
612 | private void validateRpcRequestDynamicMessageFields(ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration) { | 642 | private void validateRpcRequestDynamicMessageFields(ProtoTransportPayloadConfiguration protoTransportPayloadTypeConfiguration) { |
613 | DynamicMessage.Builder rpcRequestDynamicMessageBuilder = protoTransportPayloadTypeConfiguration.getRpcRequestDynamicMessageBuilder(protoTransportPayloadTypeConfiguration.getDeviceRpcRequestProtoSchema()); | 643 | DynamicMessage.Builder rpcRequestDynamicMessageBuilder = protoTransportPayloadTypeConfiguration.getRpcRequestDynamicMessageBuilder(protoTransportPayloadTypeConfiguration.getDeviceRpcRequestProtoSchema()); |
614 | Descriptors.Descriptor rpcRequestDynamicMessageDescriptor = rpcRequestDynamicMessageBuilder.getDescriptorForType(); | 644 | Descriptors.Descriptor rpcRequestDynamicMessageDescriptor = rpcRequestDynamicMessageBuilder.getDescriptorForType(); |
@@ -133,16 +133,16 @@ export const defaultTelemetrySchema = | @@ -133,16 +133,16 @@ export const defaultTelemetrySchema = | ||
133 | '\n' + | 133 | '\n' + |
134 | 'message SensorDataReading {\n' + | 134 | 'message SensorDataReading {\n' + |
135 | '\n' + | 135 | '\n' + |
136 | - ' double temperature = 1;\n' + | ||
137 | - ' double humidity = 2;\n' + | 136 | + ' optional double temperature = 1;\n' + |
137 | + ' optional double humidity = 2;\n' + | ||
138 | ' InnerObject innerObject = 3;\n' + | 138 | ' InnerObject innerObject = 3;\n' + |
139 | '\n' + | 139 | '\n' + |
140 | ' message InnerObject {\n' + | 140 | ' message InnerObject {\n' + |
141 | - ' string key1 = 1;\n' + | ||
142 | - ' bool key2 = 2;\n' + | ||
143 | - ' double key3 = 3;\n' + | ||
144 | - ' int32 key4 = 4;\n' + | ||
145 | - ' string key5 = 5;\n' + | 141 | + ' optional string key1 = 1;\n' + |
142 | + ' optional bool key2 = 2;\n' + | ||
143 | + ' optional double key3 = 3;\n' + | ||
144 | + ' optional int32 key4 = 4;\n' + | ||
145 | + ' optional string key5 = 5;\n' + | ||
146 | ' }\n' + | 146 | ' }\n' + |
147 | '}\n'; | 147 | '}\n'; |
148 | 148 | ||
@@ -151,8 +151,8 @@ export const defaultAttributesSchema = | @@ -151,8 +151,8 @@ export const defaultAttributesSchema = | ||
151 | 'package attributes;\n' + | 151 | 'package attributes;\n' + |
152 | '\n' + | 152 | '\n' + |
153 | 'message SensorConfiguration {\n' + | 153 | 'message SensorConfiguration {\n' + |
154 | - ' string firmwareVersion = 1;\n' + | ||
155 | - ' string serialNumber = 2;\n' + | 154 | + ' optional string firmwareVersion = 1;\n' + |
155 | + ' optional string serialNumber = 2;\n' + | ||
156 | '}'; | 156 | '}'; |
157 | 157 | ||
158 | export const defaultRpcRequestSchema = | 158 | export const defaultRpcRequestSchema = |
@@ -160,9 +160,9 @@ export const defaultRpcRequestSchema = | @@ -160,9 +160,9 @@ export const defaultRpcRequestSchema = | ||
160 | 'package rpc;\n' + | 160 | 'package rpc;\n' + |
161 | '\n' + | 161 | '\n' + |
162 | 'message RpcRequestMsg {\n' + | 162 | 'message RpcRequestMsg {\n' + |
163 | - ' string method = 1;\n' + | ||
164 | - ' int32 requestId = 2;\n' + | ||
165 | - ' string params = 3;\n' + | 163 | + ' optional string method = 1;\n' + |
164 | + ' optional int32 requestId = 2;\n' + | ||
165 | + ' optional string params = 3;\n' + | ||
166 | '}'; | 166 | '}'; |
167 | 167 | ||
168 | export const defaultRpcResponseSchema = | 168 | export const defaultRpcResponseSchema = |
@@ -170,7 +170,7 @@ export const defaultRpcResponseSchema = | @@ -170,7 +170,7 @@ export const defaultRpcResponseSchema = | ||
170 | 'package rpc;\n' + | 170 | 'package rpc;\n' + |
171 | '\n' + | 171 | '\n' + |
172 | 'message RpcResponseMsg {\n' + | 172 | 'message RpcResponseMsg {\n' + |
173 | - ' string payload = 1;\n' + | 173 | + ' optional string payload = 1;\n' + |
174 | '}'; | 174 | '}'; |
175 | 175 | ||
176 | export const coapDeviceTypeTranslationMap = new Map<CoapTransportDeviceType, string>( | 176 | export const coapDeviceTypeTranslationMap = new Map<CoapTransportDeviceType, string>( |