committed by
GitHub
61 changed files with 2180 additions and 730 deletions
@ -0,0 +1,24 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.service.lwm2m; |
|||
|
|||
import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; |
|||
|
|||
public interface LwM2MService { |
|||
|
|||
ServerSecurityConfig getServerSecurityInfo(boolean bootstrapServer); |
|||
|
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.ota; |
|||
|
|||
import org.springframework.mock.web.MockMultipartFile; |
|||
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; |
|||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; |
|||
import org.thingsboard.server.common.data.OtaPackageInfo; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; |
|||
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; |
|||
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE; |
|||
|
|||
@DaoSqlTest |
|||
public abstract class AbstractOtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { |
|||
|
|||
private final String[] resources = new String[]{"3.xml", "5.xml", "9.xml"}; |
|||
|
|||
public AbstractOtaLwM2MIntegrationTest() { |
|||
setResources(this.resources); |
|||
} |
|||
|
|||
protected OtaPackageInfo createFirmware() throws Exception { |
|||
String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; |
|||
|
|||
OtaPackageInfo firmwareInfo = new OtaPackageInfo(); |
|||
firmwareInfo.setDeviceProfileId(deviceProfile.getId()); |
|||
firmwareInfo.setType(FIRMWARE); |
|||
firmwareInfo.setTitle("My firmware"); |
|||
firmwareInfo.setVersion("v1.0"); |
|||
|
|||
OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", firmwareInfo, OtaPackageInfo.class); |
|||
|
|||
MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); |
|||
|
|||
return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); |
|||
} |
|||
|
|||
protected OtaPackageInfo createSoftware() throws Exception { |
|||
String CHECKSUM = "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a"; |
|||
|
|||
OtaPackageInfo swInfo = new OtaPackageInfo(); |
|||
swInfo.setDeviceProfileId(deviceProfile.getId()); |
|||
swInfo.setType(SOFTWARE); |
|||
swInfo.setTitle("My sw"); |
|||
swInfo.setVersion("v1.0"); |
|||
|
|||
OtaPackageInfo savedFirmwareInfo = doPost("/api/otaPackage", swInfo, OtaPackageInfo.class); |
|||
|
|||
MockMultipartFile testData = new MockMultipartFile("file", "filename.txt", "text/plain", new byte[]{1}); |
|||
|
|||
return savaData("/api/otaPackage/" + savedFirmwareInfo.getId().getId().toString() + "?checksum={checksum}&checksumAlgorithm={checksumAlgorithm}", testData, CHECKSUM, "SHA256"); |
|||
} |
|||
|
|||
protected OtaPackageInfo savaData(String urlTemplate, MockMultipartFile content, String... params) throws Exception { |
|||
MockMultipartHttpServletRequestBuilder postRequest = MockMvcRequestBuilders.multipart(urlTemplate, params); |
|||
postRequest.file(content); |
|||
setJwtToken(postRequest); |
|||
return readResponse(mockMvc.perform(postRequest).andExpect(status().isOk()), OtaPackageInfo.class); |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
|
|||
|
|||
public class RpcLwm2mIntegrationDeleteTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
/** |
|||
* if there is such an instance |
|||
* Delete {"id":"/3303/12"} |
|||
* {"result":"DELETE"} |
|||
*/ |
|||
@Test |
|||
public void testDeleteObjectInstanceIsSuchByIdKey_Result_DELETED() throws Exception { |
|||
String expectedPath = objectIdVer_3303 + "/" + objectInstanceId_12; |
|||
String actualResult = sendRPCDeleteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.DELETED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* if there is no such instance |
|||
* Delete {"id":"/19/12"} |
|||
* {"result":"NOT_FOUND"} |
|||
*/ |
|||
@Test |
|||
public void testDeleteObjectInstanceIsNotSuchByIdKey_Result_NOT_FOUND() throws Exception { |
|||
String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; |
|||
String actualResult = sendRPCDeleteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* delete object |
|||
* Delete {"id":"/19_1.1"} |
|||
* {"result":"BAD_REQUEST","error":"Invalid path /19 : Only object instances can be delete"} |
|||
*/ |
|||
@Test |
|||
public void testDeleteObjectByIdKey_Result_BAD_REQUEST() throws Exception { |
|||
String expectedPath = objectIdVer_19; |
|||
String actualResult = sendRPCDeleteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "Invalid path " + pathIdVerToObjectId((String) expectedPath) + " : Only object instances can be delete"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* delete resource |
|||
* Delete {"id":"/3/0/9"} |
|||
* {"result":"METHOD_NOT_ALLOWED"} |
|||
*/ |
|||
@Test |
|||
public void testDeleteResourceByIdKey_Result_METHOD_NOT_ALLOWED() throws Exception { |
|||
String expectedPath = objectIdVer_3 + "/" + objectInstanceId_0 + resourceId_9; |
|||
String actualResult = sendRPCDeleteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
|
|||
private String sendRPCDeleteById(String path) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Delete\", \"params\": {\"id\": \"" + path + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,165 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
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; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; |
|||
|
|||
|
|||
public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
/** |
|||
* DiscoverAll |
|||
* |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testDiscoverAll_Return_CONTENT_LinksAllObjectsAllInstancesOfClient() throws Exception { |
|||
String setRpcRequest = "{\"method\":\"DiscoverAll\"}"; |
|||
String actualResult = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
JsonNode rpcActualValue = JacksonUtil.toJsonNode(rpcActualResult.get("value").asText()); |
|||
Set actualObjects = ConcurrentHashMap.newKeySet(); |
|||
Set actualInstances = ConcurrentHashMap.newKeySet(); |
|||
rpcActualValue.forEach(node -> { |
|||
if (!node.get("url").asText().equals("/")) { |
|||
LwM2mPath path = new LwM2mPath(node.get("url").asText()); |
|||
actualObjects.add("/" + path.getObjectId()); |
|||
if (path.isObjectInstance()) { |
|||
actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId()); |
|||
} |
|||
} |
|||
}); |
|||
assertEquals(expectedInstances, actualInstances); |
|||
assertEquals(expectedObjects, actualObjects); |
|||
} |
|||
|
|||
/** |
|||
* Discover {"id":"/3"} |
|||
* |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testDiscoverObject_Return_CONTENT_LinksInstancesAndResourcesOnLyExpectedObject() { |
|||
expectedObjectIdVers.forEach(expected -> { |
|||
try { |
|||
String actualResult = sendDiscover((String) expected); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String[] actualValues = rpcActualResult.get("value").asText().split(","); |
|||
assertTrue(actualValues.length > 0); |
|||
assertEquals(0, Arrays.stream(actualValues).filter(path -> !path.contains(expectedObjectId)).collect(Collectors.toList()).size()); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Discover {"id":"3/0"} |
|||
* If WriteAttributes not implemented: |
|||
* {"result":"CONTENT","value":"</3/0>,</3/0/0>,</3/0/1>,</3/0/2>,</3/0/3>,</3/0/4>,</3/0/5>,</3/0/6>,</3/0/7>,</3/0/8>,</3/0/9>,</3/0/10>,</3/0/11>,</3/0/12>,</3/0/13>,</3/0/14>,</3/0/15>,</3/0/16>,</3/0/1 |
|||
* 7>,</3/0/18>,</3/0/19>,</3/0/20>,</3/0/21>,</3/0/22>"} |
|||
* If WriteAttributes implemented and WriteAttributes saved |
|||
* Discover {"id":"19/0"} |
|||
* {"result":"CONTENT","value":"[</19/0>;dim=2;pmin=10;pmax=60;gt=50;lt=42.2,</19/0/0>;pmax=120, </19/0/1>, </19/0/2>, </19/0/3>, </19/0/4>, </19/0/5>;lt=45]"} |
|||
*/ |
|||
@Test |
|||
public void testDiscoverInstance_Return_CONTENT_LinksResourcesOnLyExpectedInstance() throws Exception { |
|||
String expected = (String) expectedObjectIdVerInstances.stream().findAny().get(); |
|||
String actualResult = sendDiscover(expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectInstanceId = pathIdVerToObjectId(expected); |
|||
String[] actualValues = rpcActualResult.get("value").asText().split(","); |
|||
assertTrue(actualValues.length > 0); |
|||
assertEquals(0, Arrays.stream(actualValues).filter(path -> !path.contains(expectedObjectInstanceId)).collect(Collectors.toList()).size()); |
|||
} |
|||
|
|||
/** |
|||
* Discover {"id":"3/0/14"} |
|||
* If WriteAttributes implemented: |
|||
* {"result":"CONTENT","value":"</3/0/14>;pmax=100, "pmin":10, "ver"=1.0"} |
|||
* If WriteAttributes not implemented: |
|||
* {"result":"CONTENT","value":"</3/0/14>"} |
|||
* Discover {"id":"19_1.1/0/0"} |
|||
* If WriteAttributes implemented: |
|||
* {"result":"CONTENT","value":"</19/0/0>;pmax=100, "pmin":10, "ver"=1.1"} |
|||
* If WriteAttributes not implemented: |
|||
* {"result":"CONTENT","value":"</19/0/0>"} |
|||
*/ |
|||
@Test |
|||
public void testDiscoverResource_Return_CONTENT_LinksResourceOnLyExpectedResource() throws Exception { |
|||
String expectedInstance = (String) expectedInstances.stream().findFirst().get(); |
|||
String expectedObjectInstanceId = pathIdVerToObjectId(expectedInstance); |
|||
LwM2mPath expectedPath = new LwM2mPath(expectedObjectInstanceId); |
|||
int expectedResource = client.getClient().getObjectTree().getObjectEnablers().get(expectedPath.getObjectId()).getObjectModel().resources.entrySet().stream().findAny().get().getKey(); |
|||
String expected = expectedInstance + "/" + expectedResource; |
|||
String actualResult = sendDiscover(expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedResourceId = "<" + expectedObjectInstanceId + "/" + expectedResource + ">"; |
|||
String actualValue = rpcActualResult.get("value").asText(); |
|||
assertEquals(expectedResourceId, actualValue ); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Discover {"id":"2/0"} |
|||
*{"result":"NOT_FOUND"} |
|||
*/ |
|||
@Test |
|||
public void testDiscoverObjectInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { |
|||
String expected = objectIdVer_2 + "/" + objectInstanceId_0; |
|||
String actualResult = sendDiscover(expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
/** |
|||
* Discover {"id":"2/0/2"} |
|||
* {"result":"NOT_FOUND"} |
|||
*/ |
|||
@Test |
|||
public void testDiscoverResourceAbsentInObject_Return_NOT_FOUND() throws Exception { |
|||
String expected = objectIdVer_2 + "/" + objectInstanceId_0 + "/" + resourceId_2; |
|||
String actualResult = sendDiscover(expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
private String sendDiscover(String path) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
} |
|||
@ -0,0 +1,186 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
|
|||
|
|||
public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
|
|||
/** |
|||
* Update FW |
|||
* Execute {"id":"5/0/2"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteUpdateFWById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_2; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Update SW |
|||
* Execute {"id":"9/0/4"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteUpdateSWById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_9 + "/" + resourceId_4; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Reboot |
|||
* Execute {"id":"3/0/4"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteRebootById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Registration Update Trigger |
|||
* Execute {"id":"1/0/8"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteRegistrationUpdateTriggerById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_8; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* execute_resource_with_parameters (execute reboot after 60 seconds on device) |
|||
* Execute {"id":"3/0/4","value":60} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteResourceWithParametersById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_4; |
|||
Object expectedValue = 60; |
|||
String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Bootstrap-Request Trigger |
|||
* Execute {"id":"1/0/9"} |
|||
* {"result":"BAD_REQUEST","error":"probably no bootstrap server configured"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteBootstrapRequestTriggerById_Result_BAD_REQUEST_Error_NoBootstrapServerConfigured() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_1 + "/" + resourceId_9; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "probably no bootstrap server configured"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
/** |
|||
* bad: resource operation not "E" |
|||
* Execute {"id":"5/0/3"} |
|||
* {"result":"BAD_REQUEST","error":"Resource with /5/0/3 is not executable."} |
|||
*/ |
|||
@Test |
|||
public void testExecuteResourceWithOperationNotExecuteById_Result_METHOD_NOT_ALLOWED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_5 + "/" + resourceId_3; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expectedPath); |
|||
String expected = "Resource with " + expectedObjectId + " is not executable."; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
/** |
|||
* bad: execute_non_existing_resource_on_non_existing_object |
|||
* Execute {"id":"50/0/3"} |
|||
* {"result":"BAD_REQUEST","error":"Specified object id 50 absent in the list supported objects of the client or is security object!"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteNonExistingResourceOnNonExistingObjectById_Result_BAD_REQUEST() throws Exception { |
|||
String expectedPath = objectIdVer_50 + "/" + objectInstanceId_0 + "/" + resourceId_3; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expectedPath); |
|||
LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); |
|||
String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
/** |
|||
* bad: execute security object |
|||
* Execute {"id":"0/0/3"} |
|||
* {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"} |
|||
*/ |
|||
@Test |
|||
public void testExecuteSecurityObjectById_Result_NOT_FOUND() throws Exception { |
|||
String expectedPath = objectIdVer_0 + "/" + objectInstanceId_0 + "/" + resourceId_3; |
|||
String actualResult = sendRPCExecuteById(expectedPath); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expectedPath); |
|||
LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); |
|||
String expected = "Specified object id " + expectedPathId.getObjectId() + " absent in the list supported objects of the client or is security object!"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
|
|||
private String sendRPCExecuteById(String path) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCExecuteWithValueById(String path, Object value) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,190 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; |
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
|
|||
public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
/** |
|||
* ObserveReadAll |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveReadAllNothingObservation_Result_CONTENT_Value_Count_0() throws Exception { |
|||
String actualResult = sendObserve("ObserveCancelAll", null); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
actualResult = sendObserve("ObserveReadAll", null); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
assertEquals("[]", rpcActualResult.get("value").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Observe {"id":"/3/0/9"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveSingleResource_Result_CONTENT_Value_SingleResource() throws Exception { |
|||
String expectedIdVer = objectInstanceIdVer_3 + "/" + resourceId_9; |
|||
String actualResult = sendObserve("Observe", expectedIdVer); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
assertTrue(rpcActualResult.get("value").asText().contains("LwM2mSingleResource")); |
|||
} |
|||
|
|||
/** |
|||
* Observe {"id":"/3_1.1/0/13"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveWithBadVersion_Result_BadRequest_ErrorMsg_BadVersionMustBe1_0() throws Exception { |
|||
String expectedInstance = (String) expectedInstances.stream().filter(path -> !((String)path).contains("_")).findFirst().get(); |
|||
LwM2mPath expectedPath = new LwM2mPath(expectedInstance); |
|||
int expectedResource = client.getClient().getObjectTree().getObjectEnablers().get(expectedPath.getObjectId()).getObjectModel().resources.entrySet().stream().findAny().get().getKey(); |
|||
String expectedId = "/" + expectedPath.getObjectId() + "_1.2" + "/" + expectedPath.getObjectInstanceId() + "/" + expectedResource; |
|||
String actualResult = sendObserve("Observe", expectedId); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "Specified resource id " + expectedId +" is not valid version! Must be version: 1.0"; |
|||
assertEquals(expected, rpcActualResult.get("error").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Not implemented Instance |
|||
* Observe {"id":"/2/0"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveNoImplementedInstanceOnDevice_Result_NotFound() throws Exception { |
|||
String objectInstanceIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + ACCESS_CONTROL)).findFirst().get(); |
|||
String expected = objectInstanceIdVer + "/" + objectInstanceId_0; |
|||
String actualResult = sendObserve("Observe", expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.NOT_FOUND.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Not implemented Resource |
|||
* Observe {"id":"/19_1.1/0/0"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveNoImplementedResourceOnDeviceValueNull_Result_BadRequest() throws Exception { |
|||
String objectIdVer = (String) expectedObjectIdVers.stream().filter(path -> ((String)path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); |
|||
String expected = objectIdVer + "/" + objectInstanceId_0 + "/" + resourceId_0; |
|||
String actualResult = sendObserve("Observe", expected); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String expectedValue = "values MUST NOT be null"; |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
assertEquals(expectedValue, rpcActualResult.get("error").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Repeated request on Observe |
|||
* Observe {"id":"/5/0/0"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveRSourceNotRead_Result_METHOD_NOT_ALLOWED() throws Exception { |
|||
String expectedId = objectInstanceIdVer_5 + "/" + resourceId_0; |
|||
sendObserve("Observe", expectedId); |
|||
String actualResult = sendObserve("Observe", expectedId); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* Repeated request on Observe |
|||
* Observe {"id":"/3/0/0"} |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveRepeatedRequestObserveOnDevice_Result_BAD_REQUEST_ErrorMsg_AlreadyRegistered() throws Exception { |
|||
String expectedId = objectInstanceIdVer_3 + "/" + resourceId_0; |
|||
sendObserve("Observe", expectedId); |
|||
String actualResult = sendObserve("Observe", expectedId); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "Observation is already registered!"; |
|||
assertEquals(expected, rpcActualResult.get("error").asText()); |
|||
} |
|||
|
|||
/** |
|||
* ObserveReadAll |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testObserveReadAll_Result_CONTENT_Value_Contains_Paths_Count_ObserveAll() throws Exception { |
|||
sendObserve("ObserveCancelAll", null); |
|||
String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; |
|||
String expectedId_9 = objectInstanceIdVer_3 + "/" + resourceId_9; |
|||
sendObserve("Observe", expectedId_0); |
|||
sendObserve("Observe", expectedId_9); |
|||
String actualResult = sendObserve("ObserveReadAll", null); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
assertTrue(actualValues.contains(expectedId_0)); |
|||
assertTrue(actualValues.contains(expectedId_9)); |
|||
assertEquals(2, actualValues.split(",").length); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* ObserveCancel {"id":"/3/0/3"} |
|||
* ObserveCancel {"id":"/5/0/3"} |
|||
*/ |
|||
@Test |
|||
public void testObserveCancelOneResource_Result_CONTENT_Value_Count_1() throws Exception { |
|||
sendObserve("ObserveCancelAll", null); |
|||
String expectedId_0 = objectInstanceIdVer_3 + "/" + resourceId_0; |
|||
String expectedId_3 = objectInstanceIdVer_5 + "/" + resourceId_3; |
|||
sendObserve("Observe", expectedId_0); |
|||
sendObserve("Observe", expectedId_3); |
|||
String actualResult = sendObserve("ObserveCancel", expectedId_0); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
assertEquals("1", rpcActualResult.get("value").asText()); |
|||
} |
|||
|
|||
private String sendObserve(String method, String params) throws Exception { |
|||
String sendRpcRequest; |
|||
if (params == null) { |
|||
sendRpcRequest = "{\"method\": \"" + method + "\"}"; |
|||
} |
|||
else { |
|||
sendRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + params + "\"}}"; |
|||
} |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, sendRpcRequest, String.class, status().isOk()); |
|||
} |
|||
} |
|||
@ -0,0 +1,226 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.eclipse.leshan.core.LwM2mId.SERVER; |
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_0_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_19_1_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_9; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_1; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_11; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
|
|||
|
|||
public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
/** |
|||
* Read {"id":"/3"} |
|||
* Read {"id":"/6"}... |
|||
*/ |
|||
@Test |
|||
public void testReadAllObjectsInClientById_Result_CONTENT_Value_IsLwM2mObject_IsInstances() throws Exception { |
|||
expectedObjectIdVers.forEach(expected -> { |
|||
try { |
|||
String actualResult = sendRPCById((String) expected); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expected); |
|||
LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectInstances = "LwM2mObject [id=" + expectedPath.getObjectId() + ", instances={0=LwM2mObjectInstance [id=0, resources="; |
|||
if (expectedPath.getObjectId() == 2) { |
|||
expectedObjectInstances = "LwM2mObject [id=2, instances={}]"; |
|||
} |
|||
assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Read {"id":"/5/0"} |
|||
* |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testReadAllInstancesInClientById_Result_CONTENT_Value_IsInstances_IsResources() throws Exception{ |
|||
expectedObjectIdVerInstances.forEach(expected -> { |
|||
try { |
|||
String actualResult = sendRPCById((String) expected); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expected); |
|||
LwM2mPath expectedPath = new LwM2mPath(expectedObjectId); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectInstances = "LwM2mObjectInstance [id=" + expectedPath.getObjectInstanceId() + ", resources={"; |
|||
assertTrue(rpcActualResult.get("value").asText().contains(expectedObjectInstances)); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Read {"id":"/19/1/0"} |
|||
* |
|||
* @throws Exception |
|||
*/ |
|||
@Test |
|||
public void testReadMultipleResourceById_Result_CONTENT_Value_IsLwM2mMultipleResource() throws Exception { |
|||
String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_11 ; |
|||
String actualResult = sendRPCById(expectedIdVer); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; |
|||
assertTrue(rpcActualResult.get("value").asText().contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* Read {"id":"/3/0/14"} |
|||
*/ |
|||
@Test |
|||
public void testReadSingleResourceById_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { |
|||
String expectedIdVer = objectInstanceIdVer_3 +"/" + resourceId_14 ; |
|||
String actualResult = sendRPCById(expectedIdVer); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; |
|||
assertTrue(rpcActualResult.get("value").asText().contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* Read {"key":"UtfOffset"} |
|||
*/ |
|||
@Test |
|||
public void testReadSingleResourceByKey_Result_CONTENT_Value_IsLwM2mSingleResource() throws Exception { |
|||
String expectedKey = resourceIdName_3_14 ; |
|||
String actualResult = sendRPCByKey(expectedKey); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value="; |
|||
assertTrue(rpcActualResult.get("value").asText().contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* ReadComposite {"ids":["/1_1.2", "/3_1.0/0/1", "/3_1.0/0/11"]} |
|||
*/ |
|||
@Test |
|||
public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectIsLwM2mSingleResourceIsLwM2mMultipleResource() throws Exception { |
|||
String expectedIdVer_1 = (String) expectedObjectIdVers.stream().filter(path -> (!((String)path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String)path).contains("/" + SERVER))).findFirst().get(); |
|||
String objectId_1 = pathIdVerToObjectId(expectedIdVer_1); |
|||
String expectedIdVer3_0_1 = objectInstanceIdVer_3 + "/" + resourceId_1; |
|||
String expectedIdVer3_0_11 = objectInstanceIdVer_3 + "/" + resourceId_11; |
|||
String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); |
|||
String expectedIds = "[\"" + expectedIdVer_1 + "\", \"" + expectedIdVer3_0_1 + "\", \"" + expectedIdVer3_0_11 + "\"]"; |
|||
String actualResult = sendCompositeRPCByIds(expectedIds); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String expected1 = objectId_1 + "=LwM2mObject [id=" + new LwM2mPath(objectId_1).getObjectId() + ", instances={"; |
|||
String expected3_0_1 = objectInstanceId_3 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; |
|||
String expected3_0_11 = objectInstanceId_3 + "/" + resourceId_11 + "=LwM2mMultipleResource [id=" + resourceId_11 + ", values={"; |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
assertTrue(actualValues.contains(expected1)); |
|||
assertTrue(actualValues.contains(expected3_0_1)); |
|||
assertTrue(actualValues.contains(expected3_0_11)); |
|||
} |
|||
|
|||
/** |
|||
* ReadComposite {"ids":["/1_1.2/0/1", "/1_1.2/0/2", "/3_1.0/0"]} |
|||
*/ |
|||
@Test |
|||
public void testReadCompositeSingleResourceByIds_Result_CONTENT_Value_IsObjectInstanceIsLwM2mSingleResource() throws Exception { |
|||
String expectedIdVer3_0 = objectInstanceIdVer_3; |
|||
String expectedIdVer1_0_1 = objectInstanceIdVer_1 + "/" + resourceId_1; |
|||
String expectedIdVer1_0_2 = objectInstanceIdVer_1 + "/" + resourceId_2; |
|||
String expectedIds = "[\"" + expectedIdVer1_0_1 + "\", \"" + expectedIdVer1_0_2 + "\", \"" + expectedIdVer3_0 + "\"]"; |
|||
String actualResult = sendCompositeRPCByIds(expectedIds); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); |
|||
LwM2mPath path = new LwM2mPath(objectInstanceId_3); |
|||
String expected3_0 = objectInstanceId_3 + "=LwM2mObjectInstance [id=" + path.getObjectInstanceId() + ", resources={"; |
|||
String objectInstanceId_1 = pathIdVerToObjectId(objectInstanceIdVer_1); |
|||
String expected1_0_1 = objectInstanceId_1 + "/" + resourceId_1 + "=LwM2mSingleResource [id=" + resourceId_1 + ", value="; |
|||
String expected1_0_2 = objectInstanceId_1 + "/" + resourceId_2 + "=null"; |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
assertTrue(actualValues.contains(expected3_0)); |
|||
assertTrue(actualValues.contains(expected1_0_1)); |
|||
assertTrue(actualValues.contains(expected1_0_2)); |
|||
} |
|||
|
|||
/** |
|||
* ReadComposite {"keys":["batteryLevel", "UtfOffset", "dataRead", "dataWrite"]} |
|||
*/ |
|||
@Test |
|||
public void testReadCompositeSingleResourceByKeys_Result_CONTENT_Value_3_0_IsLwM2mSingleResource_19_0_0_AND_19_0_1_Null() throws Exception { |
|||
String expectedKey3_0_9 = resourceIdName_3_9; |
|||
String expectedKey3_0_14 = resourceIdName_3_14; |
|||
String expectedKey19_0_0 = resourceIdName_19_0_0; |
|||
String expectedKey19_1_0 = resourceIdName_19_1_0; |
|||
String expectedKeys = "[\"" + expectedKey3_0_9 + "\", \"" + expectedKey3_0_14 + "\", \"" + expectedKey19_0_0 + "\", \"" + expectedKey19_1_0 + "\"]"; |
|||
String actualResult = sendCompositeRPCByKeys(expectedKeys); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); |
|||
String objectInstanceId_3 = pathIdVerToObjectId(objectInstanceIdVer_3); |
|||
String objectId_19 = pathIdVerToObjectId(objectIdVer_19); |
|||
String expected3_0_9 = objectInstanceId_3 + "/" + resourceId_9 + "=LwM2mSingleResource [id=" + resourceId_9 + ", value="; |
|||
String expected3_0_14 = objectInstanceId_3 + "/" + resourceId_14 + "=LwM2mSingleResource [id=" + resourceId_14 + ", value="; |
|||
String expected19_0_0 = objectId_19 + "/" + objectInstanceId_0 + "/" + resourceId_0 + "=null"; |
|||
String expected19_1_0 = objectId_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "=null"; |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
assertTrue(actualValues.contains(expected3_0_9)); |
|||
assertTrue(actualValues.contains(expected3_0_14)); |
|||
assertTrue(actualValues.contains(expected19_0_0)); |
|||
assertTrue(actualValues.contains(expected19_1_0)); |
|||
} |
|||
|
|||
|
|||
private String sendRPCById(String path) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + path + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCByKey(String key) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"key\": \"" + key + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendCompositeRPCByIds(String paths) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"ReadComposite\", \"params\": {\"ids\":" + paths + "}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendCompositeRPCByKeys(String keys) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"ReadComposite\", \"params\": {\"keys\":" + keys + "}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_2; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_3; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_4; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_8; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
|
|||
|
|||
public class RpcLwm2mIntegrationWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
/** |
|||
* WriteAttributes {"id":"/3/0/14","attributes":{"pmax":100, "pmin":10}} |
|||
* if not implemented: |
|||
* {"result":"INTERNAL_SERVER_ERROR","error":"not implemented"} |
|||
* if implemented: |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteAttributesResourceWithParametersById_Result_INTERNAL_SERVER_ERROR() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; |
|||
String expectedValue = "{\"pmax\":100, \"pmin\":10}"; |
|||
String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.INTERNAL_SERVER_ERROR.getName(), rpcActualResult.get("result").asText()); |
|||
String expected = "not implemented"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
private String sendRPCExecuteWithValueById(String path, String value) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"WriteAttributes\", \"params\": {\"id\": \"" + path + "\", \"attributes\": " + value + " }}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,353 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.rpc.sql; |
|||
|
|||
import com.fasterxml.jackson.databind.node.ObjectNode; |
|||
import org.eclipse.leshan.core.ResponseCode; |
|||
import org.eclipse.leshan.core.node.LwM2mPath; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.transport.lwm2m.rpc.AbstractRpcLwM2MIntegrationTest; |
|||
|
|||
import static org.junit.Assert.assertEquals; |
|||
import static org.junit.Assert.assertTrue; |
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_2; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceIdName_3_14; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_14; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_15; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceInstanceId_2; |
|||
|
|||
public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { |
|||
|
|||
|
|||
/** |
|||
* update SingleResource: |
|||
* WriteReplace {"id":"3/0/14","value":"+12"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteReplaceValueSingleResourceById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_14; |
|||
String expectedValue = "+12"; |
|||
String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
actualResult = sendRPCReadById(expectedPath); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* key |
|||
* WriteReplace {"key":"timezone","value":"+10"} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteReplaceValueSingleResourceByKey_Result_CHANGED() throws Exception { |
|||
String expectedKey = resourceIdName_3_14; |
|||
String expectedValue = "+09"; |
|||
String actualResult = sendRPCWriteByKey("WriteReplace", expectedKey, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
actualResult = sendRPCReadByKey(expectedKey); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* id |
|||
* WriteReplace {"id": "/19_1.1/0/0","value": {"0":"0000ad45675600", "15":"1525ad45675600cdef"}} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteReplaceValueMultipleResource_Result_CHANGED_Value_Multi_Instance_Resource_must_in_Json_format() throws Exception { |
|||
String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0 + "/" + resourceId_0; |
|||
int resourceInstanceId0 = 0; |
|||
int resourceInstanceId15 = 15; |
|||
String expectedValue0 = "0000ad45675600"; |
|||
String expectedValue15 = "1525ad45675600cdef"; |
|||
String expectedValue = "{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId15 + "\":\"" + expectedValue15 + "\"}"; |
|||
String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedPath0 = expectedPath + "/" + resourceInstanceId0; |
|||
String expectedPath15 = expectedPath + "/" + resourceInstanceId15; |
|||
actualResult = sendRPCReadById(expectedPath0); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadById(expectedPath15); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mResourceInstance [id=" + resourceInstanceId15 + ", value=" + expectedValue15.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* id |
|||
* WriteReplace {"id":"/19/0/0","value":"0081"}.. |
|||
*/ |
|||
@Test |
|||
public void testWriteReplaceValueMultipleResourceAsSingleResource_Result_BAD_REQUEST_Value_Multi_Instance_Resource_must_be_in_Json_format() throws Exception { |
|||
String objectInstanceIdVer_19 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); |
|||
String expectedPath = objectInstanceIdVer_19 + "/" + resourceId_0; |
|||
String expectedValue = "0081"; |
|||
String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String actualValues = rpcActualResult.get("error").asText(); |
|||
String expected = "Resource value is: String. Value of Multi-Instance Resource must be in Json format!"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* bad: singleResource, operation="R" - only read |
|||
* WriteReplace {"id":"/3/0/9","value":90} |
|||
* {"result":"METHOD_NOT_ALLOWED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteReplaceValueSingleResourceR_ById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3 + "/" + resourceId_9; |
|||
Integer expectedValue = 90; |
|||
String actualResult = sendRPCWriteObjectById("WriteReplace", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.METHOD_NOT_ALLOWED.getName(), rpcActualResult.get("result").asText()); |
|||
} |
|||
|
|||
/** |
|||
* ids |
|||
* WriteUpdate {"id":"/3/0","value":{"14":"+5","15":"Kiyv/Europe"}} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteUpdateValueSingleResourceById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectInstanceIdVer_3; |
|||
String expectedValue14 = "+5"; |
|||
String expectedValue15 = "Kiyv/Europe"; |
|||
String expectedValue = "{\"" + resourceId_14 + "\":\"" + expectedValue14 + "\",\"" + resourceId_15 + "\":\"" + expectedValue15 + "\"}"; |
|||
String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedPath14 = objectInstanceIdVer_3 + "/" + resourceId_14; |
|||
String expectedPath15 = objectInstanceIdVer_3 + "/" + resourceId_15; |
|||
actualResult = sendRPCReadById(expectedPath14); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue14 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadById(expectedPath15); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue15 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* id |
|||
* WriteUpdate {"id": "/19_1.1/0","value": {"0":{"0":"00ad456756", "25":"25ad456756"}}} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteUpdateValueMultipleResourceById_Result_CHANGED() throws Exception { |
|||
String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; |
|||
int resourceInstanceId0 = 0; |
|||
int resourceInstanceId25 = 25; |
|||
String expectedValue0 = "00ad45675600"; |
|||
String expectedValue25 = "25ad45675600cdef"; |
|||
String expectedValue = "{\"" + resourceId_0 + "\":{\"" + resourceInstanceId0 + "\":\"" + expectedValue0 + "\", \"" + resourceInstanceId25 + "\":\"" + expectedValue25 + "\"}}"; |
|||
String actualResult = sendRPCWriteObjectById("WriteUpdate", expectedPath, expectedValue); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedPath0 = expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId0; |
|||
String expectedPath25 =expectedPath + "/" + resourceId_0 + "/" + resourceInstanceId25; |
|||
actualResult = sendRPCReadById(expectedPath0); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mResourceInstance [id=" + resourceInstanceId0 + ", value=" + expectedValue0.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadById(expectedPath25); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mResourceInstance [id=" + resourceInstanceId25 + ", value=" + expectedValue25.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* ResourceInstance + KeySingleResource + IdSingleResource |
|||
* WriteComposite {"nodes":{"/19/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteCompositeValueSingleResourceResourceInstanceByIdKey_Result_CHANGED() throws Exception { |
|||
int resourceInstanceId2 = 2; |
|||
String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; |
|||
String expectedValue19_1_0_2 = "00001234"; |
|||
String expectedKey3_0_14 = resourceIdName_3_14; |
|||
String expectedValue3_0_14 = "+04"; |
|||
String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; |
|||
String expectedValue3_0_15 = "Kiyv/Europe"; |
|||
String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + |
|||
"\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; |
|||
String actualResult = sendCompositeRPC(nodes); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
actualResult = sendRPCReadById(expectedPath19_1_0_2); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mResourceInstance [id=" + resourceInstanceId2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadByKey(expectedKey3_0_14); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadById(expectedPath3_0_15); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* multipleResource == error |
|||
* bad - cannot be used for value Json, only primitive: SingleResource, ResourceInstance (for Json: WriteUpdate, WriteReplace) |
|||
* WriteComposite {"nodes":{"/19/0/0":{"0":"abcd5678", "10":"abcd5678"}}} |
|||
*/ |
|||
@Test |
|||
public void testWriteCompositeValueSingleMultipleResourceByIdKey_Result_BAD_REQUEST_WriteComposite_operation_for_SingleResources_or_and_ResourceInstance() throws Exception { |
|||
String nodes = "{\"/19/0/0\":{\"0\":\"abcd5678\", \"10\":\"abcd5678\"}}"; |
|||
String actualResult = sendCompositeRPC(nodes); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String actualValues = rpcActualResult.get("error").asText(); |
|||
String expectedNodes = nodes.replaceAll("\"", "").replaceAll(":", "="); |
|||
String expected = String.format("nodes: %s is not validate value. " + |
|||
"The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", expectedNodes); |
|||
assertEquals(expected, actualValues); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* update_resourceInstances&update_singleResource |
|||
* new ResourceInstance if Resource is Multiple & Resource Single |
|||
* - WriteReplace {"id":"/19_1.2/1/0","value":{"2":ddff12"}} |
|||
* - WriteReplace {"key":"UtfOffset","value":"+04"} |
|||
* - WriteReplace {"id":"/3/0/15","value":"Kiyv/Europe"} |
|||
* WriteComposite {"nodes":{"/19_1.1/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}}} |
|||
* {"result":"CHANGED"} |
|||
*/ |
|||
@Test |
|||
public void testWriteCompositeCreateResourceInstanceUpdateSingleResourceByIdKey_Result_CHANGED() throws Exception { |
|||
String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId_2; |
|||
String expectedValue19_1_0_2 = "00001234"; |
|||
String expectedKey3_0_14 = resourceIdName_3_14; |
|||
String expectedValue3_0_14 = "+04"; |
|||
String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; |
|||
String expectedValue3_0_15 = "Kiyv/Europe"; |
|||
String nodes = "{\"" + expectedPath19_1_0_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + |
|||
"\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; |
|||
String actualResult = sendCompositeRPC(nodes); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText()); |
|||
actualResult = sendRPCReadById(expectedPath19_1_0_2); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
String actualValues = rpcActualResult.get("value").asText(); |
|||
String expected = "LwM2mResourceInstance [id=" + resourceInstanceId_2 + ", value=" + expectedValue19_1_0_2.length()/2 + "Bytes, type=OPAQUE]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadByKey(expectedKey3_0_14); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mSingleResource [id=" + resourceId_14 + ", value=" + expectedValue3_0_14 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
actualResult = sendRPCReadById(expectedPath3_0_15); |
|||
rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
actualValues = rpcActualResult.get("value").asText(); |
|||
expected = "LwM2mSingleResource [id=" + resourceId_15 + ", value=" + expectedValue3_0_15 + ", type=STRING]"; |
|||
assertTrue(actualValues.contains(expected)); |
|||
} |
|||
|
|||
/** |
|||
* composite_not created_new_instance... |
|||
* new ObjectInstance if Object is Multiple - bad |
|||
* - WriteReplace {"id":"/19_1.2/2/0","value":{"2":ddff12"}} |
|||
* - WriteReplace {"key":"UtfOffset","value":"+04"} |
|||
* - WriteReplace {"id":"/3/0/15","value":"Kiyv/Europe"} |
|||
* WriteComposite {"nodes":{"/19_1.1/1/0/2":"00001234", "UtfOffset":"+04", "/3/0/15":"Kiyv/Europe"}}} |
|||
* {"result":"BAD_REQUEST","error":"object instance /19/2 not found"} |
|||
*/ |
|||
@Test |
|||
public void testWriteCompositeCreateObjectInstanceUpdateSingleResourceByIdKey_Result_BAD_REQUEST() throws Exception { |
|||
String expectedPath19_1_2_2 = objectIdVer_19 + "/" + objectInstanceId_2 + "/" + resourceId_0 + "/" + resourceInstanceId_2; |
|||
String expectedValue19_1_0_2 = "00001234"; |
|||
String expectedKey3_0_14 = resourceIdName_3_14; |
|||
String expectedValue3_0_14 = "+04"; |
|||
String expectedPath3_0_15 = objectInstanceIdVer_3 + "/" + resourceId_15; |
|||
String expectedValue3_0_15 = "Kiyv/Europe"; |
|||
String nodes = "{\"" + expectedPath19_1_2_2 + "\":\"" + expectedValue19_1_0_2 + "\", \"" + expectedKey3_0_14 + |
|||
"\":\"" + expectedValue3_0_14 + "\", \"" + expectedPath3_0_15 + "\":\"" + expectedValue3_0_15 + "\"}"; |
|||
String actualResult = sendCompositeRPC(nodes); |
|||
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); |
|||
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); |
|||
String expectedObjectId = pathIdVerToObjectId((String) expectedPath19_1_2_2); |
|||
LwM2mPath expectedPathId = new LwM2mPath(expectedObjectId); |
|||
String expected = "object instance " + "/" + expectedPathId.getObjectId() + "/" + expectedPathId.getObjectInstanceId() + " not found"; |
|||
String actual = rpcActualResult.get("error").asText(); |
|||
assertTrue(actual.equals(expected)); |
|||
} |
|||
|
|||
private String sendRPCWriteStringById(String method, String path, String value) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": \"" + value + "\" }}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCWriteObjectById(String method, String path, Object value) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCReadById(String id) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"id\": \"" + id + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCWriteByKey(String method, String key, String value) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"" + method + "\", \"params\": {\"key\": \"" + key + "\", \"value\": \"" + value + "\" }}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendRPCReadByKey(String key) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"Read\", \"params\": {\"key\": \"" + key + "\"}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
|
|||
private String sendCompositeRPC(String nodes) throws Exception { |
|||
String setRpcRequest = "{\"method\": \"WriteComposite\", \"params\": {\"nodes\":" + nodes + "}}"; |
|||
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk()); |
|||
} |
|||
} |
|||
@ -0,0 +1,176 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.security; |
|||
|
|||
import org.eclipse.leshan.core.util.Hex; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MBootstrapCredentials; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecServerCredentials; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest; |
|||
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.math.BigInteger; |
|||
import java.security.AlgorithmParameters; |
|||
import java.security.GeneralSecurityException; |
|||
import java.security.KeyFactory; |
|||
import java.security.KeyStore; |
|||
import java.security.PrivateKey; |
|||
import java.security.PublicKey; |
|||
import java.security.cert.Certificate; |
|||
import java.security.cert.X509Certificate; |
|||
import java.security.spec.ECGenParameterSpec; |
|||
import java.security.spec.ECParameterSpec; |
|||
import java.security.spec.ECPoint; |
|||
import java.security.spec.ECPrivateKeySpec; |
|||
import java.security.spec.ECPublicKeySpec; |
|||
import java.security.spec.KeySpec; |
|||
|
|||
@DaoSqlTest |
|||
public abstract class AbstractSecurityLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { |
|||
|
|||
protected final String pskIdentity; // client public key or id used for PSK
|
|||
protected final String pskKey; // client private/secret key used for PSK
|
|||
protected final PublicKey clientPublicKey; // client public key used for RPK
|
|||
protected final PrivateKey clientPrivateKey; // client private key used for RPK
|
|||
protected final PublicKey serverPublicKey; // server public key used for RPK
|
|||
protected final PrivateKey serverPrivateKey; // server private key used for RPK
|
|||
|
|||
// client private key used for X509
|
|||
protected final PrivateKey clientPrivateKeyFromCert; |
|||
// server private key used for X509
|
|||
protected final PrivateKey serverPrivateKeyFromCert; |
|||
// client certificate signed by rootCA with a good CN (CN start by leshan_integration_test)
|
|||
protected final X509Certificate clientX509Cert; |
|||
// client certificate signed by rootCA but with bad CN (CN does not start by leshan_integration_test)
|
|||
protected final X509Certificate clientX509CertWithBadCN; |
|||
// client certificate self-signed with a good CN (CN start by leshan_integration_test)
|
|||
protected final X509Certificate clientX509CertSelfSigned; |
|||
// client certificate signed by another CA (not rootCA) with a good CN (CN start by leshan_integration_test)
|
|||
protected final X509Certificate clientX509CertNotTrusted; |
|||
// server certificate signed by rootCA
|
|||
protected final X509Certificate serverX509Cert; |
|||
// self-signed server certificate
|
|||
protected final X509Certificate serverX509CertSelfSigned; |
|||
// rootCA used by the server
|
|||
protected final X509Certificate rootCAX509Cert; |
|||
// certificates trustedby the server (should contain rootCA)
|
|||
protected final Certificate[] trustedCertificates = new Certificate[1]; |
|||
|
|||
protected static final String ENDPOINT = "deviceAEndpoint"; |
|||
|
|||
protected LwM2MTestClient client; |
|||
|
|||
private final LwM2MBootstrapCredentials defaultBootstrapCredentials; |
|||
|
|||
private final String[] resources = new String[]{"1.xml", "2.xml", "3.xml", "5.xml", "9.xml"}; |
|||
|
|||
public AbstractSecurityLwM2MIntegrationTest() { |
|||
// create client credentials
|
|||
setResources(this.resources); |
|||
setEndpoint(ENDPOINT); |
|||
try { |
|||
// Get keys PSK
|
|||
this.pskIdentity = "SOME_PSK_ID"; |
|||
this.pskKey = "73656372657450534b73656372657450"; |
|||
|
|||
// Get point values
|
|||
byte[] publicX = Hex |
|||
.decodeHex("89c048261979208666f2bfb188be1968fc9021c416ce12828c06f4e314c167b5".toCharArray()); |
|||
byte[] publicY = Hex |
|||
.decodeHex("cbf1eb7587f08e01688d9ada4be859137ca49f79394bad9179326b3090967b68".toCharArray()); |
|||
byte[] privateS = Hex |
|||
.decodeHex("e67b68d2aaeb6550f19d98cade3ad62b39532e02e6b422e1f7ea189dabaea5d2".toCharArray()); |
|||
|
|||
// Get Elliptic Curve Parameter spec for secp256r1
|
|||
AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); |
|||
algoParameters.init(new ECGenParameterSpec("secp256r1")); |
|||
ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); |
|||
|
|||
// Create key specs
|
|||
KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), |
|||
parameterSpec); |
|||
KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); |
|||
|
|||
// Get keys RPK
|
|||
clientPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); |
|||
clientPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); |
|||
|
|||
// Get certificates from key store
|
|||
char[] clientKeyStorePwd = "client".toCharArray(); |
|||
KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
|||
try (InputStream clientKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/clientKeyStore.jks")) { |
|||
clientKeyStore.load(clientKeyStoreFile, clientKeyStorePwd); |
|||
} |
|||
|
|||
clientPrivateKeyFromCert = (PrivateKey) clientKeyStore.getKey("client", clientKeyStorePwd); |
|||
clientX509Cert = (X509Certificate) clientKeyStore.getCertificate("client"); |
|||
clientX509CertWithBadCN = (X509Certificate) clientKeyStore.getCertificate("client_bad_cn"); |
|||
clientX509CertSelfSigned = (X509Certificate) clientKeyStore.getCertificate("client_self_signed"); |
|||
clientX509CertNotTrusted = (X509Certificate) clientKeyStore.getCertificate("client_not_trusted"); |
|||
} catch (GeneralSecurityException | IOException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
|
|||
// create server credentials
|
|||
try { |
|||
// Get point values
|
|||
byte[] publicX = Hex |
|||
.decodeHex("fcc28728c123b155be410fc1c0651da374fc6ebe7f96606e90d927d188894a73".toCharArray()); |
|||
byte[] publicY = Hex |
|||
.decodeHex("d2ffaa73957d76984633fc1cc54d0b763ca0559a9dff9706e9f4557dacc3f52a".toCharArray()); |
|||
byte[] privateS = Hex |
|||
.decodeHex("1dae121ba406802ef07c193c1ee4df91115aabd79c1ed7f4c0ef7ef6a5449400".toCharArray()); |
|||
|
|||
// Get Elliptic Curve Parameter spec for secp256r1
|
|||
AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); |
|||
algoParameters.init(new ECGenParameterSpec("secp256r1")); |
|||
ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); |
|||
|
|||
// Create key specs
|
|||
KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), |
|||
parameterSpec); |
|||
KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec); |
|||
|
|||
// Get keys
|
|||
serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); |
|||
serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec); |
|||
|
|||
// Get certificates from key store
|
|||
char[] serverKeyStorePwd = "server".toCharArray(); |
|||
KeyStore serverKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); |
|||
try (InputStream serverKeyStoreFile = this.getClass().getClassLoader().getResourceAsStream("lwm2m/credentials/serverKeyStore.jks")) { |
|||
serverKeyStore.load(serverKeyStoreFile, serverKeyStorePwd); |
|||
} |
|||
|
|||
serverPrivateKeyFromCert = (PrivateKey) serverKeyStore.getKey("server", serverKeyStorePwd); |
|||
rootCAX509Cert = (X509Certificate) serverKeyStore.getCertificate("rootCA"); |
|||
serverX509Cert = (X509Certificate) serverKeyStore.getCertificate("server"); |
|||
serverX509CertSelfSigned = (X509Certificate) serverKeyStore.getCertificate("server_self_signed"); |
|||
trustedCertificates[0] = rootCAX509Cert; |
|||
} catch (GeneralSecurityException | IOException e) { |
|||
throw new RuntimeException(e); |
|||
} |
|||
|
|||
defaultBootstrapCredentials = new LwM2MBootstrapCredentials(); |
|||
|
|||
NoSecServerCredentials serverCredentials = new NoSecServerCredentials(); |
|||
|
|||
defaultBootstrapCredentials.setBootstrapServer(serverCredentials); |
|||
defaultBootstrapCredentials.setLwm2mServer(serverCredentials); |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.transport.lwm2m.security.sql; |
|||
|
|||
import org.eclipse.leshan.client.object.Security; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials; |
|||
import org.thingsboard.server.common.transport.util.SslUtil; |
|||
import org.thingsboard.server.transport.lwm2m.security.AbstractSecurityLwM2MIntegrationTest; |
|||
|
|||
import static org.eclipse.leshan.client.object.Security.x509; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI; |
|||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; |
|||
|
|||
public class X509_NoTrustLwM2MIntegrationTest extends AbstractSecurityLwM2MIntegrationTest { |
|||
|
|||
@Test |
|||
public void testConnectWithCertAndObserveTelemetry() throws Exception { |
|||
X509ClientCredentials credentials = new X509ClientCredentials(); |
|||
credentials.setEndpoint(ENDPOINT); |
|||
credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted)); |
|||
Security security = x509(SECURE_URI, |
|||
SHORT_SERVER_ID, |
|||
clientX509CertNotTrusted.getEncoded(), |
|||
clientPrivateKeyFromCert.getEncoded(), |
|||
serverX509Cert.getEncoded()); |
|||
super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT); |
|||
} |
|||
|
|||
} |
|||
Binary file not shown.
Loading…
Reference in new issue