From 0a3c626333fe58a889d6bd16d170688920e23e88 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Tue, 31 Aug 2021 23:38:31 +0300 Subject: [PATCH] lwm2m: abstract integration RPC test delete, create, writeAttribute, execute --- .../transport/lwm2m/Lwm2mTestHelper.java | 5 + .../lwm2m/client/LwM2MTestClient.java | 1 - .../rpc/AbstractRpcLwM2MIntegrationTest.java | 34 +++- .../sql/RpcLwm2mIntegrationCreateTest.java | 70 ++++++- .../sql/RpcLwm2mIntegrationDeleteTest.java | 96 +++++++++ .../sql/RpcLwm2mIntegrationDiscoverTest.java | 35 ++-- .../sql/RpcLwm2mIntegrationExecuteTest.java | 186 ++++++++++++++++++ .../rpc/sql/RpcLwm2mIntegrationReadTest.java | 16 +- ...pcLwm2mIntegrationWriteAttributesTest.java | 63 ++++++ .../rpc/sql/RpcLwm2mIntegrationWriteTest.java | 71 ++++--- .../security/sql/OtaLwM2MIntegrationTest.java | 6 +- .../device/data/lwm2m/OtherConfiguration.java | 2 - .../lwm2m/server/client/LwM2mClient.java | 2 +- 13 files changed, 520 insertions(+), 67 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java create mode 100644 application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 3fb5b1a1e6..232332e554 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -45,17 +45,22 @@ public class Lwm2mTestHelper { public static final int TEMPERATURE_SENSOR = 3303; // Ids in Client + public static final int objectId_0 = 0; public static final int objectInstanceId_0 = 0; public static final int objectInstanceId_1 = 1; + public static final int objectInstanceId_2 = 2; public static final int objectInstanceId_12 = 12; public static final int resourceId_0 = 0; public static final int resourceId_1 = 1; public static final int resourceId_2 = 2; public static final int resourceId_3 = 3; + public static final int resourceId_4 = 4; + public static final int resourceId_8 = 8; public static final int resourceId_9 = 9; public static final int resourceId_11 = 11; public static final int resourceId_14 = 14; public static final int resourceId_15= 15; + public static final int resourceInstanceId_2 = 2; public static final String resourceIdName_3_9 = "batteryLevel"; public static final String resourceIdName_3_14 = "UtfOffset"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 4c5406785c..b79fb39799 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -44,7 +44,6 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java index f635de509b..13bafd39d3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/AbstractRpcLwM2MIntegrationTest.java @@ -59,6 +59,7 @@ import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; import static org.eclipse.leshan.core.LwM2mId.SERVER; +import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; 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.COAP_CONFIG; @@ -72,6 +73,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectId_0; 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; @@ -158,12 +160,16 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT public Set expectedObjectIdVerInstances; protected String objectInstanceIdVer_1; + protected String objectIdVer_0; protected String objectIdVer_2; private static final Predicate predicate_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE)); protected String objectIdVer_3; protected String objectInstanceIdVer_3; protected String objectInstanceIdVer_5; + protected String objectInstanceIdVer_9; protected String objectIdVer_19; + protected String objectIdVer_50 = "/50"; + protected String objectIdVer_3303; public AbstractRpcLwM2MIntegrationTest(){ } @@ -212,13 +218,21 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT }); } }); - objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); + String ver_Id_0 = client.getClient().getObjectTree().getModel().getObjectModel(objectId_0).version; + if ("1.0".equals(ver_Id_0)) { + objectIdVer_0 = "/" + objectId_0; + } + else { + objectIdVer_0 = "/" + objectId_0 + "_" + ver_Id_0; + } objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get(); objectIdVer_3 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); - objectIdVer_19 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get(); + objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + objectIdVer_3303 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + TEMPERATURE_SENSOR)).findFirst().get(); + objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get(); objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get(); objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get(); - objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get(); + objectInstanceIdVer_9 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + SOFTWARE_MANAGEMENT)).findFirst().get(); } protected void createDeviceProfile(String transportConfiguration) throws Exception { @@ -285,13 +299,13 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractWebsocketT return bootstrap; } - protected String objectIdVerToObjectId(String objectIdVer) { - return objectIdVer.contains("_") ? objectIdVer.split("_")[0] : objectIdVer; - } - - protected String objectInstanceIdVerToObjectInstanceId(String objectInstanceIdVer) { - String[] objectIdVer = objectInstanceIdVer.split("/"); - return objectIdVer[1].contains("_") ? objectIdVer[1].split("_")[0] + "/" + objectIdVer[2] : objectInstanceIdVer; + protected String pathIdVerToObjectId(String pathIdVer) { + if (pathIdVer.contains("_")){ + String [] objVer = pathIdVer.split("/"); + objVer[1] = objVer[1].split("_")[0]; + return String.join("/", objVer); + } + return pathIdVer; } @After diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java index 5997449d1f..4ab0d68794 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java @@ -17,6 +17,7 @@ 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; @@ -25,11 +26,29 @@ 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_1; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_0; public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTest { + /** + * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} + * + * create_2_instances_in_object + * new ObjectInstance if Object is Multiple & Resource Single + * Create {"id":"/19_1.1/12","value":{"0":{"0":"00AC", "1":1}}} + * {"{"result":"CREATED"}"} + */ + @Test + public void testCreateObjectInstanceWithInstanceIdByIdKey_Result_CREATED() throws Exception { + String expectedPath = objectIdVer_19 + "/" + objectInstanceId_12; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.CREATED.getName(), rpcActualResult.get("result").asText()); + } /** * Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}} @@ -38,10 +57,9 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe * new ObjectInstance if Object is Multiple & Resource Single * Create {"id":"/19_1.1/0","value":{"0":{"0":"00AC", "1":1}}} * {"result":"BAD_REQUEST","error":"instance 0 already exists"} - * */ @Test - public void testCreateObjectInstanceWithInstanceIdAlreadyExistsByIdKey_Result_BAD_REQUEST() throws Exception { + public void testCreateObjectInstanceWithInstanceIdAlreadyExistsById_Result_BAD_REQUEST() throws Exception { String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0; String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}"; String actualResult = sendRPCreateById(expectedPath, expectedValue); @@ -54,20 +72,58 @@ public class RpcLwm2mIntegrationCreateTest extends AbstractRpcLwM2MIntegrationTe /** * failed: cannot_create_mandatory_single_object - * Create {"id":"/3/2","value":{"0":"00AC"}} + * Create {"id":"/3/1,"value":{"0":"00AC"}} + * {"result":"BAD_REQUEST","error":"Path /3/1. Object must be Multiple !"} */ - + @Test + public void testCreateObjectInstanceWithInstanceIdMandatorySingleObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_3 + "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); + assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); + String expected = "Path " + expectedPath + ". Object must be Multiple !"; + String actual = rpcActualResult.get("error").asText(); + assertTrue(actual.equals(expected)); + } /** * failed: cannot_create_instance_of_security_object - * Create {"id":"/0/2","value":{"0":"00AC"}} + * Create {"id":"/0/2","value":{"2":4}} + * {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"} */ + @Test + public void testCreateObjectInstanceWithInstanceIdSecurityObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_0 + "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"2\":4}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + 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)); + } /** * failed: cannot_create_instance_of_absent_object - * Create {"id":"/50/2","value":{"0":"00AC"}} + * Create {"id":"/50/1","value":{"0":"00AC"}} + * {"result":"BAD_REQUEST","error":"Specified object id 50 absent in the list supported objects of the client or is security object!"} */ - + @Test + public void testCreateObjectInstanceWithInstanceIdAbsentObjectById_Result_BAD_REQUEST() throws Exception { + String expectedPath = objectIdVer_50+ "/" + objectInstanceId_1; + String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}}"; + String actualResult = sendRPCreateById(expectedPath, expectedValue); + 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 sendRPCreateById(String path, String value) throws Exception { String setRpcRequest = "{\"method\": \"Create\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java new file mode 100644 index 0000000000..6f24d7176c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDeleteTest.java @@ -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()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index 64acf699ee..b8ca7be61f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -74,7 +74,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration expectedObjectIdVers.forEach(expected -> { try { String actualResult = sendDiscover((String) expected); - String expectedObjectId = objectIdVerToObjectId ((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(","); @@ -88,8 +88,12 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration /** * Discover {"id":"3/0"} - * - * @throws Exception + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":",,,,,,,,,,,,,,,,,,,,,,,"} + * If WriteAttributes implemented and WriteAttributes saved + * Discover {"id":"19/0"} + * {"result":"CONTENT","value":"[;dim=2;pmin=10;pmax=60;gt=50;lt=42.2,;pmax=120, , , , , ;lt=45]"} */ @Test public void testDiscoverInstance_Return_CONTENT_LinksResourcesOnLyExpectedInstance() throws Exception { @@ -97,7 +101,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration String actualResult = sendDiscover(expected); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expected); + 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()); @@ -105,13 +109,20 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration /** * Discover {"id":"3/0/14"} - * - * @throws Exception + * If WriteAttributes implemented: + * {"result":"CONTENT","value":";pmax=100, "pmin":10, "ver"=1.0"} + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":""} + * Discover {"id":"19_1.1/0/0"} + * If WriteAttributes implemented: + * {"result":"CONTENT","value":";pmax=100, "pmin":10, "ver"=1.1"} + * If WriteAttributes not implemented: + * {"result":"CONTENT","value":""} */ @Test public void testDiscoverResource_Return_CONTENT_LinksResourceOnLyExpectedResource() throws Exception { String expectedInstance = (String) expectedInstances.stream().findFirst().get(); - String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (expectedInstance); + 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; @@ -125,12 +136,11 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration } /** - * Discover {"id":"2/0/2"} - * - * @throws Exception + * Discover {"id":"2/0"} + *{"result":"NOT_FOUND"} */ @Test - public void testDiscoverInstanceAbsentInObject_Return_NOT_FOUND() throws Exception { + 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); @@ -138,8 +148,7 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration } /** * Discover {"id":"2/0/2"} - * - * @throws Exception + * {"result":"NOT_FOUND"} */ @Test public void testDiscoverResourceAbsentInObject_Return_NOT_FOUND() throws Exception { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java new file mode 100644 index 0000000000..73ea0fb74c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java @@ -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()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java index 4f696e1c3c..9116659bc3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -52,7 +52,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest expectedObjectIdVers.forEach(expected -> { try { String actualResult = sendRPCById((String) expected); - String expectedObjectId = objectIdVerToObjectId ((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()); @@ -77,7 +77,7 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest expectedObjectIdVerInstances.forEach(expected -> { try { String actualResult = sendRPCById((String) expected); - String expectedObjectId = objectInstanceIdVerToObjectInstanceId ((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()); @@ -136,10 +136,10 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest @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 = objectIdVerToObjectId(expectedIdVer_1); + 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 = objectIdVerToObjectId(objectInstanceIdVer_3); + 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); @@ -165,10 +165,10 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest String actualResult = sendCompositeRPCByIds(expectedIds); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); + 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 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_1); + 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(); @@ -190,8 +190,8 @@ public class RpcLwm2mIntegrationReadTest extends AbstractRpcLwM2MIntegrationTest String actualResult = sendCompositeRPCByKeys(expectedKeys); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText()); - String objectInstanceId_3 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); - String objectId_19 = objectIdVerToObjectId(objectIdVer_19); + 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"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java new file mode 100644 index 0000000000..ea23ab48b9 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteAttributesTest.java @@ -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()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java index 0150572351..3bc9c075f1 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -17,6 +17,7 @@ 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; @@ -27,18 +28,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. 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 { /** - * id + * update SingleResource: * WriteReplace {"id":"3/0/14","value":"+12"} + * {"result":"CHANGED"} */ @Test public void testWriteReplaceValueSingleResourceById_Result_CHANGED() throws Exception { @@ -57,6 +61,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * key * WriteReplace {"key":"timezone","value":"+10"} + * {"result":"CHANGED"} */ @Test public void testWriteReplaceValueSingleResourceByKey_Result_CHANGED() throws Exception { @@ -76,6 +81,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * 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 { @@ -121,7 +127,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** - * bad - only read + * bad: singleResource, operation="R" - only read * WriteReplace {"id":"/3/0/9","value":90} * {"result":"METHOD_NOT_ALLOWED"} */ @@ -137,7 +143,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * ids * WriteUpdate {"id":"/3/0","value":{"14":"+5","15":"Kiyv/Europe"}} - * + * {"result":"CHANGED"} */ @Test public void testWriteUpdateValueSingleResourceById_Result_CHANGED() throws Exception { @@ -165,6 +171,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * id * WriteUpdate {"id": "/19_1.1/0","value": {"0":{"0":"00ad456756", "25":"25ad456756"}}} + * {"result":"CHANGED"} */ @Test public void testWriteUpdateValueMultipleResourceById_Result_CHANGED() throws Exception { @@ -194,6 +201,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** * 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 { @@ -246,15 +254,17 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes /** - * create_2_instances_in_object - * new ObjectInstance if Object is Multiple & Resource Single - * Create {"id":"/19/2","value":{"1":2}} - * Create {"id":"/19/3","value":{"0":{"0":"00AC", "1":"ddff12"}}} + * 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 testCreateObjectInstanceSingleByIdKey_Result_CHANGED() throws Exception { - int resourceInstanceId2 = 2; - String expectedPath19_1_0_2 = objectIdVer_19 + "/" + objectInstanceId_1 + "/" + resourceId_0 + "/" + resourceInstanceId2; + 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"; @@ -268,7 +278,7 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes 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]"; + 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); @@ -283,20 +293,33 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes } /** - * failed: cannot_create_mandatory_single_object - * Create {"id":"/3/2","value":{"0":"00AC"}} - */ - - - /** - * failed: cannot_create_instance_of_security_object - * Create {"id":"/0/2","value":{"0":"00AC"}} - */ - - /** - * failed: cannot_create_instance_of_absent_object - * Create {"id":"/50/2","value":{"0":"00AC"}} + * 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 + "\" }}"; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java index ffaeb3f5c6..96006cbe67 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; +import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest; @@ -40,6 +41,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.hamcrest.Matchers.hasSize; import static org.thingsboard.rest.client.utils.RestJsonConverter.toTimeseries; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.CHECKSUM_ALGORITHM; +import static org.thingsboard.server.common.data.ota.OtaPackageKey.SIZE; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADING; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; @@ -133,7 +137,7 @@ public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { "}"; @Test - public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception { + public void testFirmwareUpdateWithClientWithoutFirmwareOtaInfoFromProfile() throws Exception { String endpoint = "WithoutFirmwareInfoDevice"; createDeviceProfile(TRANSPORT_CONFIGURATION); NoSecClientCredentials clientCredentials = new NoSecClientCredentials(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java index 4722246b4f..cf841d6204 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/OtherConfiguration.java @@ -33,6 +33,4 @@ public class OtherConfiguration extends PowerSavingConfiguration { private Long pagingTransmissionWindow; private String fwUpdateResource; private String swUpdateResource; - private boolean compositeOperationsSupport; - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index ff2757ba3b..8106871aee 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -363,7 +363,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); if (verSupportedObject == null) { - return String.format("Specified resource id %s is missing from the client!", path); + return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId()); } else { String verRez = getVerFromPathIdVerOrId(path); if ((verRez != null && !verRez.equals(verSupportedObject)) ||