Browse Source

lwm2Tests: new structure

pull/5156/head
Sergey Matvienko 5 years ago
committed by nickAS21
parent
commit
b01eb2cfc5
  1. 2
      application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java
  2. 65
      application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java
  3. 2
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java
  4. 41
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java
  5. 52
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java
  6. 231
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java
  7. 150
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java
  8. 131
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java
  9. 10
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java
  10. 3
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java
  11. 307
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java
  12. 77
      application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java
  13. 17
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java
  14. 36
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java
  15. 120
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java
  16. 9
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java
  17. 9
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java
  18. 37
      application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java
  19. 144
      application/src/test/resources/lwm2m/19.xml
  20. 103
      application/src/test/resources/lwm2m/3303.xml
  21. 143
      application/src/test/resources/lwm2m/6.xml

2
application/src/test/java/org/thingsboard/server/transport/TransportSqlTestSuite.java

@ -33,7 +33,7 @@ import java.util.Arrays;
"org.thingsboard.server.transport.*.attributes.request.sql.*Test",
"org.thingsboard.server.transport.*.claim.sql.*Test",
"org.thingsboard.server.transport.*.provision.sql.*Test",
"org.thingsboard.server.transport.lwm2m.sql.*Test"
"org.thingsboard.server.transport.lwm2m.*.sql.*Test"
})
public class TransportSqlTestSuite {

65
application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java

@ -0,0 +1,65 @@
/**
* 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;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.client.object.Security;
import static org.eclipse.leshan.client.object.Security.noSec;
public class Lwm2mTestHelper {
// Server
public static final int SECURE_PORT = 5686;
public static final int SECURE_PORT_BS = 5688;
public static final String HOST = "localhost";
public static final String HOST_BS = "localhost";
public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT));
public static final String ENDPOINT_SECURITY = "deviceAEndpoint";
public static final String SECURE_URI = "coaps://localhost:" + SECURE_PORT;
public static final int PORT = 5685;
public static final int PORT_BS = 5687;
public static final int SHORT_SERVER_ID = 123;
public static final int SHORT_SERVER_ID_BS = 111;
public static final Security SECURITY = noSec("coap://localhost:" + PORT, SHORT_SERVER_ID);
public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
// Models
public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"};
public static final int BINARY_APP_DATA_CONTAINER = 19;
public static final int TEMPERATURE_SENSOR = 3303;
// Ids in Client
public static final int objectInstanceId_0 = 0;
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_9 = 9;
protected static final int resourceId_11 = 11;
public static final int resourceId_14 = 14;
protected static final int resourceId_15= 15;
public static final String resourceIdName_3_9 = "batteryLevel";
public static final String resourceIdName_3_14 = "UtfOffset";
public static final String resourceIdName_19_0_0 = "dataRead";
public static final String resourceIdName_19_1_0 = "dataWrite";
}

2
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java

@ -83,7 +83,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
@Override
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 0:

41
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MLocationParams.java

@ -0,0 +1,41 @@
/**
* 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.client;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Data
public class LwM2MLocationParams {
private Float latitude;
private Float longitude;
private Float scaleFactor = 1.0F;
private final String locationPos = "50.4501:30.5234";
private final Float locationScaleFactor = 1.0F;
protected void getPos() {
this.latitude = null;
this.longitude = null;
int c = locationPos.indexOf(':');
this.latitude = Float.valueOf(locationPos.substring(0, c));
this.longitude = Float.valueOf(locationPos.substring(c + 1));
}
}

52
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java

@ -31,7 +31,6 @@ import org.eclipse.leshan.client.observer.LwM2mClientObserver;
import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
import org.eclipse.leshan.client.resource.ObjectsInitializer;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.LwM2mId;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.californium.EndpointFactory;
import org.eclipse.leshan.core.model.InvalidDDFFileException;
@ -45,6 +44,7 @@ import org.eclipse.leshan.core.request.BootstrapRequest;
import org.eclipse.leshan.core.request.DeregisterRequest;
import org.eclipse.leshan.core.request.RegisterRequest;
import org.eclipse.leshan.core.request.UpdateRequest;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import org.junit.Assert;
@ -54,11 +54,20 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.DEVICE;
import static org.eclipse.leshan.core.LwM2mId.FIRMWARE;
import static org.eclipse.leshan.core.LwM2mId.LOCATION;
import static org.eclipse.leshan.core.LwM2mId.SECURITY;
import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_1;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_12;
@Slf4j
@Data
@ -67,24 +76,36 @@ public class LwM2MTestClient {
private final ScheduledExecutorService executor;
private final String endpoint;
private LeshanClient client;
private Server lwm2mServer;
private SimpleLwM2MDevice lwM2MDevice;
private FwLwM2MDevice fwLwM2MDevice;
private SwLwM2MDevice swLwM2MDevice;
private LwM2mBinaryAppDataContainer lwM2MBinaryAppDataContainer;
private LwM2MLocationParams locationParams;
private LwM2mTemperatureSensor lwM2MTemperatureSensor;
public void init(Security security, NetworkConfig coapConfig) throws InvalidDDFFileException, IOException {
public void init(Security security, NetworkConfig coapConfig, int port) throws InvalidDDFFileException, IOException {
Assert.assertNull("client already initialized", client);
String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "9.xml"};
List<ObjectModel> models = new ArrayList<>();
for (String resourceName : resources) {
models.addAll(ObjectLoader.loadDdfFile(LwM2MTestClient.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName), resourceName));
}
LwM2mModel model = new StaticModel(models);
ObjectsInitializer initializer = new ObjectsInitializer(model);
initializer.setInstancesForObject(SECURITY, security);
initializer.setInstancesForObject(SERVER, new Server(123, 300));
initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice());
initializer.setInstancesForObject(SERVER, lwm2mServer = new Server(123, 300));
initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice());
initializer.setInstancesForObject(FIRMWARE, fwLwM2MDevice = new FwLwM2MDevice());
initializer.setInstancesForObject(SOFTWARE_MANAGEMENT, swLwM2MDevice = new SwLwM2MDevice());
initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class);
initializer.setClassForObject(ACCESS_CONTROL, DummyInstanceEnabler.class);
initializer.setInstancesForObject(BINARY_APP_DATA_CONTAINER, lwM2MBinaryAppDataContainer = new LwM2mBinaryAppDataContainer(executor, objectInstanceId_0),
new LwM2mBinaryAppDataContainer(executor, objectInstanceId_1));
locationParams = new LwM2MLocationParams();
locationParams.getPos();
initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, objectInstanceId_0));
initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, objectInstanceId_0), new LwM2mTemperatureSensor(executor, objectInstanceId_12));
DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
dtlsConfig.setRecommendedCipherSuitesOnly(true);
@ -128,7 +149,7 @@ public class LwM2MTestClient {
LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
builder.setLocalAddress("0.0.0.0", 11000);
builder.setLocalAddress("0.0.0.0", port);
builder.setObjects(initializer.createAll());
builder.setCoapConfig(coapConfig);
builder.setDtlsConfig(dtlsConfig);
@ -136,6 +157,7 @@ public class LwM2MTestClient {
builder.setEndpointFactory(endpointFactory);
builder.setSharedExecutor(executor);
builder.setDecoder(new DefaultLwM2mDecoder(false));
builder.setEncoder(new DefaultLwM2mEncoder(new LwM2mValueConverterImpl(), false));
client = builder.build();
@ -233,13 +255,27 @@ public class LwM2MTestClient {
}
public void destroy() {
client.destroy(true);
if (client != null) {
client.destroy(true);
}
if (lwm2mServer != null) {
lwm2mServer = null;
}
if (lwM2MDevice != null) {
lwM2MDevice.destroy();
}
if (fwLwM2MDevice != null) {
fwLwM2MDevice.destroy();
}
if (swLwM2MDevice != null) {
swLwM2MDevice.destroy();
}
if (lwM2MBinaryAppDataContainer != null) {
lwM2MBinaryAppDataContainer.destroy();
}
if (lwM2MTemperatureSensor != null) {
lwM2MTemperatureSensor.destroy();
}
}
}

231
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java

@ -0,0 +1,231 @@
/**
* 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.client;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import javax.security.auth.Destroyable;
import java.sql.Time;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements Destroyable {
/**
* id = 0
* Multiple
* base64
*/
/**
* Example1:
* InNlcnZpY2VJZCI6Ik1ldGVyIiwNCiJzZXJ2aWNlRGF0YSI6ew0KImN1cnJlbnRSZWFka
* W5nIjoiNDYuMyIsDQoic2lnbmFsU3RyZW5ndGgiOjE2LA0KImRhaWx5QWN0aXZpdHlUaW1lIjo1NzA2DQo=
* "serviceId":"Meter",
* "serviceData":{
* "currentReading":"46.3",
* "signalStrength":16,
* "dailyActivityTime":5706
*/
/**
* Example2:
* InNlcnZpY2VJZCI6IldhdGVyTWV0ZXIiLA0KImNtZCI6IlNFVF9URU1QRVJBVFVSRV9SRUFEX
* 1BFUklPRCIsDQoicGFyYXMiOnsNCiJ2YWx1ZSI6NA0KICAgIH0sDQoNCg0K
* "serviceId":"WaterMeter",
* "cmd":"SET_TEMPERATURE_READ_PERIOD",
* "paras":{
* "value":4
* },
*/
// private String data = "InNlcnZpY2VJZCI6Ik1ldGVyIiwNCiJzZXJ2aWNlRGF0YSI6ew0KImN1cnJlbnRSZWFkaW5nIjoiNDYuMyIsDQoic2lnbmFsU3RyZW5ndGgiOjE2LA0KImRhaWx5QWN0aXZpdHlUaW1lIjo1NzA2DQo=";
// private byte[] data;
Map<Integer, byte[]> data;
private Integer priority = 0;
private Time timestamp;
private String description;
private String dataFormat;
private Integer appID = -1;
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 4, 5);
public LwM2mBinaryAppDataContainer() {
}
public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) {
try {
if (id != null) this.setId(id);
executorService.scheduleWithFixedDelay(() ->
// fireResourcesChange(0, 2), 5000, 5000, TimeUnit.MILLISECONDS);
fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN
} catch (Throwable e) {
log.error("[{}]Throwable", e.toString());
e.printStackTrace();
}
}
@Override
public ReadResponse read(ServerIdentity identity, int resourceId) {
// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
try {
switch (resourceId) {
case 0:
// log.warn("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
ReadResponse response = ReadResponse.success(resourceId, getData(), ResourceModel.Type.OPAQUE);
// log.warn("Response [{}]", response);
return response;
case 1:
return ReadResponse.success(resourceId, getPriority());
case 2:
return ReadResponse.success(resourceId, getTimestamp());
case 3:
return ReadResponse.success(resourceId, getDescription());
case 4:
return ReadResponse.success(resourceId, getDataFormat());
case 5:
return ReadResponse.success(resourceId, getAppID());
default:
return super.read(identity, resourceId);
}
} catch (Exception e) {
return ReadResponse.badRequest(e.getMessage());
}
}
@Override
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
log.info("Write on Device resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
switch (resourceId) {
case 0:
if (setData(value, replace)) {
return WriteResponse.success();
} else {
WriteResponse.badRequest("Invalidate value ...");
}
case 1:
setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue()));
fireResourcesChange(resourceId);
return WriteResponse.success();
case 2:
setTimestamp(((Date) value.getValue()).getTime());
fireResourcesChange(resourceId);
return WriteResponse.success();
case 3:
setDescription((String) value.getValue());
fireResourcesChange(resourceId);
return WriteResponse.success();
case 4:
setDataFormat((String) value.getValue());
fireResourcesChange(resourceId);
return WriteResponse.success();
case 5:
setAppID((Integer) value.getValue());
fireResourcesChange(resourceId);
return WriteResponse.success();
default:
return super.write(identity, replace, resourceId, value);
}
}
private Integer getAppID() {
return this.appID;
}
private void setAppID(Integer appId) {
this.appID = appId;
}
private void setDataFormat(String value) {
this.dataFormat = value;
}
private String getDataFormat() {
// return this.dataFormat == null ? "base64" : this.dataFormat;
return this.dataFormat == null ? "OPAQUE" : this.dataFormat;
}
private void setDescription(String value) {
this.description = value;
}
private String getDescription() {
return this.description == null ? "meter reading" : this.description;
}
private void setTimestamp(long time) {
this.timestamp = new Time(time);
}
private Time getTimestamp() {
return this.timestamp != null ? this.timestamp : new Time(new Date().getTime());
}
// fireResourcesChange(resourceId);
private boolean setData(LwM2mResource value, boolean replace) {
try {
if (value instanceof LwM2mMultipleResource) {
if (replace || this.data == null) {
this.data = new HashMap<>();
}
value.getInstances().values().forEach(v -> {
this.data.put(v.getId(), (byte[]) v.getValue());
});
return true;
} else {
return false;
}
} catch (Exception e) {
return false;
}
}
private Map<Integer, byte[]> getData() {
// this.data.put(23, new byte[]{0,0, 2,3});
return data;
}
@Override
public List<Integer> getAvailableResourceIds(ObjectModel model) {
return supportedResources;
}
@Override
public void destroy() {
}
private int getPriority() {
return this.priority;
}
private void setPriority(int value) {
this.priority = value;
}
}

