From 91d0f1dd1d7ca485cebd35b98b9c9f6e305ebf8b Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 1 Aug 2024 15:44:48 +0300 Subject: [PATCH 1/6] Added ability to provision gateway device on device creating using device provisioning feature --- .../transport/DefaultTransportApiService.java | 5 ++- .../MqttProvisionProtoDeviceTest.java | 39 +++++++++++++++++++ .../device/provision/ProvisionRequest.java | 1 + .../server/common/adaptor/JsonConverter.java | 1 + common/proto/src/main/proto/queue.proto | 1 + .../server/dao/device/DeviceServiceImpl.java | 6 +++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 8b29af34ed..32f7d48e29 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -417,7 +417,8 @@ public class DefaultTransportApiService implements TransportApiService { requestMsg.getCredentialsDataProto().getValidateDeviceX509CertRequestMsg().getHash()), new ProvisionDeviceProfileCredentials( requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceKey(), - requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceSecret()))); + requestMsg.getProvisionDeviceCredentialsMsg().getProvisionDeviceSecret()), + requestMsg.getGateway())); } catch (ProvisionFailedException e) { return getTransportApiResponseMsg(new DeviceCredentials(), TransportProtos.ResponseStatus.valueOf(e.getMessage())); } @@ -665,7 +666,7 @@ public class DefaultTransportApiService implements TransportApiService { private ProvisionRequest createProvisionRequest(String certificateValue) { return new ProvisionRequest(null, DeviceCredentialsType.X509_CERTIFICATE, new ProvisionDeviceCredentialsData(null, null, null, null, certificateValue), - null); + null, null); } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java index 0926459513..16b3f8a233 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.mqtt.mqttv3.provision; +import com.fasterxml.jackson.databind.JsonNode; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; import org.junit.Assert; @@ -76,6 +77,11 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { processTestProvisioningCreateNewDeviceWithoutCredentials(); } + @Test + public void testProvisioningCreateNewGatewayDevice() throws Exception { + processTestProvisioningCreateNewGatewayDevice(); + } + @Test public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { processTestProvisioningCreateNewDeviceWithAccessToken(); @@ -130,6 +136,35 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().name()); } + protected void processTestProvisioningCreateNewGatewayDevice() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Provision gateway device") + .transportPayloadType(TransportPayloadType.PROTOBUF) + .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) + .provisionKey("testProvisionKey") + .provisionSecret("testProvisionSecret") + .build(); + processBeforeTest(configProperties); + + byte[] provisionRequestMsg = createTestsProvisionMessage(null, null, true); + byte[] responseBytesMsg = createMqttClientAndPublish(provisionRequestMsg); + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(responseBytesMsg); + + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision gateway device"); + + Assert.assertNotNull(createdDevice); + + JsonNode additionalInfo = createdDevice.getAdditionalInfo(); + Assert.assertNotNull(additionalInfo); + Assert.assertTrue(additionalInfo.has("gateway")); + Assert.assertTrue(additionalInfo.get("gateway").asBoolean()); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); + + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().name()); + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().name()); + } + protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() .deviceName("Test Provision device3") @@ -280,6 +315,10 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { } protected byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData) throws Exception { + return createTestsProvisionMessage(credentialsType, credentialsData, false); + } + + protected byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData, boolean isGateway) throws Exception { return ProvisionDeviceRequestMsg.newBuilder() .setDeviceName("Test Provision device") .setCredentialsType(credentialsType != null ? credentialsType : CredentialsType.ACCESS_TOKEN) diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/provision/ProvisionRequest.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/provision/ProvisionRequest.java index d01d7be3c1..c0643f96da 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/provision/ProvisionRequest.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/provision/ProvisionRequest.java @@ -28,4 +28,5 @@ public class ProvisionRequest { private DeviceCredentialsType credentialsType; private ProvisionDeviceCredentialsData credentialsData; private ProvisionDeviceProfileCredentials credentials; + private Boolean gateway; } diff --git a/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java index f5c7bbb901..d1283d3ba0 100644 --- a/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/adaptor/JsonConverter.java @@ -635,6 +635,7 @@ public class JsonConverter { .setProvisionDeviceCredentialsMsg(buildProvisionDeviceCredentialsMsg( getStrValue(jo, DataConstants.PROVISION_KEY, true), getStrValue(jo, DataConstants.PROVISION_SECRET, true))) + .setGateway(jo.has(DataConstants.GATEWAY_PARAMETER) && jo.get(DataConstants.GATEWAY_PARAMETER).getAsBoolean()) .build(); } diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 6a8fb543f6..7ede3bdf1b 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -687,6 +687,7 @@ message ProvisionDeviceRequestMsg { CredentialsType credentialsType = 2; ProvisionDeviceCredentialsMsg provisionDeviceCredentialsMsg = 3; CredentialsDataProto credentialsDataProto = 4; + bool gateway = 5; } message ProvisionDeviceCredentialsMsg { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 5b770845c1..e7f738a90d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.device; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -564,6 +565,11 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Fri, 2 Aug 2024 09:30:25 +0300 Subject: [PATCH 2/6] Added additional tests --- .../provision/DeviceProvisionServiceTest.java | 2 +- .../CoapProvisionJsonDeviceTest.java | 59 +++++++++++++++++-- .../CoapProvisionProtoDeviceTest.java | 44 +++++++++++++- .../MqttProvisionJsonDeviceTest.java | 58 ++++++++++++++++-- .../MqttProvisionProtoDeviceTest.java | 10 ++-- .../msa/connectivity/HttpClientTest.java | 41 +++++++++++++ 6 files changed, 200 insertions(+), 14 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java index 8d5d66f6d2..75b84f50be 100644 --- a/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/device/provision/DeviceProvisionServiceTest.java @@ -236,7 +236,7 @@ public class DeviceProvisionServiceTest { private ProvisionRequest createProvisionRequest(String certificateValue) { return new ProvisionRequest(null, DeviceCredentialsType.X509_CERTIFICATE, new ProvisionDeviceCredentialsData(null, null, null, null, certificateValue), - null); + null, null); } public static String certTrimNewLinesForChainInDeviceProfile(String input) { diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java index 22d1e9e349..b2187ba7b4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionJsonDeviceTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.CoapDeviceType; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; @@ -67,6 +68,11 @@ public class CoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest { processTestProvisioningCreateNewDeviceWithoutCredentials(); } + @Test + public void testProvisioningCreateNewGatewayDevice() throws Exception { + processTestProvisioningCreateNewGatewayDevice(); + } + @Test public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { processTestProvisioningCreateNewDeviceWithAccessToken(); @@ -123,6 +129,37 @@ public class CoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest { } + private void processTestProvisioningCreateNewGatewayDevice() throws Exception { + CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() + .deviceName("Test Provision device3") + .coapDeviceType(CoapDeviceType.DEFAULT) + .transportPayloadType(TransportPayloadType.JSON) + .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) + .provisionKey("testProvisionKey") + .provisionSecret("testProvisionSecret") + .build(); + processBeforeTest(configProperties); + JsonNode response = JacksonUtil.fromBytes(createCoapClientAndPublish(true)); + Assert.assertTrue(response.hasNonNull("credentialsType")); + Assert.assertTrue(response.hasNonNull("status")); + + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device"); + + Assert.assertNotNull(createdDevice); + + JsonNode additionalInfo = createdDevice.getAdditionalInfo(); + Assert.assertNotNull(additionalInfo); + Assert.assertTrue(additionalInfo.has(DataConstants.GATEWAY_PARAMETER) + && additionalInfo.get(DataConstants.GATEWAY_PARAMETER).isBoolean()); + Assert.assertTrue(additionalInfo.get(DataConstants.GATEWAY_PARAMETER).asBoolean()); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); + + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").asText()); + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").asText()); + } + + private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() .deviceName("Test Provision device3") @@ -222,16 +259,30 @@ public class CoapProvisionJsonDeviceTest extends AbstractCoapIntegrationTest { } private byte[] createCoapClientAndPublish() throws Exception { - return createCoapClientAndPublish(""); + return createCoapClientAndPublish(false); + } + + private byte[] createCoapClientAndPublish(boolean isGateway) throws Exception { + return createCoapClientAndPublish("", isGateway); } private byte[] createCoapClientAndPublish(String deviceCredentials) throws Exception { - String provisionRequestMsg = createTestProvisionMessage(deviceCredentials); + return createCoapClientAndPublish(deviceCredentials, false); + } + + private byte[] createCoapClientAndPublish(String deviceCredentials, boolean isGateway) throws Exception { + String provisionRequestMsg = createTestProvisionMessage(deviceCredentials, isGateway); client = new CoapTestClient(accessToken, FeatureType.PROVISION); return client.postMethod(provisionRequestMsg.getBytes()).getPayload(); } - private String createTestProvisionMessage(String deviceCredentials) { - return "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials + "}"; + protected String createTestProvisionMessage(String deviceCredentials, boolean isGateway) { + String request = "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + + deviceCredentials; + if (isGateway) { + request += ",\"gateway\":true"; + } + request += "}"; + return request; } } diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java index 5a7c880d44..4b1f806f74 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/provision/CoapProvisionProtoDeviceTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.coap.provision; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapResponse; import org.junit.After; @@ -22,6 +23,7 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.CoapDeviceType; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; @@ -74,6 +76,11 @@ public class CoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest { processTestProvisioningCreateNewDeviceWithoutCredentials(); } + @Test + public void testProvisioningCreateNewGatewayDevice() throws Exception { + processTestProvisioningCreateNewGatewayDevice(); + } + @Test public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { processTestProvisioningCreateNewDeviceWithAccessToken(); @@ -124,6 +131,35 @@ public class CoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest { Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().name()); } + private void processTestProvisioningCreateNewGatewayDevice() throws Exception { + CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() + .deviceName("Test Provision device3") + .coapDeviceType(CoapDeviceType.DEFAULT) + .transportPayloadType(TransportPayloadType.PROTOBUF) + .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) + .provisionKey("testProvisionKey") + .provisionSecret("testProvisionSecret") + .build(); + processBeforeTest(configProperties); + byte[] testsProvisionMessage = createTestsProvisionMessage(null, null, true); + ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(testsProvisionMessage)); + + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device"); + + Assert.assertNotNull(createdDevice); + + JsonNode additionalInfo = createdDevice.getAdditionalInfo(); + Assert.assertNotNull(additionalInfo); + Assert.assertTrue(additionalInfo.has(DataConstants.GATEWAY_PARAMETER) + && additionalInfo.get(DataConstants.GATEWAY_PARAMETER).isBoolean()); + Assert.assertTrue(additionalInfo.get(DataConstants.GATEWAY_PARAMETER).asBoolean()); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); + + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.getCredentialsType().name()); + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.getStatus().name()); + } + private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { CoapTestConfigProperties configProperties = CoapTestConfigProperties.builder() .deviceName("Test Provision device3") @@ -233,6 +269,10 @@ public class CoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest { } private byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData) throws Exception { + return createTestsProvisionMessage(credentialsType, credentialsData, false); + } + + private byte[] createTestsProvisionMessage(CredentialsType credentialsType, CredentialsDataProto credentialsData, boolean isGateway) throws Exception { return ProvisionDeviceRequestMsg.newBuilder() .setDeviceName("Test Provision device") .setCredentialsType(credentialsType != null ? credentialsType : CredentialsType.ACCESS_TOKEN) @@ -241,7 +281,9 @@ public class CoapProvisionProtoDeviceTest extends AbstractCoapIntegrationTest { ProvisionDeviceCredentialsMsg.newBuilder() .setProvisionDeviceKey("testProvisionKey") .setProvisionDeviceSecret("testProvisionSecret") - ).build() + ) + .setGateway(isGateway) + .build() .toByteArray(); } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java index 27ed65f54a..d32ca58aa4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; @@ -68,6 +69,11 @@ public class MqttProvisionJsonDeviceTest extends AbstractMqttIntegrationTest { processTestProvisioningCreateNewDeviceWithoutCredentials(); } + @Test + public void testProvisioningCreateNewGatewayDevice() throws Exception { + processTestProvisioningCreateNewGatewayDevice(); + } + @Test public void testProvisioningCreateNewDeviceWithAccessToken() throws Exception { processTestProvisioningCreateNewDeviceWithAccessToken(); @@ -130,6 +136,37 @@ public class MqttProvisionJsonDeviceTest extends AbstractMqttIntegrationTest { } + protected void processTestProvisioningCreateNewGatewayDevice() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Provision device3") + .transportPayloadType(TransportPayloadType.JSON) + .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) + .provisionKey("testProvisionKey") + .provisionSecret("testProvisionSecret") + .build(); + super.processBeforeTest(configProperties); + byte[] result = createMqttClientAndPublish(true); + JsonNode response = JacksonUtil.fromBytes(result); + Assert.assertTrue(response.hasNonNull("credentialsType")); + Assert.assertTrue(response.hasNonNull("status")); + + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device"); + + Assert.assertNotNull(createdDevice); + + JsonNode additionalInfo = createdDevice.getAdditionalInfo(); + Assert.assertNotNull(additionalInfo); + Assert.assertTrue(additionalInfo.has(DataConstants.GATEWAY_PARAMETER) + && additionalInfo.get(DataConstants.GATEWAY_PARAMETER).isBoolean()); + Assert.assertTrue(additionalInfo.get(DataConstants.GATEWAY_PARAMETER).asBoolean()); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); + + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").asText()); + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").asText()); + } + + protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception { MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() .deviceName("Test Provision device3") @@ -264,11 +301,19 @@ public class MqttProvisionJsonDeviceTest extends AbstractMqttIntegrationTest { } protected byte[] createMqttClientAndPublish() throws Exception { - return createMqttClientAndPublish(""); + return createMqttClientAndPublish(false); + } + + protected byte[] createMqttClientAndPublish(boolean isGateway) throws Exception { + return createMqttClientAndPublish("", isGateway); } protected byte[] createMqttClientAndPublish(String deviceCredentials) throws Exception { - String provisionRequestMsg = createTestProvisionMessage(deviceCredentials); + return createMqttClientAndPublish(deviceCredentials, false); + } + + protected byte[] createMqttClientAndPublish(String deviceCredentials, boolean isGateway) throws Exception { + String provisionRequestMsg = createTestProvisionMessage(deviceCredentials, isGateway); MqttTestClient client = new MqttTestClient(); client.connectAndWait("provision"); MqttTestCallback onProvisionCallback = new MqttTestSubscribeOnTopicCallback(DEVICE_PROVISION_RESPONSE_TOPIC); @@ -280,7 +325,12 @@ public class MqttProvisionJsonDeviceTest extends AbstractMqttIntegrationTest { return onProvisionCallback.getPayloadBytes(); } - protected String createTestProvisionMessage(String deviceCredentials) { - return "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials + "}"; + protected String createTestProvisionMessage(String deviceCredentials, boolean isGateway) { + String request = "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"" + deviceCredentials; + if (isGateway) { + request += ",\"gateway\":true"; + } + request += "}"; + return request; } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java index 16b3f8a233..f05a4f8953 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java @@ -22,6 +22,7 @@ import org.junit.Assert; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.TransportPayloadType; @@ -138,7 +139,7 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { protected void processTestProvisioningCreateNewGatewayDevice() throws Exception { MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() - .deviceName("Test Provision gateway device") + .deviceName("Test Provision device3") .transportPayloadType(TransportPayloadType.PROTOBUF) .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) .provisionKey("testProvisionKey") @@ -150,14 +151,15 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { byte[] responseBytesMsg = createMqttClientAndPublish(provisionRequestMsg); ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(responseBytesMsg); - Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision gateway device"); + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device"); Assert.assertNotNull(createdDevice); JsonNode additionalInfo = createdDevice.getAdditionalInfo(); Assert.assertNotNull(additionalInfo); - Assert.assertTrue(additionalInfo.has("gateway")); - Assert.assertTrue(additionalInfo.get("gateway").asBoolean()); + Assert.assertTrue(additionalInfo.has(DataConstants.GATEWAY_PARAMETER) + && additionalInfo.get(DataConstants.GATEWAY_PARAMETER).isBoolean()); + Assert.assertTrue(additionalInfo.get(DataConstants.GATEWAY_PARAMETER).asBoolean()); DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java index 5ec80ca8be..9c33a04e64 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java @@ -21,6 +21,7 @@ import io.restassured.path.json.JsonPath; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileProvisionType; @@ -156,6 +157,46 @@ public class HttpClientTest extends AbstractContainerTest { updateDeviceProfileWithProvisioningStrategy(deviceProfile, DeviceProfileProvisionType.DISABLED); } + @Test + public void provisionRequestForGatewayDeviceWithAllowToCreateNewDevicesStrategy() throws Exception { + + String testDeviceName = "test_provision_device"; + + DeviceProfile deviceProfile = testRestClient.getDeviceProfileById(device.getDeviceProfileId()); + + deviceProfile = updateDeviceProfileWithProvisioningStrategy(deviceProfile, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES); + + JsonObject provisionRequest = new JsonObject(); + provisionRequest.addProperty("provisionDeviceKey", TEST_PROVISION_DEVICE_KEY); + provisionRequest.addProperty("provisionDeviceSecret", TEST_PROVISION_DEVICE_SECRET); + provisionRequest.addProperty("deviceName", testDeviceName); + provisionRequest.addProperty("gateway", true); + + JsonPath provisionResponse = testRestClient.postProvisionRequest(provisionRequest.toString()); + + String credentialsType = provisionResponse.get("credentialsType"); + String credentialsValue = provisionResponse.get("credentialsValue"); + String status = provisionResponse.get("status"); + + testRestClient.deleteDeviceIfExists(device.getId()); + device = testRestClient.getDeviceByName(testDeviceName); + + JsonNode additionalInfo = device.getAdditionalInfo(); + + assertThat(additionalInfo).isNotNull(); + assertThat(additionalInfo.has(DataConstants.GATEWAY_PARAMETER) + && additionalInfo.get(DataConstants.GATEWAY_PARAMETER).isBoolean()).isTrue(); + assertThat(additionalInfo.get(DataConstants.GATEWAY_PARAMETER).asBoolean()).isTrue(); + + DeviceCredentials expectedDeviceCredentials = testRestClient.getDeviceCredentialsByDeviceId(device.getId()); + + assertThat(credentialsType).isEqualTo(expectedDeviceCredentials.getCredentialsType().name()); + assertThat(credentialsValue).isEqualTo(expectedDeviceCredentials.getCredentialsId()); + assertThat(status).isEqualTo("SUCCESS"); + + updateDeviceProfileWithProvisioningStrategy(deviceProfile, DeviceProfileProvisionType.DISABLED); + } + @Test public void provisionRequestForDeviceWithDisabledProvisioningStrategy() throws Exception { From 599237d08d2d540d24ff99dc85ba843906681405 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Fri, 2 Aug 2024 09:39:23 +0300 Subject: [PATCH 3/6] Refactoring --- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index e7f738a90d..73633d041f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -28,6 +28,7 @@ import org.springframework.util.CollectionUtils; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cache.device.DeviceCacheEvictEvent; import org.thingsboard.server.cache.device.DeviceCacheKey; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.DeviceInfo; @@ -567,7 +568,7 @@ public class DeviceServiceImpl extends AbstractCachedEntityService Date: Fri, 2 Aug 2024 10:41:32 +0300 Subject: [PATCH 4/6] Test fix --- .../mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java index f05a4f8953..bc4f1cdd86 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java @@ -329,7 +329,9 @@ public class MqttProvisionProtoDeviceTest extends AbstractMqttIntegrationTest { ProvisionDeviceCredentialsMsg.newBuilder() .setProvisionDeviceKey("testProvisionKey") .setProvisionDeviceSecret("testProvisionSecret") - ).build() + ) + .setGateway(isGateway) + .build() .toByteArray(); } From 6b99fb917a2fd5ec177c5f2258ba461711a39a04 Mon Sep 17 00:00:00 2001 From: imbeacon Date: Thu, 12 Sep 2024 12:52:30 +0300 Subject: [PATCH 5/6] Fix for NPE --- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 55696c9e4b..d58249fef2 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -557,7 +557,7 @@ public class DeviceServiceImpl extends CachedVersionedEntityService Date: Thu, 12 Sep 2024 12:54:50 +0300 Subject: [PATCH 6/6] Avoided additional info creation on provisioning if the device is not a gateway --- .../org/thingsboard/server/dao/device/DeviceServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index d58249fef2..3cd25cc390 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -556,11 +556,11 @@ public class DeviceServiceImpl extends CachedVersionedEntityService