Merge remote-tracking branch 'upstream/develop/3.5' into feature/test_dependency_refactor

# Conflicts:
#	dao/src/test/java/org/thingsboard/server/dao/service/BaseDeviceServiceTest.java
#	dao/src/test/java/org/thingsboard/server/dao/service/BaseOtaPackageServiceTest.java
This commit is contained in:
Oleksandra Matviienko 2023-03-14 10:34:46 +01:00
commit c73fc3e0fc
14 changed files with 139 additions and 151 deletions

View File

@ -690,7 +690,7 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest {
edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
Assert.assertTrue(edgeImitator.waitForResponses()); Assert.assertTrue(edgeImitator.waitForResponses());
Assert.assertTrue(onUpdateCallback.getSubscribeLatch().await(5, TimeUnit.SECONDS)); Assert.assertTrue(onUpdateCallback.getSubscribeLatch().await(30, TimeUnit.SECONDS));
Assert.assertEquals(JacksonUtil.OBJECT_MAPPER.createObjectNode().put(attrKey, attrValue), Assert.assertEquals(JacksonUtil.OBJECT_MAPPER.createObjectNode().put(attrKey, attrValue),
JacksonUtil.fromBytes(onUpdateCallback.getPayloadBytes())); JacksonUtil.fromBytes(onUpdateCallback.getPayloadBytes()));

View File

@ -19,10 +19,8 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.EntityInfo;
import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.ResourceType;
@ -46,6 +44,7 @@ import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@DaoSqlTest @DaoSqlTest
@ -116,10 +115,6 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest {
.andExpect(status().isOk()); .andExpect(status().isOk());
} }
@SuppressWarnings("deprecation")
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test @Test
public void testSaveResourceWithMaxSumDataSizeOutOfLimit() throws Exception { public void testSaveResourceWithMaxSumDataSizeOutOfLimit() throws Exception {
loginSysAdmin(); loginSysAdmin();
@ -138,9 +133,9 @@ public class BaseTbResourceServiceTest extends AbstractControllerTest {
Assert.assertEquals(1, resourceService.sumDataSizeByTenantId(tenantId)); Assert.assertEquals(1, resourceService.sumDataSizeByTenantId(tenantId));
try { try {
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> createResource("test1", 1 + DEFAULT_FILE_NAME))
thrown.expectMessage(String.format("Failed to create the tb resource, files size limit is exhausted %d bytes!", limit)); .isInstanceOf(DataValidationException.class)
createResource("test1", 1 + DEFAULT_FILE_NAME); .hasMessageContaining("Failed to create the tb resource, files size limit is exhausted %d bytes!", limit);
} finally { } finally {
defaultTenantProfile.getProfileData().setConfiguration(DefaultTenantProfileConfiguration.builder().maxResourcesInBytes(0).build()); defaultTenantProfile.getProfileData().setConfiguration(DefaultTenantProfileConfiguration.builder().maxResourcesInBytes(0).build());
loginSysAdmin(); loginSysAdmin();

View File

@ -70,7 +70,7 @@ import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd;
import org.thingsboard.server.transport.AbstractTransportIntegrationTest; import org.thingsboard.server.transport.AbstractTransportIntegrationTest;
import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient; import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -108,7 +108,7 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfil
public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportIntegrationTest { public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportIntegrationTest {
@SpyBean @SpyBean
DefaultLwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandlerTest; LwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandlerTest;
@Autowired @Autowired
private LwM2mClientContext clientContextTest; private LwM2mClientContext clientContextTest;

View File

@ -45,7 +45,7 @@ import org.junit.Assert;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.io.IOException; import java.io.IOException;
@ -109,12 +109,12 @@ public class LwM2MTestClient {
private LwM2MLocationParams locationParams; private LwM2MLocationParams locationParams;
private LwM2mTemperatureSensor lwM2MTemperatureSensor; private LwM2mTemperatureSensor lwM2MTemperatureSensor;
private Set<LwM2MClientState> clientStates; private Set<LwM2MClientState> clientStates;
private DefaultLwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandlerTest; private LwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandlerTest;
private LwM2mClientContext clientContext; private LwM2mClientContext clientContext;
public void init(Security security, Configuration coapConfig, int port, boolean isRpc, boolean isBootstrap, public void init(Security security, Configuration coapConfig, int port, boolean isRpc, boolean isBootstrap,
int shortServerId, int shortServerIdBs, Security securityBs, int shortServerId, int shortServerIdBs, Security securityBs,
DefaultLwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandler, LwM2mUplinkMsgHandler defaultLwM2mUplinkMsgHandler,
LwM2mClientContext clientContext) throws InvalidDDFFileException, IOException { LwM2mClientContext clientContext) throws InvalidDDFFileException, IOException {
Assert.assertNull("client already initialized", leshanClient); Assert.assertNull("client already initialized", leshanClient);
this.defaultLwM2mUplinkMsgHandlerTest = defaultLwM2mUplinkMsgHandler; this.defaultLwM2mUplinkMsgHandlerTest = defaultLwM2mUplinkMsgHandler;

View File

@ -21,6 +21,13 @@
<!-- mute TelemetryEdgeSqlTest that causes a lot of randomly generated errors --> <!-- mute TelemetryEdgeSqlTest that causes a lot of randomly generated errors -->
<logger name="org.thingsboard.server.service.edge.rpc.EdgeGrpcSession" level="OFF"/> <logger name="org.thingsboard.server.service.edge.rpc.EdgeGrpcSession" level="OFF"/>
<!-- LwM2m lifecycle debug for the test scope -->
<logger name="org.thingsboard.server.transport.lwm2m.server.downlink.DefaultLwM2mDownlinkMsgHandler" level="TRACE"/>
<logger name="org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler" level="TRACE"/>
<logger name="org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService" level="TRACE"/>
<logger name="org.thingsboard.server.transport.lwm2m.server" level="INFO"/>
<logger name="org.eclipse.californium.core" level="INFO"/>
<root level="WARN"> <root level="WARN">
<appender-ref ref="console"/> <appender-ref ref="console"/>
</root> </root>

View File

@ -25,6 +25,7 @@ import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder;
import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServer;
import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DataConstants;
@ -35,7 +36,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore; import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@ -56,6 +57,7 @@ import static org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaU
@Slf4j @Slf4j
@Component @Component
@DependsOn({"lwM2mDownlinkMsgHandler", "lwM2mUplinkMsgHandler"})
@TbLwM2mTransportComponent @TbLwM2mTransportComponent
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultLwM2mTransportService implements LwM2MTransportService { public class DefaultLwM2mTransportService implements LwM2MTransportService {
@ -66,7 +68,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
private final LwM2mTransportContext context; private final LwM2mTransportContext context;
private final LwM2MTransportServerConfig config; private final LwM2MTransportServerConfig config;
private final OtaPackageDataCache otaPackageDataCache; private final OtaPackageDataCache otaPackageDataCache;
private final DefaultLwM2mUplinkMsgHandler handler; private final LwM2mUplinkMsgHandler handler;
private final CaliforniumRegistrationStore registrationStore; private final CaliforniumRegistrationStore registrationStore;
private final TbSecurityStore securityStore; private final TbSecurityStore securityStore;
private final TbLwM2MDtlsCertificateVerifier certificateVerifier; private final TbLwM2MDtlsCertificateVerifier certificateVerifier;

View File

@ -42,7 +42,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore;
import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil; import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil;
import java.util.Arrays; import java.util.Arrays;
@ -75,7 +75,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Autowired @Autowired
@Lazy @Lazy
private DefaultLwM2mUplinkMsgHandler defaultLwM2MUplinkMsgHandler; private LwM2mUplinkMsgHandler defaultLwM2MUplinkMsgHandler;
@Autowired @Autowired
@Lazy @Lazy
private LwM2MOtaUpdateService otaUpdateService; private LwM2MOtaUpdateService otaUpdateService;

View File

@ -85,6 +85,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.RejectedExecutionException;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -103,7 +104,7 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.ge
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.validateVersionedId; import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.validateVersionedId;
@Slf4j @Slf4j
@Service @Service("lwM2mDownlinkMsgHandler")
@TbLwM2mTransportComponent @TbLwM2mTransportComponent
@RequiredArgsConstructor @RequiredArgsConstructor
public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mDownlinkMsgHandler { public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mDownlinkMsgHandler {
@ -124,6 +125,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
log.trace("Destroying {}", getClass().getSimpleName());
super.destroy(); super.destroy();
} }
@ -521,6 +523,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
private <R extends DownlinkRequest<T>, T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback<R, T> callback, Exception e) { private <R extends DownlinkRequest<T>, T extends LwM2mResponse> void handleDownlinkError(LwM2mClient client, R request, DownlinkRequestCallback<R, T> callback, Exception e) {
log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e); log.trace("[{}] Received downlink error: {}.", client.getEndpoint(), e);
try {
client.updateLastUplinkTime(); client.updateLastUplinkTime();
executor.submit(() -> { executor.submit(() -> {
if (e instanceof TimeoutException || e instanceof ClientSleepingException) { if (e instanceof TimeoutException || e instanceof ClientSleepingException) {
@ -531,6 +534,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
} }
callback.onError(toString(request), e); callback.onError(toString(request), e);
}); });
} catch (RejectedExecutionException ree) {
log.warn("[{}] Can not handle downlink error. Executor already down", client.getEndpoint(), ree);
} catch (Exception exception) {
log.warn("[{}] Can not handle downlink error", client.getEndpoint(), exception);
}
} }
private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) { private WriteRequest getWriteRequestSingleResource(ResourceModel.Type type, ContentFormat contentFormat, int objectId, int instanceId, int resourceId, Object value) {

View File

@ -146,6 +146,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
log.trace("Destroying {}", getClass().getSimpleName());
super.destroy(); super.destroy();
} }

View File

@ -20,6 +20,8 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ObjectModel;
@ -32,6 +34,7 @@ import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance; import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.*; import org.eclipse.leshan.core.request.*;
import org.eclipse.leshan.core.request.WriteRequest.Mode; import org.eclipse.leshan.core.request.WriteRequest.Mode;
@ -122,69 +125,41 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.fr
@Slf4j @Slf4j
@Service @Service("lwM2mUplinkMsgHandler")
@TbLwM2mTransportComponent @TbLwM2mTransportComponent
@RequiredArgsConstructor
public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mUplinkMsgHandler { public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService implements LwM2mUplinkMsgHandler {
public LwM2mValueConverterImpl converter; @Getter
private final LwM2mValueConverter converter = LwM2mValueConverterImpl.getInstance();;
private final TransportService transportService; private final TransportService transportService;
private final LwM2mTransportContext context; private final LwM2mTransportContext context;
@Lazy
private final LwM2MAttributesService attributesService; private final LwM2MAttributesService attributesService;
private final LwM2MSessionManager sessionManager; private final LwM2MSessionManager sessionManager;
@Lazy
private final LwM2MOtaUpdateService otaService; private final LwM2MOtaUpdateService otaService;
private final LwM2MTransportServerConfig config; private final LwM2MTransportServerConfig config;
private final LwM2MTelemetryLogService logService; private final LwM2MTelemetryLogService logService;
private final LwM2mTransportServerHelper helper; private final LwM2mTransportServerHelper helper;
private final TbLwM2MDtlsSessionStore sessionStore; private final TbLwM2MDtlsSessionStore sessionStore;
private final LwM2mClientContext clientContext; private final LwM2mClientContext clientContext;
private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; private final LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler; //Do not use Lazy because we need live executor to handle msgs
private final LwM2mVersionedModelProvider modelProvider; private final LwM2mVersionedModelProvider modelProvider;
private final RegistrationStore registrationStore; private final RegistrationStore registrationStore;
private final TbLwM2mSecurityStore securityStore; private final TbLwM2mSecurityStore securityStore;
private final LwM2MModelConfigService modelConfigService; private final LwM2MModelConfigService modelConfigService;
public DefaultLwM2mUplinkMsgHandler(TransportService transportService,
LwM2MTransportServerConfig config,
LwM2mTransportServerHelper helper,
LwM2mClientContext clientContext,
LwM2MTelemetryLogService logService,
LwM2MSessionManager sessionManager,
@Lazy LwM2MOtaUpdateService otaService,
@Lazy LwM2MAttributesService attributesService,
@Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler,
LwM2mTransportContext context,
TbLwM2MDtlsSessionStore sessionStore,
LwM2mVersionedModelProvider modelProvider,
RegistrationStore registrationStore,
TbLwM2mSecurityStore securityStore,
LwM2MModelConfigService modelConfigService) {
this.transportService = transportService;
this.sessionManager = sessionManager;
this.attributesService = attributesService;
this.otaService = otaService;
this.config = config;
this.helper = helper;
this.clientContext = clientContext;
this.logService = logService;
this.defaultLwM2MDownlinkMsgHandler = defaultLwM2MDownlinkMsgHandler;
this.context = context;
this.sessionStore = sessionStore;
this.modelProvider = modelProvider;
this.registrationStore = registrationStore;
this.securityStore = securityStore;
this.modelConfigService = modelConfigService;
}
@PostConstruct @PostConstruct
public void init() { public void init() {
super.init(); super.init();
this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS); this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
this.converter = LwM2mValueConverterImpl.getInstance();
} }
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
log.trace("Destroying {}", getClass().getSimpleName());
super.destroy(); super.destroy();
} }
@ -955,6 +930,7 @@ public class DefaultLwM2mUplinkMsgHandler extends LwM2MExecutorAwareService impl
* *
* @param lwM2MClient - LwM2M Client * @param lwM2MClient - LwM2M Client
*/ */
@Override
public void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) { public void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue) {
Map<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); Map<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
if (!keyNamesMap.isEmpty()) { if (!keyNamesMap.isEmpty()) {

View File

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server.uplink; package org.thingsboard.server.transport.lwm2m.server.uplink;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.CreateRequest;
import org.eclipse.leshan.core.request.SendRequest; import org.eclipse.leshan.core.request.SendRequest;
@ -69,5 +70,10 @@ public interface LwM2mUplinkMsgHandler {
void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials); void onToTransportUpdateCredentials(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToTransportUpdateCredentialsProto updateCredentials);
void initAttributes(LwM2mClient lwM2MClient, boolean logFailedUpdateOfNonChangedValue);
LwM2MTransportServerConfig getConfig(); LwM2MTransportServerConfig getConfig();
LwM2mValueConverter getConverter();
} }

View File

@ -52,7 +52,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate
import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdateState;
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult;
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -289,12 +289,12 @@ public class LwM2MTransportUtil {
* Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
* Attribute [] attrs = {gt, st}; * Attribute [] attrs = {gt, st};
*/ */
public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2mUplinkMsgHandler serviceImpl) { public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, LwM2mUplinkMsgHandler serviceImpl) {
AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target)); AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target));
return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null; return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null;
} }
private static Attribute[] createWriteAttributes(Object params, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { private static Attribute[] createWriteAttributes(Object params, LwM2mUplinkMsgHandler serviceImpl, String target) {
List<Attribute> attributeLists = new ArrayList<>(); List<Attribute> attributeLists = new ArrayList<>();
Map<String, Object> map = JacksonUtil.convertValue(params, new TypeReference<>() { Map<String, Object> map = JacksonUtil.convertValue(params, new TypeReference<>() {
}); });
@ -366,19 +366,19 @@ public class LwM2MTransportUtil {
return newValues; return newValues;
} }
public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { public static Object convertWriteAttributes(String type, Object value, LwM2mUplinkMsgHandler serviceImpl, String target) {
switch (type) { switch (type) {
/** Integer [0:255]; */ /** Integer [0:255]; */
case DIMENSION: case DIMENSION:
Long dim = (Long) serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target)); Long dim = (Long) serviceImpl.getConverter().convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target));
return dim >= 0 && dim <= 255 ? dim : null; return dim >= 0 && dim <= 255 ? dim : null;
/**String;*/ /**String;*/
case OBJECT_VERSION: case OBJECT_VERSION:
return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), STRING, new LwM2mPath(target)); return serviceImpl.getConverter().convertValue(value, equalsResourceTypeGetSimpleName(value), STRING, new LwM2mPath(target));
/**INTEGER */ /**INTEGER */
case MINIMUM_PERIOD: case MINIMUM_PERIOD:
case MAXIMUM_PERIOD: case MAXIMUM_PERIOD:
return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target)); return serviceImpl.getConverter().convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target));
/**Float; */ /**Float; */
case GREATER_THAN: case GREATER_THAN:
case LESSER_THAN: case LESSER_THAN:
@ -386,7 +386,7 @@ public class LwM2MTransportUtil {
if (value.getClass().getSimpleName().equals("String")) { if (value.getClass().getSimpleName().equals("String")) {
value = Double.valueOf((String) value); value = Double.valueOf((String) value);
} }
return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), FLOAT, new LwM2mPath(target)); return serviceImpl.getConverter().convertValue(value, equalsResourceTypeGetSimpleName(value), FLOAT, new LwM2mPath(target));
default: default:
return null; return null;
} }

View File

@ -19,10 +19,8 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -54,6 +52,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@ -89,10 +88,6 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
tenantProfileService.deleteTenantProfiles(anotherTenantId); tenantProfileService.deleteTenantProfiles(anotherTenantId);
} }
@SuppressWarnings("deprecation")
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test @Test
public void testSaveDevicesWithoutMaxDeviceLimit() { public void testSaveDevicesWithoutMaxDeviceLimit() {
Device device = this.saveDevice(tenantId, "My device"); Device device = this.saveDevice(tenantId, "My device");
@ -261,9 +256,9 @@ public abstract class BaseDeviceServiceTest extends AbstractServiceTest {
savedDevice.setFirmwareId(savedFirmware.getId()); savedDevice.setFirmwareId(savedFirmware.getId());
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> deviceService.saveDevice(savedDevice))
thrown.expectMessage("Can't assign firmware with different deviceProfile!"); .isInstanceOf(DataValidationException.class)
deviceService.saveDevice(savedDevice); .hasMessageContaining("Can't assign firmware with different deviceProfile!");
} }
@Test @Test

View File

@ -19,9 +19,7 @@ import com.datastax.oss.driver.api.core.uuid.Uuids;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
@ -48,6 +46,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE; import static org.thingsboard.server.common.data.ota.OtaPackageType.FIRMWARE;
public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest { public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
@ -83,10 +82,6 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
deviceProfileId = savedDeviceProfile.getId(); deviceProfileId = savedDeviceProfile.getId();
} }
@SuppressWarnings("deprecation")
@Rule
public ExpectedException thrown = ExpectedException.none();
@After @After
public void after() { public void after() {
tenantService.deleteTenant(tenantId); tenantService.deleteTenant(tenantId);
@ -104,9 +99,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
createAndSaveFirmware(tenantId, "1"); createAndSaveFirmware(tenantId, "1");
Assert.assertEquals(1, otaPackageService.sumDataSizeByTenantId(tenantId)); Assert.assertEquals(1, otaPackageService.sumDataSizeByTenantId(tenantId));
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> createAndSaveFirmware(tenantId, "2"))
thrown.expectMessage(String.format("Failed to create the ota package, files size limit is exhausted %d bytes!", DATA_SIZE)); .isInstanceOf(DataValidationException.class)
createAndSaveFirmware(tenantId, "2"); .hasMessageContaining("Failed to create the ota package, files size limit is exhausted %d bytes!", DATA_SIZE);
} }
@Test @Test
@ -248,9 +243,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage should be assigned to tenant!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage should be assigned to tenant!");
} }
@Test @Test
@ -266,9 +261,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("Type should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("Type should be specified!");
} }
@Test @Test
@ -284,9 +279,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage title should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage title should be specified!");
} }
@Test @Test
@ -302,9 +297,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage file name should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage file name should be specified!");
} }
@Test @Test
@ -320,9 +315,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage content type should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage content type should be specified!");
} }
@Test @Test
@ -338,9 +333,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage data should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage data should be specified!");
} }
@Test @Test
@ -357,9 +352,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage is referencing to non-existent tenant!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage is referencing to non-existent tenant!");
} }
@Test @Test
@ -376,9 +371,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksum(CHECKSUM); firmware.setChecksum(CHECKSUM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage is referencing to non-existent device profile!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage is referencing to non-existent device profile!");
} }
@Test @Test
@ -394,9 +389,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM); firmware.setChecksumAlgorithm(CHECKSUM_ALGORITHM);
firmware.setData(DATA); firmware.setData(DATA);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(firmware))
thrown.expectMessage("OtaPackage checksum should be specified!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackage(firmware); .hasMessageContaining("OtaPackage checksum should be specified!");
} }
@Test @Test
@ -416,17 +411,17 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
newFirmwareInfo.setTitle(TITLE); newFirmwareInfo.setTitle(TITLE);
newFirmwareInfo.setVersion(VERSION); newFirmwareInfo.setVersion(VERSION);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(newFirmwareInfo, false))
thrown.expectMessage("OtaPackage with such title and version already exists!"); .isInstanceOf(DataValidationException.class)
otaPackageService.saveOtaPackageInfo(newFirmwareInfo, false); .hasMessageContaining("OtaPackage with such title and version already exists!");
} }
@Test @Test
public void testSaveFirmwareWithExistingTitleAndVersion() { public void testSaveFirmwareWithExistingTitleAndVersion() {
createAndSaveFirmware(tenantId, VERSION); createAndSaveFirmware(tenantId, VERSION);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> createAndSaveFirmware(tenantId, VERSION))
thrown.expectMessage("OtaPackage with such title and version already exists!"); .isInstanceOf(DataValidationException.class)
createAndSaveFirmware(tenantId, VERSION); .hasMessageContaining("OtaPackage with such title and version already exists!");
} }
@Test @Test
@ -441,9 +436,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
Device savedDevice = deviceService.saveDevice(device); Device savedDevice = deviceService.saveDevice(device);
try { try {
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()))
thrown.expectMessage("The otaPackage referenced by the devices cannot be deleted!"); .isInstanceOf(DataValidationException.class)
otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); .hasMessageContaining("The otaPackage referenced by the devices cannot be deleted!");
} finally { } finally {
deviceService.deleteDevice(tenantId, savedDevice.getId()); deviceService.deleteDevice(tenantId, savedDevice.getId());
otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId());
@ -453,12 +448,12 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
@Test @Test
public void testUpdateDeviceProfileId() { public void testUpdateDeviceProfileId() {
OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION); OtaPackage savedFirmware = createAndSaveFirmware(tenantId, VERSION);
savedFirmware.setDeviceProfileId(null);
try { try {
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackage(savedFirmware))
thrown.expectMessage("Updating otaPackage deviceProfile is prohibited!"); .isInstanceOf(DataValidationException.class)
savedFirmware.setDeviceProfileId(null); .hasMessageContaining("Updating otaPackage deviceProfile is prohibited!");
otaPackageService.saveOtaPackage(savedFirmware);
} finally { } finally {
otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId());
} }
@ -487,9 +482,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
deviceProfileService.saveDeviceProfile(savedDeviceProfile); deviceProfileService.saveDeviceProfile(savedDeviceProfile);
try { try {
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()))
thrown.expectMessage("The otaPackage referenced by the device profile cannot be deleted!"); .isInstanceOf(DataValidationException.class)
otaPackageService.deleteOtaPackage(tenantId, savedFirmware.getId()); .hasMessageContaining("The otaPackage referenced by the device profile cannot be deleted!");
} finally { } finally {
deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId()); deviceProfileService.deleteDeviceProfile(tenantId, savedDeviceProfile.getId());
} }
@ -641,12 +636,18 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmwareInfo.setType(FIRMWARE); firmwareInfo.setType(FIRMWARE);
firmwareInfo.setTitle(TITLE); firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(VERSION); firmwareInfo.setVersion(VERSION);
firmwareInfo.setUrl(" "); firmwareInfo.setUrl(" ");
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true))
thrown.expectMessage("Ota package URL should be specified!"); .as("firmwareInfo url set whitespaces")
otaPackageService.saveOtaPackageInfo(firmwareInfo, true); .isInstanceOf(DataValidationException.class)
.hasMessageContaining("Ota package URL should be specified!");
firmwareInfo.setUrl(""); firmwareInfo.setUrl("");
otaPackageService.saveOtaPackageInfo(firmwareInfo, true); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true))
.as("firmwareInfo url is empty")
.isInstanceOf(DataValidationException.class)
.hasMessageContaining("Ota package URL should be specified!");
} }
@Test @Test
@ -660,12 +661,10 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmwareInfo.setTenantId(tenantId); firmwareInfo.setTenantId(tenantId);
OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo, true); OtaPackageInfo savedFirmwareInfo = otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
thrown.expect(DataValidationException.class);
thrown.expectMessage("Updating otaPackage URL is prohibited!");
savedFirmwareInfo.setUrl("https://newurl.com"); savedFirmwareInfo.setUrl("https://newurl.com");
otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, true); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(savedFirmwareInfo, true))
.isInstanceOf(DataValidationException.class)
.hasMessageContaining("Updating otaPackage URL is prohibited!");
} }
@Test @Test
@ -678,10 +677,9 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmwareInfo.setUrl(URL); firmwareInfo.setUrl(URL);
firmwareInfo.setTenantId(tenantId); firmwareInfo.setTenantId(tenantId);
thrown.expect(DataValidationException.class); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true))
thrown.expectMessage("title length must be equal or less than 255"); .isInstanceOf(DataValidationException.class)
.hasMessageContaining("title length must be equal or less than 255");
otaPackageService.saveOtaPackageInfo(firmwareInfo, true);
} }
@Test @Test
@ -692,11 +690,11 @@ public abstract class BaseOtaPackageServiceTest extends AbstractServiceTest {
firmwareInfo.setUrl(URL); firmwareInfo.setUrl(URL);
firmwareInfo.setTenantId(tenantId); firmwareInfo.setTenantId(tenantId);
firmwareInfo.setTitle(TITLE); firmwareInfo.setTitle(TITLE);
firmwareInfo.setVersion(StringUtils.random(257)); firmwareInfo.setVersion(StringUtils.random(257));
thrown.expectMessage("version length must be equal or less than 255");
otaPackageService.saveOtaPackageInfo(firmwareInfo, true); assertThatThrownBy(() -> otaPackageService.saveOtaPackageInfo(firmwareInfo, true))
.isInstanceOf(DataValidationException.class)
.hasMessageContaining("version length must be equal or less than 255");
} }
private OtaPackage createAndSaveFirmware(TenantId tenantId, String version) { private OtaPackage createAndSaveFirmware(TenantId tenantId, String version) {