150
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java

@ -0,0 +1,150 @@
/**
* 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.client;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.response.ReadResponse;
import javax.security.auth.Destroyable;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable {
private float latitude;
private float longitude;
private float scaleFactor;
private Date timestamp;
protected static final Random RANDOM = new Random();
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 5);
public LwM2mLocation() {
this(null, null, 1.0f);
}
public LwM2mLocation(Float latitude, Float longitude, float scaleFactor) {
if (latitude != null) {
this.latitude = latitude + 90f;
} else {
this.latitude = RANDOM.nextInt(180);
}
if (longitude != null) {
this.longitude = longitude + 180f;
} else {
this.longitude = RANDOM.nextInt(360);
}
this.scaleFactor = scaleFactor;
timestamp = new Date();
}
public LwM2mLocation(Float latitude, Float longitude, float scaleFactor, ScheduledExecutorService executorService, Integer id) {
try {
if (id != null) this.setId(id);
if (latitude != null) {
this.latitude = latitude + 90f;
} else {
this.latitude = RANDOM.nextInt(180);
}
if (longitude != null) {
this.longitude = longitude + 180f;
} else {
this.longitude = RANDOM.nextInt(360);
}
this.scaleFactor = scaleFactor;
timestamp = new Date();
executorService.scheduleWithFixedDelay(() ->
fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS);
} catch (Throwable e) {
log.error("[{}]Throwable", e.toString());
e.printStackTrace();
}
}
@Override
public ReadResponse read(ServerIdentity identity, int resourceId) {
log.info("Read on Location resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
switch (resourceId) {
case 0:
return ReadResponse.success(resourceId, getLatitude());
case 1:
return ReadResponse.success(resourceId, getLongitude());
case 5:
return ReadResponse.success(resourceId, getTimestamp());
default:
return super.read(identity, resourceId);
}
}
public void moveLocation(String nextMove) {
switch (nextMove.charAt(0)) {
case 'w':
moveLatitude(1.0f);
// log.info("Move to North [{}]/[{}]", getLatitude(), getLongitude());
break;
case 'a':
moveLongitude(-1.0f);
// log.info("Move to East [{}]/[{}]", getLatitude(), getLongitude());
break;
case 's':
moveLatitude(-1.0f);
// log.info("Move to South [{}]/[{}]", getLatitude(), getLongitude());
break;
case 'd':
moveLongitude(1.0f);
// log.info("Move to West [{}]/[{}]", getLatitude(), getLongitude());
break;
}
}
private void moveLatitude(float delta) {
latitude = latitude + delta * scaleFactor;
timestamp = new Date();
fireResourcesChange(0, 5);
}
private void moveLongitude(float delta) {
longitude = longitude + delta * scaleFactor;
timestamp = new Date();
fireResourcesChange(1, 5);
}
public float getLatitude() {
return latitude - 90.0f;
}
public float getLongitude() {
return longitude - 180.f;
}
public Date getTimestamp() {
return timestamp;
}
@Override
public List<Integer> getAvailableResourceIds(ObjectModel model) {
return supportedResources;
}
}

131
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java

@ -0,0 +1,131 @@
/**
* 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.client;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.response.ExecuteResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import javax.security.auth.Destroyable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Slf4j
public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destroyable {
private static final String UNIT_CELSIUS = "cel";
private double currentTemp = 20d;
private double minMeasuredValue = currentTemp;
private double maxMeasuredValue = currentTemp;
protected static final Random RANDOM = new Random();
private static final List<Integer> supportedResources = Arrays.asList(5601, 5602, 5700, 5701);
public LwM2mTemperatureSensor() {
}
public LwM2mTemperatureSensor(ScheduledExecutorService executorService, Integer id) {
try {
if (id != null) this.setId(id);
executorService.scheduleWithFixedDelay(this::adjustTemperature, 2000, 2000, TimeUnit.MILLISECONDS);
} catch (Throwable e) {
log.error("[{}]Throwable", e.toString());
e.printStackTrace();
}
}
@Override
public synchronized ReadResponse read(ServerIdentity identity, int resourceId) {
log.info("Read on Temperature resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
switch (resourceId) {
case 5601:
return ReadResponse.success(resourceId, getTwoDigitValue(minMeasuredValue));
case 5602:
return ReadResponse.success(resourceId, getTwoDigitValue(maxMeasuredValue));
case 5700:
return ReadResponse.success(resourceId, getTwoDigitValue(currentTemp));
case 5701:
return ReadResponse.success(resourceId, UNIT_CELSIUS);
default:
return super.read(identity, resourceId);
}
}
@Override
public synchronized ExecuteResponse execute(ServerIdentity identity, int resourceId, String params) {
log.info("Execute on Temperature resource /[{}]/[{}]/[{}]", getModel().id, getId(), resourceId);
switch (resourceId) {
case 5605:
resetMinMaxMeasuredValues();
return ExecuteResponse.success();
default:
return super.execute(identity, resourceId, params);
}
}
private double getTwoDigitValue(double value) {
BigDecimal toBeTruncated = BigDecimal.valueOf(value);
return toBeTruncated.setScale(2, RoundingMode.HALF_UP).doubleValue();
}
private void adjustTemperature() {
float delta = (RANDOM.nextInt(20) - 10) / 10f;
currentTemp += delta;
Integer changedResource = adjustMinMaxMeasuredValue(currentTemp);
if (changedResource != null) {
fireResourcesChange(5700, changedResource);
} else {
fireResourcesChange(5700);
}
}
private synchronized Integer adjustMinMaxMeasuredValue(double newTemperature) {
if (newTemperature > maxMeasuredValue) {
maxMeasuredValue = newTemperature;
return 5602;
} else if (newTemperature < minMeasuredValue) {
minMeasuredValue = newTemperature;
return 5601;
} else {
return null;
}
}
private void resetMinMaxMeasuredValues() {
minMeasuredValue = currentTemp;
maxMeasuredValue = currentTemp;
}
@Override
public List<Integer> getAvailableResourceIds(ObjectModel model) {
return supportedResources;
}
@Override
public void destroy() {
}
}

10
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java

@ -40,9 +40,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
private static final Random RANDOM = new Random();
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3
// , 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21
);
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21);
@Override
public ReadResponse read(ServerIdentity identity, int resourceId) {
@ -117,7 +115,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
}
private String getManufacturer() {
return "Leshan Demo Device";
return "Thingsboard Demo Lwm2mDevice";
}
private String getModelNumber() {
@ -125,11 +123,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
}
private String getSerialNumber() {
return "LT-500-000-0001";
return "Thingsboard-500-000-0001";
}
private String getFirmwareVersion() {
return "1.0.0";
return "1.0.2";
}
private long getErrorCode() {

3
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.transport.lwm2m.client;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.client.resource.BaseInstanceEnabler;
import org.eclipse.leshan.client.servers.ServerIdentity;
@ -84,7 +83,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
@Override
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
switch (resourceId) {
case 2:

307
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/RpcAbstractLwM2MIntegrationTest.java

@ -0,0 +1,307 @@
/**
* 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;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.springframework.util.SocketUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceProfileProvisionType;
import org.thingsboard.server.common.data.DeviceProfileType;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials;
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.controller.AbstractWebsocketTest;
import org.thingsboard.server.controller.TbTestWebSocketClient;
import org.thingsboard.server.dao.service.DaoSqlTest;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapServers;
import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MServerBootstrap;
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import java.util.Base64;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Predicate;
import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.DEVICE;
import static org.eclipse.leshan.core.LwM2mId.FIRMWARE;
import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST_BS;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT_BS;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_PORT_BS;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.HOST;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.PORT;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID_BS;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.objectInstanceId_0;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR;
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_14;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resourceId_9;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources;
@DaoSqlTest
public class RpcAbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
protected final String RPC_TRANSPORT_CONFIGURATION = "{\n" +
" \"type\": \"LWM2M\",\n" +
" \"observeAttr\": {\n" +
" \"keyName\": {\n" +
" \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\": \"" + resourceIdName_3_9 + "\",\n" +
" \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\": \"" + resourceIdName_3_14 + "\",\n" +
" \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_0_0 + "\",\n" +
" \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\": \"" + resourceIdName_19_1_0 + "\"\n" +
" },\n" +
" \"observe\": [\n" +
" \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" +
" \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\"\n" +
" ],\n" +
" \"attribute\": [\n" +
" ],\n" +
" \"telemetry\": [\n" +
" \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_9 + "\",\n" +
" \"" + "/" + DEVICE + "/" + objectInstanceId_0 + "/" + resourceId_14 + "\",\n" +
" \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_0 + "/" + resourceId_0 + "\",\n" +
" \"" + "/" + BINARY_APP_DATA_CONTAINER + "/" + objectInstanceId_1 + "/" + resourceId_0 + "\"\n" +
" ],\n" +
" \"attributeLwm2m\": {}\n" +
" },\n" +
" \"bootstrap\": {\n" +
" \"servers\": {\n" +
" \"binding\": \"U\",\n" +
" \"shortId\": 123,\n" +
" \"lifetime\": 300,\n" +
" \"notifIfDisabled\": true,\n" +
" \"defaultMinPeriod\": 1\n" +
" },\n" +
" \"lwm2mServer\": {\n" +
" \"host\": \"localhost\",\n" +
" \"port\": 5686,\n" +
" \"serverId\": 123,\n" +
" \"serverPublicKey\": \"\",\n" +
" \"bootstrapServerIs\": false,\n" +
" \"clientHoldOffTime\": 1,\n" +
" \"bootstrapServerAccountTimeout\": 0\n" +
" },\n" +
" \"bootstrapServer\": {\n" +
" \"host\": \"localhost\",\n" +
" \"port\": 5687,\n" +
" \"serverId\": 111,\n" +
" \"securityMode\": \"NO_SEC\",\n" +
" \"serverPublicKey\": \"\",\n" +
" \"bootstrapServerIs\": true,\n" +
" \"clientHoldOffTime\": 1,\n" +
" \"bootstrapServerAccountTimeout\": 0\n" +
" }\n" +
" },\n" +
" \"clientLwM2mSettings\": {\n" +
" \"clientOnlyObserveAfterConnect\": 1,\n" +
" \"fwUpdateStrategy\": 1,\n" +
" \"swUpdateStrategy\": 1\n" +
" }\n" +
"}";
protected static final String ENDPOINT_RPC = "deviceEndpointRpc";
protected ScheduledExecutorService executor;
protected TbTestWebSocketClient wsClient;
protected DeviceProfile deviceProfile;
protected NoSecClientCredentials clientCredentials;
protected LwM2MTestClient client;
protected String deviceId;
public Set expectedObjects;
public Set expectedObjectIdVers;
public Set expectedInstances;
public Set expectedObjectIdVerInstances;
protected String objectInstanceIdVer_1;
protected String objectIdVer_2;
private static final Predicate predicate_3 = path -> (!((String) path).contains("/" + TEMPERATURE_SENSOR) && ((String) path).contains("/" + DEVICE));
protected String objectIdVer_3;
protected String objectInstanceIdVer_3;
protected String objectInstanceIdVer_5;
protected String objectIdVer_19;
public RpcAbstractLwM2MIntegrationTest(){ }
@Before
public void beforeTest() throws Exception {
executor = Executors.newScheduledThreadPool(10, ThingsBoardThreadFactory.forName("test-lwm2m-rpc-scheduled"));
loginTenantAdmin();
wsClient = buildAndConnectWebSocketClient();
createDeviceProfile(RPC_TRANSPORT_CONFIGURATION);
clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint(ENDPOINT_RPC);
Device device = createDevice(clientCredentials);
deviceId = device.getId().getId().toString();
client = new LwM2MTestClient(executor, ENDPOINT_RPC);
int clientPort = SocketUtils.findAvailableTcpPort();
client.init(SECURITY, COAP_CONFIG, clientPort);
for (String resourceName : resources) {
TbResource lwModel = new TbResource();
lwModel.setResourceType(ResourceType.LWM2M_MODEL);
lwModel.setTitle(resourceName);
lwModel.setFileName(resourceName);
lwModel.setTenantId(tenantId);
byte[] bytes = IOUtils.toByteArray(AbstractLwM2MIntegrationTest.class.getClassLoader().getResourceAsStream("lwm2m/" + resourceName));
lwModel.setData(Base64.getEncoder().encodeToString(bytes));
lwModel = doPostWithTypedResponse("/api/resource", lwModel, new TypeReference<>() {
});
Assert.assertNotNull(lwModel);
}
wsClient = buildAndConnectWebSocketClient();
expectedObjects = ConcurrentHashMap.newKeySet();
expectedObjectIdVers = ConcurrentHashMap.newKeySet();
expectedInstances = ConcurrentHashMap.newKeySet();
expectedObjectIdVerInstances = ConcurrentHashMap.newKeySet();
client.getClient().getObjectTree().getObjectEnablers().forEach((key, val) -> {
if (key > 0) {
String objectVerId = "/" + key;
if (!val.getObjectModel().version.equals("1.0")) {
objectVerId += ("_" + val.getObjectModel().version);
}
expectedObjects.add("/" + key);
expectedObjectIdVers.add(objectVerId);
String finalObjectVerId = objectVerId;
val.getAvailableInstanceIds().forEach(inststanceId -> {
expectedInstances.add("/" + key + "/" + inststanceId);
expectedObjectIdVerInstances.add(finalObjectVerId + "/" + inststanceId);
});
}
});
objectInstanceIdVer_1 = (String) expectedObjectIdVerInstances.stream().filter(path -> (!((String) path).contains("/" + BINARY_APP_DATA_CONTAINER) && ((String) path).contains("/" + SERVER))).findFirst().get();
objectIdVer_2 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + ACCESS_CONTROL)).findFirst().get();
objectIdVer_3 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get();
objectIdVer_19 = (String) expectedObjects.stream().filter(predicate_3).findFirst().get();
objectInstanceIdVer_3 = (String) expectedObjectIdVerInstances.stream().filter(predicate_3).findFirst().get();
objectInstanceIdVer_5 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + FIRMWARE)).findFirst().get();
objectIdVer_19 = (String) expectedObjectIdVers.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get();
}
protected void createDeviceProfile(String transportConfiguration) throws Exception {
deviceProfile = new DeviceProfile();
deviceProfile.setName("LwM2M_RPC");
deviceProfile.setType(DeviceProfileType.DEFAULT);
deviceProfile.setTenantId(tenantId);
deviceProfile.setTransportType(DeviceTransportType.LWM2M);
deviceProfile.setProvisionType(DeviceProfileProvisionType.DISABLED);
deviceProfile.setDescription(deviceProfile.getName());
DeviceProfileData deviceProfileData = new DeviceProfileData();
deviceProfileData.setConfiguration(new DefaultDeviceProfileConfiguration());
deviceProfileData.setProvisionConfiguration(new DisabledDeviceProfileProvisionConfiguration(null));
deviceProfileData.setTransportConfiguration(JacksonUtil.fromString(transportConfiguration, Lwm2mDeviceProfileTransportConfiguration.class));
deviceProfile.setProfileData(deviceProfileData);
deviceProfile = doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
Assert.assertNotNull(deviceProfile);
}
protected Device createDevice(LwM2MClientCredentials clientCredentials) throws Exception {
Device device = new Device();
device.setName("Device A");
device.setDeviceProfileId(deviceProfile.getId());
device.setTenantId(tenantId);
device = doPost("/api/device", device, Device.class);
Assert.assertNotNull(device);
DeviceCredentials deviceCredentials =
doGet("/api/device/" + device.getId().getId().toString() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(device.getId(), deviceCredentials.getDeviceId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.LWM2M_CREDENTIALS);
LwM2MCredentials credentials = new LwM2MCredentials();
credentials.setClient(clientCredentials);
credentials.setBootstrap(createBootstrapConfig());
deviceCredentials.setCredentialsValue(JacksonUtil.toString(credentials));
doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk());
return device;
}
protected LwM2MBootstrapConfig createBootstrapConfig() {
LwM2MBootstrapConfig bootstrap = new LwM2MBootstrapConfig();
LwM2MBootstrapServers servers = new LwM2MBootstrapServers();
servers.setShortId(SHORT_SERVER_ID);
bootstrap.setServers(servers);
LwM2MServerBootstrap server = new LwM2MServerBootstrap();
server.setHost(HOST);
server.setPort(PORT);
server.setSecurityHost(HOST);
server.setSecurityPort(SECURE_PORT);
server.setServerId(servers.getShortId());
server.setBootstrapServerIs(false);
bootstrap.setLwm2mServer(server);
LwM2MServerBootstrap serverBS = new LwM2MServerBootstrap();
serverBS.setHost(HOST_BS);
serverBS.setPort(PORT_BS);
serverBS.setSecurityHost(HOST_BS);
serverBS.setSecurityPort(SECURE_PORT_BS);
serverBS.setServerId(SHORT_SERVER_ID_BS);
serverBS.setBootstrapServerIs(true);
bootstrap.setBootstrapServer(serverBS);
return bootstrap;
}
protected String objectIdVerToObjectId(String objectIdVer) {
return objectIdVer.contains("_") ? objectIdVer.split("_")[0] : objectIdVer;
}
protected String objectInstanceIdVerToObjectInstanceId(String objectInstanceIdVer) {
String[] objectIdVer = objectInstanceIdVer.split("/");
return objectIdVer[1].contains("_") ? objectIdVer[1].split("_")[0] + "/" + objectIdVer[2] : objectInstanceIdVer;
}
@After
public void after() {
if (client != null) {
client.destroy();
}
executor.shutdownNow();
if (wsClient != null) {
wsClient.close();
}
}
}

77
application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationCreateTest.java

@ -0,0 +1,77 @@
/**
* 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.RpcAbstractLwM2MIntegrationTest;
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_0;
public class RpcLwm2mIntegrationCreateTest extends RpcAbstractLwM2MIntegrationTest {
/**
* Create {"id":"/19_1.1","value":{"0":{"0":"00AC"}, "1":1}}
*
* create_2_instances_in_object
* new ObjectInstance if Object is Multiple & Resource Single
* Create {"id":"/19_1.1/0","value":{"0":{"0":"00AC", "1":1}}}
* {"result":"BAD_REQUEST","error":"instance 0 already exists"}
*
*/
@Test
public void testCreateObjectInstanceWithInstanceIdAlreadyExistsByIdKey_Result_BAD_REQUEST() throws Exception {
String expectedPath = objectIdVer_19 + "/" + objectInstanceId_0;
String expectedValue = "{\"" + resourceId_0 + "\":{\"0\":\"00AC\"}, \"1\":1}";
String actualResult = sendRPCreateById(expectedPath, expectedValue);
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String expected = "instance " + objectInstanceId_0 + " already exists";
String actual = rpcActualResult.get("error").asText();
assertTrue(actual.equals(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 sendRPCreateById(String path, String value) throws Exception {
String setRpcRequest = "{\"method\": \"Create\", \"params\": {\"id\": \"" + path + "\", \"value\": " + value + " }}";
return doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setRpcRequest, String.class, status().isOk());
}
}

17
application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/lwm2m/security/AbstractLwM2MIntegrationTest.java

@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m;
package org.thingsboard.server.transport.lwm2m.security;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.io.IOUtils;
import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.client.object.Security;
import org.eclipse.leshan.core.util.Hex;
@ -26,6 +27,7 @@ import org.junit.Before;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.util.SocketUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.common.data.Device;
@ -86,6 +88,8 @@ import static org.eclipse.leshan.client.object.Security.noSec;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.common.data.ota.OtaPackageType.SOFTWARE;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY;
@DaoSqlTest
public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
@ -169,14 +173,9 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
// certificates trustedby the server (should contain rootCA)
protected final Certificate[] trustedCertificates = new Certificate[1];
protected static final int SECURE_PORT = 5686;
protected static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT));
protected static final String ENDPOINT = "deviceAEndpoint";
protected static final String SECURE_URI = "coaps://localhost:" + SECURE_PORT;
protected static final int PORT = 5685;
protected static final Security SECURITY = noSec("coap://localhost:" + PORT, 123);
protected static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
protected CoapClient client;
public AbstractLwM2MIntegrationTest() {
// create client credentials
@ -394,8 +393,8 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest
wsClient.registerWaitForUpdate();
client = new LwM2MTestClient(executor, endpoint);
client.init(security, coapConfig);
int clientPort = SocketUtils.findAvailableTcpPort();
client.init(security, coapConfig, clientPort);
String msg = wsClient.waitForUpdate();
EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);

