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 37c126df21..3fb5b1a1e6 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 @@ -49,13 +49,13 @@ public class Lwm2mTestHelper { public static final int objectInstanceId_1 = 1; public static final int objectInstanceId_12 = 12; public static final int resourceId_0 = 0; - protected static final int resourceId_1 = 1; - protected static final int resourceId_2 = 2; - protected static final int resourceId_3 = 3; + 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_9 = 9; - protected static final int resourceId_11 = 11; + public static final int resourceId_11 = 11; public static final int resourceId_14 = 14; - protected static final int resourceId_15= 15; + public static final int resourceId_15= 15; 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/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java new file mode 100644 index 0000000000..64acf699ee --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -0,0 +1,156 @@ +/** + * 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 = objectIdVerToObjectId ((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"} + * + * @throws Exception + */ + @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 = objectInstanceIdVerToObjectInstanceId (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"} + * + * @throws Exception + */ + @Test + public void testDiscoverResource_Return_CONTENT_LinksResourceOnLyExpectedResource() throws Exception { + String expectedInstance = (String) expectedInstances.stream().findFirst().get(); + String expectedObjectInstanceId = objectInstanceIdVerToObjectInstanceId (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/2"} + * + * @throws Exception + */ + @Test + public void testDiscoverInstanceAbsentInObject_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"} + * + * @throws Exception + */ + @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()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java new file mode 100644 index 0000000000..848a9563ed --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationObserveTest.java @@ -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()); + } +} 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 new file mode 100644 index 0000000000..4f696e1c3c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationReadTest.java @@ -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 = objectIdVerToObjectId ((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 = objectInstanceIdVerToObjectInstanceId ((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 = objectIdVerToObjectId(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 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 = objectInstanceIdVerToObjectInstanceId(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 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 = objectInstanceIdVerToObjectInstanceId(objectInstanceIdVer_3); + String objectId_19 = objectIdVerToObjectId(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()); + } +} 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 new file mode 100644 index 0000000000..0150572351 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationWriteTest.java @@ -0,0 +1,330 @@ +/** + * 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.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_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; + +public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTest { + + + /** + * id + * WriteReplace {"id":"3/0/14","value":"+12"} + */ + @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"} + */ + @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"}} + */ + @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 - 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"}} + * + */ + @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"}}} + */ + @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"}} + */ + @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); + } + + + /** + * 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"}}} + */ + @Test + public void testCreateObjectInstanceSingleByIdKey_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)); + } + + /** + * 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"}} + */ + + 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()); + } +} \ No newline at end of file