Merge remote-tracking branch 'origin/hotfix/3.6.1' into master-hotfix
This commit is contained in:
commit
adfa3d0b90
@ -407,6 +407,7 @@ public class ProtoUtils {
|
|||||||
.setRequestIdMSB(msg.getMsg().getId().getMostSignificantBits())
|
.setRequestIdMSB(msg.getMsg().getId().getMostSignificantBits())
|
||||||
.setRequestIdLSB(msg.getMsg().getId().getLeastSignificantBits())
|
.setRequestIdLSB(msg.getMsg().getId().getLeastSignificantBits())
|
||||||
.setOneway(msg.getMsg().isOneway())
|
.setOneway(msg.getMsg().isOneway())
|
||||||
|
.setPersisted(msg.getMsg().isPersisted())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return TransportProtos.ToDeviceRpcRequestActorMsgProto.newBuilder()
|
return TransportProtos.ToDeviceRpcRequestActorMsgProto.newBuilder()
|
||||||
|
|||||||
@ -49,6 +49,7 @@ import org.thingsboard.server.common.data.id.DeviceId;
|
|||||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
import org.thingsboard.server.common.data.id.DeviceProfileId;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
import org.thingsboard.server.common.data.id.EntityViewId;
|
import org.thingsboard.server.common.data.id.EntityViewId;
|
||||||
|
import org.thingsboard.server.common.data.id.RpcId;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
@ -57,6 +58,7 @@ import org.thingsboard.server.common.data.page.PageLink;
|
|||||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
|
import org.thingsboard.server.common.data.rpc.Rpc;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChain;
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||||
@ -64,6 +66,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static io.restassured.RestAssured.given;
|
import static io.restassured.RestAssured.given;
|
||||||
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
|
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
|
||||||
@ -320,6 +323,27 @@ public class TestRestClient {
|
|||||||
.as(JsonNode.class);
|
.as(JsonNode.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rpc getPersistedRpc(RpcId rpcId) {
|
||||||
|
return given().spec(requestSpec)
|
||||||
|
.get("/api/rpc/persistent/{rpcId}", rpcId.toString())
|
||||||
|
.then()
|
||||||
|
.statusCode(HTTP_OK)
|
||||||
|
.extract()
|
||||||
|
.as(Rpc.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageData<Rpc> getPersistedRpcByDevice(DeviceId deviceId, PageLink pageLink) {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
addPageLinkToParam(params, pageLink);
|
||||||
|
return given().spec(requestSpec).queryParams(params)
|
||||||
|
.get("/api/rpc/persistent/device/{deviceId}", deviceId.toString())
|
||||||
|
.then()
|
||||||
|
.statusCode(HTTP_OK)
|
||||||
|
.extract()
|
||||||
|
.as(new TypeRef<>() {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public PageData<DeviceProfile> getDeviceProfiles(PageLink pageLink) {
|
public PageData<DeviceProfile> getDeviceProfiles(PageLink pageLink) {
|
||||||
Map<String, String> params = new HashMap<>();
|
Map<String, String> params = new HashMap<>();
|
||||||
addPageLinkToParam(params, pageLink);
|
addPageLinkToParam(params, pageLink);
|
||||||
|
|||||||
@ -46,9 +46,11 @@ import org.thingsboard.server.common.data.Device;
|
|||||||
import org.thingsboard.server.common.data.DeviceProfile;
|
import org.thingsboard.server.common.data.DeviceProfile;
|
||||||
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
|
||||||
import org.thingsboard.server.common.data.StringUtils;
|
import org.thingsboard.server.common.data.StringUtils;
|
||||||
|
import org.thingsboard.server.common.data.id.RpcId;
|
||||||
import org.thingsboard.server.common.data.id.RuleChainId;
|
import org.thingsboard.server.common.data.id.RuleChainId;
|
||||||
import org.thingsboard.server.common.data.page.PageData;
|
import org.thingsboard.server.common.data.page.PageData;
|
||||||
import org.thingsboard.server.common.data.page.PageLink;
|
import org.thingsboard.server.common.data.page.PageLink;
|
||||||
|
import org.thingsboard.server.common.data.rpc.Rpc;
|
||||||
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
|
import org.thingsboard.server.common.data.rule.NodeConnectionInfo;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChain;
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
import org.thingsboard.server.common.data.rule.RuleChainMetaData;
|
||||||
@ -68,6 +70,7 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -76,6 +79,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
import static org.thingsboard.server.common.data.DataConstants.DEVICE;
|
import static org.thingsboard.server.common.data.DataConstants.DEVICE;
|
||||||
import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE;
|
import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE;
|
||||||
@ -307,6 +311,60 @@ public class MqttClientTest extends AbstractContainerTest {
|
|||||||
assertThat(serverResponse).isEqualTo(mapper.readTree(clientResponse.toString()));
|
assertThat(serverResponse).isEqualTo(mapper.readTree(clientResponse.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serverSidePersistedRpc() throws Exception {
|
||||||
|
DeviceCredentials deviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId());
|
||||||
|
|
||||||
|
MqttMessageListener listener = new MqttMessageListener();
|
||||||
|
MqttClient mqttClient = getMqttClient(deviceCredentials, listener);
|
||||||
|
mqttClient.on("v1/devices/me/rpc/request/+", listener, MqttQoS.AT_LEAST_ONCE).get();
|
||||||
|
|
||||||
|
// Wait until subscription is processed
|
||||||
|
TimeUnit.SECONDS.sleep(3 * timeoutMultiplier);
|
||||||
|
|
||||||
|
// Send an RPC from the server
|
||||||
|
JsonObject serverRpcPayload = new JsonObject();
|
||||||
|
serverRpcPayload.addProperty("method", "getValue");
|
||||||
|
serverRpcPayload.addProperty("params", true);
|
||||||
|
serverRpcPayload.addProperty("persistent", true);
|
||||||
|
|
||||||
|
JsonNode persistentRpcId = testRestClient.postServerSideRpc(device.getId(), mapper.readTree(serverRpcPayload.toString()));
|
||||||
|
|
||||||
|
assertNotNull(persistentRpcId);
|
||||||
|
|
||||||
|
RpcId rpcId = new RpcId(UUID.fromString(persistentRpcId.get("rpcId").asText()));
|
||||||
|
|
||||||
|
// Wait for RPC call from the server and send the response
|
||||||
|
MqttEvent requestFromServer = listener.getEvents().poll(10 * timeoutMultiplier, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertThat(Objects.requireNonNull(requestFromServer).getMessage()).isEqualTo("{\"method\":\"getValue\",\"params\":true}");
|
||||||
|
|
||||||
|
Integer requestId = Integer.valueOf(Objects.requireNonNull(requestFromServer).getTopic().substring("v1/devices/me/rpc/request/".length()));
|
||||||
|
JsonObject clientResponse = new JsonObject();
|
||||||
|
clientResponse.addProperty("response", "someResponse");
|
||||||
|
// Send a response to the server's RPC request
|
||||||
|
mqttClient.publish("v1/devices/me/rpc/response/" + requestId, Unpooled.wrappedBuffer(clientResponse.toString().getBytes())).get();
|
||||||
|
|
||||||
|
PageLink pageLink = new PageLink(10);
|
||||||
|
|
||||||
|
Awaitility.await()
|
||||||
|
.pollInterval(500, TimeUnit.MILLISECONDS)
|
||||||
|
.atMost(5 * timeoutMultiplier, TimeUnit.SECONDS)
|
||||||
|
.until(() -> {
|
||||||
|
PageData<Rpc> rpcByDevice = testRestClient.getPersistedRpcByDevice(device.getId(), pageLink);
|
||||||
|
for (Rpc rpc : rpcByDevice.getData()) {
|
||||||
|
if (rpc.getId().equals(rpcId)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
Rpc persistentRpc = testRestClient.getPersistedRpc(rpcId);
|
||||||
|
|
||||||
|
assertThat(persistentRpc.getResponse()).isEqualTo(mapper.readTree(clientResponse.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void clientSideRpc() throws Exception {
|
public void clientSideRpc() throws Exception {
|
||||||
DeviceCredentials deviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId());
|
DeviceCredentials deviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId());
|
||||||
|
|||||||
@ -47,7 +47,7 @@ public class CertPemCredentials implements ClientCredentials {
|
|||||||
protected String caCert;
|
protected String caCert;
|
||||||
private String cert;
|
private String cert;
|
||||||
private String privateKey;
|
private String privateKey;
|
||||||
private String password = "";
|
private String password;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialsType getType() {
|
public CredentialsType getType() {
|
||||||
|
|||||||
@ -38,7 +38,6 @@ import static org.thingsboard.rule.engine.credentials.CertPemCredentials.PRIVATE
|
|||||||
public class CertPemCredentialsTest {
|
public class CertPemCredentialsTest {
|
||||||
|
|
||||||
private static final String PASS = "test";
|
private static final String PASS = "test";
|
||||||
private static final String EMPTY_PASS = "";
|
|
||||||
private static final String RSA = "RSA";
|
private static final String RSA = "RSA";
|
||||||
private static final String EC = "EC";
|
private static final String EC = "EC";
|
||||||
|
|
||||||
@ -81,10 +80,10 @@ public class CertPemCredentialsTest {
|
|||||||
|
|
||||||
private static Stream<Arguments> testLoadKeyStore() {
|
private static Stream<Arguments> testLoadKeyStore() {
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of("pem/rsa_cert.pem", "pem/rsa_key.pem", EMPTY_PASS, RSA),
|
Arguments.of("pem/rsa_cert.pem", "pem/rsa_key.pem", null, RSA),
|
||||||
Arguments.of("pem/rsa_encrypted_cert.pem", "pem/rsa_encrypted_key.pem", PASS, RSA),
|
Arguments.of("pem/rsa_encrypted_cert.pem", "pem/rsa_encrypted_key.pem", PASS, RSA),
|
||||||
Arguments.of("pem/rsa_encrypted_traditional_cert.pem", "pem/rsa_encrypted_traditional_key.pem", PASS, RSA),
|
Arguments.of("pem/rsa_encrypted_traditional_cert.pem", "pem/rsa_encrypted_traditional_key.pem", PASS, RSA),
|
||||||
Arguments.of("pem/ec_cert.pem", "pem/ec_key.pem", EMPTY_PASS, EC)
|
Arguments.of("pem/ec_cert.pem", "pem/ec_key.pem", null, EC)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +97,7 @@ public class CertPemCredentialsTest {
|
|||||||
certPemCredentials.setPassword(password);
|
certPemCredentials.setPassword(password);
|
||||||
KeyStore keyStore = certPemCredentials.loadKeyStore();
|
KeyStore keyStore = certPemCredentials.loadKeyStore();
|
||||||
Assertions.assertNotNull(keyStore);
|
Assertions.assertNotNull(keyStore);
|
||||||
Key key = keyStore.getKey(PRIVATE_KEY_ALIAS, password.toCharArray());
|
Key key = keyStore.getKey(PRIVATE_KEY_ALIAS, SslUtil.getPassword(password));
|
||||||
Assertions.assertNotNull(key);
|
Assertions.assertNotNull(key);
|
||||||
Assertions.assertEquals(algorithm, key.getAlgorithm());
|
Assertions.assertEquals(algorithm, key.getAlgorithm());
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user