36
application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/NoSecLwM2MIntegrationTest.java

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.security.sql;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY;
@Slf4j
public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
@Test
public void testConnectAndObserveTelemetry() throws Exception {
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint(ENDPOINT);
super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT);
}
}

120
application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/NoSecLwM2MIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/OtaLwM2MIntegrationTest.java

@ -13,20 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.sql;
package org.thingsboard.server.transport.lwm2m.security.sql;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.SocketUtils;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest;
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import java.util.Arrays;
import java.util.Collections;
@ -48,9 +48,11 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.QUEU
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.VERIFIED;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURITY;
@Slf4j
public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
public class OtaLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
public static final int TIMEOUT = 30;
private final String OTA_TRANSPORT_CONFIGURATION = "{\n" +
@ -130,33 +132,19 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
" \"type\": \"LWM2M\"\n" +
"}";
LwM2MTestClient client = null;
@After
public void tearDown() {
if (client != null) {
client.destroy();
}
}
@Test
public void testConnectAndObserveTelemetry() throws Exception {
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint(ENDPOINT);
super.basicTestConnectionObserveTelemetry(SECURITY, clientCredentials, COAP_CONFIG, ENDPOINT);
}
@Test
public void testFirmwareUpdateWithClientWithoutFirmwareInfo() throws Exception {
LwM2MTestClient client = null;
String endpoint = "WithoutFirmwareInfoDevice";
try {
createDeviceProfile(TRANSPORT_CONFIGURATION);
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint(ENDPOINT);
clientCredentials.setEndpoint(endpoint);
Device device = createDevice(clientCredentials);
client = new LwM2MTestClient(executor, ENDPOINT);
client.init(SECURITY, COAP_CONFIG);
client = new LwM2MTestClient(executor, endpoint);
int clientPort = SocketUtils.findAvailableTcpPort();
client.init(SECURITY, COAP_CONFIG, clientPort);
Thread.sleep(1000);
@ -183,27 +171,31 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
@Test
public void testFirmwareUpdateByObject5() throws Exception {
LwM2MTestClient client = null;
String endpoint = "Ota5_Device";
List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED);
try {
createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint("OTA_" + ENDPOINT);
clientCredentials.setEndpoint(endpoint);
Device device = createDevice(clientCredentials);
device.setFirmwareId(createFirmware().getId());
device = doPost("/api/device", device, Device.class);
Device saveDevice = doPost("/api/device", device, Device.class);
Thread.sleep(1000);
client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
client.init(SECURITY, COAP_CONFIG);
client = new LwM2MTestClient(executor, endpoint);
int clientPort = SocketUtils.findAvailableTcpPort();
client.init(SECURITY, COAP_CONFIG, clientPort);
Thread.sleep(3000);
List<TsKvEntry> ts = await("await on timeseries")
.atMost(30, TimeUnit.SECONDS)
.until(()-> toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + saveDevice.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {
})), hasSize(expectedStatuses.size()));
List<TsKvEntry> ts = toTimeseries(doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + device.getId().getId() + "/values/timeseries?orderBy=ASC&keys=fw_state&startTs=0&endTs=" + System.currentTimeMillis(), new TypeReference<>() {
}));
List<OtaPackageUpdateStatus> statuses = ts.stream().sorted(Comparator.comparingLong(TsKvEntry::getTs)).map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
List<OtaPackageUpdateStatus> expectedStatuses = Arrays.asList(QUEUED, INITIATED, DOWNLOADING, DOWNLOADED, UPDATING, UPDATED);
Assert.assertEquals(expectedStatuses, statuses);
} finally {
@ -223,41 +215,49 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
//given
final List<OtaPackageUpdateStatus> expectedStatuses = List.of(
QUEUED, INITIATED, DOWNLOADING, DOWNLOADING, DOWNLOADING, DOWNLOADED, VERIFIED, UPDATED);
LwM2MTestClient client = null;
String endpoint = "Ota9_Device";
try {
createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint(endpoint);
final Device device = createDevice(clientCredentials);
device.setSoftwareId(createSoftware().getId());
final Device savedDevice = doPost("/api/device", device, Device.class); //sync call
assertThat(savedDevice).as("saved device").isNotNull();
assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice);
//when
log.warn("Init the client...");
client = new LwM2MTestClient(executor, endpoint);
int clientPort = SocketUtils.findAvailableTcpPort();
client.init(SECURITY, COAP_CONFIG, clientPort);
log.warn("AWAIT atMost {} SECONDS on timeseries List<TsKvEntry> by API with list size {}...", TIMEOUT, expectedStatuses.size());
List<TsKvEntry> ts = await("await on timeseries")
.atMost(30, TimeUnit.SECONDS)
.until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size()));
log.warn("Got the ts: {}", ts);
ts.sort(Comparator.comparingLong(TsKvEntry::getTs));
log.warn("Ts ordered: {}", ts);
ts.forEach((x) -> log.warn("ts: {} ", x));
createDeviceProfile(OTA_TRANSPORT_CONFIGURATION);
NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
clientCredentials.setEndpoint("OTA_" + ENDPOINT);
final Device device = createDevice(clientCredentials);
device.setSoftwareId(createSoftware().getId());
final Device savedDevice = doPost("/api/device", device, Device.class); //sync call
assertThat(savedDevice).as("saved device").isNotNull();
assertThat(getDeviceFromAPI(device.getId().getId())).as("fetched device").isEqualTo(savedDevice);
//when
log.warn("Init the client...");
client = new LwM2MTestClient(executor, "OTA_" + ENDPOINT);
client.init(SECURITY, COAP_CONFIG);
log.warn("AWAIT atMost {} SECONDS on timeseries List<TsKvEntry> by API with list size {}...", TIMEOUT, expectedStatuses.size());
List<TsKvEntry> ts = await("await on timeseries")
.atMost(30, TimeUnit.SECONDS)
.until(() -> getSwStateTelemetryFromAPI(device.getId().getId()), hasSize(expectedStatuses.size()));
log.warn("Got the ts: {}", ts);
ts.sort(Comparator.comparingLong(TsKvEntry::getTs));
log.warn("Ts ordered: {}", ts);
ts.forEach((x) -> log.warn("ts: {} ", x));
List<OtaPackageUpdateStatus> statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
log.warn("Converted ts to statuses: {}", statuses);
List<OtaPackageUpdateStatus> statuses = ts.stream().map(KvEntry::getValueAsString).map(OtaPackageUpdateStatus::valueOf).collect(Collectors.toList());
log.warn("Converted ts to statuses: {}", statuses);
assertThat(statuses).isEqualTo(expectedStatuses);
assertThat(statuses).isEqualTo(expectedStatuses);
} finally {
if (client != null) {
client.destroy();
}
}
}
private Device getDeviceFromAPI(UUID deviceId) throws Exception {
final Device device = doGet("/api/device/" + deviceId, Device.class);
log.warn("Fetched device by API for deviceId {}, device is {}", deviceId, device);
log.trace("Fetched device by API for deviceId {}, device is {}", deviceId, device);
return device;
}

9
application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/PskLwm2mIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/PskLwm2mIntegrationTest.java

@ -13,17 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.sql;
package org.thingsboard.server.transport.lwm2m.security.sql;
import org.eclipse.leshan.client.object.Security;
import org.eclipse.leshan.core.util.Hex;
import org.junit.Test;
import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials;
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import java.nio.charset.StandardCharsets;
import static org.eclipse.leshan.client.object.Security.psk;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID;
public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest {
@ -36,7 +39,7 @@ public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest {
clientCredentials.setKey(pskKey);
clientCredentials.setIdentity(pskIdentity);
Security security = psk(SECURE_URI,
123,
SHORT_SERVER_ID,
pskIdentity.getBytes(StandardCharsets.UTF_8),
Hex.decodeHex(pskKey.toCharArray()));
super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, ENDPOINT);

9
application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/RpkLwM2MIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/RpkLwM2MIntegrationTest.java

@ -13,15 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.sql;
package org.thingsboard.server.transport.lwm2m.security.sql;
import org.eclipse.leshan.client.object.Security;
import org.eclipse.leshan.core.util.Hex;
import org.junit.Test;
import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials;
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import static org.eclipse.leshan.client.object.Security.rpk;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID;
public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
@ -31,7 +34,7 @@ public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
rpkClientCredentials.setEndpoint(ENDPOINT);
rpkClientCredentials.setKey(Hex.encodeHexString(clientPublicKey.getEncoded()));
Security security = rpk(SECURE_URI,
123,
SHORT_SERVER_ID,
clientPublicKey.getEncoded(),
clientPrivateKey.getEncoded(),
serverX509Cert.getPublicKey().getEncoded());

37
application/src/test/java/org/thingsboard/server/transport/lwm2m/sql/X509LwM2MIntegrationTest.java → application/src/test/java/org/thingsboard/server/transport/lwm2m/security/sql/X509LwM2MIntegrationTest.java

@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.sql;
package org.thingsboard.server.transport.lwm2m.security.sql;
import org.eclipse.leshan.client.object.Security;
import org.junit.Ignore;
import org.junit.Test;
import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
import org.thingsboard.server.common.transport.util.SslUtil;
import org.thingsboard.server.transport.lwm2m.AbstractLwM2MIntegrationTest;
import org.thingsboard.server.transport.lwm2m.security.AbstractLwM2MIntegrationTest;
import static org.eclipse.leshan.client.object.Security.x509;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_COAP_CONFIG;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SECURE_URI;
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.SHORT_SERVER_ID;
public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
@ -31,25 +32,25 @@ public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
X509ClientCredentials credentials = new X509ClientCredentials();
credentials.setEndpoint(ENDPOINT);
Security security = x509(SECURE_URI,
123,
SHORT_SERVER_ID,
clientX509Cert.getEncoded(),
clientPrivateKeyFromCert.getEncoded(),
serverX509Cert.getEncoded());
super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT);
}
@Ignore //See LwM2mClientContextImpl.unregister
@Test
public void testConnectWithCertAndObserveTelemetry() throws Exception {
X509ClientCredentials credentials = new X509ClientCredentials();
credentials.setEndpoint(ENDPOINT);
credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted));
Security security = x509(SECURE_URI,
123,
clientX509CertNotTrusted.getEncoded(),
clientPrivateKeyFromCert.getEncoded(),
serverX509Cert.getEncoded());
super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT);
}
// @Ignore //See LwM2mClientContextImpl.unregister
// @Test
// public void testConnectWithCertAndObserveTelemetry() throws Exception {
// X509ClientCredentials credentials = new X509ClientCredentials();
// credentials.setEndpoint(ENDPOINT);
// credentials.setCert(SslUtil.getCertificateString(clientX509CertNotTrusted));
// Security security = x509(SECURE_URI,
// 123,
// clientX509CertNotTrusted.getEncoded(),
// clientPrivateKeyFromCert.getEncoded(),
// serverX509Cert.getEncoded());
// super.basicTestConnectionObserveTelemetry(security, credentials, SECURE_COAP_CONFIG, ENDPOINT);
// }
}

