225 changed files with 9908 additions and 2542 deletions
@ -0,0 +1,246 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; |
|||
import org.junit.Assert; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.DeviceProfileType; |
|||
import org.thingsboard.server.common.data.DeviceTransportType; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
|||
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.controller.AbstractControllerTest; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
import java.util.function.Supplier; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttIntegrationTest extends AbstractControllerTest { |
|||
|
|||
protected static final String MQTT_URL = "tcp://localhost:1883"; |
|||
|
|||
private static final AtomicInteger atomicInteger = new AtomicInteger(2); |
|||
|
|||
protected Tenant savedTenant; |
|||
protected User tenantAdmin; |
|||
|
|||
protected Device savedDevice; |
|||
protected String accessToken; |
|||
|
|||
protected Device savedGateway; |
|||
protected String gatewayAccessToken; |
|||
|
|||
protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { |
|||
loginSysAdmin(); |
|||
|
|||
Tenant tenant = new Tenant(); |
|||
tenant.setTitle("My tenant"); |
|||
savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
|||
Assert.assertNotNull(savedTenant); |
|||
|
|||
tenantAdmin = new User(); |
|||
tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
|||
tenantAdmin.setTenantId(savedTenant.getId()); |
|||
tenantAdmin.setEmail("tenant" + atomicInteger.getAndIncrement() + "@thingsboard.org"); |
|||
tenantAdmin.setFirstName("Joe"); |
|||
tenantAdmin.setLastName("Downs"); |
|||
|
|||
tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
|||
|
|||
Device device = new Device(); |
|||
device.setName(deviceName); |
|||
device.setType("default"); |
|||
|
|||
Device gateway = new Device(); |
|||
gateway.setName(gatewayName); |
|||
gateway.setType("default"); |
|||
ObjectNode additionalInfo = mapper.createObjectNode(); |
|||
additionalInfo.put("gateway", true); |
|||
gateway.setAdditionalInfo(additionalInfo); |
|||
|
|||
if (payloadType != null) { |
|||
DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic); |
|||
DeviceProfile savedDeviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class); |
|||
device.setType(savedDeviceProfile.getName()); |
|||
device.setDeviceProfileId(savedDeviceProfile.getId()); |
|||
gateway.setType(savedDeviceProfile.getName()); |
|||
gateway.setDeviceProfileId(savedDeviceProfile.getId()); |
|||
} |
|||
|
|||
savedDevice = doPost("/api/device", device, Device.class); |
|||
|
|||
DeviceCredentials deviceCredentials = |
|||
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
|||
|
|||
savedGateway = doPost("/api/device", gateway, Device.class); |
|||
|
|||
DeviceCredentials gatewayCredentials = |
|||
doGet("/api/device/" + savedGateway.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
|||
|
|||
assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); |
|||
accessToken = deviceCredentials.getCredentialsId(); |
|||
assertNotNull(accessToken); |
|||
|
|||
assertEquals(savedGateway.getId(), gatewayCredentials.getDeviceId()); |
|||
gatewayAccessToken = gatewayCredentials.getCredentialsId(); |
|||
assertNotNull(gatewayAccessToken); |
|||
|
|||
} |
|||
|
|||
protected void processAfterTest() throws Exception { |
|||
loginSysAdmin(); |
|||
if (savedTenant != null) { |
|||
doDelete("/api/tenant/" + savedTenant.getId().getId().toString()).andExpect(status().isOk()); |
|||
} |
|||
} |
|||
|
|||
protected MqttAsyncClient getMqttAsyncClient(String accessToken) throws MqttException { |
|||
String clientId = MqttAsyncClient.generateClientId(); |
|||
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); |
|||
|
|||
MqttConnectOptions options = new MqttConnectOptions(); |
|||
options.setUserName(accessToken); |
|||
client.connect(options).waitForCompletion(); |
|||
return client; |
|||
} |
|||
|
|||
protected void publishMqttMsg(MqttAsyncClient client, byte[] payload, String topic) throws MqttException { |
|||
MqttMessage message = new MqttMessage(); |
|||
message.setPayload(payload); |
|||
client.publish(topic, message); |
|||
} |
|||
|
|||
protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) { |
|||
List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>(); |
|||
TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V); |
|||
TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V); |
|||
TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "3.0", TransportProtos.KeyValueType.DOUBLE_V); |
|||
TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "4", TransportProtos.KeyValueType.LONG_V); |
|||
TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V); |
|||
keyValueProtos.add(strKeyValueProto); |
|||
keyValueProtos.add(boolKeyValueProto); |
|||
keyValueProtos.add(dblKeyValueProto); |
|||
keyValueProtos.add(longKeyValueProto); |
|||
keyValueProtos.add(jsonKeyValueProto); |
|||
return keyValueProtos; |
|||
} |
|||
|
|||
protected TransportProtos.KeyValueProto getKeyValueProto(String key, String strValue, TransportProtos.KeyValueType type) { |
|||
TransportProtos.KeyValueProto.Builder keyValueProtoBuilder = TransportProtos.KeyValueProto.newBuilder(); |
|||
keyValueProtoBuilder.setKey(key); |
|||
keyValueProtoBuilder.setType(type); |
|||
switch (type) { |
|||
case BOOLEAN_V: |
|||
keyValueProtoBuilder.setBoolV(Boolean.parseBoolean(strValue)); |
|||
break; |
|||
case LONG_V: |
|||
keyValueProtoBuilder.setLongV(Long.parseLong(strValue)); |
|||
break; |
|||
case DOUBLE_V: |
|||
keyValueProtoBuilder.setDoubleV(Double.parseDouble(strValue)); |
|||
break; |
|||
case STRING_V: |
|||
keyValueProtoBuilder.setStringV(strValue); |
|||
break; |
|||
case JSON_V: |
|||
keyValueProtoBuilder.setJsonV(strValue); |
|||
break; |
|||
} |
|||
return keyValueProtoBuilder.build(); |
|||
} |
|||
|
|||
protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType, String telemetryTopic, String attributesTopic) { |
|||
DeviceProfile deviceProfile = new DeviceProfile(); |
|||
deviceProfile.setName(transportPayloadType.name()); |
|||
deviceProfile.setType(DeviceProfileType.DEFAULT); |
|||
deviceProfile.setTransportType(DeviceTransportType.MQTT); |
|||
deviceProfile.setDescription(transportPayloadType.name() + " Test"); |
|||
DeviceProfileData deviceProfileData = new DeviceProfileData(); |
|||
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration(); |
|||
MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); |
|||
transportConfiguration.setTransportPayloadType(transportPayloadType); |
|||
if (!StringUtils.isEmpty(telemetryTopic)) { |
|||
transportConfiguration.setDeviceTelemetryTopic(telemetryTopic); |
|||
} |
|||
if (!StringUtils.isEmpty(attributesTopic)) { |
|||
transportConfiguration.setDeviceAttributesTopic(attributesTopic); |
|||
} |
|||
deviceProfileData.setTransportConfiguration(transportConfiguration); |
|||
deviceProfileData.setConfiguration(configuration); |
|||
deviceProfile.setProfileData(deviceProfileData); |
|||
deviceProfile.setDefault(false); |
|||
deviceProfile.setDefaultRuleChainId(null); |
|||
return deviceProfile; |
|||
} |
|||
|
|||
protected TransportProtos.PostAttributeMsg getPostAttributeMsg(List<String> expectedKeys) { |
|||
List<TransportProtos.KeyValueProto> kvProtos = getKvProtos(expectedKeys); |
|||
TransportProtos.PostAttributeMsg.Builder builder = TransportProtos.PostAttributeMsg.newBuilder(); |
|||
builder.addAllKv(kvProtos); |
|||
return builder.build(); |
|||
} |
|||
|
|||
protected <T> T doExecuteWithRetriesAndInterval(SupplierWithThrowable<T> supplier, int retries, int intervalMs) throws Exception { |
|||
int count = 0; |
|||
T result = null; |
|||
Throwable lastException = null; |
|||
while (count < retries) { |
|||
try { |
|||
result = supplier.get(); |
|||
if (result != null) { |
|||
return result; |
|||
} |
|||
} catch (Throwable e) { |
|||
lastException = e; |
|||
} |
|||
count++; |
|||
if (count < retries) { |
|||
Thread.sleep(intervalMs); |
|||
} |
|||
} |
|||
if (lastException != null) { |
|||
throw new RuntimeException(lastException); |
|||
} else { |
|||
return result; |
|||
} |
|||
} |
|||
|
|||
@FunctionalInterface |
|||
public interface SupplierWithThrowable<T> { |
|||
T get() throws Throwable; |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.concurrent.CountDownLatch; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqttIntegrationTest { |
|||
|
|||
protected static final String POST_ATTRIBUTES_PAYLOAD = "{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73," + |
|||
"\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}"; |
|||
|
|||
protected void processBeforeTest(String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception { |
|||
super.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic); |
|||
} |
|||
|
|||
protected void processAfterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
protected List<TransportProtos.TsKvProto> getTsKvProtoList() { |
|||
TransportProtos.TsKvProto tsKvProtoAttribute1 = getTsKvProto("attribute1", "value1", TransportProtos.KeyValueType.STRING_V); |
|||
TransportProtos.TsKvProto tsKvProtoAttribute2 = getTsKvProto("attribute2", "true", TransportProtos.KeyValueType.BOOLEAN_V); |
|||
TransportProtos.TsKvProto tsKvProtoAttribute3 = getTsKvProto("attribute3", "42.0", TransportProtos.KeyValueType.DOUBLE_V); |
|||
TransportProtos.TsKvProto tsKvProtoAttribute4 = getTsKvProto("attribute4", "73", TransportProtos.KeyValueType.LONG_V); |
|||
TransportProtos.TsKvProto tsKvProtoAttribute5 = getTsKvProto("attribute5", "{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", TransportProtos.KeyValueType.JSON_V); |
|||
List<TransportProtos.TsKvProto> tsKvProtoList = new ArrayList<>(); |
|||
tsKvProtoList.add(tsKvProtoAttribute1); |
|||
tsKvProtoList.add(tsKvProtoAttribute2); |
|||
tsKvProtoList.add(tsKvProtoAttribute3); |
|||
tsKvProtoList.add(tsKvProtoAttribute4); |
|||
tsKvProtoList.add(tsKvProtoAttribute5); |
|||
return tsKvProtoList; |
|||
} |
|||
|
|||
|
|||
protected TransportProtos.TsKvProto getTsKvProto(String key, String value, TransportProtos.KeyValueType keyValueType) { |
|||
TransportProtos.TsKvProto.Builder tsKvProtoBuilder = TransportProtos.TsKvProto.newBuilder(); |
|||
TransportProtos.KeyValueProto keyValueProto = getKeyValueProto(key, value, keyValueType); |
|||
tsKvProtoBuilder.setKv(keyValueProto); |
|||
return tsKvProtoBuilder.build(); |
|||
} |
|||
|
|||
protected TestMqttCallback getTestMqttCallback() { |
|||
CountDownLatch latch = new CountDownLatch(1); |
|||
return new TestMqttCallback(latch); |
|||
} |
|||
|
|||
protected static class TestMqttCallback implements MqttCallback { |
|||
|
|||
private final CountDownLatch latch; |
|||
private Integer qoS; |
|||
private byte[] payloadBytes; |
|||
|
|||
TestMqttCallback(CountDownLatch latch) { |
|||
this.latch = latch; |
|||
} |
|||
|
|||
public int getQoS() { |
|||
return qoS; |
|||
} |
|||
|
|||
public byte[] getPayloadBytes() { |
|||
return payloadBytes; |
|||
} |
|||
|
|||
public CountDownLatch getLatch() { |
|||
return latch; |
|||
} |
|||
|
|||
@Override |
|||
public void connectionLost(Throwable throwable) { |
|||
} |
|||
|
|||
@Override |
|||
public void messageArrived(String requestTopic, MqttMessage mqttMessage) throws Exception { |
|||
qoS = mqttMessage.getQos(); |
|||
payloadBytes = mqttMessage.getPayload(); |
|||
latch.countDown(); |
|||
} |
|||
|
|||
@Override |
|||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { |
|||
|
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,154 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertFalse; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesRequestIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Request attribute values from the server", "Gateway Test Request attribute values from the server", null, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServer() throws Exception { |
|||
processTestRequestAttributesValuesFromTheServer(); |
|||
} |
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServerGateway() throws Exception { |
|||
processTestGatewayRequestAttributesValuesFromTheServer(); |
|||
} |
|||
|
|||
protected void processTestRequestAttributesValuesFromTheServer() throws Exception { |
|||
|
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
|
|||
postAttributesAndSubscribeToTopic(savedDevice, client); |
|||
|
|||
Thread.sleep(1000); |
|||
|
|||
TestMqttCallback callback = getTestMqttCallback(); |
|||
client.setCallback(callback); |
|||
|
|||
validateResponse(client, callback.getLatch(), callback); |
|||
} |
|||
|
|||
protected void processTestGatewayRequestAttributesValuesFromTheServer() throws Exception { |
|||
|
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
|
|||
postGatewayDeviceClientAttributes(client); |
|||
|
|||
Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Request Attributes", Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(savedDevice); |
|||
|
|||
Thread.sleep(1000); |
|||
|
|||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); |
|||
|
|||
Thread.sleep(1000); |
|||
|
|||
client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, MqttQoS.AT_LEAST_ONCE.value()); |
|||
|
|||
TestMqttCallback clientAttributesCallback = getTestMqttCallback(); |
|||
client.setCallback(clientAttributesCallback); |
|||
validateClientResponseGateway(client, clientAttributesCallback); |
|||
|
|||
TestMqttCallback sharedAttributesCallback = getTestMqttCallback(); |
|||
client.setCallback(sharedAttributesCallback); |
|||
validateSharedResponseGateway(client, sharedAttributesCallback); |
|||
} |
|||
|
|||
protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception { |
|||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); |
|||
client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(POST_ATTRIBUTES_PAYLOAD.getBytes())); |
|||
client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
} |
|||
|
|||
protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { |
|||
String postClientAttributes = "{\"" + "Gateway Device Request Attributes" + "\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(postClientAttributes.getBytes())); |
|||
} |
|||
|
|||
protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
String payloadStr = "{\"clientKeys\":\"" + keys + "\", \"sharedKeys\":\"" + keys + "\"}"; |
|||
MqttMessage mqttMessage = new MqttMessage(); |
|||
mqttMessage.setPayload(payloadStr.getBytes()); |
|||
client.publish(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX + "1", mqttMessage); |
|||
latch.await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); |
|||
String expectedRequestPayload = "{\"client\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}},\"shared\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; |
|||
assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); |
|||
} |
|||
|
|||
protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": true, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; |
|||
MqttMessage mqttMessage = new MqttMessage(); |
|||
mqttMessage.setPayload(payloadStr.getBytes()); |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage); |
|||
callback.getLatch().await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); |
|||
String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; |
|||
assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); |
|||
} |
|||
|
|||
protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String payloadStr = "{\"id\": 1, \"device\": \"" + "Gateway Device Request Attributes" + "\", \"client\": false, \"keys\": [\"attribute1\", \"attribute2\", \"attribute3\", \"attribute4\", \"attribute5\"]}"; |
|||
MqttMessage mqttMessage = new MqttMessage(); |
|||
mqttMessage.setPayload(payloadStr.getBytes()); |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, mqttMessage); |
|||
callback.getLatch().await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); |
|||
String expectedRequestPayload = "{\"id\":1,\"device\":\"" + "Gateway Device Request Attributes" + "\",\"values\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; |
|||
assertEquals(JacksonUtil.toJsonNode(expectedRequestPayload), JacksonUtil.toJsonNode(new String(callback.getPayloadBytes(), StandardCharsets.UTF_8))); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesRequestJsonIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Request attribute values from the server json", "Gateway Test Request attribute values from the server json", TransportPayloadType.JSON, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServer() throws Exception { |
|||
processTestRequestAttributesValuesFromTheServer(); |
|||
} |
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServerGateway() throws Exception { |
|||
processTestGatewayRequestAttributesValuesFromTheServer(); |
|||
} |
|||
} |
|||
@ -0,0 +1,201 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.stream.Collectors; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto", TransportPayloadType.PROTOBUF, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServer() throws Exception { |
|||
processTestRequestAttributesValuesFromTheServer(); |
|||
} |
|||
|
|||
|
|||
@Test |
|||
public void testRequestAttributesValuesFromTheServerGateway() throws Exception { |
|||
processTestGatewayRequestAttributesValuesFromTheServer(); |
|||
} |
|||
|
|||
protected void postAttributesAndSubscribeToTopic(Device savedDevice, MqttAsyncClient client) throws Exception { |
|||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
List<String> expectedKeys = Arrays.asList(keys.split(",")); |
|||
TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys); |
|||
byte[] payload = postAttributeMsg.toByteArray(); |
|||
client.publish(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, new MqttMessage(payload)); |
|||
client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
} |
|||
|
|||
protected void postGatewayDeviceClientAttributes(MqttAsyncClient client) throws Exception { |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
List<String> expectedKeys = Arrays.asList(keys.split(",")); |
|||
TransportProtos.PostAttributeMsg postAttributeMsg = getPostAttributeMsg(expectedKeys); |
|||
TransportApiProtos.AttributesMsg.Builder attributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder(); |
|||
attributesMsgBuilder.setDeviceName("Gateway Device Request Attributes"); |
|||
attributesMsgBuilder.setMsg(postAttributeMsg); |
|||
TransportApiProtos.AttributesMsg attributesMsg = attributesMsgBuilder.build(); |
|||
TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributeMsgBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); |
|||
gatewayAttributeMsgBuilder.addMsg(attributesMsg); |
|||
byte[] bytes = gatewayAttributeMsgBuilder.build().toByteArray(); |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, new MqttMessage(bytes)); |
|||
} |
|||
|
|||
protected void validateResponse(MqttAsyncClient client, CountDownLatch latch, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
TransportApiProtos.AttributesRequest.Builder attributesRequestBuilder = TransportApiProtos.AttributesRequest.newBuilder(); |
|||
attributesRequestBuilder.setClientKeys(keys); |
|||
attributesRequestBuilder.setSharedKeys(keys); |
|||
TransportApiProtos.AttributesRequest attributesRequest = attributesRequestBuilder.build(); |
|||
MqttMessage mqttMessage = new MqttMessage(); |
|||
mqttMessage.setPayload(attributesRequest.toByteArray()); |
|||
client.publish(MqttTopics.DEVICE_ATTRIBUTES_REQUEST_TOPIC_PREFIX + "1", mqttMessage); |
|||
latch.await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); |
|||
TransportProtos.GetAttributeResponseMsg expectedAttributesResponse = getExpectedAttributeResponseMsg(); |
|||
TransportProtos.GetAttributeResponseMsg actualAttributesResponse = TransportProtos.GetAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); |
|||
assertEquals(expectedAttributesResponse.getRequestId(), actualAttributesResponse.getRequestId()); |
|||
List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualAttributesResponse.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualAttributesResponse.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); |
|||
assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); |
|||
} |
|||
|
|||
protected void validateClientResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, true); |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); |
|||
callback.getLatch().await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); |
|||
TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(true); |
|||
TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); |
|||
assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); |
|||
|
|||
TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); |
|||
TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); |
|||
assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); |
|||
|
|||
List<TransportProtos.KeyValueProto> expectedClientKeyValueProtos = expectedResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> actualClientKeyValueProtos = actualResponseMsg.getClientAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
assertTrue(actualClientKeyValueProtos.containsAll(expectedClientKeyValueProtos)); |
|||
} |
|||
|
|||
protected void validateSharedResponseGateway(MqttAsyncClient client, TestMqttCallback callback) throws MqttException, InterruptedException, InvalidProtocolBufferException { |
|||
String keys = "attribute1,attribute2,attribute3,attribute4,attribute5"; |
|||
TransportApiProtos.GatewayAttributesRequestMsg gatewayAttributesRequestMsg = getGatewayAttributesRequestMsg(keys, false); |
|||
client.publish(MqttTopics.GATEWAY_ATTRIBUTES_REQUEST_TOPIC, new MqttMessage(gatewayAttributesRequestMsg.toByteArray())); |
|||
callback.getLatch().await(3, TimeUnit.SECONDS); |
|||
assertEquals(MqttQoS.AT_LEAST_ONCE.value(), callback.getQoS()); |
|||
TransportApiProtos.GatewayAttributeResponseMsg expectedGatewayAttributeResponseMsg = getExpectedGatewayAttributeResponseMsg(false); |
|||
TransportApiProtos.GatewayAttributeResponseMsg actualGatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.parseFrom(callback.getPayloadBytes()); |
|||
assertEquals(expectedGatewayAttributeResponseMsg.getDeviceName(), actualGatewayAttributeResponseMsg.getDeviceName()); |
|||
|
|||
TransportProtos.GetAttributeResponseMsg expectedResponseMsg = expectedGatewayAttributeResponseMsg.getResponseMsg(); |
|||
TransportProtos.GetAttributeResponseMsg actualResponseMsg = actualGatewayAttributeResponseMsg.getResponseMsg(); |
|||
assertEquals(expectedResponseMsg.getRequestId(), actualResponseMsg.getRequestId()); |
|||
|
|||
List<TransportProtos.KeyValueProto> expectedSharedKeyValueProtos = expectedResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> actualSharedKeyValueProtos = actualResponseMsg.getSharedAttributeListList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
|
|||
assertTrue(actualSharedKeyValueProtos.containsAll(expectedSharedKeyValueProtos)); |
|||
} |
|||
|
|||
private TransportApiProtos.GatewayAttributesRequestMsg getGatewayAttributesRequestMsg(String keys, boolean client) { |
|||
return TransportApiProtos.GatewayAttributesRequestMsg.newBuilder() |
|||
.setClient(client) |
|||
.addAllKeys(Arrays.asList(keys.split(","))) |
|||
.setDeviceName("Gateway Device Request Attributes") |
|||
.setId(1).build(); |
|||
} |
|||
|
|||
private TransportProtos.GetAttributeResponseMsg getExpectedAttributeResponseMsg() { |
|||
TransportProtos.GetAttributeResponseMsg.Builder result = TransportProtos.GetAttributeResponseMsg.newBuilder(); |
|||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList(); |
|||
result.addAllClientAttributeList(tsKvProtoList); |
|||
result.addAllSharedAttributeList(tsKvProtoList); |
|||
result.setRequestId(1); |
|||
return result.build(); |
|||
} |
|||
|
|||
private TransportApiProtos.GatewayAttributeResponseMsg getExpectedGatewayAttributeResponseMsg(boolean client) { |
|||
TransportApiProtos.GatewayAttributeResponseMsg.Builder gatewayAttributeResponseMsg = TransportApiProtos.GatewayAttributeResponseMsg.newBuilder(); |
|||
TransportProtos.GetAttributeResponseMsg.Builder getAttributeResponseMsgBuilder = TransportProtos.GetAttributeResponseMsg.newBuilder(); |
|||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList(); |
|||
if (client) { |
|||
getAttributeResponseMsgBuilder.addAllClientAttributeList(tsKvProtoList); |
|||
} else { |
|||
getAttributeResponseMsgBuilder.addAllSharedAttributeList(tsKvProtoList); |
|||
} |
|||
getAttributeResponseMsgBuilder.setRequestId(1); |
|||
TransportProtos.GetAttributeResponseMsg getAttributeResponseMsg = getAttributeResponseMsgBuilder.build(); |
|||
gatewayAttributeResponseMsg.setDeviceName("Gateway Device Request Attributes"); |
|||
gatewayAttributeResponseMsg.setResponseMsg(getAttributeResponseMsg); |
|||
return gatewayAttributeResponseMsg.build(); |
|||
} |
|||
|
|||
protected List<TransportProtos.KeyValueProto> getKvProtos(List<String> expectedKeys) { |
|||
List<TransportProtos.KeyValueProto> keyValueProtos = new ArrayList<>(); |
|||
TransportProtos.KeyValueProto strKeyValueProto = getKeyValueProto(expectedKeys.get(0), "value1", TransportProtos.KeyValueType.STRING_V); |
|||
TransportProtos.KeyValueProto boolKeyValueProto = getKeyValueProto(expectedKeys.get(1), "true", TransportProtos.KeyValueType.BOOLEAN_V); |
|||
TransportProtos.KeyValueProto dblKeyValueProto = getKeyValueProto(expectedKeys.get(2), "42.0", TransportProtos.KeyValueType.DOUBLE_V); |
|||
TransportProtos.KeyValueProto longKeyValueProto = getKeyValueProto(expectedKeys.get(3), "73", TransportProtos.KeyValueType.LONG_V); |
|||
TransportProtos.KeyValueProto jsonKeyValueProto = getKeyValueProto(expectedKeys.get(4), "{\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}", TransportProtos.KeyValueType.JSON_V); |
|||
keyValueProtos.add(strKeyValueProto); |
|||
keyValueProtos.add(boolKeyValueProto); |
|||
keyValueProtos.add(dblKeyValueProto); |
|||
keyValueProtos.add(longKeyValueProto); |
|||
keyValueProtos.add(jsonKeyValueProto); |
|||
return keyValueProtos; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest; |
|||
|
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesRequestNoSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesRequestJsonSqlIntegrationTest extends AbstractMqttAttributesRequestJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestJsonIntegrationTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestProtoIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesRequestProtoSqlIntegrationTest extends AbstractMqttAttributesRequestProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.request.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.request.AbstractMqttAttributesRequestIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesRequestSqlIntegrationTest extends AbstractMqttAttributesRequestIntegrationTest { |
|||
} |
|||
@ -0,0 +1,171 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesUpdatesIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
|
|||
private static final String RESPONSE_ATTRIBUTES_PAYLOAD_DELETED = "{\"deleted\":[\"attribute5\"]}"; |
|||
|
|||
private static String getResponseGatewayAttributesUpdatedPayload() { |
|||
return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\"," + |
|||
"\"data\":{\"attribute1\":\"value1\",\"attribute2\":true,\"attribute3\":42.0,\"attribute4\":73,\"attribute5\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}}"; |
|||
} |
|||
|
|||
private static String getResponseGatewayAttributesDeletedPayload() { |
|||
return "{\"device\":\"" + "Gateway Device Subscribe to attribute updates" + "\",\"data\":{\"deleted\":[\"attribute5\"]}}"; |
|||
} |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.JSON, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { |
|||
processTestSubscribeToAttributesUpdates(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { |
|||
processGatewayTestSubscribeToAttributesUpdates(); |
|||
} |
|||
|
|||
protected void processTestSubscribeToAttributesUpdates() throws Exception { |
|||
|
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
|
|||
TestMqttCallback onUpdateCallback = getTestMqttCallback(); |
|||
client.setCallback(onUpdateCallback); |
|||
|
|||
client.subscribe(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
|
|||
Thread.sleep(1000); |
|||
|
|||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); |
|||
onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
|
|||
validateUpdateAttributesResponse(onUpdateCallback); |
|||
|
|||
TestMqttCallback onDeleteCallback = getTestMqttCallback(); |
|||
client.setCallback(onDeleteCallback); |
|||
|
|||
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); |
|||
onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
|
|||
validateDeleteAttributesResponse(onDeleteCallback); |
|||
} |
|||
|
|||
protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); |
|||
assertEquals(JacksonUtil.toJsonNode(POST_ATTRIBUTES_PAYLOAD), JacksonUtil.toJsonNode(response)); |
|||
} |
|||
|
|||
protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
String response = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); |
|||
assertEquals(JacksonUtil.toJsonNode(RESPONSE_ATTRIBUTES_PAYLOAD_DELETED), JacksonUtil.toJsonNode(response)); |
|||
} |
|||
|
|||
protected void processGatewayTestSubscribeToAttributesUpdates() throws Exception { |
|||
|
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
|
|||
TestMqttCallback onUpdateCallback = getTestMqttCallback(); |
|||
client.setCallback(onUpdateCallback); |
|||
|
|||
Device device = new Device(); |
|||
device.setName("Gateway Device Subscribe to attribute updates"); |
|||
device.setType("default"); |
|||
|
|||
byte[] connectPayloadBytes = getConnectPayloadBytes(); |
|||
|
|||
publishMqttMsg(client, connectPayloadBytes, MqttTopics.GATEWAY_CONNECT_TOPIC); |
|||
|
|||
Device savedDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + "Gateway Device Subscribe to attribute updates", Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(savedDevice); |
|||
|
|||
client.subscribe(MqttTopics.GATEWAY_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE.value()); |
|||
|
|||
Thread.sleep(1000); |
|||
|
|||
doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", POST_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); |
|||
onUpdateCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
|
|||
validateGatewayUpdateAttributesResponse(onUpdateCallback); |
|||
|
|||
TestMqttCallback onDeleteCallback = getTestMqttCallback(); |
|||
client.setCallback(onDeleteCallback); |
|||
|
|||
doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=attribute5", String.class); |
|||
onDeleteCallback.getLatch().await(3, TimeUnit.SECONDS); |
|||
|
|||
validateGatewayDeleteAttributesResponse(onDeleteCallback); |
|||
|
|||
} |
|||
|
|||
protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); |
|||
assertEquals(getResponseGatewayAttributesUpdatedPayload(), s); |
|||
} |
|||
|
|||
protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
String s = new String(callback.getPayloadBytes(), StandardCharsets.UTF_8); |
|||
assertEquals(s, getResponseGatewayAttributesDeletedPayload()); |
|||
} |
|||
|
|||
protected byte[] getConnectPayloadBytes() { |
|||
String connectPayload = "{\"device\": \"Gateway Device Subscribe to attribute updates\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; |
|||
return connectPayload.getBytes(); |
|||
} |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertFalse; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesUpdatesJsonIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.JSON, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { |
|||
processTestSubscribeToAttributesUpdates(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { |
|||
processGatewayTestSubscribeToAttributesUpdates(); |
|||
} |
|||
} |
|||
@ -0,0 +1,149 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesUpdatesProtoIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Subscribe to attribute updates", "Gateway Test Subscribe to attribute updates", TransportPayloadType.PROTOBUF, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServer() throws Exception { |
|||
processTestSubscribeToAttributesUpdates(); |
|||
} |
|||
|
|||
@Test |
|||
public void testSubscribeToAttributesUpdatesFromTheServerGateway() throws Exception { |
|||
processGatewayTestSubscribeToAttributesUpdates(); |
|||
} |
|||
|
|||
protected void validateUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); |
|||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList(); |
|||
attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); |
|||
|
|||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); |
|||
TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); |
|||
|
|||
List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedAttributeUpdateNotificationMsg.getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
|
|||
assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); |
|||
assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); |
|||
|
|||
} |
|||
|
|||
protected void validateDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); |
|||
attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); |
|||
|
|||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); |
|||
TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = TransportProtos.AttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); |
|||
|
|||
assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); |
|||
assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); |
|||
|
|||
} |
|||
|
|||
protected void validateGatewayUpdateAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
|
|||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); |
|||
List<TransportProtos.TsKvProto> tsKvProtoList = getTsKvProtoList(); |
|||
attributeUpdateNotificationMsgBuilder.addAllSharedUpdated(tsKvProtoList); |
|||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); |
|||
|
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); |
|||
gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); |
|||
gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(expectedAttributeUpdateNotificationMsg); |
|||
|
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); |
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); |
|||
|
|||
assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); |
|||
|
|||
List<TransportProtos.KeyValueProto> actualSharedUpdatedList = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
List<TransportProtos.KeyValueProto> expectedSharedUpdatedList = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg().getSharedUpdatedList().stream().map(TransportProtos.TsKvProto::getKv).collect(Collectors.toList()); |
|||
|
|||
assertEquals(expectedSharedUpdatedList.size(), actualSharedUpdatedList.size()); |
|||
assertTrue(actualSharedUpdatedList.containsAll(expectedSharedUpdatedList)); |
|||
|
|||
} |
|||
|
|||
protected void validateGatewayDeleteAttributesResponse(TestMqttCallback callback) throws InvalidProtocolBufferException { |
|||
assertNotNull(callback.getPayloadBytes()); |
|||
TransportProtos.AttributeUpdateNotificationMsg.Builder attributeUpdateNotificationMsgBuilder = TransportProtos.AttributeUpdateNotificationMsg.newBuilder(); |
|||
attributeUpdateNotificationMsgBuilder.addSharedDeleted("attribute5"); |
|||
TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotificationMsg = attributeUpdateNotificationMsgBuilder.build(); |
|||
|
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg.Builder gatewayAttributeUpdateNotificationMsgBuilder = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.newBuilder(); |
|||
gatewayAttributeUpdateNotificationMsgBuilder.setDeviceName("Gateway Device Subscribe to attribute updates"); |
|||
gatewayAttributeUpdateNotificationMsgBuilder.setNotificationMsg(attributeUpdateNotificationMsg); |
|||
|
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg expectedGatewayAttributeUpdateNotificationMsg = gatewayAttributeUpdateNotificationMsgBuilder.build(); |
|||
TransportApiProtos.GatewayAttributeUpdateNotificationMsg actualGatewayAttributeUpdateNotificationMsg = TransportApiProtos.GatewayAttributeUpdateNotificationMsg.parseFrom(callback.getPayloadBytes()); |
|||
|
|||
assertEquals(expectedGatewayAttributeUpdateNotificationMsg.getDeviceName(), actualGatewayAttributeUpdateNotificationMsg.getDeviceName()); |
|||
|
|||
TransportProtos.AttributeUpdateNotificationMsg expectedAttributeUpdateNotificationMsg = expectedGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); |
|||
TransportProtos.AttributeUpdateNotificationMsg actualAttributeUpdateNotificationMsg = actualGatewayAttributeUpdateNotificationMsg.getNotificationMsg(); |
|||
|
|||
assertEquals(expectedAttributeUpdateNotificationMsg.getSharedDeletedList().size(), actualAttributeUpdateNotificationMsg.getSharedDeletedList().size()); |
|||
assertEquals("attribute5", actualAttributeUpdateNotificationMsg.getSharedDeletedList().get(0)); |
|||
|
|||
} |
|||
|
|||
protected byte[] getConnectPayloadBytes() { |
|||
TransportApiProtos.ConnectMsg connectProto = getConnectProto(); |
|||
return connectProto.toByteArray(); |
|||
} |
|||
|
|||
private TransportApiProtos.ConnectMsg getConnectProto() { |
|||
TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); |
|||
builder.setDeviceName("Gateway Device Subscribe to attribute updates"); |
|||
builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; |
|||
|
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesUpdatesNoSqlIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesUpdatesSqlIntegrationTest extends AbstractMqttAttributesUpdatesIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesIntegrationTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesUpdatesSqlJsonIntegrationTest extends AbstractMqttAttributesUpdatesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.attributes.updates.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesJsonIntegrationTest; |
|||
import org.thingsboard.server.mqtt.attributes.updates.AbstractMqttAttributesUpdatesProtoIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesUpdatesSqlProtoIntegrationTest extends AbstractMqttAttributesUpdatesProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.ClaimRequest; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.dao.device.claim.ClaimResponse; |
|||
import org.thingsboard.server.dao.device.claim.ClaimResult; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttClaimDeviceTest extends AbstractMqttIntegrationTest { |
|||
|
|||
protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!"; |
|||
|
|||
protected User customerAdmin; |
|||
protected Customer savedCustomer; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
super.processBeforeTest("Test Claim device", "Test Claim gateway", null, null, null); |
|||
createCustomerAndUser(); |
|||
} |
|||
|
|||
protected void createCustomerAndUser() throws Exception { |
|||
Customer customer = new Customer(); |
|||
customer.setTenantId(savedTenant.getId()); |
|||
customer.setTitle("Test Claiming Customer"); |
|||
savedCustomer = doPost("/api/customer", customer, Customer.class); |
|||
assertNotNull(savedCustomer); |
|||
assertEquals(savedTenant.getId(), savedCustomer.getTenantId()); |
|||
|
|||
User user = new User(); |
|||
user.setAuthority(Authority.CUSTOMER_USER); |
|||
user.setTenantId(savedTenant.getId()); |
|||
user.setCustomerId(savedCustomer.getId()); |
|||
user.setEmail("customer@thingsboard.org"); |
|||
|
|||
customerAdmin = createUser(user, CUSTOMER_USER_PASSWORD); |
|||
assertNotNull(customerAdmin); |
|||
assertEquals(customerAdmin.getCustomerId(), savedCustomer.getId()); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testClaimingDevice() throws Exception { |
|||
processTestClaimingDevice(false); |
|||
} |
|||
|
|||
@Test |
|||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestClaimingDevice(true); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDevice() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device", false); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device empty payload", true); |
|||
} |
|||
|
|||
|
|||
protected void processTestClaimingDevice(boolean emptyPayload) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
byte[] payloadBytes; |
|||
byte[] failurePayloadBytes; |
|||
if (emptyPayload) { |
|||
payloadBytes = "{}".getBytes(); |
|||
failurePayloadBytes = "{\"durationMs\":1}".getBytes(); |
|||
} else { |
|||
payloadBytes = "{\"secretKey\":\"value\", \"durationMs\":60000}".getBytes(); |
|||
failurePayloadBytes = "{\"secretKey\":\"value\", \"durationMs\":1}".getBytes(); |
|||
} |
|||
validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes); |
|||
} |
|||
|
|||
protected void validateClaimResponse(boolean emptyPayload, MqttAsyncClient client, byte[] payloadBytes, byte[] failurePayloadBytes) throws Exception { |
|||
client.publish(MqttTopics.DEVICE_CLAIM_TOPIC, new MqttMessage(failurePayloadBytes)); |
|||
|
|||
loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD); |
|||
ClaimRequest claimRequest; |
|||
if (!emptyPayload) { |
|||
claimRequest = new ClaimRequest("value"); |
|||
} else { |
|||
claimRequest = new ClaimRequest(null); |
|||
} |
|||
|
|||
ClaimResponse claimResponse = doExecuteWithRetriesAndInterval( |
|||
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()), |
|||
20, |
|||
100 |
|||
); |
|||
|
|||
assertEquals(claimResponse, ClaimResponse.FAILURE); |
|||
|
|||
client.publish(MqttTopics.DEVICE_CLAIM_TOPIC, new MqttMessage(payloadBytes)); |
|||
|
|||
ClaimResult claimResult = doExecuteWithRetriesAndInterval( |
|||
() -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResult.class, status().isOk()), |
|||
20, |
|||
100 |
|||
); |
|||
assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS); |
|||
Device claimedDevice = claimResult.getDevice(); |
|||
assertNotNull(claimedDevice); |
|||
assertNotNull(claimedDevice.getCustomerId()); |
|||
assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId()); |
|||
|
|||
claimResponse = doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()); |
|||
assertEquals(claimResponse, ClaimResponse.CLAIMED); |
|||
} |
|||
|
|||
protected void validateGatewayClaimResponse(String deviceName, boolean emptyPayload, MqttAsyncClient client, byte[] failurePayloadBytes, byte[] payloadBytes) throws Exception { |
|||
client.publish(MqttTopics.GATEWAY_CLAIM_TOPIC, new MqttMessage(failurePayloadBytes)); |
|||
|
|||
Device savedDevice = doExecuteWithRetriesAndInterval( |
|||
() -> doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class), |
|||
20, |
|||
100 |
|||
); |
|||
|
|||
assertNotNull(savedDevice); |
|||
|
|||
loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD); |
|||
ClaimRequest claimRequest; |
|||
if (!emptyPayload) { |
|||
claimRequest = new ClaimRequest("value"); |
|||
} else { |
|||
claimRequest = new ClaimRequest(null); |
|||
} |
|||
|
|||
ClaimResponse claimResponse = doPostClaimAsync("/api/customer/device/" + deviceName + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()); |
|||
assertEquals(claimResponse, ClaimResponse.FAILURE); |
|||
|
|||
client.publish(MqttTopics.GATEWAY_CLAIM_TOPIC, new MqttMessage(payloadBytes)); |
|||
|
|||
ClaimResult claimResult = doExecuteWithRetriesAndInterval( |
|||
() -> doPostClaimAsync("/api/customer/device/" + deviceName + "/claim", claimRequest, ClaimResult.class, status().isOk()), |
|||
20, |
|||
100 |
|||
); |
|||
|
|||
assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS); |
|||
Device claimedDevice = claimResult.getDevice(); |
|||
assertNotNull(claimedDevice); |
|||
assertNotNull(claimedDevice.getCustomerId()); |
|||
assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId()); |
|||
|
|||
claimResponse = doPostClaimAsync("/api/customer/device/" + deviceName + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()); |
|||
assertEquals(claimResponse, ClaimResponse.CLAIMED); |
|||
} |
|||
|
|||
protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
byte[] failurePayloadBytes; |
|||
byte[] payloadBytes; |
|||
String failurePayload; |
|||
String payload; |
|||
if (emptyPayload) { |
|||
failurePayload = "{\"" + deviceName + "\": " + "{\"durationMs\":1}" + "}"; |
|||
payload = "{\"" + deviceName + "\": " + "{}" + "}"; |
|||
} else { |
|||
failurePayload = "{\"" + deviceName + "\": " + "{\"secretKey\":\"value\", \"durationMs\":1}" + "}"; |
|||
payload = "{\"" + deviceName + "\": " + "{\"secretKey\":\"value\", \"durationMs\":60000}" + "}"; |
|||
} |
|||
payloadBytes = payload.getBytes(); |
|||
failurePayloadBytes = failurePayload.getBytes(); |
|||
validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttClaimJsonDeviceTest extends AbstractMqttClaimDeviceTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
super.processBeforeTest("Test Claim device", "Test Claim gateway", TransportPayloadType.JSON, null, null); |
|||
createCustomerAndUser(); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.afterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testClaimingDevice() throws Exception { |
|||
processTestClaimingDevice(false); |
|||
} |
|||
|
|||
@Test |
|||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestClaimingDevice(true); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDevice() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device Json", false); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device empty payload Json", true); |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttClaimProtoDeviceTest extends AbstractMqttClaimDeviceTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Claim device", "Test Claim gateway", TransportPayloadType.PROTOBUF, null, null); |
|||
createCustomerAndUser(); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { super.afterTest(); } |
|||
|
|||
@Test |
|||
public void testClaimingDevice() throws Exception { |
|||
processTestClaimingDevice(false); |
|||
} |
|||
|
|||
@Test |
|||
public void testClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestClaimingDevice(true); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDevice() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device Proto", false); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayClaimingDeviceWithoutSecretAndDuration() throws Exception { |
|||
processTestGatewayClaimingDevice("Test claiming gateway device empty payload Proto", true); |
|||
} |
|||
|
|||
protected void processTestClaimingDevice(boolean emptyPayload) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
byte[] payloadBytes; |
|||
if (emptyPayload) { |
|||
payloadBytes = getClaimDevice(0, emptyPayload).toByteArray(); |
|||
} else { |
|||
payloadBytes = getClaimDevice(60000, emptyPayload).toByteArray(); |
|||
} |
|||
byte[] failurePayloadBytes = getClaimDevice(1, emptyPayload).toByteArray(); |
|||
validateClaimResponse(emptyPayload, client, payloadBytes, failurePayloadBytes); |
|||
} |
|||
|
|||
protected void processTestGatewayClaimingDevice(String deviceName, boolean emptyPayload) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
byte[] failurePayloadBytes; |
|||
byte[] payloadBytes; |
|||
if (emptyPayload) { |
|||
payloadBytes = getGatewayClaimMsg(deviceName, 0, emptyPayload).toByteArray(); |
|||
} else { |
|||
payloadBytes = getGatewayClaimMsg(deviceName, 60000, emptyPayload).toByteArray(); |
|||
} |
|||
failurePayloadBytes = getGatewayClaimMsg(deviceName, 1, emptyPayload).toByteArray(); |
|||
|
|||
validateGatewayClaimResponse(deviceName, emptyPayload, client, failurePayloadBytes, payloadBytes); |
|||
} |
|||
|
|||
private TransportApiProtos.GatewayClaimMsg getGatewayClaimMsg(String deviceName, long duration, boolean emptyPayload) { |
|||
TransportApiProtos.GatewayClaimMsg.Builder gatewayClaimMsgBuilder = TransportApiProtos.GatewayClaimMsg.newBuilder(); |
|||
TransportApiProtos.ClaimDeviceMsg.Builder claimDeviceMsgBuilder = TransportApiProtos.ClaimDeviceMsg.newBuilder(); |
|||
TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder(); |
|||
if (!emptyPayload) { |
|||
claimDeviceBuilder.setSecretKey("value"); |
|||
} |
|||
if (duration > 0) { |
|||
claimDeviceBuilder.setDurationMs(duration); |
|||
} |
|||
TransportApiProtos.ClaimDevice claimDevice = claimDeviceBuilder.build(); |
|||
claimDeviceMsgBuilder.setClaimRequest(claimDevice); |
|||
claimDeviceMsgBuilder.setDeviceName(deviceName); |
|||
TransportApiProtos.ClaimDeviceMsg claimDeviceMsg = claimDeviceMsgBuilder.build(); |
|||
gatewayClaimMsgBuilder.addMsg(claimDeviceMsg); |
|||
return gatewayClaimMsgBuilder.build(); |
|||
} |
|||
|
|||
private TransportApiProtos.ClaimDevice getClaimDevice(long duration, boolean emptyPayload) { |
|||
TransportApiProtos.ClaimDevice.Builder claimDeviceBuilder = TransportApiProtos.ClaimDevice.newBuilder(); |
|||
if (!emptyPayload) { |
|||
claimDeviceBuilder.setSecretKey("value"); |
|||
} |
|||
if (duration > 0) { |
|||
claimDeviceBuilder.setSecretKey("value"); |
|||
claimDeviceBuilder.setDurationMs(duration); |
|||
} |
|||
return claimDeviceBuilder.build(); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest; |
|||
|
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttClaimDeviceNoSqlTest extends AbstractMqttClaimDeviceTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttClaimDeviceJsonSqlTest extends AbstractMqttClaimJsonDeviceTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimJsonDeviceTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimProtoDeviceTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttClaimDeviceProtoSqlTest extends AbstractMqttClaimProtoDeviceTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.claim.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.claim.AbstractMqttClaimDeviceTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttClaimDeviceSqlTest extends AbstractMqttClaimDeviceTest { |
|||
} |
|||
@ -0,0 +1,137 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.rpc; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import com.nimbusds.jose.util.StandardCharset; |
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Assert; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
import org.thingsboard.server.common.data.DeviceProfileType; |
|||
import org.thingsboard.server.common.data.DeviceTransportType; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.User; |
|||
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
|||
import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.security.Authority; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.controller.AbstractControllerTest; |
|||
import org.thingsboard.server.dao.util.mapping.JacksonUtil; |
|||
import org.thingsboard.server.service.security.AccessValidator; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
/** |
|||
* @author Valerii Sosliuk |
|||
*/ |
|||
@Slf4j |
|||
public abstract class AbstractMqttServerSideRpcDefaultIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("RPC test device", "RPC test gateway", null, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttOneWayRpcDeviceOffline() throws Exception { |
|||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}"; |
|||
String deviceId = savedDevice.getId().getId().toString(); |
|||
|
|||
doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409), |
|||
asyncContextTimeoutToUseRpcPlugin); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttOneWayRpcDeviceDoesNotExist() throws Exception { |
|||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"25\",\"value\": 1}}"; |
|||
String nonExistentDeviceId = Uuids.timeBased().toString(); |
|||
|
|||
String result = doPostAsync("/api/plugins/rpc/oneway/" + nonExistentDeviceId, setGpioRequest, String.class, |
|||
status().isNotFound()); |
|||
Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttTwoWayRpcDeviceOffline() throws Exception { |
|||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}"; |
|||
String deviceId = savedDevice.getId().getId().toString(); |
|||
|
|||
doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409), |
|||
asyncContextTimeoutToUseRpcPlugin); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttTwoWayRpcDeviceDoesNotExist() throws Exception { |
|||
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"28\",\"value\": 1}}"; |
|||
String nonExistentDeviceId = Uuids.timeBased().toString(); |
|||
|
|||
String result = doPostAsync("/api/plugins/rpc/twoway/" + nonExistentDeviceId, setGpioRequest, String.class, |
|||
status().isNotFound()); |
|||
Assert.assertEquals(AccessValidator.DEVICE_WITH_REQUESTED_ID_NOT_FOUND, result); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTestGateway("Gateway Device OneWay RPC"); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTestGateway("Gateway Device TwoWay RPC"); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.rpc; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttServerSideRpcJsonIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.JSON, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTestGateway("Gateway Device OneWay RPC Json"); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Json"); |
|||
} |
|||
|
|||
protected void processOneWayRpcTestGateway(String deviceName) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
String payload = "{\"device\": \"" + deviceName + "\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; |
|||
byte[] payloadBytes = payload.getBytes(); |
|||
validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.rpc; |
|||
|
|||
import com.google.protobuf.InvalidProtocolBufferException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttException; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest { |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
super.processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttOneWayRpc() throws Exception { |
|||
processOneWayRpcTestGateway("Gateway Device OneWay RPC Proto"); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayServerMqttTwoWayRpc() throws Exception { |
|||
processTwoWayRpcTestGateway("Gateway Device TwoWay RPC Proto"); |
|||
} |
|||
|
|||
protected void processTwoWayRpcTestGateway(String deviceName) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); |
|||
byte[] payloadBytes = connectMsgProto.toByteArray(); |
|||
validateTwoWayRpcGateway(deviceName, client, payloadBytes); |
|||
} |
|||
|
|||
protected void processOneWayRpcTestGateway(String deviceName) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); |
|||
byte[] payloadBytes = connectMsgProto.toByteArray(); |
|||
validateOneWayRpcGatewayResponse(deviceName, client, payloadBytes); |
|||
} |
|||
|
|||
|
|||
private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) { |
|||
TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); |
|||
builder.setDeviceName(deviceName); |
|||
builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException { |
|||
MqttMessage message = new MqttMessage(); |
|||
if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC)) { |
|||
TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() |
|||
.setPayload(DEVICE_RESPONSE) |
|||
.setRequestId(0) |
|||
.build(); |
|||
message.setPayload(toDeviceRpcResponseMsg.toByteArray()); |
|||
} else { |
|||
TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload()); |
|||
String deviceName = msg.getDeviceName(); |
|||
int requestId = msg.getRpcRequestMsg().getRequestId(); |
|||
TransportApiProtos.GatewayRpcResponseMsg gatewayRpcResponseMsg = TransportApiProtos.GatewayRpcResponseMsg.newBuilder() |
|||
.setDeviceName(deviceName) |
|||
.setId(requestId) |
|||
.setData("{\"success\": true}") |
|||
.build(); |
|||
message.setPayload(gatewayRpcResponseMsg.toByteArray()); |
|||
} |
|||
return message; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.rpc.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcJsonIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttServerSideRpcJsonSqlIntegrationTest extends AbstractMqttServerSideRpcJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.rpc.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.rpc.AbstractMqttServerSideRpcProtoIntegrationTest; |
|||
|
|||
|
|||
@DaoSqlTest |
|||
public class MqttServerSideRpcProtoSqlIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest { |
|||
} |
|||
@ -1,163 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry; |
|||
|
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.*; |
|||
import org.junit.Before; |
|||
import org.junit.Ignore; |
|||
import org.junit.Test; |
|||
import org.springframework.web.util.UriComponentsBuilder; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.security.DeviceCredentials; |
|||
import org.thingsboard.server.controller.AbstractControllerTest; |
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
|
|||
import java.net.URI; |
|||
import java.util.*; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
/** |
|||
* @author Valerii Sosliuk |
|||
*/ |
|||
@Slf4j |
|||
public abstract class AbstractMqttTelemetryIntegrationTest extends AbstractControllerTest { |
|||
|
|||
private static final String MQTT_URL = "tcp://localhost:1883"; |
|||
|
|||
private Device savedDevice; |
|||
private String accessToken; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
loginTenantAdmin(); |
|||
|
|||
Device device = new Device(); |
|||
device.setName("Test device"); |
|||
device.setType("default"); |
|||
savedDevice = doPost("/api/device", device, Device.class); |
|||
|
|||
DeviceCredentials deviceCredentials = |
|||
doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
|||
|
|||
assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); |
|||
accessToken = deviceCredentials.getCredentialsId(); |
|||
assertNotNull(accessToken); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttRpcData() throws Exception { |
|||
String clientId = MqttAsyncClient.generateClientId(); |
|||
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId); |
|||
|
|||
MqttConnectOptions options = new MqttConnectOptions(); |
|||
options.setUserName(accessToken); |
|||
client.connect(options); |
|||
Thread.sleep(3000); |
|||
MqttMessage message = new MqttMessage(); |
|||
message.setPayload("{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4}".getBytes()); |
|||
client.publish("v1/devices/me/telemetry", message); |
|||
|
|||
String deviceId = savedDevice.getId().getId().toString(); |
|||
|
|||
Thread.sleep(2000); |
|||
List<String> actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", List.class); |
|||
Set<String> actualKeySet = new HashSet<>(actualKeys); |
|||
|
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4"); |
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
|
|||
assertEquals(expectedKeySet, actualKeySet); |
|||
|
|||
String getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet); |
|||
Map<String, List<Map<String, String>>> values = doGetAsync(getTelemetryValuesUrl, Map.class); |
|||
|
|||
assertEquals("value1", values.get("key1").get(0).get("value")); |
|||
assertEquals("true", values.get("key2").get(0).get("value")); |
|||
assertEquals("3.0", values.get("key3").get(0).get("value")); |
|||
assertEquals("4", values.get("key4").get(0).get("value")); |
|||
} |
|||
|
|||
|
|||
// @Test - Unstable
|
|||
public void testMqttQoSLevel() throws Exception { |
|||
String clientId = MqttAsyncClient.generateClientId(); |
|||
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId); |
|||
|
|||
MqttConnectOptions options = new MqttConnectOptions(); |
|||
options.setUserName(accessToken); |
|||
CountDownLatch latch = new CountDownLatch(1); |
|||
TestMqttCallback callback = new TestMqttCallback(client, latch); |
|||
client.setCallback(callback); |
|||
client.connect(options).waitForCompletion(5000); |
|||
client.subscribe("v1/devices/me/attributes", MqttQoS.AT_MOST_ONCE.value()); |
|||
String payload = "{\"key\":\"uniqueValue\"}"; |
|||
// TODO 3.1: we need to acknowledge subscription only after it is processed by device actor and not when the message is pushed to queue.
|
|||
// MqttClient -> SUB REQUEST -> Transport -> Kafka -> Device Actor (subscribed)
|
|||
// MqttClient <- SUB_ACK <- Transport
|
|||
Thread.sleep(5000); |
|||
doPostAsync("/api/plugins/telemetry/" + savedDevice.getId() + "/SHARED_SCOPE", payload, String.class, status().isOk()); |
|||
latch.await(10, TimeUnit.SECONDS); |
|||
assertEquals(payload, callback.getPayload()); |
|||
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); |
|||
} |
|||
|
|||
private static class TestMqttCallback implements MqttCallback { |
|||
|
|||
private final MqttAsyncClient client; |
|||
private final CountDownLatch latch; |
|||
private volatile Integer qoS; |
|||
private volatile String payload; |
|||
|
|||
String getPayload() { |
|||
return payload; |
|||
} |
|||
|
|||
TestMqttCallback(MqttAsyncClient client, CountDownLatch latch) { |
|||
this.client = client; |
|||
this.latch = latch; |
|||
} |
|||
|
|||
int getQoS() { |
|||
return qoS; |
|||
} |
|||
|
|||
@Override |
|||
public void connectionLost(Throwable throwable) { |
|||
log.error("Client connection lost", throwable); |
|||
} |
|||
|
|||
@Override |
|||
public void messageArrived(String requestTopic, MqttMessage mqttMessage) { |
|||
payload = new String(mqttMessage.getPayload()); |
|||
qoS = mqttMessage.getQos(); |
|||
latch.countDown(); |
|||
} |
|||
|
|||
@Override |
|||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,182 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.HashSet; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesIntegrationTest extends AbstractMqttIntegrationTest { |
|||
|
|||
protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + |
|||
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", null, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributes() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processAttributesTest(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributesGateway() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
String payload = getGatewayAttributesJsonPayload(deviceName1, deviceName2); |
|||
processGatewayAttributesTest(expectedKeys, payload.getBytes(), deviceName1, deviceName2); |
|||
} |
|||
|
|||
protected void processAttributesTest(String topic, List<String> expectedKeys, byte[] payload) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
|
|||
publishMqttMsg(client, payload, topic); |
|||
|
|||
DeviceId deviceId = savedDevice.getId(); |
|||
|
|||
long start = System.currentTimeMillis(); |
|||
long end = System.currentTimeMillis() + 5000; |
|||
|
|||
List<String> actualKeys = null; |
|||
while (start <= end) { |
|||
actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", List.class); |
|||
if (actualKeys.size() == expectedKeys.size()) { |
|||
break; |
|||
} |
|||
Thread.sleep(100); |
|||
start += 100; |
|||
} |
|||
assertNotNull(actualKeys); |
|||
|
|||
Set<String> actualKeySet = new HashSet<>(actualKeys); |
|||
|
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
|
|||
assertEquals(expectedKeySet, actualKeySet); |
|||
|
|||
String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); |
|||
List<Map<String, Object>> values = doGetAsync(getAttributesValuesUrl, List.class); |
|||
assertAttributesValues(values, expectedKeySet); |
|||
String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
|||
doDelete(deleteAttributesUrl); |
|||
} |
|||
|
|||
protected void processGatewayAttributesTest(List<String> expectedKeys, byte[] payload, String firstDeviceName, String secondDeviceName) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
|
|||
publishMqttMsg(client, payload, MqttTopics.GATEWAY_ATTRIBUTES_TOPIC); |
|||
|
|||
Device firstDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + firstDeviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(firstDevice); |
|||
|
|||
Device secondDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + secondDeviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(secondDevice); |
|||
|
|||
Thread.sleep(2000); |
|||
|
|||
List<String> firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); |
|||
Set<String> firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); |
|||
|
|||
List<String> secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/attributes/CLIENT_SCOPE", List.class); |
|||
Set<String> secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); |
|||
|
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
|
|||
assertEquals(expectedKeySet, firstDeviceActualKeySet); |
|||
assertEquals(expectedKeySet, secondDeviceActualKeySet); |
|||
|
|||
String getAttributesValuesUrlFirstDevice = getAttributesValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); |
|||
String getAttributesValuesUrlSecondDevice = getAttributesValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); |
|||
|
|||
List<Map<String, Object>> firstDeviceValues = doGetAsync(getAttributesValuesUrlFirstDevice, List.class); |
|||
List<Map<String, Object>> secondDeviceValues = doGetAsync(getAttributesValuesUrlSecondDevice, List.class); |
|||
|
|||
assertAttributesValues(firstDeviceValues, expectedKeySet); |
|||
assertAttributesValues(secondDeviceValues, expectedKeySet); |
|||
|
|||
} |
|||
|
|||
protected void assertAttributesValues(List<Map<String, Object>> deviceValues, Set<String> expectedKeySet) { |
|||
for (Map<String, Object> map : deviceValues) { |
|||
String key = (String) map.get("key"); |
|||
Object value = map.get("value"); |
|||
assertTrue(expectedKeySet.contains(key)); |
|||
switch (key) { |
|||
case "key1": |
|||
assertEquals("value1", value); |
|||
break; |
|||
case "key2": |
|||
assertEquals(true, value); |
|||
break; |
|||
case "key3": |
|||
assertEquals(3.0, value); |
|||
break; |
|||
case "key4": |
|||
assertEquals(4, value); |
|||
break; |
|||
case "key5": |
|||
assertNotNull(value); |
|||
assertEquals(3, ((LinkedHashMap) value).size()); |
|||
assertEquals(42, ((LinkedHashMap) value).get("someNumber")); |
|||
assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray")); |
|||
LinkedHashMap<String, String> someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject"); |
|||
assertEquals("value", someNestedObject.get("key")); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected String getGatewayAttributesJsonPayload(String deviceA, String deviceB) { |
|||
return "{\"" + deviceA + "\": " + PAYLOAD_VALUES_STR + ", \"" + deviceB + "\": " + PAYLOAD_VALUES_STR + "}"; |
|||
} |
|||
|
|||
private String getAttributesValuesUrl(DeviceId deviceId, Set<String> actualKeySet) { |
|||
return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesJsonIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
|
|||
private static final String POST_DATA_ATTRIBUTES_TOPIC = "data/attributes"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.JSON, null, POST_DATA_ATTRIBUTES_TOPIC); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributes() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes()); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributesGateway() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
String payload = getGatewayAttributesJsonPayload(deviceName1, deviceName2); |
|||
processGatewayAttributesTest(expectedKeys, payload.getBytes(), deviceName1, deviceName2); |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.junit.Assert.assertTrue; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttAttributesProtoIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
|
|||
private static final String POST_DATA_ATTRIBUTES_TOPIC = "proto/attributes"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Attributes device", "Test Post Attributes gateway", TransportPayloadType.PROTOBUF, null, POST_DATA_ATTRIBUTES_TOPIC); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributes() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
TransportProtos.PostAttributeMsg msg = getPostAttributeMsg(expectedKeys); |
|||
processAttributesTest(POST_DATA_ATTRIBUTES_TOPIC, expectedKeys, msg.toByteArray()); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttAttributesGateway() throws Exception { |
|||
TransportApiProtos.GatewayAttributesMsg.Builder gatewayAttributesMsgProtoBuilder = TransportApiProtos.GatewayAttributesMsg.newBuilder(); |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
TransportApiProtos.AttributesMsg firstDeviceAttributesMsgProto = getDeviceAttributesMsgProto(deviceName1, expectedKeys); |
|||
TransportApiProtos.AttributesMsg secondDeviceAttributesMsgProto = getDeviceAttributesMsgProto(deviceName2, expectedKeys); |
|||
gatewayAttributesMsgProtoBuilder.addAllMsg(Arrays.asList(firstDeviceAttributesMsgProto, secondDeviceAttributesMsgProto)); |
|||
TransportApiProtos.GatewayAttributesMsg gatewayAttributesMsg = gatewayAttributesMsgProtoBuilder.build(); |
|||
processGatewayAttributesTest(expectedKeys, gatewayAttributesMsg.toByteArray(), deviceName1, deviceName2); |
|||
} |
|||
|
|||
private TransportApiProtos.AttributesMsg getDeviceAttributesMsgProto(String deviceName, List<String> expectedKeys) { |
|||
TransportApiProtos.AttributesMsg.Builder deviceAttributesMsgBuilder = TransportApiProtos.AttributesMsg.newBuilder(); |
|||
TransportProtos.PostAttributeMsg msg = getPostAttributeMsg(expectedKeys); |
|||
deviceAttributesMsgBuilder.setDeviceName(deviceName); |
|||
deviceAttributesMsgBuilder.setMsg(msg); |
|||
return deviceAttributesMsgBuilder.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesNoSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesNoSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttAttributesNoSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesSqlIntegrationTest extends AbstractMqttAttributesIntegrationTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesSqlJsonIntegrationTest extends AbstractMqttAttributesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.attributes.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesJsonIntegrationTest; |
|||
import org.thingsboard.server.mqtt.telemetry.attributes.AbstractMqttAttributesProtoIntegrationTest; |
|||
|
|||
@DaoSqlTest |
|||
public class MqttAttributesSqlProtoIntegrationTest extends AbstractMqttAttributesProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,300 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries; |
|||
|
|||
import io.netty.handler.codec.mqtt.MqttQoS; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.eclipse.paho.client.mqttv3.MqttCallback; |
|||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; |
|||
import org.eclipse.paho.client.mqttv3.MqttMessage; |
|||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.concurrent.CountDownLatch; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttTimeseriesIntegrationTest extends AbstractMqttIntegrationTest { |
|||
|
|||
protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + |
|||
" \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Telemetry device", "Test Post Telemetry gateway", null, null, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetry() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryWithTs() throws Exception { |
|||
String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processTelemetryTest(MqttTopics.DEVICE_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryGateway() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
String payload = getGatewayTelemetryJsonPayload(deviceName1, deviceName2, "10000", "20000"); |
|||
processGatewayTelemetryTest(MqttTopics.GATEWAY_TELEMETRY_TOPIC, expectedKeys, payload.getBytes(), deviceName1, deviceName2); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayConnect() throws Exception { |
|||
String payload = "{\"device\":\"Device A\"}"; |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
publishMqttMsg(client, payload.getBytes(), MqttTopics.GATEWAY_CONNECT_TOPIC); |
|||
|
|||
String deviceName = "Device A"; |
|||
|
|||
Device device = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(device); |
|||
} |
|||
|
|||
protected void processTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, boolean withTs) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(accessToken); |
|||
publishMqttMsg(client, payload, topic); |
|||
|
|||
String deviceId = savedDevice.getId().getId().toString(); |
|||
|
|||
long start = System.currentTimeMillis(); |
|||
long end = System.currentTimeMillis() + 5000; |
|||
|
|||
List<String> actualKeys = null; |
|||
while (start <= end) { |
|||
actualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", List.class); |
|||
if (actualKeys.size() == expectedKeys.size()) { |
|||
break; |
|||
} |
|||
Thread.sleep(100); |
|||
start += 100; |
|||
} |
|||
assertNotNull(actualKeys); |
|||
|
|||
Set<String> actualKeySet = new HashSet<>(actualKeys); |
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
|
|||
assertEquals(expectedKeySet, actualKeySet); |
|||
|
|||
String getTelemetryValuesUrl; |
|||
if (withTs) { |
|||
getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=15000&keys=" + String.join(",", actualKeySet); |
|||
} else { |
|||
getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet); |
|||
} |
|||
Map<String, List<Map<String, String>>> values = doGetAsync(getTelemetryValuesUrl, Map.class); |
|||
|
|||
if (withTs) { |
|||
assertTs(values, expectedKeys, 10000, 0); |
|||
} |
|||
assertValues(values, 0); |
|||
} |
|||
|
|||
protected void processGatewayTelemetryTest(String topic, List<String> expectedKeys, byte[] payload, String firstDeviceName, String secondDeviceName) throws Exception { |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
|
|||
publishMqttMsg(client, payload, topic); |
|||
|
|||
Device firstDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + firstDeviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(firstDevice); |
|||
|
|||
Device secondDevice = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + secondDeviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(secondDevice); |
|||
|
|||
Thread.sleep(2000); |
|||
|
|||
List<String> firstDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + firstDevice.getId() + "/keys/timeseries", List.class); |
|||
Set<String> firstDeviceActualKeySet = new HashSet<>(firstDeviceActualKeys); |
|||
|
|||
List<String> secondDeviceActualKeys = doGetAsync("/api/plugins/telemetry/DEVICE/" + secondDevice.getId() + "/keys/timeseries", List.class); |
|||
Set<String> secondDeviceActualKeySet = new HashSet<>(secondDeviceActualKeys); |
|||
|
|||
Set<String> expectedKeySet = new HashSet<>(expectedKeys); |
|||
|
|||
assertEquals(expectedKeySet, firstDeviceActualKeySet); |
|||
assertEquals(expectedKeySet, secondDeviceActualKeySet); |
|||
|
|||
String getTelemetryValuesUrlFirstDevice = getTelemetryValuesUrl(firstDevice.getId(), firstDeviceActualKeySet); |
|||
String getTelemetryValuesUrlSecondDevice = getTelemetryValuesUrl(firstDevice.getId(), secondDeviceActualKeySet); |
|||
|
|||
Map<String, List<Map<String, String>>> firstDeviceValues = doGetAsync(getTelemetryValuesUrlFirstDevice, Map.class); |
|||
Map<String, List<Map<String, String>>> secondDeviceValues = doGetAsync(getTelemetryValuesUrlSecondDevice, Map.class); |
|||
|
|||
assertGatewayDeviceData(firstDeviceValues, expectedKeys); |
|||
assertGatewayDeviceData(secondDeviceValues, expectedKeys); |
|||
} |
|||
|
|||
protected String getGatewayTelemetryJsonPayload(String deviceA, String deviceB, String firstTsValue, String secondTsValue) { |
|||
String payload = "[{\"ts\": " + firstTsValue + ", \"values\": " + PAYLOAD_VALUES_STR + "}, " + |
|||
"{\"ts\": " + secondTsValue + ", \"values\": " + PAYLOAD_VALUES_STR + "}]"; |
|||
return "{\"" + deviceA + "\": " + payload + ", \"" + deviceB + "\": " + payload + "}"; |
|||
} |
|||
|
|||
private String getTelemetryValuesUrl(DeviceId deviceId, Set<String> actualKeySet) { |
|||
return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?startTs=0&endTs=25000&keys=" + String.join(",", actualKeySet); |
|||
} |
|||
|
|||
private void assertGatewayDeviceData(Map<String, List<Map<String, String>>> deviceValues, List<String> expectedKeys) { |
|||
|
|||
assertEquals(2, deviceValues.get(expectedKeys.get(0)).size()); |
|||
assertEquals(2, deviceValues.get(expectedKeys.get(1)).size()); |
|||
assertEquals(2, deviceValues.get(expectedKeys.get(2)).size()); |
|||
assertEquals(2, deviceValues.get(expectedKeys.get(3)).size()); |
|||
assertEquals(2, deviceValues.get(expectedKeys.get(4)).size()); |
|||
|
|||
assertTs(deviceValues, expectedKeys, 20000, 0); |
|||
assertTs(deviceValues, expectedKeys, 10000, 1); |
|||
|
|||
assertValues(deviceValues, 0); |
|||
assertValues(deviceValues, 1); |
|||
|
|||
} |
|||
|
|||
private void assertValues(Map<String, List<Map<String, String>>> deviceValues, int arrayIndex) { |
|||
for (Map.Entry<String, List<Map<String, String>>> entry : deviceValues.entrySet()) { |
|||
String key = entry.getKey(); |
|||
List<Map<String, String>> tsKv = entry.getValue(); |
|||
String value = tsKv.get(arrayIndex).get("value"); |
|||
switch (key) { |
|||
case "key1": |
|||
assertEquals("value1", value); |
|||
break; |
|||
case "key2": |
|||
assertEquals("true", value); |
|||
break; |
|||
case "key3": |
|||
assertEquals("3.0", value); |
|||
break; |
|||
case "key4": |
|||
assertEquals("4", value); |
|||
break; |
|||
case "key5": |
|||
assertEquals("{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void assertTs(Map<String, List<Map<String, String>>> deviceValues, List<String> expectedKeys, int ts, int arrayIndex) { |
|||
assertEquals(ts, deviceValues.get(expectedKeys.get(0)).get(arrayIndex).get("ts")); |
|||
assertEquals(ts, deviceValues.get(expectedKeys.get(1)).get(arrayIndex).get("ts")); |
|||
assertEquals(ts, deviceValues.get(expectedKeys.get(2)).get(arrayIndex).get("ts")); |
|||
assertEquals(ts, deviceValues.get(expectedKeys.get(3)).get(arrayIndex).get("ts")); |
|||
assertEquals(ts, deviceValues.get(expectedKeys.get(4)).get(arrayIndex).get("ts")); |
|||
} |
|||
|
|||
// @Test - Unstable
|
|||
public void testMqttQoSLevel() throws Exception { |
|||
String clientId = MqttAsyncClient.generateClientId(); |
|||
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); |
|||
|
|||
MqttConnectOptions options = new MqttConnectOptions(); |
|||
options.setUserName(accessToken); |
|||
CountDownLatch latch = new CountDownLatch(1); |
|||
TestMqttCallback callback = new TestMqttCallback(client, latch); |
|||
client.setCallback(callback); |
|||
client.connect(options).waitForCompletion(5000); |
|||
client.subscribe("v1/devices/me/attributes", MqttQoS.AT_MOST_ONCE.value()); |
|||
String payload = "{\"key\":\"uniqueValue\"}"; |
|||
// TODO 3.1: we need to acknowledge subscription only after it is processed by device actor and not when the message is pushed to queue.
|
|||
// MqttClient -> SUB REQUEST -> Transport -> Kafka -> Device Actor (subscribed)
|
|||
// MqttClient <- SUB_ACK <- Transport
|
|||
Thread.sleep(5000); |
|||
doPostAsync("/api/plugins/telemetry/" + savedDevice.getId() + "/SHARED_SCOPE", payload, String.class, status().isOk()); |
|||
latch.await(10, TimeUnit.SECONDS); |
|||
assertEquals(payload, callback.getPayload()); |
|||
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); |
|||
} |
|||
|
|||
private static class TestMqttCallback implements MqttCallback { |
|||
|
|||
private final MqttAsyncClient client; |
|||
private final CountDownLatch latch; |
|||
private volatile Integer qoS; |
|||
private volatile String payload; |
|||
|
|||
String getPayload() { |
|||
return payload; |
|||
} |
|||
|
|||
TestMqttCallback(MqttAsyncClient client, CountDownLatch latch) { |
|||
this.client = client; |
|||
this.latch = latch; |
|||
} |
|||
|
|||
int getQoS() { |
|||
return qoS; |
|||
} |
|||
|
|||
@Override |
|||
public void connectionLost(Throwable throwable) { |
|||
log.error("Client connection lost", throwable); |
|||
} |
|||
|
|||
@Override |
|||
public void messageArrived(String requestTopic, MqttMessage mqttMessage) { |
|||
payload = new String(mqttMessage.getPayload()); |
|||
qoS = mqttMessage.getQos(); |
|||
latch.countDown(); |
|||
} |
|||
|
|||
@Override |
|||
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttTimeseriesJsonIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { |
|||
|
|||
private static final String POST_DATA_TELEMETRY_TOPIC = "data/telemetry"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Telemetry device json payload", "Test Post Telemetry gateway json payload", TransportPayloadType.JSON, POST_DATA_TELEMETRY_TOPIC, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetry() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, PAYLOAD_VALUES_STR.getBytes(), false); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryWithTs() throws Exception { |
|||
String payloadStr = "{\"ts\": 10000, \"values\": " + PAYLOAD_VALUES_STR + "}"; |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, payloadStr.getBytes(), true); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryGateway() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
String payload = getGatewayTelemetryJsonPayload(deviceName1, deviceName2, "10000", "20000"); |
|||
processGatewayTelemetryTest(MqttTopics.GATEWAY_TELEMETRY_TOPIC, expectedKeys, payload.getBytes(), deviceName1, deviceName2); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayConnect() throws Exception { |
|||
String payload = "{\"device\":\"Device A\", \"type\": \"" + TransportPayloadType.JSON.name() + "\"}"; |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
publishMqttMsg(client, payload.getBytes(), MqttTopics.GATEWAY_CONNECT_TOPIC); |
|||
|
|||
String deviceName = "Device A"; |
|||
Device device = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class), |
|||
20, |
|||
100); |
|||
assertNotNull(device); |
|||
} |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.paho.client.mqttv3.MqttAsyncClient; |
|||
import org.junit.After; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.TransportPayloadType; |
|||
import org.thingsboard.server.common.data.device.profile.MqttTopics; |
|||
import org.thingsboard.server.gen.transport.TransportApiProtos; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertNotNull; |
|||
|
|||
@Slf4j |
|||
public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { |
|||
|
|||
private static final String POST_DATA_TELEMETRY_TOPIC = "proto/telemetry"; |
|||
|
|||
@Before |
|||
public void beforeTest() throws Exception { |
|||
processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null); |
|||
} |
|||
|
|||
@After |
|||
public void afterTest() throws Exception { |
|||
processAfterTest(); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetry() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 0); |
|||
processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), false); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryWithTs() throws Exception { |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
TransportProtos.TsKvListProto tsKvListProto = getTsKvListProto(expectedKeys, 10000); |
|||
processTelemetryTest(POST_DATA_TELEMETRY_TOPIC, expectedKeys, tsKvListProto.toByteArray(), true); |
|||
} |
|||
|
|||
@Test |
|||
public void testPushMqttTelemetryGateway() throws Exception { |
|||
TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder(); |
|||
List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); |
|||
String deviceName1 = "Device A"; |
|||
String deviceName2 = "Device B"; |
|||
TransportApiProtos.TelemetryMsg deviceATelemetryMsgProto = getDeviceTelemetryMsgProto(deviceName1, expectedKeys, 10000, 20000); |
|||
TransportApiProtos.TelemetryMsg deviceBTelemetryMsgProto = getDeviceTelemetryMsgProto(deviceName2, expectedKeys, 10000, 20000); |
|||
gatewayTelemetryMsgProtoBuilder.addAllMsg(Arrays.asList(deviceATelemetryMsgProto, deviceBTelemetryMsgProto)); |
|||
TransportApiProtos.GatewayTelemetryMsg gatewayTelemetryMsg = gatewayTelemetryMsgProtoBuilder.build(); |
|||
processGatewayTelemetryTest(MqttTopics.GATEWAY_TELEMETRY_TOPIC, expectedKeys, gatewayTelemetryMsg.toByteArray(), deviceName1, deviceName2); |
|||
} |
|||
|
|||
@Test |
|||
public void testGatewayConnect() throws Exception { |
|||
String deviceName = "Device A"; |
|||
TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName); |
|||
MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken); |
|||
publishMqttMsg(client, connectMsgProto.toByteArray(), MqttTopics.GATEWAY_CONNECT_TOPIC); |
|||
|
|||
Device device = doExecuteWithRetriesAndInterval(() -> doGet("/api/tenant/devices?deviceName=" + deviceName, Device.class), |
|||
20, |
|||
100); |
|||
|
|||
assertNotNull(device); |
|||
} |
|||
|
|||
private TransportApiProtos.ConnectMsg getConnectProto(String deviceName) { |
|||
TransportApiProtos.ConnectMsg.Builder builder = TransportApiProtos.ConnectMsg.newBuilder(); |
|||
builder.setDeviceName(deviceName); |
|||
builder.setDeviceType(TransportPayloadType.PROTOBUF.name()); |
|||
return builder.build(); |
|||
} |
|||
|
|||
private TransportApiProtos.TelemetryMsg getDeviceTelemetryMsgProto(String deviceName, List<String> expectedKeys, long firstTs, long secondTs) { |
|||
TransportApiProtos.TelemetryMsg.Builder deviceTelemetryMsgBuilder = TransportApiProtos.TelemetryMsg.newBuilder(); |
|||
TransportProtos.TsKvListProto tsKvListProto1 = getTsKvListProto(expectedKeys, firstTs); |
|||
TransportProtos.TsKvListProto tsKvListProto2 = getTsKvListProto(expectedKeys, secondTs); |
|||
TransportProtos.PostTelemetryMsg.Builder msg = TransportProtos.PostTelemetryMsg.newBuilder(); |
|||
msg.addAllTsKvList(Arrays.asList(tsKvListProto1, tsKvListProto2)); |
|||
deviceTelemetryMsgBuilder.setDeviceName(deviceName); |
|||
deviceTelemetryMsgBuilder.setMsg(msg); |
|||
return deviceTelemetryMsgBuilder.build(); |
|||
} |
|||
|
|||
private TransportProtos.TsKvListProto getTsKvListProto(List<String> expectedKeys, long ts) { |
|||
List<TransportProtos.KeyValueProto> kvProtos = getKvProtos(expectedKeys); |
|||
TransportProtos.TsKvListProto.Builder builder = TransportProtos.TsKvListProto.newBuilder(); |
|||
builder.addAllKv(kvProtos); |
|||
builder.setTs(ts); |
|||
return builder.build(); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttTimeseriesNoSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries.nosql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoNoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; |
|||
|
|||
@DaoNoSqlTest |
|||
public class MqttTimeseriesNoSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; |
|||
|
|||
/** |
|||
* Created by Valerii Sosliuk on 8/22/2017. |
|||
*/ |
|||
@DaoSqlTest |
|||
public class MqttTimeseriesSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest { |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.mqtt.telemetry.timeseries.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; |
|||
import org.thingsboard.server.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; |
|||
|
|||
/** |
|||
* Created by Valerii Sosliuk on 8/22/2017. |
|||
*/ |
|||
@DaoSqlTest |
|||
public class MqttTimeseriesSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest { |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.dao.rule; |
|||
|
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.RuleNodeId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rule.RuleNodeState; |
|||
|
|||
public interface RuleNodeStateService { |
|||
|
|||
PageData<RuleNodeState> findByRuleNodeId(TenantId tenantId, RuleNodeId ruleNodeId, PageLink pageLink); |
|||
|
|||
RuleNodeState findByRuleNodeIdAndEntityId(TenantId tenantId, RuleNodeId ruleNodeId, EntityId entityId); |
|||
|
|||
RuleNodeState save(TenantId tenantId, RuleNodeState ruleNodeState); |
|||
|
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data; |
|||
|
|||
public enum TransportPayloadType { |
|||
JSON, |
|||
PROTOBUF |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import com.fasterxml.jackson.annotation.JsonSubTypes; |
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
|||
|
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
@JsonTypeInfo( |
|||
use = JsonTypeInfo.Id.NAME, |
|||
include = JsonTypeInfo.As.PROPERTY, |
|||
property = "type") |
|||
@JsonSubTypes({ |
|||
@JsonSubTypes.Type(value = SimpleAlarmConditionSpec.class, name = "SIMPLE"), |
|||
@JsonSubTypes.Type(value = DurationAlarmConditionSpec.class, name = "DURATION"), |
|||
@JsonSubTypes.Type(value = RepeatingAlarmConditionSpec.class, name = "REPEATING")}) |
|||
public interface AlarmConditionSpec { |
|||
|
|||
@JsonIgnore |
|||
AlarmConditionSpecType getType(); |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
public enum AlarmConditionSpecType { |
|||
|
|||
SIMPLE, |
|||
DURATION, |
|||
REPEATING |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import com.fasterxml.jackson.annotation.JsonSubTypes; |
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
|||
|
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
@JsonTypeInfo( |
|||
use = JsonTypeInfo.Id.NAME, |
|||
include = JsonTypeInfo.As.PROPERTY, |
|||
property = "type") |
|||
@JsonSubTypes({ |
|||
@JsonSubTypes.Type(value = AnyTimeSchedule.class, name = "ANY_TIME"), |
|||
@JsonSubTypes.Type(value = SpecificTimeSchedule.class, name = "SPECIFIC_TIME"), |
|||
@JsonSubTypes.Type(value = CustomTimeSchedule.class, name = "CUSTOM")}) |
|||
public interface AlarmSchedule { |
|||
|
|||
AlarmScheduleType getType(); |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
public enum AlarmScheduleType { |
|||
|
|||
ANY_TIME, |
|||
SPECIFIC_TIME, |
|||
CUSTOM |
|||
|
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
public class AnyTimeSchedule implements AlarmSchedule { |
|||
|
|||
@Override |
|||
public AlarmScheduleType getType() { |
|||
return AlarmScheduleType.ANY_TIME; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class CustomTimeSchedule implements AlarmSchedule { |
|||
|
|||
private String timezone; |
|||
private List<CustomTimeScheduleItem> items; |
|||
|
|||
@Override |
|||
public AlarmScheduleType getType() { |
|||
return AlarmScheduleType.CUSTOM; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class CustomTimeScheduleItem { |
|||
|
|||
private boolean enabled; |
|||
private int dayOfWeek; |
|||
private long startsOn; |
|||
private long endsOn; |
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import lombok.Data; |
|||
|
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Data |
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
public class DurationAlarmConditionSpec implements AlarmConditionSpec { |
|||
|
|||
private TimeUnit unit; |
|||
private long value; |
|||
|
|||
@Override |
|||
public AlarmConditionSpecType getType() { |
|||
return AlarmConditionSpecType.DURATION; |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import lombok.Data; |
|||
|
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Data |
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
public class RepeatingAlarmConditionSpec implements AlarmConditionSpec { |
|||
|
|||
private int count; |
|||
|
|||
@Override |
|||
public AlarmConditionSpecType getType() { |
|||
return AlarmConditionSpecType.REPEATING; |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
@JsonIgnoreProperties(ignoreUnknown = true) |
|||
public class SimpleAlarmConditionSpec implements AlarmConditionSpec { |
|||
@Override |
|||
public AlarmConditionSpecType getType() { |
|||
return AlarmConditionSpecType.SIMPLE; |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.device.profile; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
@Data |
|||
public class SpecificTimeSchedule implements AlarmSchedule { |
|||
|
|||
private String timezone; |
|||
private Set<Integer> daysOfWeek; |
|||
private long startsOn; |
|||
private long endsOn; |
|||
|
|||
@Override |
|||
public AlarmScheduleType getType() { |
|||
return AlarmScheduleType.SPECIFIC_TIME; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.id; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
public class RuleNodeStateId extends UUIDBased { |
|||
|
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
@JsonCreator |
|||
public RuleNodeStateId(@JsonProperty("id") UUID id) { |
|||
super(id); |
|||
} |
|||
|
|||
public static RuleNodeStateId fromString(String eventId) { |
|||
return new RuleNodeStateId(UUID.fromString(eventId)); |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.rule; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class RuleChainData { |
|||
|
|||
List<RuleChain> ruleChains; |
|||
List<RuleChainMetaData> metadata; |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.rule; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class RuleChainImportResult { |
|||
|
|||
private TenantId tenantId; |
|||
private RuleChainId ruleChainId; |
|||
private ComponentLifecycleEvent lifecycleEvent; |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.rule; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.BaseData; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.RuleNodeId; |
|||
import org.thingsboard.server.common.data.id.RuleNodeStateId; |
|||
|
|||
@Data |
|||
public class RuleNodeState extends BaseData<RuleNodeStateId> { |
|||
|
|||
private RuleNodeId ruleNodeId; |
|||
private EntityId entityId; |
|||
private String stateData; |
|||
|
|||
public RuleNodeState() { |
|||
super(); |
|||
} |
|||
|
|||
public RuleNodeState(RuleNodeStateId id) { |
|||
super(id); |
|||
} |
|||
|
|||
public RuleNodeState(RuleNodeState event) { |
|||
super(event); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue