Browse Source

lwm2m - refactoring review - 02 and tests

pull/14881/head
nickAS21 5 months ago
parent
commit
444d856fb8
  1. 37
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java
  2. 52
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  3. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

37
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationExecuteTest.java

@ -119,7 +119,8 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
} }
/** /**
* execute_resource_with_parameters (execute Factory Reset after connect with link on device) * execute_resource_with_parameters (execute Factory Reset with two arguments:
* digit 2 without a value and digit 0 with the link value on device)
* Execute {"id":"3/0/5","value":"2,0='https://thingsboard.io/docs/reference/lwm2m-api/'"} * Execute {"id":"3/0/5","value":"2,0='https://thingsboard.io/docs/reference/lwm2m-api/'"}
*/ */
@Test @Test
@ -132,7 +133,8 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
} }
/** /**
* execute_resource_with_parameters (execute Factory Reset after connect with link on device) * execute_resource_with_parameters (execute Factory Reset with multiple arguments without values)
* According to the OMA LwM2M execute arguments format, this represents ten arguments (digits 0-9), all without values.
* Execute {"id":"3/0/5","value":"0,1,2,3,4,5,6,7,8,9"} * Execute {"id":"3/0/5","value":"0,1,2,3,4,5,6,7,8,9"}
*/ */
@Test @Test
@ -148,10 +150,9 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
/** /**
* execute_resource_with_parameters (execute Factory Reset after 60 seconds on device) * execute_resource_with_parameters (execute Factory Reset after 60 seconds on device)
* Execute {"id":"3/0/5","value":"'60'"} * Execute {"id":"3/0/5","value":"'60'"}
*/ */
@Test @Test
public void testExecuteResourceWithParametersSingleDigitValueInvalidById_BAD_REQUEST_Error_UintegerBetween_0_And_9_Expected() throws Exception { public void testExecuteResourceWithParametersSingleDigitValueInvalidById_Result_BAD_REQUEST_Error_IntegerBetween_0_And_9_Expected() throws Exception {
String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_5; String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_5;
Object expectedValue = "'60'"; Object expectedValue = "'60'";
String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue); String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
@ -159,7 +160,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String expected = "Unable to parse Arguments [" + expectedValue + "] : Invalid digit ['] (an integer between 0 and 9 is expected)"; String expected = "Unable to parse Arguments [" + expectedValue + "] : Invalid digit ['] (an integer between 0 and 9 is expected)";
String actual = rpcActualResult.get("error").asText(); String actual = rpcActualResult.get("error").asText();
assertTrue(actual.equals(expected)); assertTrue(actual.contains(expected));
} }
/** /**
@ -175,7 +176,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText()); assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String expected = "Unable to parse Arguments [" + expectedValue + "] : [,] separator expected at index 21 after [0,1,2,3,4,5,6,7,8,9,6]"; String expected = "Unable to parse Arguments [" + expectedValue + "] : [,] separator expected at index 21 after [0,1,2,3,4,5,6,7,8,9,6]";
String actual = rpcActualResult.get("error").asText(); String actual = rpcActualResult.get("error").asText();
assertTrue(actual.equals(expected)); assertTrue(actual.contains(expected));
} }
/** /**
@ -234,7 +235,7 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
* {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"} * {"result":"BAD_REQUEST","error":"Specified object id 0 absent in the list supported objects of the client or is security object!"}
*/ */
@Test @Test
public void testExecuteSecurityObjectById_Result_BAD_REQUEST_Error_InvalidDigit() throws Exception { public void testExecuteSecurityObjectById_Result_BAD_REQUEST_Error_SpecifiedObjectAbsent() throws Exception {
String expectedPath = objectIdVer_0 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_3; String expectedPath = objectIdVer_0 + "/" + OBJECT_INSTANCE_ID_0 + "/" + RESOURCE_ID_3;
String actualResult = sendRPCExecuteById(expectedPath); String actualResult = sendRPCExecuteById(expectedPath);
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class); ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
@ -253,8 +254,26 @@ public class RpcLwm2mIntegrationExecuteTest extends AbstractRpcLwM2MIntegrationT
} }
private String sendRPCExecuteWithValueById(String path, Object value) throws Exception { private String sendRPCExecuteWithValueById(String path, Object value) throws Exception {
String setRpcRequest = "{\"method\": \"Execute\", \"params\": {\"id\": \"" + path + "\", \"value\": \"" + value + "\"}}"; ObjectNode params = JacksonUtil.newObjectNode();
return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(), setRpcRequest, String.class, status().isOk()); params.put("id", path);
// Jackson сам вирішить: ставити лапки (рядок) чи ні (число/boolean/null)
if (value instanceof String) {
params.put("value", (String) value);
} else if (value instanceof Integer) {
params.put("value", (Integer) value);
} else if (value instanceof Boolean) {
params.put("value", (Boolean) value);
} else {
params.set("value", JacksonUtil.valueToTree(value));
}
ObjectNode setRpcRequest = JacksonUtil.newObjectNode();
setRpcRequest.put("method", "Execute");
setRpcRequest.set("params", params);
return doPostAsync("/api/plugins/rpc/twoway/" + lwM2MTestClient.getDeviceIdStr(),
JacksonUtil.toString(setRpcRequest), String.class, status().isOk());
} }
} }

52
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -271,40 +271,34 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
validateVersionedId(client, request); validateVersionedId(client, request);
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId())); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(request.getVersionedId()));
ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), modelProvider); ResourceModel resourceModelExecute = client.getResourceModel(request.getVersionedId(), modelProvider);
if (resourceModelExecute == null) { if (resourceModelExecute == null && pathIds.isResource()) {
LwM2mModel model = createModelsDefault(); resourceModelExecute = createModelsDefault().getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (pathIds.isResource()) {
resourceModelExecute = model.getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
}
} }
if (resourceModelExecute == null) { if (resourceModelExecute == null) {
callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + throw new InvalidArgumentException(String.format("ResourceModel with %s is absent in the system. Need to add Model with id= %s ver=%s to profile.",
" is absent in system. Need to add Model with id=" + pathIds.getObjectId() + " ver=" + request.getVersionedId(), pathIds.getObjectId(), getVerFromPathIdVerOrId(request.getVersionedId())));
getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); }
} else if (resourceModelExecute.operations.isExecutable()) { if (!resourceModelExecute.operations.isExecutable()) {
ExecuteRequest downlink; throw new InvalidArgumentException(String.format("Resource with %s is not executable.", request.getVersionedId()));
if (request.getParams() != null && !resourceModelExecute.multiple) { }
Object params = request.getParams();
ResourceModel.Type resourceModel = equalsResourceTypeGetSimpleName(params); ExecuteRequest downlink;
if (resourceModel == null) { Object params = request.getParams();
throw new InvalidArgumentException("Unsupported parameter type: " + params.getClass().getSimpleName() + // 4. Handle parameters if they exist and the resource is not a multiple-instance resource
". Only simple types (String, Integer, Boolean, etc.) are allowed for Execute arguments."); if (params != null && !resourceModelExecute.multiple) {
} ResourceModel.Type resourceModelType = equalsResourceTypeGetSimpleName(params);
String args = (String) this.converter.convertValue(params, resourceModel, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId())); if (resourceModelType == null) {
try { throw new InvalidArgumentException(String.format("Unsupported parameter type: %s. Only simple types (String, Integer, Boolean, etc.) are allowed for Execute arguments.",
Arguments arguments = Arguments.parse(args); params.getClass().getSimpleName()));
downlink = new ExecuteRequest(request.getObjectId(), arguments);
} catch (IllegalArgumentException e) {
downlink = new ExecuteRequest(request.getObjectId(), args);
}
} else {
downlink = new ExecuteRequest(request.getObjectId());
} }
sendSimpleRequest(client, downlink, request.getTimeout(), callback); String args = (String) this.converter.convertValue(params, resourceModelType, ResourceModel.Type.STRING, pathIds);
downlink = new ExecuteRequest(request.getObjectId(), args);
} else { } else {
callback.onValidationError(request.toString(), "Resource with " + request.getVersionedId() + " is not executable."); downlink = new ExecuteRequest(request.getObjectId());
} }
} catch (InvalidRequestException | InvalidArgumentException e) { sendSimpleRequest(client, downlink, request.getTimeout(), callback);
} catch (Exception e) {
log.error("[{}] Validation failed for Execute request: {}", client.getEndpoint(), e.getMessage());
callback.onValidationError(request.toString(), e.getMessage()); callback.onValidationError(request.toString(), e.getMessage());
} }
} }

12
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -242,12 +242,12 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
RpcExecuteRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcExecuteRequest.class); RpcExecuteRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcExecuteRequest.class);
TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(clientContext.getRequestTimeout(client)).build(); Object value = requestBody != null ? requestBody.getValue() : null;
if (!requestMsg.getParams().isEmpty()) { TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder()
downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId) .versionedId(versionedId)
.params(requestBody.getValue()) .params(value)
.timeout(clientContext.getRequestTimeout(client)).build(); .timeout(clientContext.getRequestTimeout(client))
} .build();
var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId); var mainCallback = new TbLwM2MExecuteCallback(logService, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback); var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback); downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback);

Loading…
Cancel
Save