144
application/src/test/resources/lwm2m/19.xml

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-LwM2M_BinaryAppDataContainer-V1_0_1-20190221-A
Type: xml
Public Reachable Information
Path: http://www.openmobilealliance.org/tech/profiles
Name: LwM2M_BinaryAppDataContainer-v1_0_1.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LWM2M_BinaryAppDataContainer-V1_0_1
This is available at http://www.openmobilealliance.org/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
CHANGE HISTORY
15062018 Status changed to Approved by DM, Doc Ref # OMA-DM&SE-2018-0061-INP_LWM2M_APPDATA_V1_0_ERP_for_final_Approval
21022019 Status changed to Approved by IPSO, Doc Ref # OMA-IPSO-2019-0025-INP_LwM2M_Object_App_Data_Container_1_0_1_for_Final_Approval
LEGAL DISCLAIMER
Copyright 2019 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd">
<Object ObjectType="MODefinition">
<Name>BinaryAppDataContainer</Name>
<Description1><![CDATA[This LwM2M Objects provides the application service data related to a LwM2M Server, eg. Water meter data.
There are several methods to create instance to indicate the message direction based on the negotiation between Application and LwM2M. The Client and Server should negotiate the instance(s) used to exchange the data. For example:
- Using a single instance for both directions communication, from Client to Server and from Server to Client.
- Using an instance for communication from Client to Server and another one for communication from Server to Client
- Using several instances
]]></Description1>
<ObjectID>19</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:19:1.1</ObjectURN>
<LWM2MVersion>1.1</LWM2MVersion>
<ObjectVersion>1.1</ObjectVersion>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Resources>
<Item ID="0"><Name>Data</Name>
<Operations>RW</Operations>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration />
<Units />
<Description><![CDATA[Indicates the application data content.]]></Description>
</Item>
<Item ID="1"><Name>Data Priority</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>1 bytes</RangeEnumeration>
<Units />
<Description><![CDATA[Indicates the Application data priority:
0:Immediate
1:BestEffort
2:Latest
3-100: Reserved for future use.
101-254: Proprietary mode.]]></Description>
</Item>
<Item ID="2"><Name>Data Creation Time</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Time</Type>
<RangeEnumeration />
<Units />
<Description><![CDATA[Indicates the Data instance creation timestamp.]]></Description>
</Item>
<Item ID="3"><Name>Data Description</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>32 bytes</RangeEnumeration>
<Units />
<Description><![CDATA[Indicates the data description.
e.g. "meter reading".]]></Description>
</Item>
<Item ID="4"><Name>Data Format</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration>32 bytes</RangeEnumeration>
<Units />
<Description><![CDATA[Indicates the format of the Application Data.
e.g. YG-Meter-Water-Reading
UTF8-string
]]></Description>
</Item>
<Item ID="5"><Name>App ID</Name>
<Operations>RW</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Integer</Type>
<RangeEnumeration>2 bytes</RangeEnumeration>
<Units />
<Description><![CDATA[Indicates the destination Application ID.]]></Description>
</Item></Resources>
<Description2><![CDATA[]]></Description2>
</Object>
</LWM2M>

