lwm2m: add test, Write Attributes implemented and read Attributes (Discover)
This commit is contained in:
		
							parent
							
								
									8c5210b387
								
							
						
					
					
						commit
						6bcb00b6b9
					
				@ -47,7 +47,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
 | 
			
		||||
    private static final int min = 5;
 | 
			
		||||
    private static final int max = 50;
 | 
			
		||||
    private static final  PrimitiveIterator.OfInt randomIterator = new Random().ints(min,max + 1).iterator();
 | 
			
		||||
    private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 6, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21);
 | 
			
		||||
    private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public SimpleLwM2MDevice() {
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,18 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.client;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.leshan.client.LwM2mClient;
 | 
			
		||||
@ -5,7 +20,6 @@ import org.eclipse.leshan.client.resource.BaseObjectEnabler;
 | 
			
		||||
import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
 | 
			
		||||
import org.eclipse.leshan.client.resource.LwM2mInstanceEnabler;
 | 
			
		||||
import org.eclipse.leshan.client.resource.LwM2mInstanceEnablerFactory;
 | 
			
		||||
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
 | 
			
		||||
import org.eclipse.leshan.client.resource.listener.ResourceListener;
 | 
			
		||||
import org.eclipse.leshan.client.servers.LwM2mServer;
 | 
			
		||||
import org.eclipse.leshan.client.servers.ServersInfoExtractor;
 | 
			
		||||
@ -16,6 +30,7 @@ import org.eclipse.leshan.core.Startable;
 | 
			
		||||
import org.eclipse.leshan.core.Stoppable;
 | 
			
		||||
import org.eclipse.leshan.core.link.lwm2m.LwM2mLink;
 | 
			
		||||
import org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttribute;
 | 
			
		||||
import org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributeSet;
 | 
			
		||||
import org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributes;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
			
		||||
import org.eclipse.leshan.core.model.ResourceModel;
 | 
			
		||||
@ -54,6 +69,7 @@ import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
@ -66,21 +82,24 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
    private static Logger LOG = LoggerFactory.getLogger(DummyInstanceEnabler.class);
 | 
			
		||||
 | 
			
		||||
    protected Map<Integer, LwM2mInstanceEnabler> instances;
 | 
			
		||||
 | 
			
		||||
    protected LwM2mInstanceEnablerFactory instanceFactory;
 | 
			
		||||
    protected ContentFormat defaultContentFormat;
 | 
			
		||||
 | 
			
		||||
    private LinkFormatHelper tbLinkFormatHelper;
 | 
			
		||||
 | 
			
		||||
    protected Map<LwM2mPath, LwM2mAttributeSet> lwM2mAttributes;
 | 
			
		||||
    public TbLwm2mObjectEnabler(int id, ObjectModel objectModel, Map<Integer, LwM2mInstanceEnabler> instances,
 | 
			
		||||
                                LwM2mInstanceEnablerFactory instanceFactory, ContentFormat defaultContentFormat) {
 | 
			
		||||
        super(id, objectModel);
 | 
			
		||||
        this.instances = new HashMap<>(instances);
 | 
			
		||||
        ;
 | 
			
		||||
        this.instanceFactory = instanceFactory;
 | 
			
		||||
        this.defaultContentFormat = defaultContentFormat;
 | 
			
		||||
        for (Entry<Integer, LwM2mInstanceEnabler> entry : this.instances.entrySet()) {
 | 
			
		||||
            instances.put(entry.getKey(), entry.getValue());
 | 
			
		||||
            listenInstance(entry.getValue(), entry.getKey());
 | 
			
		||||
        }
 | 
			
		||||
        this.lwM2mAttributes = new HashMap<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public TbLwm2mObjectEnabler(int id, ObjectModel objectModel) {
 | 
			
		||||
@ -555,11 +574,55 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
        if (server.isLwm2mBootstrapServer()) {
 | 
			
		||||
            return WriteAttributesResponse.methodNotAllowed();
 | 
			
		||||
        }
 | 
			
		||||
        // TODO should be implemented here to be available for all object enabler
 | 
			
		||||
        // This should be a not implemented error, but this is not defined in the spec.
 | 
			
		||||
        return WriteAttributesResponse.internalServerError("not implemented");
 | 
			
		||||
//        return WriteAttributesResponse.internalServerError("not implemented");
 | 
			
		||||
        return doWriteAttributes(server, request);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *  <NOTIFICATION> Class Attributes
 | 
			
		||||
     * - pmin             (def = 0(sec)) Integer Resource/Object Instance/Object Readable Resource
 | 
			
		||||
     * - pmax             (def = -- )    Integer Resource/Object Instance/Object Readable Resource
 | 
			
		||||
     * - Greater Than  gt (def = -- )    Float   Resource                        Numerical&Readable Resource
 | 
			
		||||
     * - Less Than     lt (def = -- )    Float   Resource                        Numerical&Readable Resource
 | 
			
		||||
     * - Step          st (def = -- )    Float   Resource                        Numerical&Readable Resource
 | 
			
		||||
     */
 | 
			
		||||
    public  WriteAttributesResponse doWriteAttributes(LwM2mServer server, WriteAttributesRequest request) {
 | 
			
		||||
        LwM2mPath lwM2mPath = request.getPath();
 | 
			
		||||
        LwM2mAttributeSet attributeSet = lwM2mAttributes.get(lwM2mPath);
 | 
			
		||||
        Map <String, LwM2mAttribute<?>> attributes = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        for (LwM2mAttribute attr : request.getAttributes().getLwM2mAttributes()) {
 | 
			
		||||
            if (attr.getName().equals("pmax") || attr.getName().equals("pmin")) {
 | 
			
		||||
                if (lwM2mPath.isObject() || lwM2mPath.isObjectInstance() || lwM2mPath.isResource()) {
 | 
			
		||||
                    attributes.put(attr.getName(), attr);
 | 
			
		||||
                } else {
 | 
			
		||||
                    return WriteAttributesResponse.badRequest("Attribute " + attr.getName() + " can be used for only Resource/Object Instance/Object.");
 | 
			
		||||
                }
 | 
			
		||||
            } else if (attr.getName().equals("gt") || attr.getName().equals("lt") || attr.getName().equals("st")) {
 | 
			
		||||
                if (lwM2mPath.isResource()) {
 | 
			
		||||
                    attributes.put(attr.getName(), attr);
 | 
			
		||||
                } else {
 | 
			
		||||
                    return WriteAttributesResponse.badRequest("Attribute " + attr.getName() + " can be used for only Resource.");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (attributes.size()>0){
 | 
			
		||||
            if (attributeSet == null) {
 | 
			
		||||
                attributeSet = new LwM2mAttributeSet(attributes.values());
 | 
			
		||||
            } else {
 | 
			
		||||
                Iterable<LwM2mAttribute<?>> lwM2mAttributeIterable = attributeSet.getLwM2mAttributes();
 | 
			
		||||
              Map <String, LwM2mAttribute<?>> attributesOld = new HashMap<>();
 | 
			
		||||
                for (LwM2mAttribute<?> attr : lwM2mAttributeIterable) {
 | 
			
		||||
                    attributesOld.put(attr.getName(), attr);
 | 
			
		||||
                }
 | 
			
		||||
                attributesOld.putAll(attributes);
 | 
			
		||||
                attributeSet = new LwM2mAttributeSet(attributesOld.values());
 | 
			
		||||
            }
 | 
			
		||||
            lwM2mAttributes.put(lwM2mPath, attributeSet);
 | 
			
		||||
            return WriteAttributesResponse.success();
 | 
			
		||||
        }
 | 
			
		||||
        return WriteAttributesResponse.internalServerError("not implemented");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public synchronized DiscoverResponse discover(LwM2mServer server, DiscoverRequest request) {
 | 
			
		||||
@ -580,8 +643,7 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
 | 
			
		||||
        LwM2mPath path = request.getPath();
 | 
			
		||||
        if (path.isObject()) {
 | 
			
		||||
            // Manage discover on object
 | 
			
		||||
            LwM2mLink[] ObjectLinks = this.tbLinkFormatHelper.getObjectDescription(this, null);
 | 
			
		||||
            LwM2mLink[] ObjectLinks = linkUpdateAttributes(this.tbLinkFormatHelper.getObjectDescription(this, null), server);
 | 
			
		||||
            return DiscoverResponse.success(ObjectLinks);
 | 
			
		||||
 | 
			
		||||
        } else if (path.isObjectInstance()) {
 | 
			
		||||
@ -589,7 +651,7 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
            if (!getAvailableInstanceIds().contains(path.getObjectInstanceId()))
 | 
			
		||||
                return DiscoverResponse.notFound();
 | 
			
		||||
 | 
			
		||||
            LwM2mLink[] instanceLink = this.tbLinkFormatHelper.getInstanceDescription(this, path.getObjectInstanceId(), null);
 | 
			
		||||
            LwM2mLink[] instanceLink =  linkUpdateAttributes(this.tbLinkFormatHelper.getInstanceDescription(this, path.getObjectInstanceId(), null), server);
 | 
			
		||||
            return DiscoverResponse.success(instanceLink);
 | 
			
		||||
 | 
			
		||||
        } else if (path.isResource()) {
 | 
			
		||||
@ -603,23 +665,52 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
 | 
			
		||||
            if (!getAvailableResourceIds(path.getObjectInstanceId()).contains(path.getResourceId()))
 | 
			
		||||
                return DiscoverResponse.notFound();
 | 
			
		||||
            LwM2mLink resourceLink = this.getResourceAttributes(server, path, resourceModel, this);
 | 
			
		||||
            if (resourceLink == null) {
 | 
			
		||||
                resourceLink = this.tbLinkFormatHelper.getResourceDescription(this, path.getObjectInstanceId(), path.getResourceId(), null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            LwM2mLink resourceLink  = linkAddAttribute(
 | 
			
		||||
                    this.tbLinkFormatHelper.getResourceDescription(this, path.getObjectInstanceId(), path.getResourceId(), null),
 | 
			
		||||
                    server);
 | 
			
		||||
            return DiscoverResponse.success(new LwM2mLink[] { resourceLink });
 | 
			
		||||
        }
 | 
			
		||||
        return DiscoverResponse.badRequest(null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected LwM2mLink getResourceAttributes (LwM2mServer server, LwM2mPath path, ResourceModel resourceModel, LwM2mObjectEnabler objectEnabler)    {
 | 
			
		||||
        LwM2mAttribute attrResource = null;
 | 
			
		||||
        if (resourceModel.multiple) {
 | 
			
		||||
             attrResource = getResourceAttributeDim(path, server);
 | 
			
		||||
    private LwM2mLink[] linkUpdateAttributes(LwM2mLink[] links, LwM2mServer server) {
 | 
			
		||||
        return  Arrays.stream(links)
 | 
			
		||||
                .map(link -> linkAddAttribute(link, server))
 | 
			
		||||
                .toArray(LwM2mLink[]::new);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private LwM2mLink linkAddAttribute(LwM2mLink link, LwM2mServer server) {
 | 
			
		||||
 | 
			
		||||
        LwM2mAttributeSet lwM2mAttributeSetDop = null;
 | 
			
		||||
        if (this.lwM2mAttributes.get(link.getPath())!= null){
 | 
			
		||||
            lwM2mAttributeSetDop = this.lwM2mAttributes.get(link.getPath());
 | 
			
		||||
        }
 | 
			
		||||
        LwM2mAttribute resourceAttributeDim = getResourceAttributes (server, link.getPath());
 | 
			
		||||
 | 
			
		||||
        return attrResource != null ? new LwM2mLink(null, new LwM2mPath(objectEnabler.getId(), path.getObjectInstanceId(), path.getResourceId()), attrResource) : null;
 | 
			
		||||
        Map <String, LwM2mAttribute<?>> attributes = new HashMap<>();
 | 
			
		||||
        if (link.getAttributes() != null) {
 | 
			
		||||
            for (LwM2mAttribute attr : link.getAttributes().getLwM2mAttributes()) {
 | 
			
		||||
                attributes.put(attr.getName(), attr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (lwM2mAttributeSetDop != null) {
 | 
			
		||||
            for (LwM2mAttribute attr : lwM2mAttributeSetDop.getLwM2mAttributes()) {
 | 
			
		||||
                attributes.put(attr.getName(), attr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (resourceAttributeDim != null) {
 | 
			
		||||
            attributes.put(resourceAttributeDim.getName(), resourceAttributeDim);
 | 
			
		||||
        }
 | 
			
		||||
        return new LwM2mLink(link.getRootPath(), link.getPath(), attributes.values());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected LwM2mAttribute getResourceAttributes (LwM2mServer server, LwM2mPath path)    {
 | 
			
		||||
        ResourceModel resourceModel = getObjectModel().resources.get(path.getResourceId());
 | 
			
		||||
        if (path.isResource() && resourceModel.multiple) {
 | 
			
		||||
            return getResourceAttributeDim(path, server);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected LwM2mAttribute getResourceAttributeDim(LwM2mPath path, LwM2mServer server) {
 | 
			
		||||
@ -635,7 +726,6 @@ public class TbLwm2mObjectEnabler extends BaseObjectEnabler implements Destroyab
 | 
			
		||||
        } catch (Exception e ){
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,18 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.client;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.leshan.client.resource.BaseInstanceEnablerFactory;
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@ import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_0;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_ID_1;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_0;
 | 
			
		||||
@ -62,6 +63,7 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg
 | 
			
		||||
 | 
			
		||||
    protected String objectInstanceIdVer_1;
 | 
			
		||||
    protected String objectIdVer_0;
 | 
			
		||||
    protected String objectIdVer_1;
 | 
			
		||||
    protected String objectIdVer_2;
 | 
			
		||||
    private static final Predicate PREDICATE_3 = path -> (!((String) path).startsWith("/" + TEMPERATURE_SENSOR) && ((String) path).startsWith("/" + DEVICE));
 | 
			
		||||
    protected String objectIdVer_3;
 | 
			
		||||
@ -106,7 +108,9 @@ public abstract class AbstractRpcLwM2MIntegrationTest extends AbstractLwM2MInteg
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        String ver_Id_0 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_0).version;
 | 
			
		||||
        String ver_Id_1 = lwM2MTestClient.getLeshanClient().getObjectTree().getModel().getObjectModel(OBJECT_ID_1).version;
 | 
			
		||||
        objectIdVer_0 = "/" + OBJECT_ID_0 + "_" + ver_Id_0;
 | 
			
		||||
        objectIdVer_1 = "/" + OBJECT_ID_1 + "_" + ver_Id_1;
 | 
			
		||||
        objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).startsWith("/" + ACCESS_CONTROL)).findFirst().get();
 | 
			
		||||
        objectIdVer_3 = (String) expectedObjectIdVers.stream().filter(PREDICATE_3).findFirst().get();
 | 
			
		||||
        objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).startsWith("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get();
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,226 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.RESOURCE_ID_6;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_7;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class RpcLwm2mIntegrationDiscoverWriteAttributesTest extends AbstractRpcLwM2MIntegrationTest {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * WriteAttributes {"id":"/3_1.2/0/6","attributes":{"pmax":100, "pmin":10}}
 | 
			
		||||
     * if not implemented:
 | 
			
		||||
     * {"result":"INTERNAL_SERVER_ERROR","error":"not implemented"}
 | 
			
		||||
     * if implemented:
 | 
			
		||||
     * {"result":"BAD_REQUEST","error":"Attribute pmax can be used for only Resource/Object Instance/Object."}
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesResourceWithParametersByResourceInstanceId_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6 + "/1";
 | 
			
		||||
        String expectedValue = "{\"pmax\":100, \"pmin\":10}";
 | 
			
		||||
        String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute pmax can be used for only Resource/Object Instance/Object.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * WriteAttributes {"id":"/3_1.2/0/6","attributes":{"pmax":100, "pmin":10}}
 | 
			
		||||
     * if not implemented:
 | 
			
		||||
     * {"result":"INTERNAL_SERVER_ERROR","error":"not implemented"}
 | 
			
		||||
     * if implemented:
 | 
			
		||||
     * {"result":"BAD_REQUEST","error":"Attribute pmax can be used for only Resource/Object Instance/Object."}
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributeResourceDimWithParametersByResourceId_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6;
 | 
			
		||||
        String expectedValue = "{\"dim\":3}";
 | 
			
		||||
        String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute dim is of class PROPERTIES but only NOTIFICATION attribute can be used in WRITE ATTRIBUTE request.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesResourceVerWithParametersById_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath = objectIdVer_3;
 | 
			
		||||
        String expectedValue = "{\"ver\":1.3}";
 | 
			
		||||
        String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute ver is of class PROPERTIES but only NOTIFICATION attribute can be used in WRITE ATTRIBUTE request.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesResourceServerUriWithParametersById_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath =  objectInstanceIdVer_1;
 | 
			
		||||
        String actualResult = sendRPCReadById(expectedPath);
 | 
			
		||||
        String expectedValue = "{\"uri\":\"coaps://localhost:5690\"}";
 | 
			
		||||
        actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute uri is of class PROPERTIES but only NOTIFICATION attribute can be used in WRITE ATTRIBUTE request.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <PROPERTIES> Class Attributes
 | 
			
		||||
     * Dimension 	dim Integer [0:255]
 | 
			
		||||
     * Number of instances existing for a Multiple-Instance Resource
 | 
			
		||||
     * <ObjectID>3</ObjectID>
 | 
			
		||||
     * 			<Item ID="6">
 | 
			
		||||
     * 				<Name>Available Power Sources</Name>
 | 
			
		||||
     *         <Operations>R</Operations>
 | 
			
		||||
     *         <MultipleInstances>Multiple</MultipleInstances>
 | 
			
		||||
     * 				<Type>Integer</Type>
 | 
			
		||||
     * 				<RangeEnumeration>0..7</RangeEnumeration>
 | 
			
		||||
     * WriteAttributes  implemented:	Discover {"id":"3/0/6"} ->  'dim' = 3
 | 
			
		||||
     * "ver" only for objectId
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testReadDIM_3_0_6_Only_R () throws Exception {
 | 
			
		||||
        String path = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6;
 | 
			
		||||
        String actualResult = sendDiscover(path);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "</3/0/6>;dim=3";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().equals(expected));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <PROPERTIES> Class Attributes
 | 
			
		||||
     * Object Version   ver   Object
 | 
			
		||||
     * Provide the  version of the associated Object.
 | 
			
		||||
     * "ver" only for objectId
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testReadVer () throws Exception {
 | 
			
		||||
        String path = objectIdVer_3;
 | 
			
		||||
        String actualResult = sendDiscover(path);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "</3>;ver=1.2";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <NOTIFICATION> Class Attributes
 | 
			
		||||
     * Minimum/Maximum Period pmin/pmax
 | 
			
		||||
     * Notes: The Minimum Period Attribute:
 | 
			
		||||
     * -- indicates the minimum time in seconds the LwM2M Client MUST wait between two notifications. If a notification of an observed Resource is supposed to be generated but it is before pmin expiry, notification MUST be sent as soon as pmin expires. In the absence of this parameter, the Minimum Period is defined by the Default Minimum Period set in the LwM2M Server Account.
 | 
			
		||||
     * Notes: The Maximum Period Attribute:
 | 
			
		||||
     * -- indicates the maximum time in seconds the LwM2M Client MAY wait between two notifications. When this "Maximum Period" expires after the last notification, a new notification MUST be sent. In the absence of this parameter, the "Maximum Period" is defined by the Default Maximum Period when set in the LwM2M Server Account or considered as 0 otherwise. The value of 0, means pmax MUST be ignored. The maximum period parameter MUST be greater than the minimum period parameter otherwise pmax will be ignored for the Resource to which such inconsistent timing conditions are applied.
 | 
			
		||||
     * Greater Than  gt Resource
 | 
			
		||||
     * Less Than     lt Resource
 | 
			
		||||
     * Step          st Resource
 | 
			
		||||
     *
 | 
			
		||||
     * Object Id = 1
 | 
			
		||||
     * Default Minimum Period 	Id = 2 		300 or 0
 | 
			
		||||
     * Default Maximum Period 	Id = 3 		6000 or "-"
 | 
			
		||||
     * </3/0>;pmax=65, </3/0/1>, <3/0/2>, </3/0/3>, </3/0/4>,
 | 
			
		||||
     * <3/0/6>;dim=8,<3/0/7>;gt=50;lt=42.2;st=0.5,<3/0/8>;...
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesPeriodLtGt () throws Exception {
 | 
			
		||||
        String expectedPath = objectInstanceIdVer_3;
 | 
			
		||||
        String expectedValue = "{\"pmax\":60}";
 | 
			
		||||
        String actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3;
 | 
			
		||||
        expectedValue = "{\"pmax\":65}";
 | 
			
		||||
        actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_7;
 | 
			
		||||
        expectedValue ="{\"gt\":50, \"lt\":42.2, \"st\":0.5}";
 | 
			
		||||
        actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CHANGED.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
            // ObjectId
 | 
			
		||||
        expectedPath = objectIdVer_3;
 | 
			
		||||
        actualResult = sendDiscover(expectedPath);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
            // String expected = "</3>;ver=1.2,</3/0>;pmax=60,</3/0/0>,</3/0/1>,</3/0/2>,</3/0/3>,</3/0/6>;dim=3,</3/0/7>;st=0.5;lt=42.2;gt=50.0,</3/0/8>,</3/0/9>,</3/0/10>,</3/0/11>;dim=1,</3/0/13>,</3/0/14>,</3/0/15>,</3/0/16>,</3/0/17>,</3/0/18>,</3/0/19>,</3/0/20>,</3/0/21>";
 | 
			
		||||
        String expected = "</3>;ver=1.2,</3/0>;pmax=65";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
        expected = "</3/0/6>;dim=3,</3/0/7>;st=0.5;lt=42.2;gt=50.0";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
            // ObjectInstanceId
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3;
 | 
			
		||||
        actualResult = sendDiscover(expectedPath);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expected = "</3/0>;pmax=65";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
        expected = "</3/0/6>;dim=3,</3/0/7>;st=0.5;lt=42.2;gt=50.0";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
            // ResourceId
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6;
 | 
			
		||||
        actualResult = sendDiscover(expectedPath);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expected = "</3/0/6>;dim=3";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_7;
 | 
			
		||||
        actualResult = sendDiscover(expectedPath);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expected = "</3/0/7>;st=0.5;lt=42.2;gt=50.0";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().contains(expected));
 | 
			
		||||
            // ResourceInstanceId
 | 
			
		||||
        expectedPath = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6+ "/1";
 | 
			
		||||
        actualResult = sendDiscover(expectedPath);
 | 
			
		||||
        rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.INTERNAL_SERVER_ERROR.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        expected = "InvalidRequestException: Discover request cannot target resource instance path: /3/0/6/1";
 | 
			
		||||
        assertTrue(rpcActualResult.get("error").asText().contains(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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String sendRPCReadById(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 sendDiscover(String path) throws Exception {
 | 
			
		||||
        String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}";
 | 
			
		||||
        return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -66,7 +66,7 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testObserveSingleResourceWithout_IdVer_1_0_Result_CONTENT_Value_SingleResource() throws Exception {
 | 
			
		||||
        String expectedId = objectInstanceIdVer_3 + "/" + RESOURCE_ID_0;
 | 
			
		||||
        String expectedId = objectInstanceIdVer_9 + "/" + RESOURCE_ID_0;
 | 
			
		||||
        String actualResult = sendRpcObserve("Observe", fromVersionedIdToObjectId(expectedId));
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
@ -147,16 +147,17 @@ public class RpcLwm2mIntegrationObserveTest extends AbstractRpcLwM2MIntegrationT
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Repeated request on Observe
 | 
			
		||||
     * Observe {"id":"/3/0/9"}
 | 
			
		||||
     * Observe {"id":"/3_1.2/0/9"}
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testObserveRepeatedRequestObserveOnDevice_Result_BAD_REQUEST_ErrorMsg_AlreadyRegistered() throws Exception {
 | 
			
		||||
        String idVer_3_0_0 = objectInstanceIdVer_3 + "/" + RESOURCE_ID_0;
 | 
			
		||||
        sendRpcObserve("Observe", fromVersionedIdToObjectId(idVer_3_0_0));
 | 
			
		||||
        sendRpcObserve("ObserveReadAll", null);
 | 
			
		||||
        String actualResult = sendRpcObserve("Observe", idVer_3_0_0);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        actualResult = sendRpcObserve("Observe", idVer_3_0_0);
 | 
			
		||||
        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());
 | 
			
		||||
 | 
			
		||||
@ -1,133 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2023 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.RESOURCE_ID_15;
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.RESOURCE_ID_6;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 + "/" + RESOURCE_ID_15;
 | 
			
		||||
        sendRPCReadById(expectedPath);
 | 
			
		||||
        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));
 | 
			
		||||
    }
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesResourceVerWithParametersById_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath = objectIdVer_3;
 | 
			
		||||
        String actualResult = sendRPCReadById(expectedPath);
 | 
			
		||||
        String expectedValue = "{\"ver\":1.3}";
 | 
			
		||||
        actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute ver is of class PROPERTIES but only NOTIFICATION attribute can be used in WRITE ATTRIBUTE request.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testWriteAttributesResourceServerUriWithParametersById_Result_BAD_REQUEST() throws Exception {
 | 
			
		||||
        String expectedPath =  objectInstanceIdVer_1;
 | 
			
		||||
        String actualResult = sendRPCReadById(expectedPath);
 | 
			
		||||
        String expectedValue = "{\"uri\":\"coaps://localhost:5690\"}";
 | 
			
		||||
        actualResult = sendRPCExecuteWithValueById(expectedPath, expectedValue);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "Attribute uri is of class PROPERTIES but only NOTIFICATION attribute can be used in WRITE ATTRIBUTE request.";
 | 
			
		||||
        String actual = rpcActualResult.get("error").asText();
 | 
			
		||||
        assertTrue(actual.equals(expected));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <PROPERTIES> Class Attributes
 | 
			
		||||
     * Dimension 	dim Integer [0:255]
 | 
			
		||||
     * Number of instances existing for a Multiple-Instance Resource
 | 
			
		||||
     * <ObjectID>3</ObjectID>
 | 
			
		||||
     * 			<Item ID="6">
 | 
			
		||||
     * 				<Name>Available Power Sources</Name>
 | 
			
		||||
     *         <Operations>R</Operations>
 | 
			
		||||
     *         <MultipleInstances>Multiple</MultipleInstances>
 | 
			
		||||
     * 				<Type>Integer</Type>
 | 
			
		||||
     * 				<RangeEnumeration>0..7</RangeEnumeration>
 | 
			
		||||
     * WriteAttributes  implemented:	Discover {"id":"3/0/6"} ->  'dim' = 3
 | 
			
		||||
     * "ver" only for objectId
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDIM_3_0_6_Only_R () throws Exception {
 | 
			
		||||
        String path = objectInstanceIdVer_3 + "/" + RESOURCE_ID_6;
 | 
			
		||||
        String actualResult = sendDiscover(path);
 | 
			
		||||
        ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
 | 
			
		||||
        assertEquals(ResponseCode.CONTENT.getName(), rpcActualResult.get("result").asText());
 | 
			
		||||
        String expected = "</3/0/6>;dim=3";
 | 
			
		||||
        assertTrue(rpcActualResult.get("value").asText().equals(expected));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * <NOTIFICATION> Class Attributes
 | 
			
		||||
     * Minimum/Maximum Period
 | 
			
		||||
     * Notes: The Minimum Period Attribute:
 | 
			
		||||
     * -- indicates the minimum time in seconds the LwM2M Client MUST wait between two notifications. If a notification of an observed Resource is supposed to be generated but it is before pmin expiry, notification MUST be sent as soon as pmin expires. In the absence of this parameter, the Minimum Period is defined by the Default Minimum Period set in the LwM2M Server Account.
 | 
			
		||||
     * Notes: The Maximum Period Attribute:
 | 
			
		||||
     * -- indicates the maximum time in seconds the LwM2M Client MAY wait between two notifications. When this "Maximum Period" expires after the last notification, a new notification MUST be sent. In the absence of this parameter, the "Maximum Period" is defined by the Default Maximum Period when set in the LwM2M Server Account or considered as 0 otherwise. The value of 0, means pmax MUST be ignored. The maximum period parameter MUST be greater than the minimum period parameter otherwise pmax will be ignored for the Resource to which such inconsistent timing conditions are applied.
 | 
			
		||||
     * Object Id = 1
 | 
			
		||||
     * Default Minimum Period 	Id = 2 		300
 | 
			
		||||
     * Default Maximum Period 	Id = 3 		6000
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testPeriod () {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String sendRPCReadById(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 sendDiscover(String path) throws Exception {
 | 
			
		||||
        String setRpcRequest = "{\"method\": \"Discover\", \"params\": {\"id\": \"" + path + "\"}}";
 | 
			
		||||
        return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user