103
application/src/test/resources/lwm2m/3303.xml

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright © 2016-2018 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.
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://openmobilealliance.org/tech/profiles/LWM2M.xsd">
<Object ObjectType="MODefinition">
<Name>Temperature</Name>
<Description1>This IPSO object should be used with a temperature sensor to report a temperature measurement. It also provides resources for minimum/maximum measured values and the minimum/maximum range that can be measured by the temperature sensor. An example measurement unit is degrees Celsius.</Description1>
<ObjectID>3303</ObjectID>
<ObjectURN>urn:oma:lwm2m:ext:3303</ObjectURN>
<LWM2MVersion>1.0</LWM2MVersion>
<ObjectVersion>1.0</ObjectVersion>
<MultipleInstances>Multiple</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Resources>
<Item ID="5700">
<Name>Sensor Value</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>Last or Current Measured Value from the Sensor</Description>
</Item>
<Item ID="5601">
<Name>Min Measured Value</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>The minimum value measured by the sensor since power ON or reset</Description>
</Item>
<Item ID="5602">
<Name>Max Measured Value</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>The maximum value measured by the sensor since power ON or reset</Description>
</Item>
<Item ID="5603">
<Name>Min Range Value</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>The minimum value that can be measured by the sensor</Description>
</Item>
<Item ID="5604">
<Name>Max Range Value</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>The maximum value that can be measured by the sensor</Description>
</Item>
<Item ID="5701">
<Name>Sensor Units</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>String</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>Measurement Units Definition.</Description>
</Item>
<Item ID="5605">
<Name>Reset Min and Max Measured Values</Name>
<Operations>E</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type></Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description>Reset the Min and Max Measured Values to Current Value</Description>
</Item>
</Resources>
<Description2></Description2>
</Object>
</LWM2M>

143
application/src/test/resources/lwm2m/6.xml

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
FILE INFORMATION
OMA Permanent Document
File: OMA-SUP-XML_6-V1_0-20201110-A.xml
http://www.openmobilealliance.org/release/ObjLwM2M_Location/
OMNA LwM2M Registry
Path: https://github.com/OpenMobileAlliance/lwm2m-registry
Name: 6.xml
NORMATIVE INFORMATION
Information about this file can be found in the latest revision of
OMA-TS-LightweightM2M-V1_0_2
OMA-TS-LightweightM2M_Core-V1_1_1
This is available at http://www.openmobilealliance.org/release/LightweightM2M/
Send comments to https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues
LEGAL DISCLAIMER
Copyright 2020 Open Mobile Alliance.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
The above license is used as a license under copyright only. Please
reference the OMA IPR Policy for patent licensing terms:
https://www.omaspecworks.org/about/intellectual-property-rights/
-->
<LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.openmobilealliance.org/tech/profiles/LWM2M.xsd">
<Object ObjectType="MODefinition">
<Name>Location</Name>
<Description1><![CDATA[This LwM2M Object provides a range of location telemetry related information which can be queried by the LwM2M Server.]]></Description1>
<ObjectID>6</ObjectID>
<ObjectURN>urn:oma:lwm2m:oma:6</ObjectURN>
<LWM2MVersion>1.0</LWM2MVersion>
<ObjectVersion>1.0</ObjectVersion>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Resources>
<Item ID="0">
<Name>Latitude</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units>lat</Units>
<Description><![CDATA[The decimal notation of latitude, e.g. -43.5723 [World Geodetic System 1984].]]></Description>
</Item>
<Item ID="1">
<Name>Longitude</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units>lon</Units>
<Description><![CDATA[The decimal notation of longitude, e.g. 153.21760 [World Geodetic System 1984].]]></Description>
</Item>
<Item ID="2">
<Name>Altitude</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units>m</Units>
<Description><![CDATA[The decimal notation of altitude in meters above sea level.]]></Description>
</Item>
<Item ID="3">
<Name>Radius</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units>m</Units>
<Description><![CDATA[The value in this resource indicates the radius of a circular area in meters. The circular area is used to describe uncertainty about a point for coordinates in a two-dimensional coordinate reference systems (CRS). The center point of a circular area is specified by using the Latitude and the Longitude Resources.]]></Description>
</Item>
<Item ID="4">
<Name>Velocity</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Opaque</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The velocity of the LwM2M Client, as defined in [3GPP-TS_23.032].]]></Description>
</Item>
<Item ID="5">
<Name>Timestamp</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Mandatory</Mandatory>
<Type>Time</Type>
<RangeEnumeration></RangeEnumeration>
<Units></Units>
<Description><![CDATA[The timestamp of when the location measurement was performed.]]></Description>
</Item>
<Item ID="6"><Name>Speed</Name>
<Operations>R</Operations>
<MultipleInstances>Single</MultipleInstances>
<Mandatory>Optional</Mandatory>
<Type>Float</Type>
<RangeEnumeration></RangeEnumeration>
<Units>m/s</Units>
<Description><![CDATA[Speed is the time rate of change in position of a LwM2M Client without regard for direction: the scalar component of velocity.]]></Description>
</Item></Resources>
<Description2></Description2>
</Object>
</LWM2M>
Loading…
Cancel
Save